Add ability to set DialContext/ListenPacket for tracker announcements (#760)
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.
This commit is contained in:
parent
75cc4e98d4
commit
f120b93e1c
@ -1,6 +1,7 @@
|
|||||||
package torrent
|
package torrent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"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
|
// Defines proxy for HTTP requests, such as for trackers. It's commonly set from the result of
|
||||||
// "net/http".ProxyURL(HTTPProxy).
|
// "net/http".ProxyURL(HTTPProxy).
|
||||||
HTTPProxy func(*http.Request) (*url.URL, error)
|
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.
|
// 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)
|
// Used in case DNS lookups require a special setup (i.e., dns-over-https)
|
||||||
LookupTrackerIp func(*url.URL) ([]net.IP, error)
|
LookupTrackerIp func(*url.URL) ([]net.IP, error)
|
||||||
|
@ -2,6 +2,7 @@ package tracker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/anacrolix/log"
|
"github.com/anacrolix/log"
|
||||||
@ -19,8 +20,9 @@ type AnnounceOpt = trHttp.AnnounceOpt
|
|||||||
type NewClientOpts struct {
|
type NewClientOpts struct {
|
||||||
Http trHttp.NewClientOpts
|
Http trHttp.NewClientOpts
|
||||||
// Overrides the network in the scheme. Probably a legacy thing.
|
// Overrides the network in the scheme. Probably a legacy thing.
|
||||||
UdpNetwork string
|
UdpNetwork string
|
||||||
Logger log.Logger
|
Logger log.Logger
|
||||||
|
ListenPacket func(network, addr string) (net.PacketConn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(urlStr string, opts NewClientOpts) (Client, error) {
|
func NewClient(urlStr string, opts NewClientOpts) (Client, error) {
|
||||||
@ -37,9 +39,10 @@ func NewClient(urlStr string, opts NewClientOpts) (Client, error) {
|
|||||||
network = opts.UdpNetwork
|
network = opts.UdpNetwork
|
||||||
}
|
}
|
||||||
cc, err := udp.NewConnClient(udp.NewConnClientOpts{
|
cc, err := udp.NewConnClient(udp.NewConnClientOpts{
|
||||||
Network: network,
|
Network: network,
|
||||||
Host: _url.Host,
|
Host: _url.Host,
|
||||||
Logger: opts.Logger,
|
Logger: opts.Logger,
|
||||||
|
ListenPacket: opts.ListenPacket,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
@ -12,9 +14,11 @@ type Client struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProxyFunc func(*http.Request) (*url.URL, error)
|
type ProxyFunc func(*http.Request) (*url.URL, error)
|
||||||
|
type DialContextFunc func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||||
|
|
||||||
type NewClientOpts struct {
|
type NewClientOpts struct {
|
||||||
Proxy ProxyFunc
|
Proxy ProxyFunc
|
||||||
|
DialContext DialContextFunc
|
||||||
ServerName string
|
ServerName string
|
||||||
AllowKeepAlive bool
|
AllowKeepAlive bool
|
||||||
}
|
}
|
||||||
@ -24,6 +28,7 @@ func NewClient(url_ *url.URL, opts NewClientOpts) Client {
|
|||||||
url_: url_,
|
url_: url_,
|
||||||
hc: &http.Client{
|
hc: &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
|
DialContext: opts.DialContext,
|
||||||
Proxy: opts.Proxy,
|
Proxy: opts.Proxy,
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
@ -33,13 +34,15 @@ type AnnounceEvent = udp.AnnounceEvent
|
|||||||
var ErrBadScheme = errors.New("unknown scheme")
|
var ErrBadScheme = errors.New("unknown scheme")
|
||||||
|
|
||||||
type Announce struct {
|
type Announce struct {
|
||||||
TrackerUrl string
|
TrackerUrl string
|
||||||
Request AnnounceRequest
|
Request AnnounceRequest
|
||||||
HostHeader string
|
HostHeader string
|
||||||
HTTPProxy func(*http.Request) (*url.URL, error)
|
HTTPProxy func(*http.Request) (*url.URL, error)
|
||||||
ServerName string
|
DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||||
UserAgent string
|
ListenPacket func(network, addr string) (net.PacketConn, error)
|
||||||
UdpNetwork string
|
ServerName string
|
||||||
|
UserAgent string
|
||||||
|
UdpNetwork string
|
||||||
// If the port is zero, it's assumed to be the same as the Request.Port.
|
// If the port is zero, it's assumed to be the same as the Request.Port.
|
||||||
ClientIp4 krpc.NodeAddr
|
ClientIp4 krpc.NodeAddr
|
||||||
// If the port is zero, it's assumed to be the same as the Request.Port.
|
// 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) {
|
func (me Announce) Do() (res AnnounceResponse, err error) {
|
||||||
cl, err := NewClient(me.TrackerUrl, NewClientOpts{
|
cl, err := NewClient(me.TrackerUrl, NewClientOpts{
|
||||||
Http: trHttp.NewClientOpts{
|
Http: trHttp.NewClientOpts{
|
||||||
Proxy: me.HTTPProxy,
|
Proxy: me.HTTPProxy,
|
||||||
ServerName: me.ServerName,
|
DialContext: me.DialContext,
|
||||||
|
ServerName: me.ServerName,
|
||||||
},
|
},
|
||||||
UdpNetwork: me.UdpNetwork,
|
UdpNetwork: me.UdpNetwork,
|
||||||
Logger: me.Logger.WithContextValue(fmt.Sprintf("tracker client for %q", me.TrackerUrl)),
|
Logger: me.Logger.WithContextValue(fmt.Sprintf("tracker client for %q", me.TrackerUrl)),
|
||||||
|
ListenPacket: me.ListenPacket,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"github.com/anacrolix/missinggo/v2"
|
"github.com/anacrolix/missinggo/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type listenPacketFunc func(network, addr string) (net.PacketConn, error)
|
||||||
|
|
||||||
type NewConnClientOpts struct {
|
type NewConnClientOpts struct {
|
||||||
// The network to operate to use, such as "udp4", "udp", "udp6".
|
// The network to operate to use, such as "udp4", "udp", "udp6".
|
||||||
Network string
|
Network string
|
||||||
@ -18,6 +20,8 @@ type NewConnClientOpts struct {
|
|||||||
Ipv6 *bool
|
Ipv6 *bool
|
||||||
// Logger to use for internal errors.
|
// Logger to use for internal errors.
|
||||||
Logger log.Logger
|
Logger log.Logger
|
||||||
|
// Custom function to use as a substitute for net.ListenPacket
|
||||||
|
ListenPacket listenPacketFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manages a Client with a specific connection.
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -156,17 +156,19 @@ func (me *trackerScraper) announce(ctx context.Context, event tracker.AnnounceEv
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
me.t.logger.WithDefaultLevel(log.Debug).Printf("announcing to %q: %#v", me.u.String(), req)
|
me.t.logger.WithDefaultLevel(log.Debug).Printf("announcing to %q: %#v", me.u.String(), req)
|
||||||
res, err := tracker.Announce{
|
res, err := tracker.Announce{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
HTTPProxy: me.t.cl.config.HTTPProxy,
|
HTTPProxy: me.t.cl.config.HTTPProxy,
|
||||||
UserAgent: me.t.cl.config.HTTPUserAgent,
|
DialContext: me.t.cl.config.TrackerDialContext,
|
||||||
TrackerUrl: me.trackerUrl(ip),
|
ListenPacket: me.t.cl.config.TrackerListenPacket,
|
||||||
Request: req,
|
UserAgent: me.t.cl.config.HTTPUserAgent,
|
||||||
HostHeader: me.u.Host,
|
TrackerUrl: me.trackerUrl(ip),
|
||||||
ServerName: me.u.Hostname(),
|
Request: req,
|
||||||
UdpNetwork: me.u.Scheme,
|
HostHeader: me.u.Host,
|
||||||
ClientIp4: krpc.NodeAddr{IP: me.t.cl.config.PublicIp4},
|
ServerName: me.u.Hostname(),
|
||||||
ClientIp6: krpc.NodeAddr{IP: me.t.cl.config.PublicIp6},
|
UdpNetwork: me.u.Scheme,
|
||||||
Logger: me.t.logger,
|
ClientIp4: krpc.NodeAddr{IP: me.t.cl.config.PublicIp4},
|
||||||
|
ClientIp6: krpc.NodeAddr{IP: me.t.cl.config.PublicIp6},
|
||||||
|
Logger: me.t.logger,
|
||||||
}.Do()
|
}.Do()
|
||||||
me.t.logger.WithDefaultLevel(log.Debug).Printf("announce to %q returned %#v: %v", me.u.String(), res, err)
|
me.t.logger.WithDefaultLevel(log.Debug).Printf("announce to %q returned %#v: %v", me.u.String(), res, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user