]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Add ability to set DialContext/ListenPacket for tracker announcements (#760)
authorCraig Campbell <me@craig.is>
Thu, 7 Jul 2022 05:51:58 +0000 (01:51 -0400)
committerGitHub <noreply@github.com>
Thu, 7 Jul 2022 05:51:58 +0000 (15:51 +1000)
This is useful if you want to use a custom dialer to proxy requests via
an external server since the HTTPProxy can only be used with tcp
trackers and not udp.

config.go
tracker/client.go
tracker/http/client.go
tracker/tracker.go
tracker/udp/conn-client.go
tracker_scraper.go

index 398fdd33cd2dee57271b55be9818708b8a363153..11e70d6830f45dd616f75e774ba732f1c889ee5a 100644 (file)
--- a/config.go
+++ b/config.go
@@ -1,6 +1,7 @@
 package torrent
 
 import (
+       "context"
        "net"
        "net/http"
        "net/url"
@@ -90,6 +91,10 @@ type ClientConfig struct {
        // Defines proxy for HTTP requests, such as for trackers. It's commonly set from the result of
        // "net/http".ProxyURL(HTTPProxy).
        HTTPProxy func(*http.Request) (*url.URL, error)
+       // Defines DialContext func to use for HTTP tracker announcements
+       TrackerDialContext func(ctx context.Context, network, addr string) (net.Conn, error)
+       // Defines ListenPacket func to use for UDP tracker announcements
+       TrackerListenPacket func(network, addr string) (net.PacketConn, error)
        // Takes a tracker's hostname and requests DNS A and AAAA records.
        // Used in case DNS lookups require a special setup (i.e., dns-over-https)
        LookupTrackerIp func(*url.URL) ([]net.IP, error)
index 1df0aa430aa29aa82d71858346f88f70148839b1..2558da70488d25f2d6112a9af7427465a2e12c1e 100644 (file)
@@ -2,6 +2,7 @@ package tracker
 
 import (
        "context"
+       "net"
        "net/url"
 
        "github.com/anacrolix/log"
@@ -19,8 +20,9 @@ type AnnounceOpt = trHttp.AnnounceOpt
 type NewClientOpts struct {
        Http trHttp.NewClientOpts
        // Overrides the network in the scheme. Probably a legacy thing.
-       UdpNetwork string
-       Logger     log.Logger
+       UdpNetwork   string
+       Logger       log.Logger
+       ListenPacket func(network, addr string) (net.PacketConn, error)
 }
 
 func NewClient(urlStr string, opts NewClientOpts) (Client, error) {
@@ -37,9 +39,10 @@ func NewClient(urlStr string, opts NewClientOpts) (Client, error) {
                        network = opts.UdpNetwork
                }
                cc, err := udp.NewConnClient(udp.NewConnClientOpts{
-                       Network: network,
-                       Host:    _url.Host,
-                       Logger:  opts.Logger,
+                       Network:      network,
+                       Host:         _url.Host,
+                       Logger:       opts.Logger,
+                       ListenPacket: opts.ListenPacket,
                })
                if err != nil {
                        return nil, err
index d0c27a023e8ec7e2496ae517c96702e797f979ca..cd18f65ab30b58a5c9ed128af135f0e72de23937 100644 (file)
@@ -1,7 +1,9 @@
 package http
 
 import (
+       "context"
        "crypto/tls"
+       "net"
        "net/http"
        "net/url"
 )
@@ -12,9 +14,11 @@ type Client struct {
 }
 
 type ProxyFunc func(*http.Request) (*url.URL, error)
+type DialContextFunc func(ctx context.Context, network, addr string) (net.Conn, error)
 
 type NewClientOpts struct {
        Proxy          ProxyFunc
+       DialContext    DialContextFunc
        ServerName     string
        AllowKeepAlive bool
 }
@@ -24,6 +28,7 @@ func NewClient(url_ *url.URL, opts NewClientOpts) Client {
                url_: url_,
                hc: &http.Client{
                        Transport: &http.Transport{
+                               DialContext: opts.DialContext,
                                Proxy: opts.Proxy,
                                TLSClientConfig: &tls.Config{
                                        InsecureSkipVerify: true,
index 7c3a5f6dd4b5394e720df31c92b1a702c9c00a62..a9721c77171511d34fc9c9c44fad51d7a973102e 100644 (file)
@@ -4,6 +4,7 @@ import (
        "context"
        "errors"
        "fmt"
+       "net"
        "net/http"
        "net/url"
        "time"
@@ -33,13 +34,15 @@ type AnnounceEvent = udp.AnnounceEvent
 var ErrBadScheme = errors.New("unknown scheme")
 
 type Announce struct {
-       TrackerUrl string
-       Request    AnnounceRequest
-       HostHeader string
-       HTTPProxy  func(*http.Request) (*url.URL, error)
-       ServerName string
-       UserAgent  string
-       UdpNetwork string
+       TrackerUrl   string
+       Request      AnnounceRequest
+       HostHeader   string
+       HTTPProxy    func(*http.Request) (*url.URL, error)
+       DialContext  func(ctx context.Context, network, addr string) (net.Conn, error)
+       ListenPacket func(network, addr string) (net.PacketConn, error)
+       ServerName   string
+       UserAgent    string
+       UdpNetwork   string
        // If the port is zero, it's assumed to be the same as the Request.Port.
        ClientIp4 krpc.NodeAddr
        // If the port is zero, it's assumed to be the same as the Request.Port.
@@ -54,11 +57,13 @@ const DefaultTrackerAnnounceTimeout = 15 * time.Second
 func (me Announce) Do() (res AnnounceResponse, err error) {
        cl, err := NewClient(me.TrackerUrl, NewClientOpts{
                Http: trHttp.NewClientOpts{
-                       Proxy:      me.HTTPProxy,
-                       ServerName: me.ServerName,
+                       Proxy:       me.HTTPProxy,
+                       DialContext: me.DialContext,
+                       ServerName:  me.ServerName,
                },
-               UdpNetwork: me.UdpNetwork,
-               Logger:     me.Logger.WithContextValue(fmt.Sprintf("tracker client for %q", me.TrackerUrl)),
+               UdpNetwork:   me.UdpNetwork,
+               Logger:       me.Logger.WithContextValue(fmt.Sprintf("tracker client for %q", me.TrackerUrl)),
+               ListenPacket: me.ListenPacket,
        })
        if err != nil {
                return
index 2e1cac79013ae16a08ea6ca9a2b775147ad066b9..f500fc3f2171afb6bde63e8f4776769e54afc21c 100644 (file)
@@ -9,6 +9,8 @@ import (
        "github.com/anacrolix/missinggo/v2"
 )
 
+type listenPacketFunc func(network, addr string) (net.PacketConn, error)
+
 type NewConnClientOpts struct {
        // The network to operate to use, such as "udp4", "udp", "udp6".
        Network string
@@ -18,6 +20,8 @@ type NewConnClientOpts struct {
        Ipv6 *bool
        // Logger to use for internal errors.
        Logger log.Logger
+       // Custom function to use as a substitute for net.ListenPacket
+       ListenPacket listenPacketFunc
 }
 
 // Manages a Client with a specific connection.
@@ -80,7 +84,13 @@ func (me clientWriter) Write(p []byte) (n int, err error) {
 }
 
 func NewConnClient(opts NewConnClientOpts) (cc *ConnClient, err error) {
-       conn, err := net.ListenPacket(opts.Network, ":0")
+       var conn net.PacketConn
+       if opts.ListenPacket != nil {
+               conn, err = opts.ListenPacket(opts.Network, ":0")
+       } else {
+               conn, err = net.ListenPacket(opts.Network, ":0")
+       }
+
        if err != nil {
                return
        }
index b441efb9e7028010a919a63a324383ba53304629..de65d9fbe30b84a512498fc29bcaa2dcf5050d93 100644 (file)
@@ -156,17 +156,19 @@ func (me *trackerScraper) announce(ctx context.Context, event tracker.AnnounceEv
        defer cancel()
        me.t.logger.WithDefaultLevel(log.Debug).Printf("announcing to %q: %#v", me.u.String(), req)
        res, err := tracker.Announce{
-               Context:    ctx,
-               HTTPProxy:  me.t.cl.config.HTTPProxy,
-               UserAgent:  me.t.cl.config.HTTPUserAgent,
-               TrackerUrl: me.trackerUrl(ip),
-               Request:    req,
-               HostHeader: me.u.Host,
-               ServerName: me.u.Hostname(),
-               UdpNetwork: me.u.Scheme,
-               ClientIp4:  krpc.NodeAddr{IP: me.t.cl.config.PublicIp4},
-               ClientIp6:  krpc.NodeAddr{IP: me.t.cl.config.PublicIp6},
-               Logger:     me.t.logger,
+               Context:      ctx,
+               HTTPProxy:    me.t.cl.config.HTTPProxy,
+               DialContext:  me.t.cl.config.TrackerDialContext,
+               ListenPacket: me.t.cl.config.TrackerListenPacket,
+               UserAgent:    me.t.cl.config.HTTPUserAgent,
+               TrackerUrl:   me.trackerUrl(ip),
+               Request:      req,
+               HostHeader:   me.u.Host,
+               ServerName:   me.u.Hostname(),
+               UdpNetwork:   me.u.Scheme,
+               ClientIp4:    krpc.NodeAddr{IP: me.t.cl.config.PublicIp4},
+               ClientIp6:    krpc.NodeAddr{IP: me.t.cl.config.PublicIp6},
+               Logger:       me.t.logger,
        }.Do()
        me.t.logger.WithDefaultLevel(log.Debug).Printf("announce to %q returned %#v: %v", me.u.String(), res, err)
        if err != nil {