Don't expose Peer network through RemoteAddr

This commit is contained in:
Matt Joiner 2021-01-25 14:22:24 +11:00
parent 955e337b78
commit 9f9953be52
6 changed files with 47 additions and 41 deletions

View File

@ -677,7 +677,7 @@ func (cl *Client) initiateProtocolHandshakes(
nc net.Conn, nc net.Conn,
t *Torrent, t *Torrent,
outgoing, encryptHeader bool, outgoing, encryptHeader bool,
remoteAddr net.Addr, remoteAddr PeerRemoteAddr,
network, connString string, network, connString string,
) ( ) (
c *PeerConn, err error, c *PeerConn, err error,
@ -699,7 +699,7 @@ func (cl *Client) initiateProtocolHandshakes(
} }
// Returns nil connection and nil error if no connection could be established for valid reasons. // Returns nil connection and nil error if no connection could be established for valid reasons.
func (cl *Client) establishOutgoingConnEx(t *Torrent, addr net.Addr, obfuscatedHeader bool) (*PeerConn, error) { func (cl *Client) establishOutgoingConnEx(t *Torrent, addr PeerRemoteAddr, obfuscatedHeader bool) (*PeerConn, error) {
dialCtx, cancel := context.WithTimeout(context.Background(), func() time.Duration { dialCtx, cancel := context.WithTimeout(context.Background(), func() time.Duration {
cl.rLock() cl.rLock()
defer cl.rUnlock() defer cl.rUnlock()
@ -723,7 +723,7 @@ func (cl *Client) establishOutgoingConnEx(t *Torrent, addr net.Addr, obfuscatedH
// Returns nil connection and nil error if no connection could be established // Returns nil connection and nil error if no connection could be established
// for valid reasons. // for valid reasons.
func (cl *Client) establishOutgoingConn(t *Torrent, addr net.Addr) (c *PeerConn, err error) { func (cl *Client) establishOutgoingConn(t *Torrent, addr PeerRemoteAddr) (c *PeerConn, err error) {
torrent.Add("establish outgoing connection", 1) torrent.Add("establish outgoing connection", 1)
obfuscatedHeaderFirst := cl.config.HeaderObfuscationPolicy.Preferred obfuscatedHeaderFirst := cl.config.HeaderObfuscationPolicy.Preferred
c, err = cl.establishOutgoingConnEx(t, addr, obfuscatedHeaderFirst) c, err = cl.establishOutgoingConnEx(t, addr, obfuscatedHeaderFirst)
@ -748,7 +748,7 @@ func (cl *Client) establishOutgoingConn(t *Torrent, addr net.Addr) (c *PeerConn,
// Called to dial out and run a connection. The addr we're given is already // Called to dial out and run a connection. The addr we're given is already
// considered half-open. // considered half-open.
func (cl *Client) outgoingConnection(t *Torrent, addr net.Addr, ps PeerSource, trusted bool) { func (cl *Client) outgoingConnection(t *Torrent, addr PeerRemoteAddr, ps PeerSource, trusted bool) {
cl.dialRateLimiter.Wait(context.Background()) cl.dialRateLimiter.Wait(context.Background())
c, err := cl.establishOutgoingConn(t, addr) c, err := cl.establishOutgoingConn(t, addr)
cl.lock() cl.lock()
@ -967,7 +967,7 @@ func (cl *Client) sendInitialMessages(conn *PeerConn, torrent *Torrent) {
// that might be used to cache pending writes. Assuming 512KiB cached for // that might be used to cache pending writes. Assuming 512KiB cached for
// sending, for 16KiB chunks. // sending, for 16KiB chunks.
Reqq: 1 << 5, Reqq: 1 << 5,
YourIp: pp.CompactIp(addrIpOrNil(conn.RemoteAddr)), YourIp: pp.CompactIp(conn.remoteIp()),
Encryption: cl.config.HeaderObfuscationPolicy.Preferred || !cl.config.HeaderObfuscationPolicy.RequirePreferred, Encryption: cl.config.HeaderObfuscationPolicy.Preferred || !cl.config.HeaderObfuscationPolicy.RequirePreferred,
Port: cl.incomingPeerPort(), Port: cl.incomingPeerPort(),
MetadataSize: torrent.metadataSize(), MetadataSize: torrent.metadataSize(),
@ -1062,7 +1062,7 @@ func (cl *Client) gotMetadataExtensionMsg(payload []byte, t *Torrent, c *PeerCon
} }
} }
func (cl *Client) badPeerAddr(addr net.Addr) bool { func (cl *Client) badPeerAddr(addr PeerRemoteAddr) bool {
if ipa, ok := tryIpPortFromNetAddr(addr); ok { if ipa, ok := tryIpPortFromNetAddr(addr); ok {
return cl.badPeerIPPort(ipa.IP, ipa.Port) return cl.badPeerIPPort(ipa.IP, ipa.Port)
} }
@ -1099,7 +1099,8 @@ func (cl *Client) newTorrent(ih metainfo.Hash, specStorage storage.ClientImpl) (
peers: prioritizedPeers{ peers: prioritizedPeers{
om: btree.New(32), om: btree.New(32),
getPrio: func(p PeerInfo) peerPriority { getPrio: func(p PeerInfo) peerPriority {
return bep40PriorityIgnoreError(cl.publicAddr(addrIpOrNil(p.Addr)), p.addr()) ipPort := p.addr()
return bep40PriorityIgnoreError(cl.publicAddr(ipPort.IP), ipPort)
}, },
}, },
conns: make(map[*PeerConn]struct{}, 2*cl.config.EstablishedConnsPerTorrent), conns: make(map[*PeerConn]struct{}, 2*cl.config.EstablishedConnsPerTorrent),
@ -1366,7 +1367,7 @@ func (cl *Client) banPeerIP(ip net.IP) {
cl.badPeerIPs[ip.String()] = struct{}{} cl.badPeerIPs[ip.String()] = struct{}{}
} }
func (cl *Client) newConnection(nc net.Conn, outgoing bool, remoteAddr net.Addr, network, connString string) (c *PeerConn) { func (cl *Client) newConnection(nc net.Conn, outgoing bool, remoteAddr PeerRemoteAddr, network, connString string) (c *PeerConn) {
c = &PeerConn{ c = &PeerConn{
Peer: Peer{ Peer: Peer{
outgoing: outgoing, outgoing: outgoing,
@ -1483,7 +1484,7 @@ func (cl *Client) ListenAddrs() (ret []net.Addr) {
return return
} }
func (cl *Client) onBadAccept(addr net.Addr) { func (cl *Client) onBadAccept(addr PeerRemoteAddr) {
ipa, ok := tryIpPortFromNetAddr(addr) ipa, ok := tryIpPortFromNetAddr(addr)
if !ok { if !ok {
return return

View File

@ -56,12 +56,15 @@ func (me ipPortAddr) String() string {
return net.JoinHostPort(me.IP.String(), strconv.FormatInt(int64(me.Port), 10)) return net.JoinHostPort(me.IP.String(), strconv.FormatInt(int64(me.Port), 10))
} }
func tryIpPortFromNetAddr(na net.Addr) (ret ipPortAddr, ok bool) { func tryIpPortFromNetAddr(addr PeerRemoteAddr) (ipPortAddr, bool) {
ret.IP = addrIpOrNil(na) ok := true
if ret.IP == nil { host, port, err := net.SplitHostPort(addr.String())
return if err != nil {
ok = false
} }
ret.Port = addrPortOrZero(na) portI64, err := strconv.ParseInt(port, 10, 0)
ok = true if err != nil {
return ok = false
}
return ipPortAddr{net.ParseIP(host), int(portI64)}, ok
} }

View File

@ -1,8 +1,6 @@
package torrent package torrent
import ( import (
"net"
"github.com/anacrolix/dht/v2/krpc" "github.com/anacrolix/dht/v2/krpc"
"github.com/anacrolix/torrent/peer_protocol" "github.com/anacrolix/torrent/peer_protocol"
@ -11,7 +9,7 @@ import (
// Peer connection info, handed about publicly. // Peer connection info, handed about publicly.
type PeerInfo struct { type PeerInfo struct {
Id [20]byte Id [20]byte
Addr net.Addr Addr PeerRemoteAddr
Source PeerSource Source PeerSource
// Peer is known to support encryption. // Peer is known to support encryption.
SupportsEncryption bool SupportsEncryption bool
@ -41,5 +39,6 @@ func (me *PeerInfo) FromPex(na krpc.NodeAddr, fs peer_protocol.PexPeerFlags) {
} }
func (me PeerInfo) addr() IpPort { func (me PeerInfo) addr() IpPort {
return IpPort{IP: addrIpOrNil(me.Addr), Port: uint16(addrPortOrZero(me.Addr))} ipPort, _ := tryIpPortFromNetAddr(me.Addr)
return IpPort{ipPort.IP, uint16(ipPort.Port)}
} }

View File

@ -42,6 +42,10 @@ type peerRequestState struct {
data []byte data []byte
} }
type PeerRemoteAddr interface {
String() string
}
type Peer struct { type Peer struct {
// First to ensure 64-bit alignment for atomics. See #262. // First to ensure 64-bit alignment for atomics. See #262.
_stats ConnStats _stats ConnStats
@ -52,7 +56,7 @@ type Peer struct {
outgoing bool outgoing bool
network string network string
RemoteAddr net.Addr RemoteAddr PeerRemoteAddr
// True if the connection is operating over MSE obfuscation. // True if the connection is operating over MSE obfuscation.
headerEncrypted bool headerEncrypted bool
cryptoMethod mse.CryptoMethod cryptoMethod mse.CryptoMethod
@ -169,7 +173,7 @@ func (cn *Peer) expectingChunks() bool {
// Returns true if the connection is over IPv6. // Returns true if the connection is over IPv6.
func (cn *PeerConn) ipv6() bool { func (cn *PeerConn) ipv6() bool {
ip := addrIpOrNil(cn.RemoteAddr) ip := cn.remoteIp()
if ip.To4() != nil { if ip.To4() != nil {
return false return false
} }
@ -1626,7 +1630,8 @@ func (c *Peer) peerPriority() (peerPriority, error) {
} }
func (c *Peer) remoteIp() net.IP { func (c *Peer) remoteIp() net.IP {
return addrIpOrNil(c.RemoteAddr) host, _, _ := net.SplitHostPort(c.RemoteAddr.String())
return net.ParseIP(host)
} }
func (c *Peer) remoteIpPort() IpPort { func (c *Peer) remoteIpPort() IpPort {
@ -1642,7 +1647,7 @@ func (c *PeerConn) pexPeerFlags() pp.PexPeerFlags {
if c.outgoing { if c.outgoing {
f |= pp.PexOutgoingConn f |= pp.PexOutgoingConn
} }
if c.RemoteAddr != nil && strings.Contains(c.RemoteAddr.Network(), "udp") { if c.utp() {
f |= pp.PexSupportsUtp f |= pp.PexSupportsUtp
} }
return f return f
@ -1650,7 +1655,7 @@ func (c *PeerConn) pexPeerFlags() pp.PexPeerFlags {
// This returns the address to use if we want to dial the peer again. It incorporates the peer's // This returns the address to use if we want to dial the peer again. It incorporates the peer's
// advertised listen port. // advertised listen port.
func (c *PeerConn) dialAddr() net.Addr { func (c *PeerConn) dialAddr() PeerRemoteAddr {
if !c.outgoing && c.PeerListenPort != 0 { if !c.outgoing && c.PeerListenPort != 0 {
switch addr := c.RemoteAddr.(type) { switch addr := c.RemoteAddr.(type) {
case *net.TCPAddr: case *net.TCPAddr:

View File

@ -159,10 +159,10 @@ func TestConnPexPeerFlags(t *testing.T) {
{&PeerConn{Peer: Peer{outgoing: false, PeerPrefersEncryption: true}}, pp.PexPrefersEncryption}, {&PeerConn{Peer: Peer{outgoing: false, PeerPrefersEncryption: true}}, pp.PexPrefersEncryption},
{&PeerConn{Peer: Peer{outgoing: true, PeerPrefersEncryption: false}}, pp.PexOutgoingConn}, {&PeerConn{Peer: Peer{outgoing: true, PeerPrefersEncryption: false}}, pp.PexOutgoingConn},
{&PeerConn{Peer: Peer{outgoing: true, PeerPrefersEncryption: true}}, pp.PexOutgoingConn | pp.PexPrefersEncryption}, {&PeerConn{Peer: Peer{outgoing: true, PeerPrefersEncryption: true}}, pp.PexOutgoingConn | pp.PexPrefersEncryption},
{&PeerConn{Peer: Peer{RemoteAddr: udpAddr}}, pp.PexSupportsUtp}, {&PeerConn{Peer: Peer{RemoteAddr: udpAddr, network: udpAddr.Network()}}, pp.PexSupportsUtp},
{&PeerConn{Peer: Peer{RemoteAddr: udpAddr, outgoing: true}}, pp.PexOutgoingConn | pp.PexSupportsUtp}, {&PeerConn{Peer: Peer{RemoteAddr: udpAddr, network: udpAddr.Network(), outgoing: true}}, pp.PexOutgoingConn | pp.PexSupportsUtp},
{&PeerConn{Peer: Peer{RemoteAddr: tcpAddr, outgoing: true}}, pp.PexOutgoingConn}, {&PeerConn{Peer: Peer{RemoteAddr: tcpAddr, network: tcpAddr.Network(), outgoing: true}}, pp.PexOutgoingConn},
{&PeerConn{Peer: Peer{RemoteAddr: tcpAddr}}, 0}, {&PeerConn{Peer: Peer{RemoteAddr: tcpAddr, network: tcpAddr.Network()}}, 0},
} }
for i, tc := range testcases { for i, tc := range testcases {
f := tc.conn.pexPeerFlags() f := tc.conn.pexPeerFlags()
@ -184,22 +184,22 @@ func TestConnPexEvent(t *testing.T) {
}{ }{
{ {
pexAdd, pexAdd,
&PeerConn{Peer: Peer{RemoteAddr: udpAddr}}, &PeerConn{Peer: Peer{RemoteAddr: udpAddr, network: udpAddr.Network()}},
pexEvent{pexAdd, udpAddr, pp.PexSupportsUtp}, pexEvent{pexAdd, udpAddr, pp.PexSupportsUtp},
}, },
{ {
pexDrop, pexDrop,
&PeerConn{Peer: Peer{RemoteAddr: tcpAddr, outgoing: true, PeerListenPort: dialTcpAddr.Port}}, &PeerConn{Peer: Peer{RemoteAddr: tcpAddr, network: tcpAddr.Network(), outgoing: true, PeerListenPort: dialTcpAddr.Port}},
pexEvent{pexDrop, tcpAddr, pp.PexOutgoingConn}, pexEvent{pexDrop, tcpAddr, pp.PexOutgoingConn},
}, },
{ {
pexAdd, pexAdd,
&PeerConn{Peer: Peer{RemoteAddr: tcpAddr, PeerListenPort: dialTcpAddr.Port}}, &PeerConn{Peer: Peer{RemoteAddr: tcpAddr, network: tcpAddr.Network(), PeerListenPort: dialTcpAddr.Port}},
pexEvent{pexAdd, dialTcpAddr, 0}, pexEvent{pexAdd, dialTcpAddr, 0},
}, },
{ {
pexDrop, pexDrop,
&PeerConn{Peer: Peer{RemoteAddr: udpAddr, PeerListenPort: dialUdpAddr.Port}}, &PeerConn{Peer: Peer{RemoteAddr: udpAddr, network: udpAddr.Network(), PeerListenPort: dialUdpAddr.Port}},
pexEvent{pexDrop, dialUdpAddr, pp.PexSupportsUtp}, pexEvent{pexDrop, dialUdpAddr, pp.PexSupportsUtp},
}, },
} }

14
pex.go
View File

@ -25,7 +25,7 @@ const (
// represents a single connection (t=pexAdd) or disconnection (t=pexDrop) event // represents a single connection (t=pexAdd) or disconnection (t=pexDrop) event
type pexEvent struct { type pexEvent struct {
t pexEventType t pexEventType
addr net.Addr addr PeerRemoteAddr
f pp.PexPeerFlags f pp.PexPeerFlags
} }
@ -45,7 +45,7 @@ func (me *pexMsgFactory) DeltaLen() int {
type addrKey string type addrKey string
// Returns the key to use to identify a given addr in the factory. // Returns the key to use to identify a given addr in the factory.
func (me *pexMsgFactory) addrKey(addr net.Addr) addrKey { func (me *pexMsgFactory) addrKey(addr PeerRemoteAddr) addrKey {
return addrKey(addr.String()) return addrKey(addr.String())
} }
@ -161,12 +161,10 @@ func (me *pexMsgFactory) PexMsg() pp.PexMsg {
// Convert an arbitrary torrent peer Addr into one that can be represented by the compact addr // Convert an arbitrary torrent peer Addr into one that can be represented by the compact addr
// format. // format.
func nodeAddr(addr net.Addr) (_ krpc.NodeAddr, ok bool) { func nodeAddr(addr PeerRemoteAddr) (krpc.NodeAddr, bool) {
ipport, ok := tryIpPortFromNetAddr(addr) ipport, _ := tryIpPortFromNetAddr(addr)
if !ok { ok := ipport.IP != nil
return return krpc.NodeAddr{IP: shortestIP(ipport.IP), Port: ipport.Port}, ok
}
return krpc.NodeAddr{IP: shortestIP(ipport.IP), Port: ipport.Port}, true
} }
// mainly for the krpc marshallers // mainly for the krpc marshallers