Revert "feat(filtering): implement the divert policy ()" ()

This reverts commit 851b9913fae77e6b2d57fd7b1c1c04ee5a187ab1 because
it seems it's not enough to allow us to see certificate errors with
quic, plus it's complex code. So, we'd rather develop a better approach,
and perhaps a simpler one, that works with QUIC as well.
This commit is contained in:
Simone Basso 2021-11-03 14:01:32 +01:00 committed by GitHub
parent 851b9913fa
commit 100cc559a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 0 additions and 497 deletions
internal/netxlite/filtering

@ -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

@ -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) {