diff --git a/internal/netxlite/filtering/tproxy.go b/internal/netxlite/filtering/tproxy.go index 6ed50f7..59fb03f 100644 --- a/internal/netxlite/filtering/tproxy.go +++ b/internal/netxlite/filtering/tproxy.go @@ -7,8 +7,6 @@ import ( "fmt" "net" "os" - "strconv" - "strings" "time" "github.com/miekg/dns" @@ -41,10 +39,6 @@ const ( // TProxyPolicyHijackHTTP causes the dialer to replace the target // address with the address of the local censored HTTP server. TProxyPolicyHijackHTTP = TProxyPolicy("hijack-http") - - // TProxyPolicyDivert causes the dialer, or WriteTo, to look into the - // divert table to map the endpoint to another endpoint. - TProxyPolicyDivert = TProxyPolicy("divert") ) // TProxyConfig contains configuration for TProxy. @@ -58,10 +52,6 @@ type TProxyConfig struct { // method _before_ using the TProxy. DNSCache map[string][]string - // Divert is a table that maps an endpoint to another endpoint. This - // table is only cheched when using the "divert" policy in the Endpoints table. - Divert map[string]string - // Domains contains rules for filtering the lookup of domains. Note // that the map MUST contain FQDNs. That is, you need to append // a final dot to the domain name (e.g., `example.com.`). If you @@ -234,53 +224,11 @@ func (c *tProxyUDPLikeConn) WriteTo(pkt []byte, addr net.Addr) (int, error) { case TProxyPolicyDropData: c.proxy.logger.Infof("tproxy: WriteTo: %s => %s", endpoint, policy) return len(pkt), nil - case TProxyPolicyDivert: - c.proxy.logger.Infof("tproxy: WriteTo: %s => %s", endpoint, policy) - return c.writeToWithDivert(pkt, endpoint) default: return c.UDPLikeConn.WriteTo(pkt, addr) } } -var ( - errMissingDivertEntry = errors.New("tproxy: missing divert entry") - errInvalidDivertProtocol = errors.New("tproxy: invalid divert protocol") - errInvalidDivertIP = errors.New("tproxy: invalid divert IP") - errInvalidDivertPort = errors.New("tproxy: invalid divert port") -) - -func (c *tProxyUDPLikeConn) writeToWithDivert(pkt []byte, endpoint string) (int, error) { - divert := c.proxy.config.Divert[endpoint] - if divert == "" { - return 0, errMissingDivertEntry - } - idx := strings.LastIndex(divert, "/udp") - if idx < 0 { - return 0, errInvalidDivertProtocol - } - divert = divert[:idx] - addr, port, err := net.SplitHostPort(divert) - if err != nil { - return 0, err - } - ipAddr := net.ParseIP(addr) - if ipAddr == nil { - return 0, errInvalidDivertIP - } - portnum, err := strconv.Atoi(port) - if err != nil { - return 0, err - } - if portnum <= 0 || portnum > 65535 { - return 0, errInvalidDivertPort - } - udpAddr := &net.UDPAddr{ - IP: ipAddr, - Port: portnum, - } - return c.UDPLikeConn.WriteTo(pkt, udpAddr) -} - // // System resolver // @@ -328,9 +276,6 @@ func (d *tProxyDialer) DialContext(ctx context.Context, network, address string) case TProxyPolicyTCPRejectSYN: d.proxy.logger.Infof("tproxy: DialContext: %s/%s => %s", address, network, policy) return nil, netxlite.ECONNREFUSED - case TProxyPolicyDivert: - d.proxy.logger.Infof("tproxy: DialContext: %s/%s => %s", address, network, policy) - return d.dialContextWithDivert(ctx, network, endpoint) case TProxyPolicyHijackDNS: d.proxy.logger.Infof("tproxy: DialContext: %s/%s => %s", address, network, policy) address = d.proxy.dnsListener.LocalAddr().String() @@ -343,29 +288,6 @@ func (d *tProxyDialer) DialContext(ctx context.Context, network, address string) default: // nothing } - return d.doDialContext(ctx, network, address) -} - -func (d *tProxyDialer) dialContextWithDivert( - ctx context.Context, network, endpoint string) (net.Conn, error) { - divert := d.proxy.config.Divert[endpoint] - if divert == "" { - return nil, errMissingDivertEntry - } - idx := strings.LastIndex(divert, "/") - if idx < 0 { - return nil, errInvalidDivertProtocol - } - address := divert[:idx] - protocol := divert[idx+1:] - if protocol != "tcp" && protocol != "udp" { - return nil, errInvalidDivertProtocol - } - return d.doDialContext(ctx, network, address) -} - -func (d *tProxyDialer) doDialContext( - ctx context.Context, network, address string) (net.Conn, error) { conn, err := d.dialer.DialContext(ctx, network, address) if err != nil { return nil, err diff --git a/internal/netxlite/filtering/tproxy_test.go b/internal/netxlite/filtering/tproxy_test.go index 1fed6a8..aca4247 100644 --- a/internal/netxlite/filtering/tproxy_test.go +++ b/internal/netxlite/filtering/tproxy_test.go @@ -224,320 +224,6 @@ func TestTProxyQUIC(t *testing.T) { t.Fatal("called") } }) - - t.Run("with divert policy", func(t *testing.T) { - t.Run("no divert entry", func(t *testing.T) { - config := &TProxyConfig{ - Endpoints: map[string]TProxyPolicy{ - "127.0.0.1:1234/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - var called bool - proxy.listenUDP = func(network string, laddr *net.UDPAddr) (quicx.UDPLikeConn, error) { - return &mocks.QUICUDPLikeConn{ - MockWriteTo: func(p []byte, addr net.Addr) (int, error) { - called = true - return len(p), nil - }, - }, nil - } - pconn, err := proxy.ListenUDP("udp", &net.UDPAddr{}) - if err != nil { - t.Fatal(err) - } - data := make([]byte, 128) - destAddr := &net.UDPAddr{ - IP: net.IPv4(127, 0, 0, 1), - Port: 1234, - Zone: "", - } - count, err := pconn.WriteTo(data, destAddr) - if !errors.Is(err, errMissingDivertEntry) { - t.Fatal("unexpected err", err) - } - if count != 0 { - t.Fatal("unexpected number of bytes written") - } - if called { - t.Fatal("called") - } - }) - - t.Run("invalid protocol", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "127.0.0.1:1234/udp": "127.0.0.1:1235", - }, - Endpoints: map[string]TProxyPolicy{ - "127.0.0.1:1234/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - var called bool - proxy.listenUDP = func(network string, laddr *net.UDPAddr) (quicx.UDPLikeConn, error) { - return &mocks.QUICUDPLikeConn{ - MockWriteTo: func(p []byte, addr net.Addr) (int, error) { - called = true - return len(p), nil - }, - }, nil - } - pconn, err := proxy.ListenUDP("udp", &net.UDPAddr{}) - if err != nil { - t.Fatal(err) - } - data := make([]byte, 128) - destAddr := &net.UDPAddr{ - IP: net.IPv4(127, 0, 0, 1), - Port: 1234, - Zone: "", - } - count, err := pconn.WriteTo(data, destAddr) - if !errors.Is(err, errInvalidDivertProtocol) { - t.Fatal("unexpected err", err) - } - if count != 0 { - t.Fatal("unexpected number of bytes written") - } - if called { - t.Fatal("called") - } - }) - - t.Run("invalid addrport", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "127.0.0.1:1234/udp": "127.0.0.1/udp", - }, - Endpoints: map[string]TProxyPolicy{ - "127.0.0.1:1234/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - var called bool - proxy.listenUDP = func(network string, laddr *net.UDPAddr) (quicx.UDPLikeConn, error) { - return &mocks.QUICUDPLikeConn{ - MockWriteTo: func(p []byte, addr net.Addr) (int, error) { - called = true - return len(p), nil - }, - }, nil - } - pconn, err := proxy.ListenUDP("udp", &net.UDPAddr{}) - if err != nil { - t.Fatal(err) - } - data := make([]byte, 128) - destAddr := &net.UDPAddr{ - IP: net.IPv4(127, 0, 0, 1), - Port: 1234, - Zone: "", - } - count, err := pconn.WriteTo(data, destAddr) - if err == nil || !strings.HasSuffix(err.Error(), "missing port in address") { - t.Fatal("unexpected err", err) - } - if count != 0 { - t.Fatal("unexpected number of bytes written") - } - if called { - t.Fatal("called") - } - }) - - t.Run("invalid address", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "127.0.0.1:1234/udp": "localhost:1235/udp", - }, - Endpoints: map[string]TProxyPolicy{ - "127.0.0.1:1234/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - var called bool - proxy.listenUDP = func(network string, laddr *net.UDPAddr) (quicx.UDPLikeConn, error) { - return &mocks.QUICUDPLikeConn{ - MockWriteTo: func(p []byte, addr net.Addr) (int, error) { - called = true - return len(p), nil - }, - }, nil - } - pconn, err := proxy.ListenUDP("udp", &net.UDPAddr{}) - if err != nil { - t.Fatal(err) - } - data := make([]byte, 128) - destAddr := &net.UDPAddr{ - IP: net.IPv4(127, 0, 0, 1), - Port: 1234, - Zone: "", - } - count, err := pconn.WriteTo(data, destAddr) - if !errors.Is(err, errInvalidDivertIP) { - t.Fatal("unexpected err", err) - } - if count != 0 { - t.Fatal("unexpected number of bytes written") - } - if called { - t.Fatal("called") - } - }) - - t.Run("invalid port syntax", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "127.0.0.1:1234/udp": "127.0.0.1:xo/udp", - }, - Endpoints: map[string]TProxyPolicy{ - "127.0.0.1:1234/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - var called bool - proxy.listenUDP = func(network string, laddr *net.UDPAddr) (quicx.UDPLikeConn, error) { - return &mocks.QUICUDPLikeConn{ - MockWriteTo: func(p []byte, addr net.Addr) (int, error) { - called = true - return len(p), nil - }, - }, nil - } - pconn, err := proxy.ListenUDP("udp", &net.UDPAddr{}) - if err != nil { - t.Fatal(err) - } - data := make([]byte, 128) - destAddr := &net.UDPAddr{ - IP: net.IPv4(127, 0, 0, 1), - Port: 1234, - Zone: "", - } - count, err := pconn.WriteTo(data, destAddr) - if err == nil || !strings.HasSuffix(err.Error(), "invalid syntax") { - t.Fatal("unexpected err", err) - } - if count != 0 { - t.Fatal("unexpected number of bytes written") - } - if called { - t.Fatal("called") - } - }) - - t.Run("invalid port value", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "127.0.0.1:1234/udp": "127.0.0.1:65536/udp", - }, - Endpoints: map[string]TProxyPolicy{ - "127.0.0.1:1234/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - var called bool - proxy.listenUDP = func(network string, laddr *net.UDPAddr) (quicx.UDPLikeConn, error) { - return &mocks.QUICUDPLikeConn{ - MockWriteTo: func(p []byte, addr net.Addr) (int, error) { - called = true - return len(p), nil - }, - }, nil - } - pconn, err := proxy.ListenUDP("udp", &net.UDPAddr{}) - if err != nil { - t.Fatal(err) - } - data := make([]byte, 128) - destAddr := &net.UDPAddr{ - IP: net.IPv4(127, 0, 0, 1), - Port: 1234, - Zone: "", - } - count, err := pconn.WriteTo(data, destAddr) - if !errors.Is(err, errInvalidDivertPort) { - t.Fatal("unexpected err", err) - } - if count != 0 { - t.Fatal("unexpected number of bytes written") - } - if called { - t.Fatal("called") - } - }) - - t.Run("correct settings", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "127.0.0.1:1234/udp": "127.0.0.1:1235/udp", - }, - Endpoints: map[string]TProxyPolicy{ - "127.0.0.1:1234/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - var realAddr *net.UDPAddr - proxy.listenUDP = func(network string, laddr *net.UDPAddr) (quicx.UDPLikeConn, error) { - return &mocks.QUICUDPLikeConn{ - MockWriteTo: func(p []byte, addr net.Addr) (int, error) { - realAddr = addr.(*net.UDPAddr) - return len(p), nil - }, - }, nil - } - pconn, err := proxy.ListenUDP("udp", &net.UDPAddr{}) - if err != nil { - t.Fatal(err) - } - data := make([]byte, 128) - destAddr := &net.UDPAddr{ - IP: net.IPv4(127, 0, 0, 1), - Port: 1234, - Zone: "", - } - count, err := pconn.WriteTo(data, destAddr) - if err != nil { - t.Fatal(err) - } - if count != len(data) { - t.Fatal("unexpected number of bytes written") - } - if realAddr == nil || (*realAddr).Port != 1235 { - t.Fatal("invalid realAddr or invalid port value") - } - }) - }) }) } @@ -835,111 +521,6 @@ func TestTProxyDial(t *testing.T) { t.Fatal("expected nil conn here") } }) - - t.Run("with divert", func(t *testing.T) { - t.Run("with missing entry", func(t *testing.T) { - config := &TProxyConfig{ - Endpoints: map[string]TProxyPolicy{ - "8.8.8.8:53/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - dialer := proxy.NewTProxyDialer(10 * time.Second) - resolver := netxlite.NewResolverUDP( - log.Log, &tProxyDialerAdapter{dialer}, "8.8.8.8:53") - addrs, err := resolver.LookupHost(context.Background(), "example.com") - if !errors.Is(err, errMissingDivertEntry) { - t.Fatal("unexpected err", err) - } - if len(addrs) != 0 { - t.Fatal("expected no addrs here") - } - }) - - t.Run("with no divert protocol", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "8.8.8.8:53/udp": "8.8.8.8:54", - }, - Endpoints: map[string]TProxyPolicy{ - "8.8.8.8:53/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - dialer := proxy.NewTProxyDialer(10 * time.Second) - resolver := netxlite.NewResolverUDP( - log.Log, &tProxyDialerAdapter{dialer}, "8.8.8.8:53") - addrs, err := resolver.LookupHost(context.Background(), "example.com") - if !errors.Is(err, errInvalidDivertProtocol) { - t.Fatal("unexpected err", err) - } - if len(addrs) != 0 { - t.Fatal("expected no addrs here") - } - }) - - t.Run("with invalid divert protocol", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "8.8.8.8:53/udp": "8.8.8.8:54/antani", - }, - Endpoints: map[string]TProxyPolicy{ - "8.8.8.8:53/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - dialer := proxy.NewTProxyDialer(10 * time.Second) - resolver := netxlite.NewResolverUDP( - log.Log, &tProxyDialerAdapter{dialer}, "8.8.8.8:53") - addrs, err := resolver.LookupHost(context.Background(), "example.com") - if !errors.Is(err, errInvalidDivertProtocol) { - t.Fatal("unexpected err", err) - } - if len(addrs) != 0 { - t.Fatal("expected no addrs here") - } - }) - - t.Run("with all good", func(t *testing.T) { - config := &TProxyConfig{ - Divert: map[string]string{ - "8.8.8.8:53/udp": "8.8.8.8:54/udp", - }, - Endpoints: map[string]TProxyPolicy{ - "8.8.8.8:53/udp": TProxyPolicyDivert, - }, - } - proxy, err := NewTProxy(config, log.Log) - if err != nil { - t.Fatal(err) - } - defer proxy.Close() - dialer := proxy.NewTProxyDialer(10 * time.Second) - resolver := netxlite.NewResolverUDP( - log.Log, &tProxyDialerAdapter{dialer}, "8.8.8.8:53") - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - addrs, err := resolver.LookupHost(ctx, "example.com") - if err == nil || err.Error() != netxlite.FailureGenericTimeoutError { - t.Fatal("unexpected err", err) - } - if len(addrs) != 0 { - t.Fatal("expected no addrs here") - } - }) - }) } func TestTProxyDNSCache(t *testing.T) {