Add TCP CONNECT support to MASQUE (RFC 9114)
Extend MASQUE implementation to support TCP tunneling via standard HTTP/3 CONNECT method, in addition to existing UDP support via CONNECT-UDP: - Add StreamConn type for TCP data transfer over HTTP/3 stream body - Update handler to dispatch based on :protocol pseudo-header: - "connect-udp" for UDP (RFC 9298) - Empty/"HTTP/3.0" for TCP (RFC 9114) - Add handleConnectTCP() using bidirectional stream relay - Update connector to support both TCP and UDP networks - Add connectTCP() for standard CONNECT requests TCP uses :authority for target address and stream body for data. UDP uses path template and HTTP/3 datagrams for data.
This commit is contained in:
@@ -174,3 +174,105 @@ var (
|
||||
_ net.Conn = (*DatagramConn)(nil)
|
||||
_ net.PacketConn = (*DatagramConn)(nil)
|
||||
)
|
||||
|
||||
// StreamReadWriter is an interface for reading and writing to HTTP/3 streams.
|
||||
// Both http3.Stream and http3.RequestStream implement this interface.
|
||||
type StreamReadWriter interface {
|
||||
io.Reader
|
||||
io.Writer
|
||||
io.Closer
|
||||
SetDeadline(t time.Time) error
|
||||
SetReadDeadline(t time.Time) error
|
||||
SetWriteDeadline(t time.Time) error
|
||||
}
|
||||
|
||||
// StreamConn wraps an HTTP/3 stream as net.Conn for TCP tunneling (RFC 9114).
|
||||
// Unlike DatagramConn which uses HTTP/3 datagrams, StreamConn reads/writes
|
||||
// directly to the HTTP/3 stream body for reliable, ordered byte streams.
|
||||
type StreamConn struct {
|
||||
stream StreamReadWriter
|
||||
localAddr net.Addr
|
||||
remoteAddr net.Addr
|
||||
closed chan struct{}
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// NewStreamConn creates a new StreamConn wrapping an HTTP/3 stream (server-side).
|
||||
// This is used for TCP CONNECT tunneling where data flows through the stream body.
|
||||
func NewStreamConn(stream *http3.Stream, laddr, raddr net.Addr) *StreamConn {
|
||||
return &StreamConn{
|
||||
stream: stream,
|
||||
localAddr: laddr,
|
||||
remoteAddr: raddr,
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// NewStreamConnFromRequestStream creates a new StreamConn wrapping an HTTP/3 request stream (client-side).
|
||||
// This is used for TCP CONNECT tunneling where data flows through the stream body.
|
||||
func NewStreamConnFromRequestStream(stream *http3.RequestStream, laddr, raddr net.Addr) *StreamConn {
|
||||
return &StreamConn{
|
||||
stream: stream,
|
||||
localAddr: laddr,
|
||||
remoteAddr: raddr,
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads data from the HTTP/3 stream body.
|
||||
func (c *StreamConn) Read(b []byte) (n int, err error) {
|
||||
select {
|
||||
case <-c.closed:
|
||||
return 0, net.ErrClosed
|
||||
default:
|
||||
}
|
||||
return c.stream.Read(b)
|
||||
}
|
||||
|
||||
// Write writes data to the HTTP/3 stream body.
|
||||
func (c *StreamConn) Write(b []byte) (n int, err error) {
|
||||
select {
|
||||
case <-c.closed:
|
||||
return 0, net.ErrClosed
|
||||
default:
|
||||
}
|
||||
return c.stream.Write(b)
|
||||
}
|
||||
|
||||
// Close closes the stream connection.
|
||||
func (c *StreamConn) Close() error {
|
||||
var err error
|
||||
c.closeOnce.Do(func() {
|
||||
close(c.closed)
|
||||
err = c.stream.Close()
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// LocalAddr returns the local network address.
|
||||
func (c *StreamConn) LocalAddr() net.Addr {
|
||||
return c.localAddr
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
func (c *StreamConn) RemoteAddr() net.Addr {
|
||||
return c.remoteAddr
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines.
|
||||
func (c *StreamConn) SetDeadline(t time.Time) error {
|
||||
return c.stream.SetDeadline(t)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the read deadline.
|
||||
func (c *StreamConn) SetReadDeadline(t time.Time) error {
|
||||
return c.stream.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the write deadline.
|
||||
func (c *StreamConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.stream.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
// Ensure StreamConn implements net.Conn
|
||||
var _ net.Conn = (*StreamConn)(nil)
|
||||
|
||||
Reference in New Issue
Block a user