7625973ca1
Implement UDP tunneling over HTTP/3 using HTTP Datagrams (RFC 9297): - Add masque handler for server-side CONNECT-UDP - Add masque connector and h3-masque dialer for client-side - Add enableDatagrams option to HTTP/3 listener - Add shared utilities for datagram connections and path parsing Resource management and connection caching: - Add deferred stream cleanup in connector on error paths - Add IsClosed() and Close() methods to Client for proper session management - Clean up stale cached clients in dialer before reuse - Close underlying stream when DatagramConn is closed - Move RequestStream opening from connector to dialer to enable dead connection detection and cache invalidation (follows QUIC dialer pattern)
61 lines
1.5 KiB
Go
61 lines
1.5 KiB
Go
package masque
|
|
|
|
import (
|
|
"errors"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// WellKnownPath is the well-known path prefix for MASQUE UDP proxying
|
|
WellKnownPath = "/.well-known/masque/udp/"
|
|
)
|
|
|
|
var (
|
|
ErrInvalidPath = errors.New("masque: invalid path template")
|
|
ErrInvalidPort = errors.New("masque: invalid port number")
|
|
)
|
|
|
|
// ParseMasquePath parses a MASQUE UDP proxy path template.
|
|
// The expected format is: /.well-known/masque/udp/{host}/{port}/
|
|
// Returns the host and port extracted from the path.
|
|
func ParseMasquePath(path string) (host string, port int, err error) {
|
|
if !strings.HasPrefix(path, WellKnownPath) {
|
|
return "", 0, ErrInvalidPath
|
|
}
|
|
|
|
remainder := strings.TrimPrefix(path, WellKnownPath)
|
|
remainder = strings.TrimSuffix(remainder, "/")
|
|
|
|
parts := strings.Split(remainder, "/")
|
|
if len(parts) != 2 {
|
|
return "", 0, ErrInvalidPath
|
|
}
|
|
|
|
host = parts[0]
|
|
if host == "" {
|
|
return "", 0, ErrInvalidPath
|
|
}
|
|
|
|
// URL decode the host in case it contains percent-encoded characters
|
|
host, err = url.PathUnescape(host)
|
|
if err != nil {
|
|
return "", 0, ErrInvalidPath
|
|
}
|
|
|
|
port, err = strconv.Atoi(parts[1])
|
|
if err != nil || port <= 0 || port > 65535 {
|
|
return "", 0, ErrInvalidPort
|
|
}
|
|
|
|
return host, port, nil
|
|
}
|
|
|
|
// BuildMasquePath constructs a MASQUE UDP proxy path from host and port.
|
|
func BuildMasquePath(host string, port int) string {
|
|
// URL encode the host in case it contains special characters (like IPv6 addresses)
|
|
encodedHost := url.PathEscape(host)
|
|
return WellKnownPath + encodedHost + "/" + strconv.Itoa(port) + "/"
|
|
}
|