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  }