Skip to content
This repository has been archived by the owner on May 26, 2022. It is now read-only.

Commit

Permalink
Merge pull request #122 from libp2p/set-stateless-reset-key
Browse files Browse the repository at this point in the history
use a stateless reset key derived from the private key
  • Loading branch information
marten-seemann authored Mar 25, 2020
2 parents cfc4947 + 9637bdb commit 506057f
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 12 deletions.
56 changes: 52 additions & 4 deletions conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import (
"io/ioutil"
mrand "math/rand"
"net"
"sync/atomic"
"time"

ic "github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
tpt "github.com/libp2p/go-libp2p-core/transport"
filter "github.com/libp2p/go-maddr-filter"
quicproxy "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy"
ma "github.com/multiformats/go-multiaddr"

. "github.com/onsi/ginkgo"
Expand Down Expand Up @@ -52,9 +54,9 @@ var _ = Describe("Connection", func() {

runServer := func(tr tpt.Transport, multiaddr string) tpt.Listener {
addr, err := ma.NewMultiaddr(multiaddr)
Expect(err).ToNot(HaveOccurred())
ExpectWithOffset(1, err).ToNot(HaveOccurred())
ln, err := tr.Listen(addr)
Expect(err).ToNot(HaveOccurred())
ExpectWithOffset(1, err).ToNot(HaveOccurred())
return ln
}

Expand Down Expand Up @@ -183,13 +185,13 @@ var _ = Describe("Connection", func() {
Expect(err).ToNot(HaveOccurred())

// make sure that connection attempts fails
quicConfig.HandshakeTimeout = 250 * time.Millisecond
clientTransport.(*transport).config.HandshakeTimeout = 250 * time.Millisecond
_, err = clientTransport.Dial(context.Background(), ln.Multiaddr(), serverID)
Expect(err).To(HaveOccurred())
Expect(err.(net.Error).Timeout()).To(BeTrue())

// now allow the address and make sure the connection goes through
quicConfig.HandshakeTimeout = 2 * time.Second
clientTransport.(*transport).config.HandshakeTimeout = 2 * time.Second
filters.AddFilter(ipNet, filter.ActionAccept)
conn, err := clientTransport.Dial(context.Background(), ln.Multiaddr(), serverID)
Expect(err).ToNot(HaveOccurred())
Expand Down Expand Up @@ -256,4 +258,50 @@ var _ = Describe("Connection", func() {
Eventually(done, 5*time.Second).Should(Receive())
Eventually(done, 5*time.Second).Should(Receive())
})

It("sends stateless resets", func() {
serverTransport, err := NewTransport(serverKey, nil, nil)
Expect(err).ToNot(HaveOccurred())
ln := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")

var drop uint32
serverPort := ln.Addr().(*net.UDPAddr).Port
proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
RemoteAddr: fmt.Sprintf("localhost:%d", serverPort),
DropPacket: func(quicproxy.Direction, []byte) bool {
return atomic.LoadUint32(&drop) > 0
},
})
Expect(err).ToNot(HaveOccurred())
defer proxy.Close()

// establish a connection
clientTransport, err := NewTransport(clientKey, nil, nil)
Expect(err).ToNot(HaveOccurred())
proxyAddr, err := toQuicMultiaddr(proxy.LocalAddr())
Expect(err).ToNot(HaveOccurred())
conn, err := clientTransport.Dial(context.Background(), proxyAddr, serverID)
Expect(err).ToNot(HaveOccurred())
str, err := conn.OpenStream()
Expect(err).ToNot(HaveOccurred())

// Stop forwarding packets and close the server.
// This prevents the CONNECTION_CLOSE from reaching the client.
atomic.StoreUint32(&drop, 1)
Expect(ln.Close()).To(Succeed())
time.Sleep(100 * time.Millisecond) // give the kernel some time to free the UDP port
ln = runServer(serverTransport, fmt.Sprintf("/ip4/127.0.0.1/udp/%d/quic", serverPort))
defer ln.Close()
// Now that the new server is up, re-enable packet forwarding.
atomic.StoreUint32(&drop, 0)

// The new server doesn't have any state for the previously established connection.
// We expect it to send a stateless reset.
_, rerr := str.Write([]byte("foobar"))
if rerr == nil {
_, rerr = str.Read([]byte{0, 0})
}
Expect(rerr).To(HaveOccurred())
Expect(rerr.Error()).To(ContainSubstring("received a stateless reset"))
})
})
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ require (
github.com/libp2p/go-libp2p-tls v0.1.3
github.com/libp2p/go-maddr-filter v0.0.5
github.com/lucas-clemente/quic-go v0.15.2
github.com/minio/sha256-simd v0.1.1
github.com/multiformats/go-multiaddr v0.2.1
github.com/multiformats/go-multiaddr-fmt v0.1.0
github.com/multiformats/go-multiaddr-net v0.1.3
github.com/onsi/ginkgo v1.12.0
github.com/onsi/gomega v1.9.0
github.com/vishvananda/netlink v1.1.0
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
)
6 changes: 0 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,10 @@ github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lg
github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.1 h1:rVAztJYMhCQ7vEFr8FvxW3mS+HF2eY/oPbOMeS0ZDnE=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr v0.2.0 h1:lR52sFwcTCuQb6bTfnXF6zA2XfyYvyd+5a9qECv/J90=
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
github.com/multiformats/go-multiaddr v0.2.1 h1:SgG/cw5vqyB5QQe5FPe2TqggU9WtrA9X4nZw7LlVqOI=
github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multiaddr-net v0.1.2 h1:P7zcBH9FRETdPkDrylcXVjQLQ2t1JQtNItZULWNWgeg=
github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=
github.com/multiformats/go-multiaddr-net v0.1.3 h1:q/IYAvoPKuRzGeERn3uacWgm0LIWkLZBAvO5DxSzq3g=
github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=
Expand All @@ -190,8 +186,6 @@ github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRH
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc=
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-varint v0.0.1 h1:TR/0rdQtnNxuN2IhiB639xC3tWM4IUi7DkTBVTdGW/M=
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg=
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
Expand Down
2 changes: 1 addition & 1 deletion listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func newListener(rconn *reuseConn, t *transport, localPeer peer.ID, key ic.PrivK
conf, _ := identity.ConfigForAny()
return conf, nil
}
ln, err := quic.Listen(rconn, &tlsConf, quicConfig)
ln, err := quic.Listen(rconn, &tlsConf, t.config)
if err != nil {
return nil, err
}
Expand Down
20 changes: 19 additions & 1 deletion transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package libp2pquic
import (
"context"
"errors"
"io"
"net"

"github.com/minio/sha256-simd"
"golang.org/x/crypto/hkdf"

logging "github.com/ipfs/go-log"
ic "github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
Expand Down Expand Up @@ -32,6 +36,8 @@ var quicConfig = &quic.Config{
KeepAlive: true,
}

const statelessResetKeyInfo = "libp2p quic stateless reset key"

type connManager struct {
reuseUDP4 *reuse
reuseUDP6 *reuse
Expand Down Expand Up @@ -85,6 +91,7 @@ type transport struct {
localPeer peer.ID
identity *p2ptls.Identity
connManager *connManager
config *quic.Config
}

var _ tpt.Transport = &transport{}
Expand All @@ -107,12 +114,23 @@ func NewTransport(key ic.PrivKey, psk pnet.PSK, filters *filter.Filters) (tpt.Tr
if err != nil {
return nil, err
}
config := quicConfig.Clone()
keyBytes, err := key.Raw()
if err != nil {
return nil, err
}
keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte(statelessResetKeyInfo))
config.StatelessResetKey = make([]byte, 32)
if _, err := io.ReadFull(keyReader, config.StatelessResetKey); err != nil {
return nil, err
}

return &transport{
privKey: key,
localPeer: localPeer,
identity: identity,
connManager: connManager,
config: config,
}, nil
}

Expand All @@ -135,7 +153,7 @@ func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tp
if err != nil {
return nil, err
}
sess, err := quic.DialContext(ctx, pconn, addr, host, tlsConf, quicConfig)
sess, err := quic.DialContext(ctx, pconn, addr, host, tlsConf, t.config)
if err != nil {
pconn.DecreaseCount()
return nil, err
Expand Down

0 comments on commit 506057f

Please sign in to comment.