Liu Song’s Projects


~/Projects/go-shadowsocks2

git clone https://code.lsong.org/go-shadowsocks2

Commit

Commit
580a1996f85917cfbb9f7fa09df48a2a65e5fc0d
Author
Riobard <[email protected]>
Date
2020-01-31 18:41:10 +0800 +0800
Diffstat
 nfutil/nf_linux.go | 55 ++++++++++++++++++++++++++++++
 pfutil/pf_darwin.go | 51 ++++++++++++++++++++++++++++
 tcp_darwin.go | 54 ++---------------------------
 tcp_linux.go | 84 ++++++----------------------------------------
  | 1 
  | 2 

Split Netfilter and pf code into subpackages


diff --git a/nfutil/nf_linux.go b/nfutil/nf_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..dc1653630e024563c4a68a5799e2462d77db3094
--- /dev/null
+++ b/nfutil/nf_linux.go
@@ -0,0 +1,55 @@
+package nfutil
+
+import (
+	"net"
+	"syscall"
+	"unsafe"
+)
+
+// Get the original destination of a TCP connection redirected by Netfilter.
+func GetOrigDst(c *net.TCPConn, ipv6 bool) (*net.TCPAddr, error) {
+	rc, err := c.SyscallConn()
+	if err != nil {
+		return nil, err
+	}
+	var addr *net.TCPAddr
+	rc.Control(func(fd uintptr) {
+		if ipv6 {
+			addr, err = ipv6_getorigdst(fd)
+		} else {
+			addr, err = getorigdst(fd)
+		}
+	})
+	return addr, err
+}
+
+// Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+func getorigdst(fd uintptr) (*net.TCPAddr, error) {
+	const _SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv4.h
+	var raw syscall.RawSockaddrInet4
+	siz := unsafe.Sizeof(raw)
+	if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, _SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
+		return nil, err
+	}
+	var addr net.TCPAddr
+	addr.IP = raw.Addr[:]
+	port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian
+	addr.Port = int(port[0])<<8 | int(port[1])
+	return &addr, nil
+}
+
+// Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+// NOTE: I haven't tried yet but it should work since Linux 3.8.
+func ipv6_getorigdst(fd uintptr) (*net.TCPAddr, error) {
+	const _IP6T_SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv6/ip6_tables.h
+	var raw syscall.RawSockaddrInet6
+	siz := unsafe.Sizeof(raw)
+	if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, _IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
+		return nil, err
+	}
+	var addr net.TCPAddr
+	addr.IP = raw.Addr[:]
+	port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian
+	addr.Port = int(port[0])<<8 | int(port[1])
+	return &addr, nil
+}




diff --git a/nfutil/socketcall_linux_386.go b/nfutil/socketcall_linux_386.go
new file mode 100644
index 0000000000000000000000000000000000000000..e4c91e48cbd8114b324c253f143ff73a1d3190d3
--- /dev/null
+++ b/nfutil/socketcall_linux_386.go
@@ -0,0 +1,17 @@
+package nfutil
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+const GETSOCKOPT = 15 // https://golang.org/src/syscall/syscall_linux_386.go#L183
+
+func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error {
+	var a [6]uintptr
+	a[0], a[1], a[2], a[3], a[4], a[5] = a0, a1, a2, a3, a4, a5
+	if _, _, errno := syscall.Syscall6(syscall.SYS_SOCKETCALL, call, uintptr(unsafe.Pointer(&a)), 0, 0, 0, 0); errno != 0 {
+		return errno
+	}
+	return nil
+}




diff --git a/nfutil/socketcall_linux_other.go b/nfutil/socketcall_linux_other.go
new file mode 100644
index 0000000000000000000000000000000000000000..6f7ca324b41d6b5359e11ed8e4c1c283d8bf0dc6
--- /dev/null
+++ b/nfutil/socketcall_linux_other.go
@@ -0,0 +1,14 @@
+// +build linux,!386
+
+package nfutil
+
+import "syscall"
+
+const GETSOCKOPT = syscall.SYS_GETSOCKOPT
+
+func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error {
+	if _, _, errno := syscall.Syscall6(call, a0, a1, a2, a3, a4, a5); errno != 0 {
+		return errno
+	}
+	return nil
+}




diff --git a/pfutil/pf_darwin.go b/pfutil/pf_darwin.go
new file mode 100644
index 0000000000000000000000000000000000000000..ad2127fb41c5b17ab0c94010a10dbb7d30b8540a
--- /dev/null
+++ b/pfutil/pf_darwin.go
@@ -0,0 +1,51 @@
+package pfutil
+
+import (
+	"net"
+	"syscall"
+	"unsafe"
+)
+
+func NatLookup(c *net.TCPConn) (*net.TCPAddr, error) {
+	const (
+		PF_INOUT     = 0
+		PF_IN        = 1
+		PF_OUT       = 2
+		IOC_OUT      = 0x40000000
+		IOC_IN       = 0x80000000
+		IOC_INOUT    = IOC_IN | IOC_OUT
+		IOCPARM_MASK = 0x1FFF
+		LEN          = 4*16 + 4*4 + 4*1
+		// #define	_IOC(inout,group,num,len) (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
+		// #define	_IOWR(g,n,t)	_IOC(IOC_INOUT,	(g), (n), sizeof(t))
+		// #define DIOCNATLOOK		_IOWR('D', 23, struct pfioc_natlook)
+		DIOCNATLOOK = IOC_INOUT | ((LEN & IOCPARM_MASK) << 16) | ('D' << 8) | 23
+	)
+	fd, err := syscall.Open("/dev/pf", 0, syscall.O_RDONLY)
+	if err != nil {
+		return nil, err
+	}
+	defer syscall.Close(fd)
+	nl := struct { // struct pfioc_natlook
+		saddr, daddr, rsaddr, rdaddr       [16]byte
+		sxport, dxport, rsxport, rdxport   [4]byte
+		af, proto, protoVariant, direction uint8
+	}{
+		af:        syscall.AF_INET,
+		proto:     syscall.IPPROTO_TCP,
+		direction: PF_OUT,
+	}
+	saddr := c.RemoteAddr().(*net.TCPAddr)
+	daddr := c.LocalAddr().(*net.TCPAddr)
+	copy(nl.saddr[:], saddr.IP)
+	copy(nl.daddr[:], daddr.IP)
+	nl.sxport[0], nl.sxport[1] = byte(saddr.Port>>8), byte(saddr.Port)
+	nl.dxport[0], nl.dxport[1] = byte(daddr.Port>>8), byte(daddr.Port)
+	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), DIOCNATLOOK, uintptr(unsafe.Pointer(&nl))); errno != 0 {
+		return nil, errno
+	}
+	var addr net.TCPAddr
+	addr.IP = nl.rdaddr[:4]
+	addr.Port = int(nl.rdxport[0])<<8 | int(nl.rdxport[1])
+	return &addr, nil
+}




diff --git a/tcp_darwin.go b/tcp_darwin.go
index ca2c77dc97956dd1a85eb84b56d86b28d8a45d61..d2e854c6a428890a5845d2539fab2f37644e70fb 100644
--- a/tcp_darwin.go
+++ b/tcp_darwin.go
@@ -2,69 +2,23 @@ package main
 
 import (
 	"net"
-	"syscall"
+
-	"unsafe"
-
+	"github.com/riobard/go-shadowsocks2/pfutil"
 	"github.com/riobard/go-shadowsocks2/socks"
 )
 
-func redirLocal(addr string, d Dialer)  { tcpLocal(addr, d, pfNatLookup) }
+func redirLocal(addr string, d Dialer)  { tcpLocal(addr, d, natLookup) }
 func redir6Local(addr string, d Dialer) { panic("TCP6 redirect not supported") }
 func tproxyTCP(addr string, d Dialer)   { panic("TPROXY TCP not supported") }
 
-func pfNatLookup(c net.Conn) (socks.Addr, error) {
-	const (
-		PF_INOUT     = 0
-package main
 	"syscall"
-package main
 	"unsafe"
-		IOC_OUT      = 0x40000000
-		IOC_IN       = 0x80000000
-		IOC_INOUT    = IOC_IN | IOC_OUT
-		IOCPARM_MASK = 0x1FFF
-		LEN          = 4*16 + 4*4 + 4*1
-		// #define	_IOC(inout,group,num,len) (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
-		// #define	_IOWR(g,n,t)	_IOC(IOC_INOUT,	(g), (n), sizeof(t))
-		// #define DIOCNATLOOK		_IOWR('D', 23, struct pfioc_natlook)
-
 	"syscall"
-	)
-
-
 	"github.com/riobard/go-shadowsocks2/socks"
-
+	"syscall"
 )
-		return nil, err
-	}
-	defer syscall.Close(fd)
-
-	nl := struct { // struct pfioc_natlook
-		saddr, daddr, rsaddr, rdaddr       [16]byte
-		sxport, dxport, rsxport, rdxport   [4]byte
-import (
 	"syscall"
-	}{
-		af:        syscall.AF_INET,
-		proto:     syscall.IPPROTO_TCP,
-import (
 func redirLocal(addr string, d Dialer)  { tcpLocal(addr, d, pfNatLookup) }
 	}
-	saddr := c.RemoteAddr().(*net.TCPAddr)
-	daddr := c.LocalAddr().(*net.TCPAddr)
-	copy(nl.saddr[:], saddr.IP)
-	copy(nl.daddr[:], daddr.IP)
-	nl.sxport[0], nl.sxport[1] = byte(saddr.Port>>8), byte(saddr.Port)
-	nl.dxport[0], nl.dxport[1] = byte(daddr.Port>>8), byte(daddr.Port)
-
-	"net"
 	"unsafe"
-		return nil, errno
-import (
-
-	addr := make([]byte, 1+net.IPv4len+2)
-	addr[0] = socks.AtypIPv4
-	copy(addr[1:1+net.IPv4len], nl.rdaddr[:4])
-	copy(addr[1+net.IPv4len:], nl.rdxport[:2])
-	return addr, nil
 }




diff --git a/tcp_linux.go b/tcp_linux.go
index ade14c29a2a58f17fb78f45d42bf3e92f20d9b03..4823c2d1cedf01008502103268941ff6dd0d0903 100644
--- a/tcp_linux.go
+++ b/tcp_linux.go
@@ -1,104 +1,44 @@
 package main
 
 import (
-	"errors"
 	"net"
 	"syscall"
-	"unsafe"
 
 	"github.com/riobard/go-shadowsocks2/socks"
-)
-
-const (
-	SO_ORIGINAL_DST      = 80 // from linux/include/uapi/linux/netfilter_ipv4.h
-	IP6T_SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv6/ip6_tables.h
-)
-
-// Listen on addr for netfilter redirected TCP connections
-func redirLocal(addr string, d Dialer) {
-	// logf("TCP redirect %s <-> %s", addr, server)
-	tcpLocal(addr, d, func(c net.Conn) (socks.Addr, error) { return getOrigDst(c, false) })
-package main
 	"unsafe"
-
-package main
 	"github.com/riobard/go-shadowsocks2/socks"
-package main
 )
 
-	tcpLocal(addr, d, func(c net.Conn) (socks.Addr, error) { return getOrigDst(c, true) })
+func getOrigDst(c net.Conn, ipv6 bool) (socks.Addr, error) {
-}
-
-// Get the original destination of a TCP connection.
-func getOrigDst(conn net.Conn, ipv6 bool) (socks.Addr, error) {
-	c, ok := conn.(*net.TCPConn)
-	if !ok {
-		return nil, errors.New("only work with TCP connection")
-	}
-
-
 	"github.com/riobard/go-shadowsocks2/socks"
-
 )
-import (
+)
-	}
-
-import (
+)
 package main
 
-	rc.Control(func(fd uintptr) {
-		if ipv6 {
-			addr, err = ipv6_getorigdst(fd)
-		} else {
-			addr, err = getorigdst(fd)
-import (
 	"unsafe"
-	})
+)
 
-	return addr, err
 }
 
-// Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
-	"errors"
 package main
-	raw := syscall.RawSockaddrInet4{}
-	"errors"
 import (
-	"errors"
+package main
 	"errors"
-		return nil, err
-	}
-
-	"errors"
+package main
 	"net"
-	"errors"
+package main
 	"syscall"
-	"errors"
+package main
 	"unsafe"
-	port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian
-	addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1]
-	return addr, nil
+
 package main
-	"unsafe"
-
+	"github.com/riobard/go-shadowsocks2/socks"
-	"net"
 package main
+)
-	"net"
 
-func ipv6_getorigdst(fd uintptr) (socks.Addr, error) {
-	raw := syscall.RawSockaddrInet6{}
-	siz := unsafe.Sizeof(raw)
-	if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
-import (
 
-	"unsafe"
-
-	addr := make([]byte, 1+net.IPv6len+2)
-	addr[0] = socks.AtypIPv6
-	copy(addr[1:1+net.IPv6len], raw.Addr[:])
-	port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian
-	addr[1+net.IPv6len], addr[1+net.IPv6len+1] = port[0], port[1]
-	return addr, nil
+package main
 }
 
 func tproxyTCP(addr string, d Dialer) error {




diff --git a/tcp_linux_386.go b/tcp_linux_386.go
deleted file mode 100644
index 8b8db6fb554eb19504d037a7e6a14fc1a1e0d993..0000000000000000000000000000000000000000
--- a/tcp_linux_386.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package main
-
-import (
-	"syscall"
-	"unsafe"
-)
-
-const GETSOCKOPT = 15 // https://golang.org/src/syscall/syscall_linux_386.go#L183
-
-func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error {
-	var a [6]uintptr
-	a[0], a[1], a[2], a[3], a[4], a[5] = a0, a1, a2, a3, a4, a5
-	if _, _, errno := syscall.Syscall6(syscall.SYS_SOCKETCALL, call, uintptr(unsafe.Pointer(&a)), 0, 0, 0, 0); errno != 0 {
-		return errno
-	}
-	return nil
-}




diff --git a/tcp_linux_other.go b/tcp_linux_other.go
deleted file mode 100644
index 96f9561a6ef9847abc5ad61a52b5be370c33dc60..0000000000000000000000000000000000000000
--- a/tcp_linux_other.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// +build linux,!386
-
-package main
-
-import "syscall"
-
-const GETSOCKOPT = syscall.SYS_GETSOCKOPT
-
-func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error {
-	if _, _, errno := syscall.Syscall6(call, a0, a1, a2, a3, a4, a5); errno != 0 {
-		return errno
-	}
-	return nil
-}