2020-06-07 13:43:15 +08:00
|
|
|
// Copyright 2020 xgfone
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package dht
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"time"
|
2023-03-01 22:50:46 +08:00
|
|
|
|
|
|
|
"github.com/xgfone/bt/krpc"
|
2020-06-07 13:43:15 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Blacklist is used to manage the ip blacklist.
|
|
|
|
//
|
|
|
|
// Notice: The implementation should clear the address existed for long time.
|
|
|
|
type Blacklist interface {
|
|
|
|
// In reports whether the address, ip and port, is in the blacklist.
|
2023-03-01 22:50:46 +08:00
|
|
|
In(krpc.Addr) bool
|
2020-06-07 13:43:15 +08:00
|
|
|
|
|
|
|
// If port is equal to 0, it should ignore port and only use ip when matching.
|
2023-03-01 22:50:46 +08:00
|
|
|
Add(krpc.Addr)
|
2020-06-07 13:43:15 +08:00
|
|
|
|
|
|
|
// If port is equal to 0, it should delete the address by only the ip.
|
2023-03-01 22:50:46 +08:00
|
|
|
Del(krpc.Addr)
|
2020-06-07 13:43:15 +08:00
|
|
|
|
2023-03-01 22:50:46 +08:00
|
|
|
// Close is used to notice the implementation to release the underlying resource.
|
2020-06-07 13:43:15 +08:00
|
|
|
Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
type noopBlacklist struct{}
|
|
|
|
|
2023-03-01 22:50:46 +08:00
|
|
|
func (nbl noopBlacklist) In(krpc.Addr) bool { return false }
|
|
|
|
func (nbl noopBlacklist) Add(krpc.Addr) {}
|
|
|
|
func (nbl noopBlacklist) Del(krpc.Addr) {}
|
|
|
|
func (nbl noopBlacklist) Close() {}
|
2020-06-07 13:43:15 +08:00
|
|
|
|
|
|
|
// NewNoopBlacklist returns a no-op Blacklist.
|
|
|
|
func NewNoopBlacklist() Blacklist { return noopBlacklist{} }
|
|
|
|
|
|
|
|
// DebugBlacklist returns a new Blacklist to log the information as debug.
|
|
|
|
func DebugBlacklist(bl Blacklist, logf func(string, ...interface{})) Blacklist {
|
|
|
|
return logBlacklist{Blacklist: bl, logf: logf}
|
|
|
|
}
|
|
|
|
|
|
|
|
type logBlacklist struct {
|
|
|
|
Blacklist
|
|
|
|
logf func(string, ...interface{})
|
|
|
|
}
|
|
|
|
|
2023-03-01 22:50:46 +08:00
|
|
|
func (l logBlacklist) Add(addr krpc.Addr) {
|
|
|
|
l.logf("add the addr '%s' into the blacklist", addr.String())
|
|
|
|
l.Blacklist.Add(addr)
|
2020-06-07 13:43:15 +08:00
|
|
|
}
|
|
|
|
|
2023-03-01 22:50:46 +08:00
|
|
|
func (l logBlacklist) Del(addr krpc.Addr) {
|
|
|
|
l.logf("delete the addr '%s' from the blacklist", addr.String())
|
|
|
|
l.Blacklist.Del(addr)
|
2020-06-07 13:43:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
|
|
|
|
|
|
// NewMemoryBlacklist returns a blacklst implementation based on memory.
|
|
|
|
//
|
|
|
|
// if maxnum is equal to 0, no limit.
|
|
|
|
func NewMemoryBlacklist(maxnum int, duration time.Duration) Blacklist {
|
|
|
|
bl := &blacklist{
|
|
|
|
num: maxnum,
|
|
|
|
ips: make(map[string]*wrappedPort, 128),
|
|
|
|
exit: make(chan struct{}),
|
|
|
|
}
|
|
|
|
go bl.loop(duration)
|
|
|
|
return bl
|
|
|
|
}
|
|
|
|
|
|
|
|
type wrappedPort struct {
|
|
|
|
Time time.Time
|
|
|
|
Enable bool
|
2023-03-01 22:50:46 +08:00
|
|
|
Ports map[uint16]struct{}
|
2020-06-07 13:43:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type blacklist struct {
|
|
|
|
exit chan struct{}
|
|
|
|
lock sync.RWMutex
|
|
|
|
ips map[string]*wrappedPort
|
|
|
|
num int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bl *blacklist) loop(interval time.Duration) {
|
|
|
|
tick := time.NewTicker(interval)
|
|
|
|
defer tick.Stop()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-bl.exit:
|
|
|
|
return
|
|
|
|
case now := <-tick.C:
|
|
|
|
bl.lock.Lock()
|
|
|
|
for ip, wp := range bl.ips {
|
|
|
|
if now.Sub(wp.Time) > interval {
|
|
|
|
delete(bl.ips, ip)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bl.lock.Unlock()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bl *blacklist) Close() {
|
|
|
|
select {
|
|
|
|
case <-bl.exit:
|
|
|
|
default:
|
|
|
|
close(bl.exit)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// In reports whether the address, ip and port, is in the blacklist.
|
2023-03-01 22:50:46 +08:00
|
|
|
func (bl *blacklist) In(addr krpc.Addr) (yes bool) {
|
2020-06-07 13:43:15 +08:00
|
|
|
bl.lock.RLock()
|
2023-03-01 22:50:46 +08:00
|
|
|
if wp, ok := bl.ips[addr.IP.String()]; ok {
|
2020-06-07 13:43:15 +08:00
|
|
|
if wp.Enable {
|
2023-03-01 22:50:46 +08:00
|
|
|
_, yes = wp.Ports[addr.Port]
|
2020-06-07 13:43:15 +08:00
|
|
|
} else {
|
|
|
|
yes = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bl.lock.RUnlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-01 22:50:46 +08:00
|
|
|
func (bl *blacklist) Add(addr krpc.Addr) {
|
|
|
|
ip := addr.IP.String()
|
2020-06-07 13:43:15 +08:00
|
|
|
bl.lock.Lock()
|
|
|
|
wp, ok := bl.ips[ip]
|
|
|
|
if !ok {
|
|
|
|
if bl.num > 0 && len(bl.ips) >= bl.num {
|
|
|
|
bl.lock.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
wp = &wrappedPort{Enable: true}
|
|
|
|
bl.ips[ip] = wp
|
|
|
|
}
|
|
|
|
|
2023-03-01 22:50:46 +08:00
|
|
|
if addr.Port < 1 {
|
2020-06-07 13:43:15 +08:00
|
|
|
wp.Enable = false
|
|
|
|
wp.Ports = nil
|
|
|
|
} else if wp.Ports == nil {
|
2023-03-01 22:50:46 +08:00
|
|
|
wp.Ports = map[uint16]struct{}{addr.Port: {}}
|
2020-06-07 13:43:15 +08:00
|
|
|
} else {
|
2023-03-01 22:50:46 +08:00
|
|
|
wp.Ports[addr.Port] = struct{}{}
|
2020-06-07 13:43:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
wp.Time = time.Now()
|
|
|
|
bl.lock.Unlock()
|
|
|
|
}
|
|
|
|
|
2023-03-01 22:50:46 +08:00
|
|
|
func (bl *blacklist) Del(addr krpc.Addr) {
|
|
|
|
ip := addr.IP.String()
|
2020-06-07 13:43:15 +08:00
|
|
|
bl.lock.Lock()
|
|
|
|
if wp, ok := bl.ips[ip]; ok {
|
2023-03-01 22:50:46 +08:00
|
|
|
if addr.Port < 1 {
|
2020-06-07 13:43:15 +08:00
|
|
|
delete(bl.ips, ip)
|
|
|
|
} else if wp.Enable {
|
|
|
|
switch len(wp.Ports) {
|
|
|
|
case 0, 1:
|
|
|
|
delete(bl.ips, ip)
|
|
|
|
default:
|
2023-03-01 22:50:46 +08:00
|
|
|
delete(wp.Ports, addr.Port)
|
2020-06-07 13:43:15 +08:00
|
|
|
wp.Time = time.Now()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bl.lock.Unlock()
|
|
|
|
}
|