2018-04-12 09:41:07 +08:00
|
|
|
package torrent
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-12-22 16:19:16 +08:00
|
|
|
"fmt"
|
2018-04-12 09:41:07 +08:00
|
|
|
"net"
|
2018-06-08 18:52:36 +08:00
|
|
|
"net/url"
|
2018-04-12 09:41:07 +08:00
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/anacrolix/missinggo"
|
2018-06-15 20:42:05 +08:00
|
|
|
"github.com/anacrolix/missinggo/perf"
|
2018-11-19 17:35:21 +08:00
|
|
|
"github.com/pkg/errors"
|
2018-07-07 09:36:58 +08:00
|
|
|
"golang.org/x/net/proxy"
|
2018-04-12 09:41:07 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type dialer interface {
|
|
|
|
dial(_ context.Context, addr string) (net.Conn, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type socket interface {
|
|
|
|
net.Listener
|
|
|
|
dialer
|
|
|
|
}
|
|
|
|
|
2018-06-08 18:52:36 +08:00
|
|
|
func getProxyDialer(proxyURL string) (proxy.Dialer, error) {
|
|
|
|
fixedURL, err := url.Parse(proxyURL)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return proxy.FromURL(fixedURL, proxy.Direct)
|
|
|
|
}
|
|
|
|
|
2018-11-28 07:30:21 +08:00
|
|
|
func listen(n network, addr, proxyURL string, f firewallCallback) (socket, error) {
|
|
|
|
switch {
|
|
|
|
case n.Tcp:
|
|
|
|
return listenTcp(n.String(), addr, proxyURL)
|
|
|
|
case n.Udp:
|
|
|
|
return listenUtp(n.String(), addr, proxyURL, f)
|
|
|
|
default:
|
|
|
|
panic(n)
|
2018-04-12 09:41:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-08 18:52:36 +08:00
|
|
|
func listenTcp(network, address, proxyURL string) (s socket, err error) {
|
2018-04-12 09:41:07 +08:00
|
|
|
l, err := net.Listen(network, address)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-06-15 12:34:58 +08:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
l.Close()
|
|
|
|
}
|
|
|
|
}()
|
2018-06-08 18:52:36 +08:00
|
|
|
|
|
|
|
// If we don't need the proxy - then we should return default net.Dialer,
|
|
|
|
// otherwise, let's try to parse the proxyURL and return proxy.Dialer
|
|
|
|
if len(proxyURL) != 0 {
|
2019-12-22 16:19:16 +08:00
|
|
|
dl := disabledListener{l}
|
2019-12-31 01:58:06 +08:00
|
|
|
dialer, err := getProxyDialer(proxyURL)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2018-06-08 18:52:36 +08:00
|
|
|
}
|
2019-12-31 01:58:06 +08:00
|
|
|
return tcpSocket{dl, func(ctx context.Context, addr string) (conn net.Conn, err error) {
|
|
|
|
defer perf.ScopeTimerErr(&err)()
|
|
|
|
return dialer.Dial(network, addr)
|
|
|
|
}}, nil
|
2018-06-08 18:52:36 +08:00
|
|
|
}
|
2018-06-15 12:34:58 +08:00
|
|
|
dialer := net.Dialer{}
|
|
|
|
return tcpSocket{l, func(ctx context.Context, addr string) (conn net.Conn, err error) {
|
|
|
|
defer perf.ScopeTimerErr(&err)()
|
|
|
|
return dialer.DialContext(ctx, network, addr)
|
|
|
|
}}, nil
|
2018-04-12 09:41:07 +08:00
|
|
|
}
|
|
|
|
|
2019-12-22 16:19:16 +08:00
|
|
|
type disabledListener struct {
|
|
|
|
net.Listener
|
|
|
|
}
|
|
|
|
|
|
|
|
func (dl disabledListener) Accept() (net.Conn, error) {
|
|
|
|
return nil, fmt.Errorf("tcp listener disabled due to proxy")
|
|
|
|
}
|
|
|
|
|
2018-04-12 09:41:07 +08:00
|
|
|
type tcpSocket struct {
|
|
|
|
net.Listener
|
2018-06-15 12:34:58 +08:00
|
|
|
d func(ctx context.Context, addr string) (net.Conn, error)
|
2018-04-12 09:41:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (me tcpSocket) dial(ctx context.Context, addr string) (net.Conn, error) {
|
2018-06-15 12:34:58 +08:00
|
|
|
return me.d(ctx, addr)
|
2018-04-12 09:41:07 +08:00
|
|
|
}
|
|
|
|
|
2018-11-28 07:30:21 +08:00
|
|
|
func listenAll(networks []network, getHost func(string) string, port int, proxyURL string, f firewallCallback) ([]socket, error) {
|
2018-04-12 09:41:07 +08:00
|
|
|
if len(networks) == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2018-04-12 13:06:53 +08:00
|
|
|
var nahs []networkAndHost
|
|
|
|
for _, n := range networks {
|
2018-11-28 07:30:21 +08:00
|
|
|
nahs = append(nahs, networkAndHost{n, getHost(n.String())})
|
2018-04-12 13:06:53 +08:00
|
|
|
}
|
2018-04-12 09:41:07 +08:00
|
|
|
for {
|
2018-07-25 15:11:09 +08:00
|
|
|
ss, retry, err := listenAllRetry(nahs, port, proxyURL, f)
|
2018-04-12 09:41:07 +08:00
|
|
|
if !retry {
|
|
|
|
return ss, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-12 13:06:53 +08:00
|
|
|
type networkAndHost struct {
|
2018-11-28 07:30:21 +08:00
|
|
|
Network network
|
2018-04-12 13:06:53 +08:00
|
|
|
Host string
|
|
|
|
}
|
|
|
|
|
2018-07-25 15:11:09 +08:00
|
|
|
func listenAllRetry(nahs []networkAndHost, port int, proxyURL string, f firewallCallback) (ss []socket, retry bool, err error) {
|
2018-04-12 13:06:53 +08:00
|
|
|
ss = make([]socket, 1, len(nahs))
|
|
|
|
portStr := strconv.FormatInt(int64(port), 10)
|
2018-07-25 15:11:09 +08:00
|
|
|
ss[0], err = listen(nahs[0].Network, net.JoinHostPort(nahs[0].Host, portStr), proxyURL, f)
|
2018-04-12 09:41:07 +08:00
|
|
|
if err != nil {
|
2018-11-19 17:35:21 +08:00
|
|
|
return nil, false, errors.Wrap(err, "first listen")
|
2018-04-12 09:41:07 +08:00
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if err != nil || retry {
|
|
|
|
for _, s := range ss {
|
|
|
|
s.Close()
|
|
|
|
}
|
|
|
|
ss = nil
|
|
|
|
}
|
|
|
|
}()
|
2018-04-12 13:06:53 +08:00
|
|
|
portStr = strconv.FormatInt(int64(missinggo.AddrPort(ss[0].Addr())), 10)
|
|
|
|
for _, nah := range nahs[1:] {
|
2018-07-25 15:11:09 +08:00
|
|
|
s, err := listen(nah.Network, net.JoinHostPort(nah.Host, portStr), proxyURL, f)
|
2018-04-12 09:41:07 +08:00
|
|
|
if err != nil {
|
|
|
|
return ss,
|
|
|
|
missinggo.IsAddrInUse(err) && port == 0,
|
2018-11-19 17:35:21 +08:00
|
|
|
errors.Wrap(err, "subsequent listen")
|
2018-04-12 09:41:07 +08:00
|
|
|
}
|
|
|
|
ss = append(ss, s)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-07-25 15:11:09 +08:00
|
|
|
type firewallCallback func(net.Addr) bool
|
|
|
|
|
|
|
|
func listenUtp(network, addr, proxyURL string, fc firewallCallback) (s socket, err error) {
|
|
|
|
us, err := NewUtpSocket(network, addr, fc)
|
2018-04-12 09:41:07 +08:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-06-08 18:52:36 +08:00
|
|
|
|
|
|
|
// If we don't need the proxy - then we should return default net.Dialer,
|
|
|
|
// otherwise, let's try to parse the proxyURL and return proxy.Dialer
|
|
|
|
if len(proxyURL) != 0 {
|
2019-12-22 16:19:16 +08:00
|
|
|
ds := disabledUtpSocket{us}
|
2019-12-31 01:58:06 +08:00
|
|
|
dialer, err := getProxyDialer(proxyURL)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2018-06-08 18:52:36 +08:00
|
|
|
}
|
2019-12-31 01:58:06 +08:00
|
|
|
return utpSocketSocket{ds, network, dialer}, nil
|
2018-06-08 18:52:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return utpSocketSocket{us, network, nil}, nil
|
2018-04-12 09:41:07 +08:00
|
|
|
}
|
|
|
|
|
2019-12-22 16:19:16 +08:00
|
|
|
type disabledUtpSocket struct {
|
|
|
|
utpSocket
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ds disabledUtpSocket) Accept() (net.Conn, error) {
|
|
|
|
return nil, fmt.Errorf("utp listener disabled due to proxy")
|
|
|
|
}
|
|
|
|
|
2018-04-12 09:41:07 +08:00
|
|
|
type utpSocketSocket struct {
|
|
|
|
utpSocket
|
|
|
|
network string
|
2018-06-08 18:52:36 +08:00
|
|
|
d proxy.Dialer
|
2018-04-12 09:41:07 +08:00
|
|
|
}
|
|
|
|
|
2018-06-15 20:42:05 +08:00
|
|
|
func (me utpSocketSocket) dial(ctx context.Context, addr string) (conn net.Conn, err error) {
|
|
|
|
defer perf.ScopeTimerErr(&err)()
|
2018-06-08 18:52:36 +08:00
|
|
|
if me.d != nil {
|
|
|
|
return me.d.Dial(me.network, addr)
|
|
|
|
}
|
|
|
|
|
2018-04-12 09:41:07 +08:00
|
|
|
return me.utpSocket.DialContext(ctx, me.network, addr)
|
|
|
|
}
|