diff --git a/go.mod b/go.mod index 9bc3f6df7..f83b53862 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/coreos/stream-metadata-go v0.4.4 github.com/dustin/go-humanize v1.0.1 github.com/google/gopacket v1.1.19 + github.com/inetaf/tcpproxy v0.0.0-20240214030015-3ce58045626c github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 github.com/mdlayher/vsock v1.2.1 @@ -26,7 +27,6 @@ require ( golang.org/x/sync v0.6.0 golang.org/x/sys v0.18.0 gvisor.dev/gvisor v0.0.0-20231023213702-2691a8f9b1cf - inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 ) require ( diff --git a/go.sum b/go.sum index 00e71e060..2e2b9ab4f 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= +github.com/inetaf/tcpproxy v0.0.0-20240214030015-3ce58045626c h1:gYfYE403/nlrGNYj6BEOs9ucLCAGB9gstlSk92DttTg= +github.com/inetaf/tcpproxy v0.0.0-20240214030015-3ce58045626c/go.mod h1:Di7LXRyUcnvAcLicFhtM9/MlZl/TNgRSDHORM2c6CMI= github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f h1:l1QCwn715k8nYkj4Ql50rzEog3WnMdrd4YYMMwemxEo= github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= @@ -198,5 +200,3 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gvisor.dev/gvisor v0.0.0-20231023213702-2691a8f9b1cf h1:0A28IFBR6VcMacM0m6Rn5/nr8pk8xa2TyIkjSaFAOPc= gvisor.dev/gvisor v0.0.0-20231023213702-2691a8f9b1cf/go.mod h1:8hmigyCdYtw5xJGfQDJzSH5Ju8XEIDBnpyi8+O6GRt8= -inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 h1:PqdHrvQRVK1zapJkd0qf6+tevvSIcWdfenVqJd3PHWU= -inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0/go.mod h1:Tojt5kmHpDIR2jMojxzZK2w2ZR7OILODmUo2gaSwjrk= diff --git a/pkg/services/forwarder/ports.go b/pkg/services/forwarder/ports.go index 887092cbd..7d6c06c2d 100644 --- a/pkg/services/forwarder/ports.go +++ b/pkg/services/forwarder/ports.go @@ -17,12 +17,12 @@ import ( "github.com/containers/gvisor-tap-vsock/pkg/sshclient" "github.com/containers/gvisor-tap-vsock/pkg/types" + "github.com/inetaf/tcpproxy" log "github.com/sirupsen/logrus" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" "gvisor.dev/gvisor/pkg/tcpip/stack" - "inet.af/tcpproxy" ) type PortsForwarder struct { diff --git a/pkg/services/forwarder/tcp.go b/pkg/services/forwarder/tcp.go index 9026d662d..6493c94c6 100644 --- a/pkg/services/forwarder/tcp.go +++ b/pkg/services/forwarder/tcp.go @@ -6,13 +6,13 @@ import ( "net" "sync" + "github.com/inetaf/tcpproxy" log "github.com/sirupsen/logrus" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" "gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" "gvisor.dev/gvisor/pkg/waiter" - "inet.af/tcpproxy" ) const linkLocalSubnet = "169.254.0.0/16" diff --git a/pkg/virtualnetwork/mux.go b/pkg/virtualnetwork/mux.go index 94e89e030..cc61c5d75 100644 --- a/pkg/virtualnetwork/mux.go +++ b/pkg/virtualnetwork/mux.go @@ -8,11 +8,11 @@ import ( "strconv" "github.com/containers/gvisor-tap-vsock/pkg/types" + "github.com/inetaf/tcpproxy" log "github.com/sirupsen/logrus" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" - "inet.af/tcpproxy" ) func (n *VirtualNetwork) Mux() *http.ServeMux { diff --git a/vendor/inet.af/tcpproxy/.travis.yml b/vendor/github.com/inetaf/tcpproxy/.travis.yml similarity index 100% rename from vendor/inet.af/tcpproxy/.travis.yml rename to vendor/github.com/inetaf/tcpproxy/.travis.yml diff --git a/vendor/inet.af/tcpproxy/CONTRIBUTING.md b/vendor/github.com/inetaf/tcpproxy/CONTRIBUTING.md similarity index 100% rename from vendor/inet.af/tcpproxy/CONTRIBUTING.md rename to vendor/github.com/inetaf/tcpproxy/CONTRIBUTING.md diff --git a/vendor/inet.af/tcpproxy/LICENSE b/vendor/github.com/inetaf/tcpproxy/LICENSE similarity index 100% rename from vendor/inet.af/tcpproxy/LICENSE rename to vendor/github.com/inetaf/tcpproxy/LICENSE diff --git a/vendor/inet.af/tcpproxy/README.md b/vendor/github.com/inetaf/tcpproxy/README.md similarity index 59% rename from vendor/inet.af/tcpproxy/README.md rename to vendor/github.com/inetaf/tcpproxy/README.md index f526c213a..8181ceb91 100644 --- a/vendor/inet.af/tcpproxy/README.md +++ b/vendor/github.com/inetaf/tcpproxy/README.md @@ -1,5 +1,5 @@ # tcpproxy -For library usage, see https://godoc.org/inet.af/tcpproxy/ +For library usage, see https://pkg.go.dev/github.com/inetaf/tcpproxy/ For CLI usage, see https://github.com/inetaf/tcpproxy/blob/master/cmd/tlsrouter/README.md diff --git a/vendor/inet.af/tcpproxy/http.go b/vendor/github.com/inetaf/tcpproxy/http.go similarity index 100% rename from vendor/inet.af/tcpproxy/http.go rename to vendor/github.com/inetaf/tcpproxy/http.go diff --git a/vendor/inet.af/tcpproxy/listener.go b/vendor/github.com/inetaf/tcpproxy/listener.go similarity index 100% rename from vendor/inet.af/tcpproxy/listener.go rename to vendor/github.com/inetaf/tcpproxy/listener.go diff --git a/vendor/inet.af/tcpproxy/sni.go b/vendor/github.com/inetaf/tcpproxy/sni.go similarity index 51% rename from vendor/inet.af/tcpproxy/sni.go rename to vendor/github.com/inetaf/tcpproxy/sni.go index 53b53c24d..c2d37e01e 100644 --- a/vendor/inet.af/tcpproxy/sni.go +++ b/vendor/github.com/inetaf/tcpproxy/sni.go @@ -21,7 +21,6 @@ import ( "crypto/tls" "io" "net" - "strings" ) // AddSNIRoute appends a route to the ipPort listener that routes to @@ -29,10 +28,6 @@ import ( // match, rule processing continues for any additional routes on // ipPort. // -// By default, the proxy will route all ACME tls-sni-01 challenges -// received on ipPort to all SNI dests. You can disable ACME routing -// with AddStopACMESearch. -// // The ipPort is any valid net.Listen TCP address. func (p *Proxy) AddSNIRoute(ipPort, sni string, dest Target) { p.AddSNIMatchRoute(ipPort, equals(sni), dest) @@ -43,115 +38,43 @@ func (p *Proxy) AddSNIRoute(ipPort, sni string, dest Target) { // matcher. If it doesn't match, rule processing continues for any // additional routes on ipPort. // -// By default, the proxy will route all ACME tls-sni-01 challenges -// received on ipPort to all SNI dests. You can disable ACME routing -// with AddStopACMESearch. -// // The ipPort is any valid net.Listen TCP address. func (p *Proxy) AddSNIMatchRoute(ipPort string, matcher Matcher, dest Target) { - cfg := p.configFor(ipPort) - if !cfg.stopACME { - if len(cfg.acmeTargets) == 0 { - p.addRoute(ipPort, &acmeMatch{cfg}) - } - cfg.acmeTargets = append(cfg.acmeTargets, dest) - } - - p.addRoute(ipPort, sniMatch{matcher, dest}) + p.addRoute(ipPort, sniMatch{matcher: matcher, target: dest}) } -// AddStopACMESearch prevents ACME probing of subsequent SNI routes. -// Any ACME challenges on ipPort for SNI routes previously added -// before this call will still be proxied to all possible SNI -// backends. -func (p *Proxy) AddStopACMESearch(ipPort string) { - p.configFor(ipPort).stopACME = true +// SNITargetFunc is the func callback used by Proxy.AddSNIRouteFunc. +type SNITargetFunc func(ctx context.Context, sniName string) (t Target, ok bool) + +// AddSNIRouteFunc adds a route to ipPort that matches an SNI request and calls +// fn to map its nap to a target. +func (p *Proxy) AddSNIRouteFunc(ipPort string, fn SNITargetFunc) { + p.addRoute(ipPort, sniMatch{targetFunc: fn}) } type sniMatch struct { matcher Matcher target Target -} -func (m sniMatch) match(br *bufio.Reader) (Target, string) { - sni := clientHelloServerName(br) - if m.matcher(context.TODO(), sni) { - return m.target, sni - } - return nil, "" + // Alternatively, if targetFunc is non-nil, it's used instead: + targetFunc SNITargetFunc } -// acmeMatch matches "*.acme.invalid" ACME tls-sni-01 challenges and -// searches for a Target in cfg.acmeTargets that has the challenge -// response. -type acmeMatch struct { - cfg *config -} - -func (m *acmeMatch) match(br *bufio.Reader) (Target, string) { +func (m sniMatch) match(br *bufio.Reader) (Target, string) { sni := clientHelloServerName(br) - if !strings.HasSuffix(sni, ".acme.invalid") { + if sni == "" { return nil, "" } - - // TODO: cache. ACME issuers will hit multiple times in a short - // burst for each issuance event. A short TTL cache + singleflight - // should have an excellent hit rate. - // TODO: maybe an acme-specific timeout as well? - // TODO: plumb context upwards? - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - ch := make(chan Target, len(m.cfg.acmeTargets)) - for _, target := range m.cfg.acmeTargets { - go tryACME(ctx, ch, target, sni) - } - for range m.cfg.acmeTargets { - if target := <-ch; target != nil { - return target, sni + if m.targetFunc != nil { + if t, ok := m.targetFunc(context.TODO(), sni); ok { + return t, sni } + return nil, "" } - - // No target was happy with the provided challenge. - return nil, "" -} - -func tryACME(ctx context.Context, ch chan<- Target, dest Target, sni string) { - var ret Target - defer func() { ch <- ret }() - - conn, targetConn := net.Pipe() - defer conn.Close() - go dest.HandleConn(targetConn) - - deadline, ok := ctx.Deadline() - if ok { - conn.SetDeadline(deadline) - } - - client := tls.Client(conn, &tls.Config{ - ServerName: sni, - InsecureSkipVerify: true, - }) - if err := client.Handshake(); err != nil { - // TODO: log? - return - } - certs := client.ConnectionState().PeerCertificates - if len(certs) == 0 { - // TODO: log? - return - } - // acme says the first cert offered by the server must match the - // challenge hostname. - if err := certs[0].VerifyHostname(sni); err != nil { - // TODO: log? - return + if m.matcher(context.TODO(), sni) { + return m.target, sni } - - // Target presented what looks like a valid challenge - // response, send it back to the matcher. - ret = dest + return nil, "" } // clientHelloServerName returns the SNI server name inside the TLS ClientHello, diff --git a/vendor/inet.af/tcpproxy/tcpproxy.go b/vendor/github.com/inetaf/tcpproxy/tcpproxy.go similarity index 92% rename from vendor/inet.af/tcpproxy/tcpproxy.go rename to vendor/github.com/inetaf/tcpproxy/tcpproxy.go index 321ac88f2..1f03e3201 100644 --- a/vendor/inet.af/tcpproxy/tcpproxy.go +++ b/vendor/github.com/inetaf/tcpproxy/tcpproxy.go @@ -18,14 +18,14 @@ // // Typical usage: // -// var p tcpproxy.Proxy -// p.AddHTTPHostRoute(":80", "foo.com", tcpproxy.To("10.0.0.1:8081")) -// p.AddHTTPHostRoute(":80", "bar.com", tcpproxy.To("10.0.0.2:8082")) -// p.AddRoute(":80", tcpproxy.To("10.0.0.1:8081")) // fallback -// p.AddSNIRoute(":443", "foo.com", tcpproxy.To("10.0.0.1:4431")) -// p.AddSNIRoute(":443", "bar.com", tcpproxy.To("10.0.0.2:4432")) -// p.AddRoute(":443", tcpproxy.To("10.0.0.1:4431")) // fallback -// log.Fatal(p.Run()) +// var p tcpproxy.Proxy +// p.AddHTTPHostRoute(":80", "foo.com", tcpproxy.To("10.0.0.1:8081")) +// p.AddHTTPHostRoute(":80", "bar.com", tcpproxy.To("10.0.0.2:8082")) +// p.AddRoute(":80", tcpproxy.To("10.0.0.1:8081")) // fallback +// p.AddSNIRoute(":443", "foo.com", tcpproxy.To("10.0.0.1:4431")) +// p.AddSNIRoute(":443", "bar.com", tcpproxy.To("10.0.0.2:4432")) +// p.AddRoute(":443", tcpproxy.To("10.0.0.1:4431")) // fallback +// log.Fatal(p.Run()) // // Calling Run (or Start) on a proxy also starts all the necessary // listeners. @@ -93,9 +93,7 @@ func equals(want string) Matcher { // config contains the proxying state for one listener. type config struct { - routes []route - acmeTargets []Target // accumulates targets that should be probed for acme. - stopACME bool // if true, AddSNIRoute doesn't add targets to acmeTargets. + routes []route } // A route matches a connection to a target. @@ -347,8 +345,30 @@ func UnderlyingConn(c net.Conn) net.Conn { return c } +func tcpConn(c net.Conn) (t *net.TCPConn, ok bool) { + if c, ok := UnderlyingConn(c).(*net.TCPConn); ok { + return c, ok + } + if c, ok := c.(*net.TCPConn); ok { + return c, ok + } + return nil, false +} + func goCloseConn(c net.Conn) { go c.Close() } +func closeRead(c net.Conn) { + if c, ok := tcpConn(c); ok { + c.CloseRead() + } +} + +func closeWrite(c net.Conn) { + if c, ok := tcpConn(c); ok { + c.CloseWrite() + } +} + // HandleConn implements the Target interface. func (dp *DialProxy) HandleConn(src net.Conn) { ctx := context.Background() @@ -373,20 +393,19 @@ func (dp *DialProxy) HandleConn(src net.Conn) { defer goCloseConn(src) if ka := dp.keepAlivePeriod(); ka > 0 { - if c, ok := UnderlyingConn(src).(*net.TCPConn); ok { - c.SetKeepAlive(true) - c.SetKeepAlivePeriod(ka) - } - if c, ok := dst.(*net.TCPConn); ok { - c.SetKeepAlive(true) - c.SetKeepAlivePeriod(ka) + for _, c := range []net.Conn{src, dst} { + if c, ok := tcpConn(c); ok { + c.SetKeepAlive(true) + c.SetKeepAlivePeriod(ka) + } } } - errc := make(chan error, 1) + errc := make(chan error, 2) go proxyCopy(errc, src, dst) go proxyCopy(errc, dst, src) <-errc + <-errc } func (dp *DialProxy) sendProxyHeader(w io.Writer, src net.Conn) error { @@ -422,6 +441,9 @@ func (dp *DialProxy) sendProxyHeader(w io.Writer, src net.Conn) error { // It's a named function instead of a func literal so users get // named goroutines in debug goroutine stack dumps. func proxyCopy(errc chan<- error, dst, src net.Conn) { + defer closeRead(src) + defer closeWrite(dst) + // Before we unwrap src and/or dst, copy any buffered data. if wc, ok := src.(*Conn); ok && len(wc.Peeked) > 0 { if _, err := dst.Write(wc.Peeked); err != nil { diff --git a/vendor/modules.txt b/vendor/modules.txt index 0353dbbfa..ddbb750c0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -41,6 +41,9 @@ github.com/google/go-cmp/cmp/internal/value ## explicit; go 1.12 github.com/google/gopacket github.com/google/gopacket/layers +# github.com/inetaf/tcpproxy v0.0.0-20240214030015-3ce58045626c +## explicit; go 1.16 +github.com/inetaf/tcpproxy # github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f ## explicit; go 1.13 github.com/insomniacslk/dhcp/dhcpv4 @@ -262,6 +265,3 @@ gvisor.dev/gvisor/pkg/tcpip/transport/tcp gvisor.dev/gvisor/pkg/tcpip/transport/tcpconntrack gvisor.dev/gvisor/pkg/tcpip/transport/udp gvisor.dev/gvisor/pkg/waiter -# inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 -## explicit; go 1.16 -inet.af/tcpproxy