2015-02-05 18:15:16 +00:00
|
|
|
package identify
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2016-05-31 23:24:11 +00:00
|
|
|
pstore "github.com/ipfs/go-libp2p-peerstore"
|
2016-04-27 19:45:16 +00:00
|
|
|
ma "github.com/jbenet/go-multiaddr"
|
2015-02-05 18:15:16 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ObservedAddr is an entry for an address reported by our peers.
|
|
|
|
// We only use addresses that:
|
|
|
|
// - have been observed more than once. (counter symmetric nats)
|
|
|
|
// - have been observed recently (10min), because our position in the
|
|
|
|
// network, or network port mapppings, may have changed.
|
|
|
|
type ObservedAddr struct {
|
2015-06-07 23:47:34 +00:00
|
|
|
Addr ma.Multiaddr
|
|
|
|
SeenBy map[string]struct{}
|
|
|
|
LastSeen time.Time
|
2015-02-05 18:15:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ObservedAddrSet keeps track of a set of ObservedAddrs
|
|
|
|
// the zero-value is ready to be used.
|
|
|
|
type ObservedAddrSet struct {
|
|
|
|
sync.Mutex // guards whole datastruct.
|
|
|
|
|
2015-06-07 23:47:34 +00:00
|
|
|
addrs map[string]*ObservedAddr
|
2015-02-05 18:15:16 +00:00
|
|
|
ttl time.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
func (oas *ObservedAddrSet) Addrs() []ma.Multiaddr {
|
|
|
|
oas.Lock()
|
|
|
|
defer oas.Unlock()
|
|
|
|
|
|
|
|
// for zero-value.
|
|
|
|
if oas.addrs == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
now := time.Now()
|
|
|
|
addrs := make([]ma.Multiaddr, 0, len(oas.addrs))
|
|
|
|
for s, a := range oas.addrs {
|
|
|
|
// remove timed out addresses.
|
|
|
|
if now.Sub(a.LastSeen) > oas.ttl {
|
|
|
|
delete(oas.addrs, s)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// we only use an address if we've seen it more than once
|
|
|
|
// because symmetric nats may cause all our peers to see
|
|
|
|
// different port numbers and thus report always different
|
|
|
|
// addresses (different ports) for us. These wouldn't be
|
|
|
|
// very useful. We make the assumption that if we've
|
|
|
|
// connected to two different peers, and they both have
|
|
|
|
// reported seeing the same address, it is probably useful.
|
2015-06-07 23:47:34 +00:00
|
|
|
//
|
|
|
|
// Note: make sure not to double count observers.
|
|
|
|
if len(a.SeenBy) > 1 {
|
2015-02-05 18:15:16 +00:00
|
|
|
addrs = append(addrs, a.Addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return addrs
|
|
|
|
}
|
|
|
|
|
2015-06-07 23:47:34 +00:00
|
|
|
func (oas *ObservedAddrSet) Add(addr ma.Multiaddr, observer ma.Multiaddr) {
|
2015-02-05 18:15:16 +00:00
|
|
|
oas.Lock()
|
|
|
|
defer oas.Unlock()
|
|
|
|
|
|
|
|
// for zero-value.
|
|
|
|
if oas.addrs == nil {
|
2015-06-07 23:47:34 +00:00
|
|
|
oas.addrs = make(map[string]*ObservedAddr)
|
2016-05-31 23:24:11 +00:00
|
|
|
oas.ttl = pstore.OwnObservedAddrTTL
|
2015-02-05 18:15:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s := addr.String()
|
2015-06-07 23:47:34 +00:00
|
|
|
oa, found := oas.addrs[s]
|
|
|
|
|
|
|
|
// first time seeing address.
|
|
|
|
if !found {
|
|
|
|
oa = &ObservedAddr{
|
|
|
|
Addr: addr,
|
|
|
|
SeenBy: make(map[string]struct{}),
|
|
|
|
}
|
|
|
|
oas.addrs[s] = oa
|
2015-02-05 18:15:16 +00:00
|
|
|
}
|
2015-06-07 23:47:34 +00:00
|
|
|
|
2015-06-08 00:00:56 +00:00
|
|
|
// mark the observer
|
|
|
|
oa.SeenBy[observerGroup(observer)] = struct{}{}
|
2015-06-07 23:47:34 +00:00
|
|
|
oa.LastSeen = time.Now()
|
2015-02-05 18:15:16 +00:00
|
|
|
}
|
|
|
|
|
2015-06-08 00:00:56 +00:00
|
|
|
// observerGroup is a function that determines what part of
|
|
|
|
// a multiaddr counts as a different observer. for example,
|
|
|
|
// two ipfs nodes at the same IP/TCP transport would get
|
|
|
|
// the exact same NAT mapping; they would count as the
|
|
|
|
// same observer. This may protect against NATs who assign
|
|
|
|
// different ports to addresses at different IP hosts, but
|
|
|
|
// not TCP ports.
|
|
|
|
//
|
|
|
|
// Here, we use the root multiaddr address. This is mostly
|
|
|
|
// IP addresses. In practice, this is what we want.
|
|
|
|
func observerGroup(m ma.Multiaddr) string {
|
|
|
|
return ma.Split(m)[0].String()
|
|
|
|
}
|
|
|
|
|
2015-02-05 18:15:16 +00:00
|
|
|
func (oas *ObservedAddrSet) SetTTL(ttl time.Duration) {
|
|
|
|
oas.Lock()
|
|
|
|
defer oas.Unlock()
|
|
|
|
oas.ttl = ttl
|
|
|
|
}
|
|
|
|
|
|
|
|
func (oas *ObservedAddrSet) TTL() time.Duration {
|
|
|
|
oas.Lock()
|
|
|
|
defer oas.Unlock()
|
|
|
|
// for zero-value.
|
|
|
|
if oas.addrs == nil {
|
2016-05-31 23:24:11 +00:00
|
|
|
oas.ttl = pstore.OwnObservedAddrTTL
|
2015-02-05 18:15:16 +00:00
|
|
|
}
|
|
|
|
return oas.ttl
|
|
|
|
}
|