config: Add --whitelist support.

This commit is contained in:
David Hill 2017-08-31 09:59:43 -04:00
parent 42b969a827
commit a2085c68f8
4 changed files with 79 additions and 2 deletions

View file

@ -103,6 +103,7 @@ type config struct {
DisableBanning bool `long:"nobanning" description:"Disable banning of misbehaving peers"`
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
Whitelists []string `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"`
RPCUser string `short:"u" long:"rpcuser" description:"Username for RPC connections"`
RPCPass string `short:"P" long:"rpcpass" default-mask:"-" description:"Password for RPC connections"`
RPCLimitUser string `long:"rpclimituser" description:"Username for limited RPC connections"`
@ -163,6 +164,7 @@ type config struct {
addCheckpoints []chaincfg.Checkpoint
miningAddrs []btcutil.Address
minRelayTxFee btcutil.Amount
whitelists []*net.IPNet
}
// serviceOptions defines the configuration options for the daemon as a service on
@ -630,6 +632,38 @@ func loadConfig() (*config, []string, error) {
return nil, nil, err
}
// Validate any given whitelisted IP addresses and networks.
if len(cfg.Whitelists) > 0 {
var ip net.IP
cfg.whitelists = make([]*net.IPNet, 0, len(cfg.Whitelists))
for _, addr := range cfg.Whitelists {
_, ipnet, err := net.ParseCIDR(addr)
if err != nil {
ip = net.ParseIP(addr)
if ip == nil {
str := "%s: The whitelist value of '%s' is invalid"
err = fmt.Errorf(str, funcName, addr)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
var bits int
if ip.To4() == nil {
// IPv6
bits = 128
} else {
bits = 32
}
ipnet = &net.IPNet{
IP: ip,
Mask: net.CIDRMask(bits, bits),
}
}
cfg.whitelists = append(cfg.whitelists, ipnet)
}
}
// --addPeer and --connect do not mix.
if len(cfg.AddPeers) > 0 && len(cfg.ConnectPeers) > 0 {
str := "%s: the --addpeer and --connect options can not be " +

6
doc.go
View file

@ -35,10 +35,12 @@ Application Options:
(default all interfaces port: 8333, testnet: 18333)
--maxpeers= Max number of inbound and outbound peers (125)
--nobanning Disable banning of misbehaving peers
--banthreshold= Maximum allowed ban score before disconnecting and
banning misbehaving peers.
--banduration= How long to ban misbehaving peers. Valid time units
are {s, m, h}. Minimum 1 second (24h0m0s)
--banthreshold= Maximum allowed ban score before disconnecting and
banning misbehaving peers.
--whitelist= Add an IP network or IP that will not be banned.
(eg. 192.168.1.0/24 or ::1)
-u, --rpcuser= Username for RPC connections
-P, --rpcpass= Password for RPC connections
--rpclimituser= Username for limited RPC connections

View file

@ -114,6 +114,13 @@
; banduration=24h
; banduration=11h30m15s
; Add whitelisted IP networks and IPs. Connected peers whose IP matches a
; whitelist will not have their ban score increased.
; whitelist=127.0.0.1
; whitelist=::1
; whitelist=192.168.0.0/24
; whitelist=fd00::/16
; Disable DNS seeding for peers. By default, when btcd starts, it will use
; DNS to query for available peers to connect with.
; nodnsseed=1

View file

@ -223,6 +223,7 @@ type serverPeer struct {
relayMtx sync.Mutex
disableRelayTx bool
sentAddrs bool
isWhitelisted bool
filter *bloom.Filter
knownAddresses map[string]struct{}
banScore connmgr.DynamicBanScore
@ -315,6 +316,11 @@ func (sp *serverPeer) addBanScore(persistent, transient uint32, reason string) {
if cfg.DisableBanning {
return
}
if sp.isWhitelisted {
peerLog.Debugf("Misbehaving whitelisted peer %s: %s", sp, reason)
return
}
warnThreshold := cfg.BanThreshold >> 1
if transient == 0 && persistent == 0 {
// The score is not being increased, but a warning message is still
@ -1590,6 +1596,7 @@ func newPeerConfig(sp *serverPeer) *peer.Config {
// for disconnection.
func (s *server) inboundPeerConnected(conn net.Conn) {
sp := newServerPeer(s, false)
sp.isWhitelisted = isWhitelisted(conn.RemoteAddr())
sp.Peer = peer.NewInboundPeer(newPeerConfig(sp))
sp.AssociateConnection(conn)
go s.peerDoneHandler(sp)
@ -1609,6 +1616,7 @@ func (s *server) outboundPeerConnected(c *connmgr.ConnReq, conn net.Conn) {
}
sp.Peer = p
sp.connReq = c
sp.isWhitelisted = isWhitelisted(conn.RemoteAddr())
sp.AssociateConnection(conn)
go s.peerDoneHandler(sp)
s.addrManager.Attempt(sp.NA())
@ -2599,6 +2607,32 @@ func dynamicTickDuration(remaining time.Duration) time.Duration {
return time.Hour
}
// isWhitelisted returns whether the IP address is included in the whitelisted
// networks and IPs.
func isWhitelisted(addr net.Addr) bool {
if len(cfg.whitelists) == 0 {
return false
}
host, _, err := net.SplitHostPort(addr.String())
if err != nil {
srvrLog.Warnf("Unable to SplitHostPort on '%s': %v", addr, err)
return false
}
ip := net.ParseIP(host)
if ip == nil {
srvrLog.Warnf("Unable to parse IP '%s'", addr)
return false
}
for _, ipnet := range cfg.whitelists {
if ipnet.Contains(ip) {
return true
}
}
return false
}
// checkpointSorter implements sort.Interface to allow a slice of checkpoints to
// be sorted.
type checkpointSorter []chaincfg.Checkpoint