From 03d3dd6d56ce059fe3d05e507719e2304d53679a Mon Sep 17 00:00:00 2001 From: Oleksii Shevchuk Date: Tue, 31 Dec 2019 09:29:44 +0200 Subject: [PATCH] pproxy: improve ipv6 support --- pupy/pupylib/PupyOffload.py | 18 +++++++++++++- pupy/pupylib/PupyServer.py | 17 +++++++++++--- services/proxy/daemon.go | 19 ++++++++++++--- services/proxy/generate.go | 23 +++++++++++++++--- services/proxy/main.go | 47 ++++++++++++++++++------------------- services/proxy/streams.go | 13 +++++----- 6 files changed, 96 insertions(+), 41 deletions(-) diff --git a/pupy/pupylib/PupyOffload.py b/pupy/pupylib/PupyOffload.py index 62e6d1bb..a28878e4 100644 --- a/pupy/pupylib/PupyOffload.py +++ b/pupy/pupylib/PupyOffload.py @@ -34,9 +34,11 @@ REQUEST_TCP_LISTENER = 2 REQUEST_KCP_LISTENER = 3 REQUEST_TLS_LISTENER = 4 + class OffloadProxyCommonError(Exception): pass + class MsgPackMessages(object): def __init__(self, conn): self._conn = conn @@ -59,6 +61,7 @@ class MsgPackMessages(object): datalen_b = struct.pack('>I', datalen) self._conn.sendall(datalen_b + data) + class PupyOffloadDNS(threading.Thread): QTYPE = QTYPE.reverse @@ -135,6 +138,7 @@ class PupyOffloadDNS(threading.Thread): if self.handler: self.handler.finished.set() + class PupyOffloadSocket(object): def __init__(self, sock, lhost, lport, rhost, rport): self._sock = sock @@ -152,6 +156,7 @@ class PupyOffloadSocket(object): return getattr(self, attr) return getattr(self._sock, attr) + class PupyOffloadAcceptor(object): def __init__(self, manager, proto, port=None, extra={}, mtu=0): self._manager = manager @@ -239,8 +244,19 @@ class PupyOffloadAcceptor(object): class PupyOffloadManager(object): def __init__(self, server, ca, key, crt, via): if ':' in server: - host, port = server.rsplit(':', 1) + if server.startswith('['): + ipv6_end = server.index(']') + host = server[1:ipv6_end] + rest = server[ipv6_end:] + if ':' in rest: + _, port = rest.rsplit(':', 1) + else: + raise OffloadProxyCommonError('Invalid server specification') + else: + host, port = server.rsplit(':', 1) + self._server = (host, int(port)) + elif len(server) == 2: self._server = server else: diff --git a/pupy/pupylib/PupyServer.py b/pupy/pupylib/PupyServer.py index bb3aeac4..0f7603f5 100644 --- a/pupy/pupylib/PupyServer.py +++ b/pupy/pupylib/PupyServer.py @@ -309,15 +309,23 @@ class Listener(Thread): self.close() def __str__(self): + if self.external: + external = self.external + if ':' in external: + external = '[' + external + ']' + else: + external = '' + if self.port == 0: return '{}: pproxy:{}:{}'.format( - self.name, self.external, self.external_port + self.name, external, self.external_port ) result = str(self.port) if self.address: result = '{}:{}'.format( - self.address if not self.ipv6 else '[{}]'.format(self.address), + self.address if not self.ipv6 and ':' not in self.address + else '[{}]'.format(self.address), self.port ) @@ -326,7 +334,7 @@ class Listener(Thread): result = '0.0.0.0:{}'.format(result) result = 'Remote: {}:{} -> Local: {}'.format( - self.external, self.external_port, result + external, self.external_port, result ) if self.kwargs: @@ -627,6 +635,9 @@ class PupyServer(object): except: client_ip, client_port = '0.0.0.0', 0 + if ':' in client_ip: + client_ip = '[' + client_ip + ']' + remote = ' ({}:{})'.format(client_ip, client_port) user = client_info.get('user', '?') diff --git a/services/proxy/daemon.go b/services/proxy/daemon.go index e0f2dd67..4e176062 100644 --- a/services/proxy/daemon.go +++ b/services/proxy/daemon.go @@ -120,12 +120,25 @@ func (d *Daemon) handle(conn net.Conn) { d.DNSLock.Unlock() case INFO: - ip := GetOutboundIP() + var ip string + if CheckExternalBindHostIP() { ip = ExternalBindHost - } + if string(ip[0]) == "[" { + ip = ip[1 : len(ip)-1] + } - log.Warning("Request: External IP:", ip) + log.Warning("Request: External IP:", ip, " (Manual)") + } else { + ipv4 := GetOutboundIPv4() + ipv6 := GetOutboundIPv6() + + log.Warning( + "Request: External IPv4:", ipv4, + " IPv6:", ipv6, " (Auto)") + + ip = ipv4 + } SendMessage(conn, &IPInfo{ IP: ip, diff --git a/services/proxy/generate.go b/services/proxy/generate.go index dfd26153..4594fbc8 100644 --- a/services/proxy/generate.go +++ b/services/proxy/generate.go @@ -16,7 +16,7 @@ import ( log "github.com/sirupsen/logrus" ) -func GetOutboundIP() string { +func GetOutboundIPv4() string { conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { log.Fatal(err) @@ -28,7 +28,24 @@ func GetOutboundIP() string { return localAddr.IP.String() } +func GetOutboundIPv6() string { + conn, err := net.Dial("udp", "[2001:4860:4860::8888]:80") + if err != nil { + log.Fatal(err) + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP.String() +} + func CheckExternalBindHostIP() bool { + host := ExternalBindHost + if string(host[0]) == "[" { + host = ExternalBindHost[1 : len(ExternalBindHost)-1] + } + ifaces, err := net.Interfaces() if err != nil { return false @@ -51,7 +68,7 @@ func CheckExternalBindHostIP() bool { } // process IP address - if ip.String() == ExternalBindHost { + if ip.String() == host { return true } } @@ -69,7 +86,7 @@ func getCN() string { return ExternalBindHost default: - return GetOutboundIP() + return GetOutboundIPv4() } } diff --git a/services/proxy/main.go b/services/proxy/main.go index dff9dbbd..faaeb38f 100644 --- a/services/proxy/main.go +++ b/services/proxy/main.go @@ -1,7 +1,7 @@ package main import ( - "fmt" + "net" "path" "io/ioutil" @@ -18,18 +18,18 @@ import ( ) var ( - ProxyBindHost = "0.0.0.0" - ExternalBindHost = "0.0.0.0" - ProxyBindPort uint = 9876 - DnsBindPort uint = 5454 - ProxyHostname = "" - UDPSize uint = 1400 - ListenerCA = path.Join("..", "crypto", "proxy-ca.crt") - ListenerCAKey = path.Join("..", "crypto", "proxy-ca.key") - ListenerKey = path.Join("..", "crypto", "proxy.key") - ListenerCert = path.Join("..", "crypto", "proxy.crt") - ClientKey = path.Join("..", "crypto", "proxy-client.key") - ClientCert = path.Join("..", "crypto", "proxy-client.crt") + ProxyBindHost = "[::]:9876" + ExternalBindHost = "::" + + DnsBindPort uint = 5454 + ProxyHostname = "" + UDPSize uint = 1400 + ListenerCA = path.Join("..", "crypto", "proxy-ca.crt") + ListenerCAKey = path.Join("..", "crypto", "proxy-ca.key") + ListenerKey = path.Join("..", "crypto", "proxy.key") + ListenerCert = path.Join("..", "crypto", "proxy.crt") + ClientKey = path.Join("..", "crypto", "proxy-client.key") + ClientCert = path.Join("..", "crypto", "proxy-client.crt") PortMaps []PortMap @@ -45,7 +45,6 @@ func init() { portmap := "" flag.StringVar(&ProxyBindHost, "listen-proxy", ProxyBindHost, "IP address to bind pupysh listener side") - flag.UintVar(&ProxyBindPort, "port-proxy", ProxyBindPort, "Port to bind pupysh listener side") flag.StringVar(&ExternalBindHost, "listen", ExternalBindHost, "IP address to bind services listener side") flag.UintVar(&DnsBindPort, "dns-port", DnsBindPort, "Port to bind DNS listeners (if any)") flag.UintVar(&UDPSize, "udp-mtu-size", UDPSize, "MTU Size for DNS and KCP UDP Packets") @@ -115,22 +114,22 @@ func init() { } } - if strings.Index(ProxyBindHost, ":") == -1 { - if ExternalBindHost == "0.0.0.0" { - ExternalBindHost = ProxyBindHost - } + host, _, err := net.SplitHostPort(ExternalBindHost) + if err == nil && host != "" { + ExternalBindHost = host + } - ProxyBindHost = fmt.Sprintf("%s:%d", ProxyBindHost, ProxyBindPort) - } else { - if ExternalBindHost == "0.0.0.0" { - ExternalBindHost = strings.SplitN(ProxyBindHost, ":", 1)[0] - } + if ExternalBindHost == "" { + ExternalBindHost = "::" } if strings.Index(ExternalBindHost, ":") != -1 { - log.Fatalln("External IP address should be specified without port") + ExternalBindHost = "[" + ExternalBindHost + "]" } + log.Warn("Mapper binds to ", ExternalBindHost) + log.Warn("Proxy binds to ", ProxyBindHost) + if generate { log.Warn("Genrating NEW keys") generateKeys() diff --git a/services/proxy/streams.go b/services/proxy/streams.go index c839e9f6..591fdebf 100644 --- a/services/proxy/streams.go +++ b/services/proxy/streams.go @@ -5,7 +5,6 @@ import ( "io" "net" "strconv" - "strings" "time" @@ -107,16 +106,16 @@ func NewNetForwarder(pproxy, remote net.Conn) *NetForwarder { } func (n *NetForwarder) sendRemoteConnectionInfo() error { - localAddr := strings.Split(n.remote.LocalAddr().String(), ":") - remoteAddr := strings.Split(n.remote.RemoteAddr().String(), ":") + localAddr, localPortS, _ := net.SplitHostPort(n.remote.LocalAddr().String()) + remoteAddr, remotePortS, _ := net.SplitHostPort(n.remote.RemoteAddr().String()) - localPort, _ := strconv.Atoi(localAddr[1]) - remotePort, _ := strconv.Atoi(remoteAddr[1]) + localPort, _ := strconv.Atoi(localPortS) + remotePort, _ := strconv.Atoi(remotePortS) return SendMessage(n.pproxy, ConnectionAcceptHeader{ - LocalHost: localAddr[0], + LocalHost: localAddr, LocalPort: localPort, - RemoteHost: remoteAddr[0], + RemoteHost: remoteAddr, RemotePort: remotePort, }) }