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

use a stateless reset key derived from the private key #122

Merged
merged 4 commits into from
Mar 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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