From 7477fe4d0ff86b42316b07618b150b3b181e3948 Mon Sep 17 00:00:00 2001 From: Jin Qing <1091147665@qq.com> Date: Sat, 30 Sep 2017 09:50:02 +0800 Subject: [PATCH] Add rule to judge if node is bad Judge whether the peer is bad before connect it. If it is bad won't connect it. Signed-off-by: Jin Qing <1091147665@qq.com> --- net/message/address.go | 4 +- net/node/knowaddrlist.go | 127 ++++++++++++++++++++++++++++++++++++++- net/protocol/protocol.go | 2 + 3 files changed, 128 insertions(+), 5 deletions(-) diff --git a/net/message/address.go b/net/message/address.go index 6366a2e2..8e4b56db 100644 --- a/net/message/address.go +++ b/net/message/address.go @@ -93,9 +93,7 @@ func (msg addrReq) Handle(node Noder) error { var addrstr []NodeAddr var count uint64 - //select atmost 8 addr from know address list to send - addrtmp := []NodeAddr{} - addrstr = node.LocalNode().RandGetAddresses(addrtmp) + addrstr = node.LocalNode().RandSelectAddresses() count = uint64(len(addrstr)) buf, err := NewAddrs(addrstr, count) if err != nil { diff --git a/net/node/knowaddrlist.go b/net/node/knowaddrlist.go index d0813e5b..32d905f1 100644 --- a/net/node/knowaddrlist.go +++ b/net/node/knowaddrlist.go @@ -5,16 +5,26 @@ import ( . "DNA/net/protocol" "math/rand" "sync" + "time" ) const ( // needAddressThreshold is the number of addresses under which the // address manager will claim to need more addresses. needAddressThreshold = 1000 + // numMissingDays is the number of days before which we assume an + // address has vanished if we have not seen it announced in that long. + numMissingDays = 30 + // numRetries is the number of tried without a single success before + // we assume an address is bad. + numRetries = 10 ) type KnownAddress struct { - srcAddr NodeAddr + srcAddr NodeAddr + lastattempt time.Time + lastDisconnect time.Time + attempts int } type KnownAddressList struct { @@ -23,6 +33,82 @@ type KnownAddressList struct { addrCount uint64 } +func (ka *KnownAddress) LastAttempt() time.Time { + return ka.lastattempt +} + +func (ka *KnownAddress) increaseAttempts() { + ka.attempts++ +} + +func (ka *KnownAddress) updateLastAttempt() { + // set last tried time to now + ka.lastattempt = time.Now() +} + +func (ka *KnownAddress) updateLastDisconnect() { + // set last disconnect time to now + ka.lastDisconnect = time.Now() +} + +// chance returns the selection probability for a known address. The priority +// depends upon how recently the address has been seen, how recently it was last +// attempted and how often attempts to connect to it have failed. +func (ka *KnownAddress) chance() float64 { + now := time.Now() + lastAttempt := now.Sub(ka.lastattempt) + + if lastAttempt < 0 { + lastAttempt = 0 + } + + c := 1.0 + + // Very recent attempts are less likely to be retried. + if lastAttempt < 10*time.Minute { + c *= 0.01 + } + + // Failed attempts deprioritise. + for i := ka.attempts; i > 0; i-- { + c /= 1.5 + } + + return c +} + +// isBad returns true if the address in question has not been tried in the last +// minute and meets one of the following criteria: +// 1) Just tried in one minute +// 2) It hasn't been seen in over a month +// 3) It has failed at least ten times +// 4) It has failed ten times in the last week +// All addresses that meet these criteria are assumed to be worthless and not +// worth keeping hold of. +func (ka *KnownAddress) isBad() bool { + // just tried in one minute? + if ka.lastattempt.After(time.Now().Add(-1 * time.Minute)) { + return false + } + + // Over a month old? + if ka.srcAddr.Time < (time.Now().Add(-1 * numMissingDays * time.Hour * 24)).UnixNano() { + return true + } + + // Just disconnected in one minute? + if ka.lastDisconnect.After(time.Now().Add(-1 * time.Minute)) { + return true + } + + // tried too many times? + if ka.attempts >= numRetries { + return true + } + + return false +} + func (ka *KnownAddress) SaveAddr(na NodeAddr) { ka.srcAddr.Time = na.Time ka.srcAddr.Services = na.Services @@ -51,6 +137,11 @@ func (al *KnownAddressList) AddressExisted(uid uint64) bool { return ok } +func (al *KnownAddressList) UpdateLastDisconn(id uint64) { + ka := al.List[id] + ka.updateLastDisconnect() +} + func (al *KnownAddressList) AddAddressToKnownAddress(na NodeAddr) { al.Lock() defer al.Unlock() @@ -105,7 +196,8 @@ func (al *KnownAddressList) RandGetAddresses(nbrAddrs []NodeAddr) []NodeAddr { var keys []uint64 for k := range al.List { isInNbr := isInNbrList(k, nbrAddrs) - if isInNbr == false { + isBad := al.List[k].isBad() + if isInNbr == false && isBad == false { keys = append(keys, k) } } @@ -131,6 +223,8 @@ func (al *KnownAddressList) RandGetAddresses(nbrAddrs []NodeAddr) []NodeAddr { if !ok { continue } + ka.increaseAttempts() + ka.updateLastAttempt() addrs = append(addrs, ka.srcAddr) keys = append(keys[:j], keys[j+1:]...) break @@ -141,3 +235,32 @@ func (al *KnownAddressList) RandGetAddresses(nbrAddrs []NodeAddr) []NodeAddr { return addrs } + +func (al *KnownAddressList) RandSelectAddresses() []NodeAddr { + al.RLock() + defer al.RUnlock() + var keys []uint64 + addrs := []NodeAddr{} + for k := range al.List { + keys = append(keys, k) + } + addrLen := len(keys) + + var count int + if MAXOUTBOUNDCNT > addrLen { + count = addrLen + } else { + count = MAXOUTBOUNDCNT + } + for i, v := range keys { + if i < count { + ka, ok := al.List[v] + if !ok { + continue + } + addrs = append(addrs, ka.srcAddr) + } + } + + return addrs +} diff --git a/net/protocol/protocol.go b/net/protocol/protocol.go index 67f5e51c..dd08c9a3 100644 --- a/net/protocol/protocol.go +++ b/net/protocol/protocol.go @@ -149,6 +149,8 @@ type Noder interface { GetMaxOutboundCnt() uint GetGetAddrMax() uint NeedMoreAddresses() bool + RandSelectAddresses() []NodeAddr + UpdateLastDisconn(id uint64) } func (msg *NodeAddr) Deserialization(p []byte) error {