Skip to content

Commit

Permalink
fix missing context ID in datagrams
Browse files Browse the repository at this point in the history
For UDP payloads, the context ID is 0, see section 5 of RFC 9298.
  • Loading branch information
marten-seemann committed Aug 16, 2024
1 parent acf6987 commit 44a8db5
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 6 deletions.
17 changes: 14 additions & 3 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package masque
import (
"context"
"errors"
"fmt"
"io"
"log"
"net"
Expand Down Expand Up @@ -77,16 +78,26 @@ start:
}
return 0, nil, os.ErrDeadlineExceeded
}
contextID, n, err := quicvarint.Parse(data)
if err != nil {
return 0, nil, fmt.Errorf("masque: malformed datagram: %w", err)

Check warning on line 83 in conn.go

View check run for this annotation

Codecov / codecov/patch

conn.go#L83

Added line #L83 was not covered by tests
}
if contextID != 0 {
// Drop this datagram. We currently only support proxying of UDP payloads.
goto start

Check warning on line 87 in conn.go

View check run for this annotation

Codecov / codecov/patch

conn.go#L87

Added line #L87 was not covered by tests
}
// If b is too small, additional bytes are discarded.
// This mirrors the behavior of large UDP datagrams received on a UDP socket (on Linux).
n = copy(b, data)
return n, c.remoteAddr, nil
return copy(b, data[n:]), c.remoteAddr, nil
}

// WriteTo sends a UDP datagram to the target.
// The net.Addr parameter is ignored.
func (c *proxiedConn) WriteTo(p []byte, _ net.Addr) (n int, err error) {
return len(p), c.str.SendDatagram(p)
data := make([]byte, 0, len(contextIDZero)+len(p))
data = append(data, contextIDZero...)
data = append(data, p...)
return len(p), c.str.SendDatagram(data)
}

func (c *proxiedConn) Close() error {
Expand Down
17 changes: 15 additions & 2 deletions proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const (
uriTemplateTargetPort = "target_port"
)

var contextIDZero = quicvarint.Append([]byte{}, 0)

type proxyEntry struct {
str http3.Stream
conn *net.UDPConn
Expand Down Expand Up @@ -126,7 +128,15 @@ func (s *Proxy) proxyConnSend(conn *net.UDPConn, str http3.Stream) error {
if err != nil {
return err
}
if _, err := conn.Write(data); err != nil {
contextID, n, err := quicvarint.Parse(data)
if err != nil {
return err

Check warning on line 133 in proxy.go

View check run for this annotation

Codecov / codecov/patch

proxy.go#L133

Added line #L133 was not covered by tests
}
if contextID != 0 {
// Drop this datagram. We currently only support proxying of UDP payloads.
continue
}
if _, err := conn.Write(data[n:]); err != nil {
return err
}
}
Expand All @@ -139,7 +149,10 @@ func (s *Proxy) proxyConnReceive(conn *net.UDPConn, str http3.Stream) error {
if err != nil {
return err
}
if err := str.SendDatagram(b[:n]); err != nil {
data := make([]byte, 0, len(contextIDZero)+n)
data = append(data, contextIDZero...)
data = append(data, b[:n]...)
if err := str.SendDatagram(data); err != nil {
return err
}
}
Expand Down
2 changes: 1 addition & 1 deletion proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestProxyCloseProxiedConn(t *testing.T) {
done := make(chan struct{})
str := NewMockStream(gomock.NewController(t))
str.EXPECT().ReceiveDatagram(gomock.Any()).DoAndReturn(func(context.Context) ([]byte, error) {
return []byte("foo"), nil
return append(contextIDZero, []byte("foo")...), nil
})
// This datagram is received after the connection is closed.
// We expect that it won't get sent on.
Expand Down

0 comments on commit 44a8db5

Please sign in to comment.