]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Add support for disabling IPv4 and IPv4 peers
authorMatt Joiner <anacrolix@gmail.com>
Thu, 15 Feb 2018 23:46:11 +0000 (10:46 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Thu, 15 Feb 2018 23:46:11 +0000 (10:46 +1100)
client.go
client_test.go
config.go
utp.go

index 6eb1e5fa244a337a92448bfc6fbf171b4da76aac..18ff016c7848bb98fd6f9fafa65222e88dac6273 100644 (file)
--- a/client.go
+++ b/client.go
@@ -309,13 +309,10 @@ func NewClient(cfg *Config) (cl *Client, err error) {
        cl.tcpListener, cl.utpSock, cl.listenAddr, err = listen(
                !cl.config.DisableTCP,
                !cl.config.DisableUTP,
-               func() string {
-                       if cl.config.DisableIPv6 {
-                               return "4"
-                       } else {
-                               return ""
-                       }
-               }(),
+               // We'll listen to IPv4 for TCP even if IPv4 peer connections are
+               // disabled because we want to ensure peers don't connect to some
+               // other process on that port.
+               ipNetworkSuffix(!cl.config.DisableIPv4, !cl.config.DisableIPv6),
                cl.config.ListenAddr)
        if err != nil {
                return
@@ -419,6 +416,21 @@ func (cl *Client) waitAccept() {
        }
 }
 
+func (cl *Client) rejectAccepted(conn net.Conn) bool {
+       ra := conn.RemoteAddr()
+       rip := missinggo.AddrIP(ra)
+       if cl.config.DisableIPv4Peers && rip.To4() != nil {
+               return true
+       }
+       if cl.config.DisableIPv4 && len(rip) == net.IPv4len {
+               return true
+       }
+       if cl.config.DisableIPv6 && len(rip) == net.IPv6len && rip.To4() == nil {
+               return true
+       }
+       return cl.badPeerIPPort(rip, missinggo.AddrPort(ra))
+}
+
 func (cl *Client) acceptConnections(l net.Listener, utp bool) {
        cl.mu.Lock()
        defer cl.mu.Unlock()
@@ -440,35 +452,20 @@ func (cl *Client) acceptConnections(l net.Listener, utp bool) {
                        // routine just fucked off.
                        return
                }
+               log.Fmsg("accepted connection from %s", conn.RemoteAddr()).AddValue(debugLogValue).Log(cl.logger)
+               go torrent.Add(fmt.Sprintf("accepted conn remote IP len=%d", len(missinggo.AddrIP(conn.RemoteAddr()))), 1)
+               go torrent.Add(fmt.Sprintf("accepted conn network=%s", conn.RemoteAddr().Network()), 1)
                if utp {
-                       torrent.Add("accepted utp connections", 1)
+                       go torrent.Add("accepted utp connections", 1)
                } else {
-                       torrent.Add("accepted tcp connections", 1)
-               }
-               torrent.Add(fmt.Sprintf("accepted conn with network %q", conn.RemoteAddr().Network()), 1)
-               remoteIP := missinggo.AddrIP(conn.RemoteAddr())
-               if remoteIP.To4() != nil {
-                       torrent.Add("accepted conn from ipv4 address", 1)
-               } else if remoteIP.To16() != nil {
-                       torrent.Add("accepted conn from ipv6 address", 1)
-               } else {
-                       torrent.Add("accepted conn from unknown ip address type", 1)
-               }
-               if cl.config.Debug {
-                       log.Printf("accepted connection from %s", conn.RemoteAddr())
+                       go torrent.Add("accepted tcp connections", 1)
                }
-               reject := cl.badPeerIPPort(
-                       missinggo.AddrIP(conn.RemoteAddr()),
-                       missinggo.AddrPort(conn.RemoteAddr()))
-               if reject {
-                       if cl.config.Debug {
-                               log.Printf("rejecting connection from %s", conn.RemoteAddr())
-                       }
-                       torrent.Add("rejected accepted connection", 1)
+               if cl.rejectAccepted(conn) {
+                       go torrent.Add("rejected accepted connections", 1)
                        conn.Close()
-                       continue
+               } else {
+                       go cl.incomingConnection(conn, utp)
                }
-               go cl.incomingConnection(conn, utp)
        }
 }
 
@@ -524,9 +521,12 @@ func (cl *Client) dopplegangerAddr(addr string) bool {
 
 func (cl *Client) dialTCP(ctx context.Context, addr string) (c net.Conn, err error) {
        d := net.Dialer{
+       // Can't bind to the listen address, even though we intend to create an
+       // endpoint pair that is distinct. Oh well.
+
        // LocalAddr: cl.tcpListener.Addr(),
        }
-       c, err = d.DialContext(ctx, "tcp", addr)
+       c, err = d.DialContext(ctx, "tcp"+ipNetworkSuffix(!cl.config.DisableIPv4 && !cl.config.DisableIPv4Peers, !cl.config.DisableIPv6), addr)
        countDialResult(err)
        if err == nil {
                c.(*net.TCPConn).SetLinger(0)
@@ -535,8 +535,37 @@ func (cl *Client) dialTCP(ctx context.Context, addr string) (c net.Conn, err err
        return
 }
 
+func (cl *Client) utpDialNetwork() string {
+       // We want to restrict the addr resolve inside the utp library to the
+       // correct network, since the utp Socket may be listening to a broader
+       // network for DHT purposes or otherwise.
+       if !cl.config.DisableIPv4Peers {
+               return ""
+       }
+       n := cl.utpSock.Addr().Network()
+       switch n {
+       case "udp", "udp4", "udp6":
+               return "udp6"
+       default:
+               panic(n)
+       }
+}
+
+func ipNetworkSuffix(allowIpv4, allowIpv6 bool) string {
+       switch {
+       case allowIpv4 && allowIpv6:
+               return ""
+       case allowIpv4 && !allowIpv6:
+               return "4"
+       case !allowIpv4 && allowIpv6:
+               return "6"
+       default:
+               panic("unhandled ip network combination")
+       }
+}
+
 func (cl *Client) dialUTP(ctx context.Context, addr string) (c net.Conn, err error) {
-       c, err = cl.utpSock.DialContext(ctx, addr)
+       c, err = cl.utpSock.DialContext(ctx, cl.utpDialNetwork(), addr)
        countDialResult(err)
        return
 }
index 597785e223ed505b7a59742ac8f7e64f413504e7..d0d88cdf8fc5b5b99122dcc775495c735dfd00e6 100644 (file)
@@ -1,6 +1,7 @@
 package torrent
 
 import (
+       "context"
        "encoding/binary"
        "fmt"
        "io"
@@ -171,7 +172,7 @@ func TestUTPRawConn(t *testing.T) {
        s, err := NewUtpSocket("udp", "")
        require.NoError(t, err)
        defer s.Close()
-       utpPeer, err := s.Dial(fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr())))
+       utpPeer, err := s.DialContext(context.Background(), "", fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr())))
        require.NoError(t, err)
        defer utpPeer.Close()
        peer, err := net.ListenPacket("udp", ":0")
index b02f1af7c34cef138f9180a744fe3a9136c3a157..ff222b325e828e7d4093e5ed0cfc65034eea4d75 100644 (file)
--- a/config.go
+++ b/config.go
@@ -77,8 +77,10 @@ type Config struct {
 
        EncryptionPolicy
 
-       IPBlocklist iplist.Ranger
-       DisableIPv6 bool `long:"disable-ipv6"`
+       IPBlocklist      iplist.Ranger
+       DisableIPv6      bool `long:"disable-ipv6"`
+       DisableIPv4      bool
+       DisableIPv4Peers bool
        // Perform logging and any other behaviour that will help debug.
        Debug bool `help:"enable debugging"`
 
diff --git a/utp.go b/utp.go
index aafd574e0b320e6d4a68c20f38bc235862f06a78..3066ca0923fce265ef365a86b813686cb030bd8a 100644 (file)
--- a/utp.go
+++ b/utp.go
@@ -13,6 +13,6 @@ type utpSocket interface {
        Accept() (net.Conn, error)
        Addr() net.Addr
        // net.Dialer but there's no interface.
-       DialContext(ctx context.Context, addr string) (net.Conn, error)
-       Dial(addr string) (net.Conn, error)
+       DialContext(ctx context.Context, network, addr string) (net.Conn, error)
+       // Dial(addr string) (net.Conn, error)
 }