github.com/anacrolix/torrent@v1.61.0/config.go (about) 1 package torrent 2 3 import ( 4 "context" 5 "log/slog" 6 "net" 7 "net/http" 8 "net/url" 9 "time" 10 11 "github.com/anacrolix/dht/v2" 12 "github.com/anacrolix/dht/v2/krpc" 13 "github.com/anacrolix/log" 14 "github.com/anacrolix/missinggo/v2" 15 16 "github.com/pion/webrtc/v4" 17 "golang.org/x/time/rate" 18 19 "github.com/anacrolix/torrent/iplist" 20 "github.com/anacrolix/torrent/metainfo" 21 22 "github.com/anacrolix/torrent/mse" 23 "github.com/anacrolix/torrent/storage" 24 "github.com/anacrolix/torrent/version" 25 ) 26 27 // Contains config elements that are exclusive to tracker handling. There may be other fields in 28 // ClientConfig that are also relevant. 29 type ClientTrackerConfig struct { 30 // Don't announce to trackers. This only leaves DHT to discover peers. 31 DisableTrackers bool `long:"disable-trackers"` 32 // Defines DialContext func to use for HTTP tracker announcements 33 TrackerDialContext func(ctx context.Context, network, addr string) (net.Conn, error) 34 // Defines ListenPacket func to use for UDP tracker announcements 35 TrackerListenPacket func(network, addr string) (net.PacketConn, error) 36 // Deprecated. Takes a tracker's hostname and requests DNS A and AAAA records. Used in case DNS lookups 37 // require a special setup (i.e., dns-over-https). TODO: Wire back into UDP tracker client 38 // implementation, or deprecate in favour of a Client DNS resolver. It was done manually before 39 // calling the Announce.Do wrapper. 40 LookupTrackerIp func(*url.URL) ([]net.IP, error) 41 } 42 43 type ClientDhtConfig struct { 44 // Don't create a DHT. 45 // cfg.NoDHT aka cfg.DisableDHT 46 NoDHT bool `long:"disable-dht"` 47 DhtStartingNodes func(network string) dht.StartingNodesGetter 48 // Called for each anacrolix/dht Server created for the Client. 49 ConfigureAnacrolixDhtServer func(*dht.ServerConfig) 50 PeriodicallyAnnounceTorrentsToDht bool 51 // OnQuery hook func 52 DHTOnQuery func(query *krpc.Msg, source net.Addr) (propagate bool) 53 } 54 55 // Probably not safe to modify this after it's given to a Client, or to pass it to multiple Clients. 56 type ClientConfig struct { 57 ClientTrackerConfig 58 ClientDhtConfig 59 MetainfoSourcesConfig 60 61 // Store torrent file data in this directory unless DefaultStorage is 62 // specified. 63 DataDir string `long:"data-dir" description:"directory to store downloaded torrent data"` 64 // The address to listen for new uTP and TCP BitTorrent protocol connections. DHT shares a UDP 65 // socket with uTP unless configured otherwise. 66 ListenHost func(network string) string 67 ListenPort int 68 // cfg.NoDefaultPortForwarding aka cfg.DisableUpnp 69 NoDefaultPortForwarding bool 70 UpnpID string 71 DisablePEX bool `long:"disable-pex"` 72 73 // Never send chunks to peers. 74 NoUpload bool `long:"no-upload"` 75 // Disable uploading even when it isn't fair. 76 DisableAggressiveUpload bool `long:"disable-aggressive-upload"` 77 // Upload even after there's nothing in it for us. By default uploading is 78 // not altruistic, we'll only upload to encourage the peer to reciprocate. 79 Seed bool `long:"seed"` 80 // Only applies to chunks uploaded to peers, to maintain responsiveness communicating local 81 // Client state to peers. Each limiter token represents one byte. The Limiter's burst must be 82 // large enough to fit a whole chunk, which is usually 16 KiB (see TorrentSpec.ChunkSize). If 83 // limit is not Inf, and burst is left at 0, the implementation will choose a suitable burst. 84 UploadRateLimiter *rate.Limiter 85 // Rate limits all reads from connections to peers. Each limiter token represents one byte. The 86 // Limiter's burst must be bigger than the largest Read performed on the underlying 87 // rate-limiting io.Reader minus one. This is likely to be the larger of the main read loop 88 // buffer (~4096), and the requested chunk size (~16KiB, see TorrentSpec.ChunkSize). If limit is 89 // not Inf, and burst is left at 0, the implementation will choose a suitable burst. 90 // 91 // If the field is nil, no rate limiting is applied. And it can't be adjusted dynamically. 92 DownloadRateLimiter *rate.Limiter 93 // Maximum unverified bytes across all torrents. Not used if zero. 94 MaxUnverifiedBytes int64 95 96 // User-provided Client peer ID. If not present, one is generated automatically. 97 PeerID string 98 // For the bittorrent protocol. 99 DisableUTP bool 100 // For the bittorrent protocol. 101 DisableTCP bool `long:"disable-tcp"` 102 // Called to instantiate storage for each added torrent. Builtin backends 103 // are in the storage package. If not set, the "file" implementation is 104 // used (and Closed when the Client is Closed). 105 DefaultStorage storage.ClientImpl 106 107 HeaderObfuscationPolicy HeaderObfuscationPolicy 108 // The crypto methods to offer when initiating connections with header obfuscation. 109 CryptoProvides mse.CryptoMethod 110 // Chooses the crypto method to use when receiving connections with header obfuscation. 111 CryptoSelector mse.CryptoSelector 112 113 IPBlocklist iplist.Ranger 114 DisableIPv6 bool `long:"disable-ipv6"` 115 DisableIPv4 bool 116 DisableIPv4Peers bool 117 // Perform logging and any other behaviour that will help debug. 118 Debug bool `help:"enable debugging"` 119 // If Slogger is set, will be forwarded automatically to Slogger. This is recommended. 120 Logger log.Logger 121 // If unset, falls back to deferring to the old analog Logger. 122 Slogger *slog.Logger 123 124 // Used for torrent sources and webseeding if set. 125 WebTransport http.RoundTripper 126 // Defines proxy for HTTP requests, such as for trackers. It's commonly set from the result of 127 // "net/http".ProxyURL(HTTPProxy). 128 HTTPProxy func(*http.Request) (*url.URL, error) 129 // Defines DialContext func to use for HTTP requests, such as for fetching metainfo and webtorrent seeds 130 HTTPDialContext func(ctx context.Context, network, addr string) (net.Conn, error) 131 // HTTPUserAgent changes default UserAgent for HTTP requests 132 HTTPUserAgent string 133 // HttpRequestDirector modifies the request before it's sent. 134 // Useful for adding authentication headers, for example 135 HttpRequestDirector func(*http.Request) error 136 // WebsocketTrackerHttpHeader returns a custom header to be used when dialing a websocket connection 137 // to the tracker. Useful for adding authentication headers 138 WebsocketTrackerHttpHeader func() http.Header 139 // Updated occasionally to when there's been some changes to client 140 // behaviour in case other clients are assuming anything of us. See also 141 // `bep20`. 142 ExtendedHandshakeClientVersion string 143 // Peer ID client identifier prefix. We'll update this occasionally to 144 // reflect changes to client behaviour that other clients may depend on. 145 // Also see `extendedHandshakeClientVersion`. 146 Bep20 string 147 148 // Peer dial timeout to use when there are limited peers. 149 NominalDialTimeout time.Duration 150 // Minimum peer dial timeout to use (even if we have lots of peers). 151 MinDialTimeout time.Duration 152 EstablishedConnsPerTorrent int 153 HalfOpenConnsPerTorrent int 154 TotalHalfOpenConns int 155 // Maximum number of peer addresses in reserve. 156 TorrentPeersHighWater int 157 // Minumum number of peers before effort is made to obtain more peers. 158 TorrentPeersLowWater int 159 160 // Limit how long handshake can take. This is to reduce the lingering 161 // impact of a few bad apples. 4s loses 1% of successful handshakes that 162 // are obtained with 60s timeout, and 5% of unsuccessful handshakes. 163 HandshakesTimeout time.Duration 164 // How long between writes before sending a keep alive message on a peer connection that we want 165 // to maintain. 166 KeepAliveTimeout time.Duration 167 // Maximum bytes to buffer per peer connection for peer request data before it is sent. This 168 // must be >= the request chunk size from peers. 169 MaxAllocPeerRequestDataPerConn int 170 171 // The IP addresses as our peers should see them. May differ from the 172 // local interfaces due to NAT or other network configurations. 173 PublicIp4 net.IP 174 PublicIp6 net.IP 175 176 // Accept rate limiting affects excessive connection attempts from IPs that fail during 177 // handshakes or request torrents that we don't have. 178 DisableAcceptRateLimiting bool 179 // Don't add connections that have the same peer ID as an existing 180 // connection for a given Torrent. 181 DropDuplicatePeerIds bool 182 // Drop peers that are complete if we are also complete and have no use for the peer. This is a 183 // bit of a special case, since a peer could also be useless if they're just not interested, or 184 // we don't intend to obtain all of a torrent's data. 185 DropMutuallyCompletePeers bool 186 // Use dialers to obtain connections to regular peers. 187 DialForPeerConns bool 188 // Whether to accept peer connections at all. 189 AcceptPeerConnections bool 190 // Whether a Client should want conns without delegating to any attached Torrents. This is 191 // useful when torrents might be added dynamically in callbacks for example. 192 AlwaysWantConns bool 193 194 Extensions PeerExtensionBits 195 // Bits that peers must have set to proceed past handshakes. 196 MinPeerExtensions PeerExtensionBits 197 198 DisableWebtorrent bool 199 DisableWebseeds bool 200 201 Callbacks Callbacks 202 203 // ICEServerList defines a slice describing servers available to be used by 204 // ICE, such as STUN and TURN servers. 205 ICEServerList []webrtc.ICEServer 206 207 // Deprecated. ICEServers does not support server authentication and therefore 208 // it cannot be used with most TURN servers. Use ICEServerList instead. 209 // ICEServers is kept for legacy support. 210 ICEServers []string 211 212 DialRateLimiter *rate.Limiter 213 214 PieceHashersPerTorrent int // default: 2 215 } 216 217 func (cfg *ClientConfig) SetListenAddr(addr string) *ClientConfig { 218 host, port, err := missinggo.ParseHostPort(addr) 219 if err != nil { 220 panic(err) 221 } 222 cfg.ListenHost = func(string) string { return host } 223 cfg.ListenPort = port 224 return cfg 225 } 226 227 func NewDefaultClientConfig() *ClientConfig { 228 cc := &ClientConfig{ 229 HTTPUserAgent: version.DefaultHttpUserAgent, 230 ExtendedHandshakeClientVersion: version.DefaultExtendedHandshakeClientVersion, 231 Bep20: version.DefaultBep20Prefix, 232 UpnpID: version.DefaultUpnpId, 233 NominalDialTimeout: 20 * time.Second, 234 MinDialTimeout: 3 * time.Second, 235 EstablishedConnsPerTorrent: 50, 236 HalfOpenConnsPerTorrent: 25, 237 TotalHalfOpenConns: 100, 238 TorrentPeersHighWater: 500, 239 TorrentPeersLowWater: 50, 240 HandshakesTimeout: 4 * time.Second, 241 KeepAliveTimeout: time.Minute, 242 MaxAllocPeerRequestDataPerConn: 1 << 20, 243 ListenHost: func(string) string { return "" }, 244 UploadRateLimiter: unlimited, 245 DisableAcceptRateLimiting: true, 246 DropMutuallyCompletePeers: true, 247 HeaderObfuscationPolicy: HeaderObfuscationPolicy{ 248 Preferred: true, 249 RequirePreferred: false, 250 }, 251 CryptoSelector: mse.DefaultCryptoSelector, 252 CryptoProvides: mse.AllSupportedCrypto, 253 ListenPort: 42069, 254 Extensions: defaultPeerExtensionBytes(), 255 DialForPeerConns: true, 256 AcceptPeerConnections: true, 257 MaxUnverifiedBytes: 64 << 20, 258 DialRateLimiter: rate.NewLimiter(10, 10), 259 PieceHashersPerTorrent: 2, 260 } 261 cc.DhtStartingNodes = func(network string) dht.StartingNodesGetter { 262 return func() ([]dht.Addr, error) { return dht.GlobalBootstrapAddrs(network) } 263 } 264 cc.PeriodicallyAnnounceTorrentsToDht = true 265 cc.MetainfoSourcesMerger = func(t *Torrent, info *metainfo.MetaInfo) error { 266 return t.MergeSpec(TorrentSpecFromMetaInfo(info)) 267 } 268 return cc 269 } 270 271 type HeaderObfuscationPolicy struct { 272 RequirePreferred bool // Whether the value of Preferred is a strict requirement. 273 Preferred bool // Whether header obfuscation is preferred. 274 } 275 276 func (cfg *ClientConfig) setRateLimiterBursts() { 277 // What about chunk size? 278 if cfg.UploadRateLimiter.Burst() == 0 { 279 cfg.UploadRateLimiter.SetBurst(cfg.MaxAllocPeerRequestDataPerConn) 280 } 281 setDefaultDownloadRateLimiterBurstIfZero(cfg.DownloadRateLimiter) 282 } 283 284 // Returns the download rate.Limit handling the special nil case. 285 func EffectiveDownloadRateLimit(l *rate.Limiter) rate.Limit { 286 if l == nil { 287 return rate.Inf 288 } 289 return l.Limit() 290 } 291 292 type MetainfoSourcesConfig struct { 293 // Used for torrent metainfo sources only. Falls back to the http.Client created to wrap 294 // WebTransport. 295 MetainfoSourcesClient *http.Client 296 // If a sources successfully fetches metainfo, this function is called to apply the metainfo. t 297 // is provided to prevent a race as the fetcher for the source was bound to it. Returning an 298 // error will kill the respective sourcer. 299 MetainfoSourcesMerger func(t *Torrent, info *metainfo.MetaInfo) error 300 }