-
-
Notifications
You must be signed in to change notification settings - Fork 66
/
dht.go
163 lines (143 loc) · 5.32 KB
/
dht.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package dht
import (
"context"
"crypto"
_ "crypto/sha1"
"errors"
"math/rand"
"net"
"time"
"github.com/anacrolix/log"
"github.com/anacrolix/missinggo/v2"
"github.com/anacrolix/torrent/iplist"
"github.com/anacrolix/torrent/metainfo"
"golang.org/x/time/rate"
"github.com/anacrolix/dht/v2/bep44"
"github.com/anacrolix/dht/v2/krpc"
peer_store "github.com/anacrolix/dht/v2/peer-store"
"github.com/anacrolix/dht/v2/transactions"
)
func defaultQueryResendDelay() time.Duration {
// This should be the highest reasonable UDP latency an end-user might have.
return 2 * time.Second
}
type transactionKey = transactions.Key
type StartingNodesGetter func() ([]Addr, error)
// ServerConfig allows setting up a configuration of the `Server` instance to be created with
// NewServer.
type ServerConfig struct {
// Set NodeId Manually. Caller must ensure that if NodeId does not conform
// to DHT Security Extensions, that NoSecurity is also set.
NodeId krpc.ID
Conn net.PacketConn
// Don't respond to queries from other nodes.
Passive bool
// Whether to wait for rate limiting to allow us to reply.
WaitToReply bool
// Called when there are no good nodes to use in the routing table. This might be called any
// time when there are no nodes, including during bootstrap if one is performed. Typically it
// returns the resolve addresses of bootstrap or "router" nodes that are designed to kick-start
// a routing table.
StartingNodes StartingNodesGetter
// Disable the DHT security extension: http://www.libtorrent.org/dht_sec.html.
NoSecurity bool
// Initial IP blocklist to use. Applied before serving and bootstrapping
// begins.
IPBlocklist iplist.Ranger
// Used to secure the server's ID. Defaults to the Conn's LocalAddr(). Set to the IP that remote
// nodes will see, as that IP is what they'll use to validate our ID.
PublicIP net.IP
// Hook received queries. Return false if you don't want to propagate to the default handlers.
OnQuery func(query *krpc.Msg, source net.Addr) (propagate bool)
// Called when a peer successfully announces to us.
OnAnnouncePeer func(infoHash metainfo.Hash, ip net.IP, port int, portOk bool)
// How long to wait before resending queries that haven't received a response. Defaults to 2s.
// After the last send, a query is aborted after this time.
QueryResendDelay func() time.Duration
// TODO: Expose Peers, to return NodeInfo for received get_peers queries.
PeerStore peer_store.Interface
// BEP-44: Storing arbitrary data in the DHT. If not store provided, a default in-memory
// implementation will be used.
Store bep44.Store
// BEP-44: expiration time with non-announced items. Two hours by default
Exp time.Duration
// If no Logger is provided, log.Default is used and log.Debug messages are filtered out. Note
// that all messages without a log.Level, have log.Debug added to them before being passed to
// this Logger.
Logger log.Logger
DefaultWant []krpc.Want
SendLimiter *rate.Limiter
}
// ServerStats instance is returned by Server.Stats() and stores Server metrics
type ServerStats struct {
// Count of nodes in the node table that responded to our last query or
// haven't yet been queried.
GoodNodes int
// Count of nodes in the node table.
Nodes int
// Transactions awaiting a response.
OutstandingTransactions int
// Individual announce_peer requests that got a success response.
SuccessfulOutboundAnnouncePeerQueries int64
// Nodes that have been blocked.
BadNodes uint
OutboundQueriesAttempted int64
}
func jitterDuration(average time.Duration, plusMinus time.Duration) time.Duration {
return average - plusMinus/2 + time.Duration(rand.Int63n(int64(plusMinus)))
}
type Peer = krpc.NodeAddr
var DefaultGlobalBootstrapHostPorts = []string{
"router.utorrent.com:6881",
"router.bittorrent.com:6881",
"dht.transmissionbt.com:6881",
"dht.aelitis.com:6881", // Vuze
"router.silotis.us:6881", // IPv6
"dht.libtorrent.org:25401", // @arvidn's
"dht.anacrolix.link:42069",
"router.bittorrent.cloud:42069",
}
// Returns the resolved addresses of the default global bootstrap nodes. Network is unused but was
// historically passed by anacrolix/torrent.
func GlobalBootstrapAddrs(network string) ([]Addr, error) {
return ResolveHostPorts(DefaultGlobalBootstrapHostPorts)
}
// Resolves host:port strings to dht.Addrs, using the dht DNS resolver cache. Suitable for use with
// ServerConfig.BootstrapAddrs.
func ResolveHostPorts(hostPorts []string) (addrs []Addr, err error) {
initDnsResolver()
for _, s := range hostPorts {
host, port, err := net.SplitHostPort(s)
if err != nil {
panic(err)
}
hostAddrs, err := dnsResolver.LookupHost(context.Background(), host)
if err != nil {
// log.Default.WithDefaultLevel(log.Debug).Printf("error looking up %q: %v", s, err)
continue
}
for _, a := range hostAddrs {
ua, err := net.ResolveUDPAddr("udp", net.JoinHostPort(a, port))
if err != nil {
log.Printf("error resolving %q: %v", a, err)
continue
}
addrs = append(addrs, NewAddr(ua))
}
}
if len(addrs) == 0 {
err = errors.New("nothing resolved")
}
return
}
// Deprecated: Use function from krpc.
func RandomNodeID() (id krpc.ID) {
return krpc.RandomNodeID()
}
func MakeDeterministicNodeID(public net.Addr) (id krpc.ID) {
h := crypto.SHA1.New()
h.Write([]byte(public.String()))
h.Sum(id[:0:20])
SecureNodeId(&id, missinggo.AddrIP(public))
return
}