Skip to content

Commit

Permalink
Merge pull request #207 from getlantern/nelson/bump-quic-go
Browse files Browse the repository at this point in the history
Bump to quic-go 0.40
  • Loading branch information
myleshorton authored Nov 17, 2023
2 parents f0d5e59 + 15c26ab commit 7d46643
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 42 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Instructions last updated March 29, 2023. If something's not working and it's be

5. Build the browser widget: `cd cmd && ./build_web.sh`

6. Start Freddie: `cd freddie && PORT=9000 go run freddie.go`
6. Start Freddie: `cd freddie/cmd && PORT=9000 go run main.go`

7. Start the egress server: `cd egress/cmd && PORT=8000 go run egress.go`

Expand Down
58 changes: 35 additions & 23 deletions clientcore/quic.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"net/url"
"sync"
"time"

"github.com/quic-go/quic-go"

Expand Down Expand Up @@ -41,61 +42,72 @@ type QUICLayerOptions struct {
func NewQUICLayer(bfconn *BroflakeConn, qopt *QUICLayerOptions) (*QUICLayer, error) {
q := &QUICLayer{
bfconn: bfconn,
t: &quic.Transport{Conn: bfconn},
tlsConfig: &tls.Config{
ServerName: qopt.ServerName,
InsecureSkipVerify: qopt.InsecureSkipVerify,
NextProtos: []string{"broflake"},
RootCAs: qopt.CA,
},
eventualConn: newEventualConn(),
dialTimeout: 8 * time.Second,
}

return q, nil
}

type QUICLayer struct {
bfconn *BroflakeConn
t *quic.Transport
tlsConfig *tls.Config
eventualConn *eventualConn
mx sync.RWMutex
ctx context.Context
cancel context.CancelFunc
dialTimeout time.Duration
}

// DialAndMaintainQUICConnection attempts to create and maintain an e2e QUIC connection by dialing
// the other end, detecting if that connection breaks, and redialing. Forever.
func (c *QUICLayer) DialAndMaintainQUICConnection() {
c.ctx, c.cancel = context.WithCancel(context.Background())

go func() {
for {
var conn quic.Connection

// State 1 of 2: Keep dialing until we acquire a connection
for {
select {
case <-c.ctx.Done():
common.Debugf("Cancelling QUIC dialer!")
return
default:
// Do nothing
}

var err error
conn, err = quic.Dial(c.bfconn, common.DebugAddr("NELSON WUZ HERE"), "DEBUG", c.tlsConfig, &common.QUICCfg)
if err != nil {
common.Debugf("QUIC dial failed (%v), retrying...", err)
continue
}
break
// State 1 of 2: Keep dialing until we acquire a connection
for {
select {
case <-c.ctx.Done():
common.Debugf("Cancelling QUIC dialer!")
return
default:
// Do nothing
}

ctxDial, cancelDial := context.WithTimeout(context.Background(), c.dialTimeout)
connEstablished := make(chan quic.Connection)
connErr := make(chan error)

go func() {
defer cancelDial()
conn, err := c.t.Dial(ctxDial, common.DebugAddr("NELSON WUZ HERE"), c.tlsConfig, &common.QUICCfg)

if err != nil {
connErr <- err
return
}

connEstablished <- conn
}()

select {
case err := <-connErr:
common.Debugf("QUIC dial failed (%v), retrying...", err)
case conn := <-connEstablished:
c.mx.Lock()
c.eventualConn.set(conn)
c.mx.Unlock()
common.Debug("QUIC connection established, ready to proxy!")

// State 2 of 2: Connection established, block until we detect a half open or a context cancellation
// State 2 of 2: Connection established, block until we detect a half open or a ctx cancel
_, err := conn.AcceptStream(c.ctx)
if err != nil {
common.Debugf("QUIC connection error (%v), closing!", err)
Expand All @@ -110,7 +122,7 @@ func (c *QUICLayer) DialAndMaintainQUICConnection() {
c.eventualConn = newEventualConn()
c.mx.Unlock()
}
}()
}
}

// Close a QUICLayer which was previously opened via a call to DialAndMaintainQUICConnection.
Expand Down
57 changes: 46 additions & 11 deletions clientcore/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"context"
"net"
"sync"
"time"

"github.com/google/uuid"

Expand All @@ -18,20 +19,42 @@ import (

type BroflakeConn struct {
net.PacketConn
writeChan chan IPCMsg
readChan chan IPCMsg
addr common.DebugAddr
writeChan chan IPCMsg
readChan chan IPCMsg
addr common.DebugAddr
readDeadline time.Time
updateReadDeadline chan time.Time
}

func (c BroflakeConn) LocalAddr() net.Addr {
return c.addr
}

func (c BroflakeConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
msg := <-c.readChan
payload := msg.Data.([]byte)
copy(p, payload)
return len(payload), common.DebugAddr("DEBUG NELSON WUZ HERE"), nil
for {
var ctx context.Context

// If the deadline is zero value, never expire; otherwise obey the deadline
if c.readDeadline.IsZero() {
ctx, _ = context.WithCancel(context.Background())
} else {
ctx, _ = context.WithDeadline(context.Background(), c.readDeadline)
}

select {
case msg := <-c.readChan:
// The read completed, let's return some bytes!
payload := msg.Data.([]byte)
copy(p, payload)
return len(payload), common.DebugAddr("DEBUG NELSON WUZ HERE"), nil
case <-ctx.Done():
// We're past our deadline, so let's return failure!
return 0, common.DebugAddr("DEBUG NELSON WUZ HERE"), ctx.Err()
case d := <-c.updateReadDeadline:
// Someone updated the read deadline, so let's iterate to respect the new deadline
c.readDeadline = d
}
}
}

func (c BroflakeConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
Expand All @@ -49,6 +72,16 @@ func (c BroflakeConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
return len(b), nil
}

// XXX: A note about deadlines: as of quic-go 0.34, the QUIC dialer didn't seem to care about read
// or write deadlines, and it was happy to use a net.PacketConn which didn't properly implement them.
// But when we bumped to quic-go 0.40, it emerged that the dialer wouldn't work unless we added
// support for read deadlines. Since there's still no evidence that the dialer cares about write
// deadlines, we haven't added support for those yet.
func (c BroflakeConn) SetReadDeadline(t time.Time) error {
c.updateReadDeadline <- t
return nil
}

func NewProducerUserStream(wg *sync.WaitGroup) (*BroflakeConn, *WorkerFSM) {
worker := NewWorkerFSM(wg, []FSMstate{
FSMstate(func(ctx context.Context, com *ipcChan, input []interface{}) (int, []interface{}) {
Expand All @@ -61,10 +94,12 @@ func NewProducerUserStream(wg *sync.WaitGroup) (*BroflakeConn, *WorkerFSM) {
})

bfconn := BroflakeConn{
PacketConn: &net.UDPConn{},
writeChan: worker.com.tx,
readChan: worker.com.rx,
addr: common.DebugAddr(uuid.NewString()),
PacketConn: &net.UDPConn{},
writeChan: worker.com.tx,
readChan: worker.com.rx,
addr: common.DebugAddr(uuid.NewString()),
readDeadline: time.Time{},
updateReadDeadline: make(chan time.Time, 512),
}

return &bfconn, worker
Expand Down
2 changes: 1 addition & 1 deletion cmd/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func runLocalProxy(port string, bfconn *clientcore.BroflakeConn, ca, sn string)
return
}

ql.DialAndMaintainQUICConnection()
go ql.DialAndMaintainQUICConnection()
proxy.Tr = clientcore.CreateHTTPTransport(ql)

proxy.OnRequest().DoFunc(
Expand Down
13 changes: 7 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ require (
github.com/getlantern/telemetry v0.0.0-20230523155019-be7c1d8cd8cb
github.com/google/uuid v1.3.0
github.com/pion/webrtc/v3 v3.2.6
github.com/quic-go/quic-go v0.34.0
github.com/quic-go/quic-go v0.40.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0
go.opentelemetry.io/otel v1.16.0
go.opentelemetry.io/otel/metric v1.16.0
go.opentelemetry.io/otel/trace v1.16.0
golang.org/x/mod v0.8.0
golang.org/x/mod v0.11.0
nhooyr.io/websocket v1.8.7
)

Expand All @@ -25,13 +25,13 @@ require (
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/klauspost/compress v1.10.3 // indirect
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect
github.com/pion/ice/v2 v2.3.5 // indirect
Expand All @@ -52,7 +52,7 @@ require (
github.com/pkg/errors v0.8.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/stretchr/testify v1.8.3 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0 // indirect
Expand All @@ -62,12 +62,13 @@ require (
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
go.opentelemetry.io/otel/sdk/metric v0.39.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/mock v0.3.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/tools v0.9.1 // indirect
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
google.golang.org/grpc v1.55.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
Expand Down
16 changes: 16 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
Expand Down Expand Up @@ -202,10 +204,13 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/dtls/v2 v2.2.6/go.mod h1:t8fWJCIquY5rlQZwA2yWxUS1+OCrAdXrhVKXB5oD/wY=
Expand Down Expand Up @@ -263,8 +268,12 @@ github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc8
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.34.0 h1:OvOJ9LFjTySgwOTYUZmNoq0FzVicP8YujpV0kB7m2lU=
github.com/quic-go/quic-go v0.34.0/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw=
github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
Expand All @@ -276,6 +285,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
Expand Down Expand Up @@ -323,6 +333,8 @@ go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLk
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
Expand Down Expand Up @@ -369,6 +381,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -545,6 +559,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down

0 comments on commit 7d46643

Please sign in to comment.