Unverified Commit 9d8055d4 authored by Marten Seemann's avatar Marten Seemann Committed by GitHub
Browse files

Merge pull request #27 from libp2p/fix-ip-version

obey the multiaddr's IP version
parents 43da075e bd2c36a8
...@@ -18,6 +18,10 @@ before_install: ...@@ -18,6 +18,10 @@ before_install:
- export GOARCH=$TRAVIS_GOARCH - export GOARCH=$TRAVIS_GOARCH
- go env # for debugging - go env # for debugging
# see https://github.com/travis-ci/travis-ci/issues/8361#issuecomment-350090030
before_script:
- sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6'
script: script:
- ginkgo -r -v --cover --randomizeAllSpecs --randomizeSuites --trace --progress - ginkgo -r -v --cover --randomizeAllSpecs --randomizeSuites --trace --progress
......
...@@ -35,12 +35,12 @@ var _ = Describe("Connection", func() { ...@@ -35,12 +35,12 @@ var _ = Describe("Connection", func() {
return id, priv return id, priv
} }
runServer := func(tr tpt.Transport) (ma.Multiaddr, <-chan tpt.Conn) { runServer := func(tr tpt.Transport, multiaddr string) (ma.Multiaddr, <-chan tpt.Conn) {
addrChan := make(chan ma.Multiaddr) addrChan := make(chan ma.Multiaddr)
connChan := make(chan tpt.Conn) connChan := make(chan tpt.Conn)
go func() { go func() {
defer GinkgoRecover() defer GinkgoRecover()
addr, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic") addr, err := ma.NewMultiaddr(multiaddr)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
ln, err := tr.Listen(addr) ln, err := tr.Listen(addr)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
...@@ -62,10 +62,30 @@ var _ = Describe("Connection", func() { ...@@ -62,10 +62,30 @@ var _ = Describe("Connection", func() {
clientID, clientKey = createPeer() clientID, clientKey = createPeer()
}) })
It("handshakes", func() { It("handshakes on IPv4", func() {
serverTransport, err := NewTransport(serverKey) serverTransport, err := NewTransport(serverKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
serverAddr, serverConnChan := runServer(serverTransport) serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")
clientTransport, err := NewTransport(clientKey)
Expect(err).ToNot(HaveOccurred())
conn, err := clientTransport.Dial(context.Background(), serverAddr, serverID)
Expect(err).ToNot(HaveOccurred())
serverConn := <-serverConnChan
Expect(conn.LocalPeer()).To(Equal(clientID))
Expect(conn.LocalPrivateKey()).To(Equal(clientKey))
Expect(conn.RemotePeer()).To(Equal(serverID))
Expect(conn.RemotePublicKey()).To(Equal(serverKey.GetPublic()))
Expect(serverConn.LocalPeer()).To(Equal(serverID))
Expect(serverConn.LocalPrivateKey()).To(Equal(serverKey))
Expect(serverConn.RemotePeer()).To(Equal(clientID))
Expect(serverConn.RemotePublicKey()).To(Equal(clientKey.GetPublic()))
})
It("handshakes on IPv6", func() {
serverTransport, err := NewTransport(serverKey)
Expect(err).ToNot(HaveOccurred())
serverAddr, serverConnChan := runServer(serverTransport, "/ip6/::1/udp/0/quic")
clientTransport, err := NewTransport(clientKey) clientTransport, err := NewTransport(clientKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
...@@ -85,7 +105,7 @@ var _ = Describe("Connection", func() { ...@@ -85,7 +105,7 @@ var _ = Describe("Connection", func() {
It("opens and accepts streams", func() { It("opens and accepts streams", func() {
serverTransport, err := NewTransport(serverKey) serverTransport, err := NewTransport(serverKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
serverAddr, serverConnChan := runServer(serverTransport) serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")
clientTransport, err := NewTransport(clientKey) clientTransport, err := NewTransport(clientKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
...@@ -110,7 +130,7 @@ var _ = Describe("Connection", func() { ...@@ -110,7 +130,7 @@ var _ = Describe("Connection", func() {
serverTransport, err := NewTransport(serverKey) serverTransport, err := NewTransport(serverKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
serverAddr, serverConnChan := runServer(serverTransport) serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")
clientTransport, err := NewTransport(clientKey) clientTransport, err := NewTransport(clientKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
...@@ -124,7 +144,7 @@ var _ = Describe("Connection", func() { ...@@ -124,7 +144,7 @@ var _ = Describe("Connection", func() {
It("fails if the client presents an invalid cert chain", func() { It("fails if the client presents an invalid cert chain", func() {
serverTransport, err := NewTransport(serverKey) serverTransport, err := NewTransport(serverKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
serverAddr, serverConnChan := runServer(serverTransport) serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")
clientTransport, err := NewTransport(clientKey) clientTransport, err := NewTransport(clientKey)
invalidateCertChain(clientTransport.(*transport).tlsConf) invalidateCertChain(clientTransport.(*transport).tlsConf)
...@@ -139,7 +159,7 @@ var _ = Describe("Connection", func() { ...@@ -139,7 +159,7 @@ var _ = Describe("Connection", func() {
serverTransport, err := NewTransport(serverKey) serverTransport, err := NewTransport(serverKey)
invalidateCertChain(serverTransport.(*transport).tlsConf) invalidateCertChain(serverTransport.(*transport).tlsConf)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
serverAddr, serverConnChan := runServer(serverTransport) serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")
clientTransport, err := NewTransport(clientKey) clientTransport, err := NewTransport(clientKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
...@@ -152,7 +172,7 @@ var _ = Describe("Connection", func() { ...@@ -152,7 +172,7 @@ var _ = Describe("Connection", func() {
It("keeps accepting connections after a failed connection attempt", func() { It("keeps accepting connections after a failed connection attempt", func() {
serverTransport, err := NewTransport(serverKey) serverTransport, err := NewTransport(serverKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
serverAddr, serverConnChan := runServer(serverTransport) serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")
// first dial with an invalid cert chain // first dial with an invalid cert chain
clientTransport1, err := NewTransport(clientKey) clientTransport1, err := NewTransport(clientKey)
...@@ -175,10 +195,10 @@ var _ = Describe("Connection", func() { ...@@ -175,10 +195,10 @@ var _ = Describe("Connection", func() {
serverTransport, err := NewTransport(serverKey) serverTransport, err := NewTransport(serverKey)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
serverAddr, serverConnChan := runServer(serverTransport) serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")
serverTransport2, err := NewTransport(serverKey2) serverTransport2, err := NewTransport(serverKey2)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
serverAddr2, serverConnChan2 := runServer(serverTransport2) serverAddr2, serverConnChan2 := runServer(serverTransport2, "/ip4/127.0.0.1/udp/0/quic")
data := bytes.Repeat([]byte{'a'}, 5*1<<20) // 5 MB data := bytes.Repeat([]byte{'a'}, 5*1<<20) // 5 MB
// wait for both servers to accept a connection // wait for both servers to accept a connection
......
...@@ -27,11 +27,19 @@ type listener struct { ...@@ -27,11 +27,19 @@ type listener struct {
var _ tpt.Listener = &listener{} var _ tpt.Listener = &listener{}
func newListener(addr ma.Multiaddr, transport tpt.Transport, localPeer peer.ID, key ic.PrivKey, tlsConf *tls.Config) (tpt.Listener, error) { func newListener(addr ma.Multiaddr, transport tpt.Transport, localPeer peer.ID, key ic.PrivKey, tlsConf *tls.Config) (tpt.Listener, error) {
_, host, err := manet.DialArgs(addr) lnet, host, err := manet.DialArgs(addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ln, err := quicListenAddr(host, tlsConf, quicConfig) laddr, err := net.ResolveUDPAddr(lnet, host)
if err != nil {
return nil, err
}
conn, err := net.ListenUDP(lnet, laddr)
if err != nil {
return nil, err
}
ln, err := quic.Listen(conn, tlsConf, quicConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -15,10 +15,7 @@ import ( ...@@ -15,10 +15,7 @@ import (
) )
var _ = Describe("Listener", func() { var _ = Describe("Listener", func() {
var ( var t tpt.Transport
t tpt.Transport
localAddr ma.Multiaddr
)
BeforeEach(func() { BeforeEach(func() {
rsaKey, err := rsa.GenerateKey(rand.Reader, 1024) rsaKey, err := rsa.GenerateKey(rand.Reader, 1024)
...@@ -27,41 +24,76 @@ var _ = Describe("Listener", func() { ...@@ -27,41 +24,76 @@ var _ = Describe("Listener", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
t, err = NewTransport(key) t, err = NewTransport(key)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
localAddr, err = ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic")
Expect(err).ToNot(HaveOccurred())
}) })
It("returns the address it is listening on", func() { Context("listening on the right address", func() {
ln, err := t.Listen(localAddr) It("returns the address it is listening on", func() {
Expect(err).ToNot(HaveOccurred()) localAddr, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic")
netAddr := ln.Addr() ln, err := t.Listen(localAddr)
Expect(netAddr).To(BeAssignableToTypeOf(&net.UDPAddr{})) Expect(err).ToNot(HaveOccurred())
port := netAddr.(*net.UDPAddr).Port netAddr := ln.Addr()
Expect(port).ToNot(BeZero()) Expect(netAddr).To(BeAssignableToTypeOf(&net.UDPAddr{}))
Expect(ln.Multiaddr().String()).To(Equal(fmt.Sprintf("/ip4/127.0.0.1/udp/%d/quic", port))) port := netAddr.(*net.UDPAddr).Port
}) Expect(port).ToNot(BeZero())
Expect(ln.Multiaddr().String()).To(Equal(fmt.Sprintf("/ip4/127.0.0.1/udp/%d/quic", port)))
})
It("returns Accept when it is closed", func() { It("returns the address it is listening on, for listening on IPv4", func() {
addr, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic") localAddr, err := ma.NewMultiaddr("/ip4/0.0.0.0/udp/0/quic")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
ln, err := t.Listen(addr) ln, err := t.Listen(localAddr)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
done := make(chan struct{}) netAddr := ln.Addr()
go func() { Expect(netAddr).To(BeAssignableToTypeOf(&net.UDPAddr{}))
defer GinkgoRecover() port := netAddr.(*net.UDPAddr).Port
ln.Accept() Expect(port).ToNot(BeZero())
close(done) Expect(ln.Multiaddr().String()).To(Equal(fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic", port)))
}() })
Consistently(done).ShouldNot(BeClosed())
Expect(ln.Close()).To(Succeed()) It("returns the address it is listening on, for listening on IPv6", func() {
Eventually(done).Should(BeClosed()) localAddr, err := ma.NewMultiaddr("/ip6/::/udp/0/quic")
Expect(err).ToNot(HaveOccurred())
ln, err := t.Listen(localAddr)
Expect(err).ToNot(HaveOccurred())
netAddr := ln.Addr()
Expect(netAddr).To(BeAssignableToTypeOf(&net.UDPAddr{}))
port := netAddr.(*net.UDPAddr).Port
Expect(port).ToNot(BeZero())
Expect(ln.Multiaddr().String()).To(Equal(fmt.Sprintf("/ip6/::/udp/%d/quic", port)))
})
}) })
It("doesn't accept Accept calls after it is closed", func() { Context("accepting connections", func() {
ln, err := t.Listen(localAddr) var localAddr ma.Multiaddr
Expect(err).ToNot(HaveOccurred())
Expect(ln.Close()).To(Succeed()) BeforeEach(func() {
_, err = ln.Accept() var err error
Expect(err).To(HaveOccurred()) localAddr, err = ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic")
Expect(err).ToNot(HaveOccurred())
})
It("returns Accept when it is closed", func() {
addr, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic")
Expect(err).ToNot(HaveOccurred())
ln, err := t.Listen(addr)
Expect(err).ToNot(HaveOccurred())
done := make(chan struct{})
go func() {
defer GinkgoRecover()
ln.Accept()
close(done)
}()
Consistently(done).ShouldNot(BeClosed())
Expect(ln.Close()).To(Succeed())
Eventually(done).Should(BeClosed())
})
It("doesn't accept Accept calls after it is closed", func() {
ln, err := t.Listen(localAddr)
Expect(err).ToNot(HaveOccurred())
Expect(ln.Close()).To(Succeed())
_, err = ln.Accept()
Expect(err).To(HaveOccurred())
})
}) })
}) })
...@@ -5,7 +5,9 @@ import ( ...@@ -5,7 +5,9 @@ import (
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"errors" "errors"
"fmt"
"net" "net"
"sync"
ic "github.com/libp2p/go-libp2p-crypto" ic "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer" peer "github.com/libp2p/go-libp2p-peer"
...@@ -27,12 +29,47 @@ var quicConfig = &quic.Config{ ...@@ -27,12 +29,47 @@ var quicConfig = &quic.Config{
KeepAlive: true, KeepAlive: true,
} }
type connManager struct {
connIPv4Once sync.Once
connIPv4 net.PacketConn
connIPv6Once sync.Once
connIPv6 net.PacketConn
}
func (c *connManager) GetConnForAddr(network string) (net.PacketConn, error) {
switch network {
case "udp4":
var err error
c.connIPv4Once.Do(func() {
c.connIPv4, err = c.createConn(network, "0.0.0.0:0")
})
return c.connIPv4, err
case "udp6":
var err error
c.connIPv6Once.Do(func() {
c.connIPv6, err = c.createConn(network, ":0")
})
return c.connIPv6, err
default:
return nil, fmt.Errorf("unsupported network: %s", network)
}
}
func (c *connManager) createConn(network, host string) (net.PacketConn, error) {
addr, err := net.ResolveUDPAddr(network, host)
if err != nil {
return nil, err
}
return net.ListenUDP(network, addr)
}
// The Transport implements the tpt.Transport interface for QUIC connections. // The Transport implements the tpt.Transport interface for QUIC connections.
type transport struct { type transport struct {
privKey ic.PrivKey privKey ic.PrivKey
localPeer peer.ID localPeer peer.ID
tlsConf *tls.Config tlsConf *tls.Config
pconn net.PacketConn connManager *connManager
} }
var _ tpt.Transport = &transport{} var _ tpt.Transport = &transport{}
...@@ -48,27 +85,21 @@ func NewTransport(key ic.PrivKey) (tpt.Transport, error) { ...@@ -48,27 +85,21 @@ func NewTransport(key ic.PrivKey) (tpt.Transport, error) {
return nil, err return nil, err
} }
// create a packet conn for outgoing connections
addr, err := net.ResolveUDPAddr("udp", "localhost:0")
if err != nil {
return nil, err
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
return nil, err
}
return &transport{ return &transport{
privKey: key, privKey: key,
localPeer: localPeer, localPeer: localPeer,
tlsConf: tlsConf, tlsConf: tlsConf,
pconn: conn, connManager: &connManager{},
}, nil }, nil
} }
// Dial dials a new QUIC connection // Dial dials a new QUIC connection
func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.Conn, error) { func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.Conn, error) {
_, host, err := manet.DialArgs(raddr) network, host, err := manet.DialArgs(raddr)
if err != nil {
return nil, err
}
pconn, err := t.connManager.GetConnForAddr(network)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -100,7 +131,7 @@ func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tp ...@@ -100,7 +131,7 @@ func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tp
} }
return nil return nil
} }
sess, err := quic.DialContext(ctx, t.pconn, addr, host, tlsConf, quicConfig) sess, err := quic.DialContext(ctx, pconn, addr, host, tlsConf, quicConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment