diff --git a/README.md b/README.md index cd7c3bb..77279b6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![PkgGoDev](https://pkg.go.dev/badge/github.com/invisv-privacy/masque)](https://pkg.go.dev/github.com/invisv-privacy/masque) ![Build Status](https://github.com/invisv-privacy/masque/actions/workflows/build.yaml/badge.svg?branch=main) +[![godocs.io](https://godocs.io/github.com/invisv-privacy/masque?status.svg)](https://godocs.io/github.com/invisv-privacy/masque) ## What is INVISV masque? @@ -52,6 +53,10 @@ $ curl -v --proxy http://localhost:32190 ipinfo.io/ip 146.75.153.247 ``` +## Example application: Preproxy + +In addition to the Relay HTTP Proxy sample application, we have included an application we call the "preproxy". This performs a combination of functions: reverse proxying of inbound traffic and tunneling of that traffic via a (multi-hop) MASQUE tunnel to a given destination. This enables use of unmodified applications with MASQUE tunnels, where the remote client network stack is potentially unaware of the MASQUE tunnel yet wishes to use a MASQUE to reach a destination. See the documentation of preproxy for details. + ## Testing We have automated tests which utilize an h2o container that we can leverage as the MASQUE target. diff --git a/config.go b/config.go index 6fbd690..a36d08f 100644 --- a/config.go +++ b/config.go @@ -1,3 +1,4 @@ +// Package masque implements a client-side IETF MASQUE protocol stack. package masque import "time" diff --git a/example/preproxy/main.go b/example/preproxy/main.go index aa75195..a775f8a 100644 --- a/example/preproxy/main.go +++ b/example/preproxy/main.go @@ -20,6 +20,7 @@ import ( ) // A port list to be used as a default if one is not provided via a file. +// These are the ports that preproxy should listen on. var PortListBase = []int{ 80, 443, 5349, 7880, } @@ -33,6 +34,7 @@ var PortListBaseUdp = []int{ var insecure *bool // This port range is to allow a large number of UDP ports to be added. +// This is useful when a client may use an unknown high port number. const PortRangeUdpMin = 50000 const PortRangeUdpMax = 60000 @@ -53,8 +55,10 @@ func defaultPortList() ([]int, []int) { return portListTCP, portListUDP } -// Load the provided port file. Returns a list of TCP and UDP ports to forward. -// The format of the file is tcp:port_number or udp:port_number on individual lines. +// loadPortFile loads the provided port file. It returns a list of TCP and UDP +// ports to forward. The format of the file is tcp:port_number or +// udp:port_number on individual lines. +// // TODO: Support port ranges in the form of udp:port_start-port_end func loadPortFile(portFile string) ([]int, []int, error) { portList, err := os.ReadFile(portFile) @@ -91,10 +95,10 @@ func loadPortFile(portFile string) ([]int, []int, error) { return portListTCP, portListUDP, nil } -// Preproxy executable. Starts running the preproxy on localaddr by tunneling connections thru the given proxyaddr +// Starts running the preproxy on localaddr by tunneling connections thru the given proxyaddr // to the final destination targetServer for the ports configured (either by default or via the portconf file). func main() { - invisvRelay := flag.String("invisvRelay", "fastest.pgpp.stations.invisv.com", "Invisv Relay Server") + invisvRelay := flag.String("invisvRelay", "", "Invisv Relay Server") invisvRelayPort := flag.String("invisvRelayPort", "443", "Invisv Relay Server Port") targetServer := flag.String("targetServer", "", "Target server to proxy all connections to") @@ -294,10 +298,12 @@ func Transfer(dst io.WriteCloser, src io.ReadCloser) { } } -// A connFailFunc is called when a Relay stream creation fails. It is given the connection being proxied so it can reply to the client if needed. +// A connFailFunc is called when a Relay stream creation fails. It is given the +// connection being proxied so it can reply to the client if needed. type connFailFunc func(c net.Conn) -// HandleConnectMasque creates a new TCP or UDP stream via the relayClient and returns the connected stream upon success. +// HandleConnectMasque creates a new TCP or UDP stream via the relayClient and +// returns the connected stream upon success. func HandleConnectMasque(relayClient *masqueH3.Client, c net.Conn, target string, isTcp bool, fail connFailFunc) (io.ReadWriteCloser, error) { _, port, err := net.SplitHostPort(target) if err != nil { diff --git a/example/relay-http-proxy/main.go b/example/relay-http-proxy/main.go index 992fcd6..ab2ea2c 100644 --- a/example/relay-http-proxy/main.go +++ b/example/relay-http-proxy/main.go @@ -1,10 +1,8 @@ -/* -relay-http-proxy is a sample application that uses the INVISV IETF MASQUE -stack. It listens on a local port, presenting an ordinary HTTP proxy -interface, and sends requests it receives to the destination host via the -MASQUE relay server, such as the one run by INVISV. In effect, this tunnels -ordinary HTTP via MASQUE (which is itself an extension to HTTP). -*/ +// relay-http-proxy is a sample application that uses the INVISV IETF MASQUE +// stack. It listens on a local port, presenting an ordinary HTTP proxy +// interface, and sends requests it receives to the destination host via the +// MASQUE relay server, such as the one run by INVISV. In effect, this tunnels +// ordinary HTTP via MASQUE (which is itself an extension to HTTP). package main import ( diff --git a/http2/client.go b/http2/client.go index fef0da9..d24f976 100644 --- a/http2/client.go +++ b/http2/client.go @@ -31,11 +31,14 @@ const ( // Client is a MASQUE HTTP/2 client that supports HTTP CONNECT and CONNECT-UDP. // All CONNECT requests are multiplexed using a HTTP/2 transport. // Each CONNECT-UDP request is performed in HTTP/1.1 and sent individually -// via its own TLS connection. Any CONNECT or CONNECT-UDP requests that need HTTP/3 should not directly use this. +// via its own TLS connection. Any CONNECT or CONNECT-UDP requests that +// need HTTP/3 should not directly use this. // // The tlsTimeout setting determines the duration the client waits when // attempting to create a new TLS connection to the proxy. An error is returned // if the connection is not ready to use within the specified tlsTimeout. +// +// prot if not nil should be called before connect. type Client struct { proxyAddr string authToken string @@ -45,7 +48,7 @@ type Client struct { tlsTimeout time.Duration tcpReqs map[uint64]*Conn udpReqs map[uint64]*Conn - prot SocketProtector // Call before connect + prot SocketProtector certData []byte makingSpare bool lowLatencyAddrs map[string]bool @@ -54,6 +57,8 @@ type Client struct { ignoreCert bool } +// ClientConfig is a configuration for a MASQUE client to be used to set +// the configuration of a new Client to be created. type ClientConfig struct { ProxyAddr string AuthToken string diff --git a/http2/conn.go b/http2/conn.go index 4cd5223..e060ecb 100644 --- a/http2/conn.go +++ b/http2/conn.go @@ -33,8 +33,8 @@ type connCleanupFunc func(bool, uint64) // and a pair of I/O handles, namely |IoInc| and |IoOut|, designed for // sending and receiving data via the proxied TCP/UDP connection. // -// For CONNECT-UDP using HTTP/1.1, the |transport| field keeps track of the unique -// HTTP/1.1 TLS connection to the destination proxy server. +// For CONNECT-UDP using HTTP/1.1, the |transport| field keeps track of the +// unique HTTP/1.1 TLS connection to the destination proxy server. // // The |Alive| field indicates the liveness of the underlying CONNECT-UDP HTTP connection. // Users should only send data through this proxied connection if |Alive| is true. diff --git a/http3/client.go b/http3/client.go index 7672988..99c2e1a 100644 --- a/http3/client.go +++ b/http3/client.go @@ -74,6 +74,7 @@ type Client struct { // ClientConfig is options to give when creating a new Client with NewClient(). // Note that sane defaults are used when value is not provided/initialized. type ClientConfig struct { + // The proxy to connect to in host:port format. ProxyAddr string // Maximium number of incoming streams. Typically not an issue, as @@ -108,8 +109,10 @@ type ClientConfig struct { // DatagramStream is an object for Proxied UDP Streams that implements I/O functionality. // This object contains information necessary to communicate with the Client // message receiver loop. +// // Read/Write on a DatagramStream works as expected, though note it will use // Datagram framing semantics (each block is an individual UDP packet). +// // It is important that the caller DO NOT close the quic.Stream OR the quic.Connection // object that is given inside of the struct. type DatagramStream struct { @@ -337,7 +340,8 @@ func (c *Client) stopReceiveLoop() error { return nil } -// Gets a new H3_DATAGRAM Flow ID to be used with a UDP stream. +// getNewDatagramID gets a new H3_DATAGRAM Flow ID to be used with a UDP +// stream. func (c *Client) getNewDatagramID() uint64 { c.mutex.Lock() defer c.mutex.Unlock() @@ -573,7 +577,7 @@ func (s *DatagramStream) Read(b []byte) (int, error) { } -// Writes to a datagram stream. May block if the stream buffer is full. +// Write writes to a datagram stream. May block if the stream buffer is full. // Note that this function requires prepending 1 to 9 bytes to send the datagram: // this means that the MTU size of the connection will be below what the caller // may expect. diff --git a/internal/utils/tls.go b/internal/utils/tls.go index c796dea..c7264f7 100644 --- a/internal/utils/tls.go +++ b/internal/utils/tls.go @@ -8,7 +8,7 @@ import ( ) // TLSVerifyFunc takes a cert data byte slice and returns a function that can be -// passed to the tls.Config.VerifyPeerCertificate for pinning +// passed to the tls.Config.VerifyPeerCertificate for pinning. func TLSVerifyFunc(certData []byte) (func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error, error) { block, _ := pem.Decode(certData) if block == nil {