tproxy: add base udp tproxy listener codes

This commit is contained in:
nadoo 2017-09-09 15:06:44 +08:00
parent 4fe5eb97bb
commit fdbb9a5034
9 changed files with 100 additions and 14 deletions

View File

@ -42,7 +42,7 @@ General:
TODO: TODO:
- [x] UDP over TCP Tunnel (client <-udp-> uottun <-tcp-> ss <-udp-> target) - [x] UDP over TCP Tunnel (client <-udp-> uottun <-tcp-> ss <-udp-> target)
- [ ] Linux tproxy support - [ ] Transparent UDP proxy (linux tproxy)
- [ ] TUN/TAP device support - [ ] TUN/TAP device support
- [ ] Code refactoring: support proxy registering so it can be pluggable - [ ] Code refactoring: support proxy registering so it can be pluggable
- [ ] Conditional compilation so we can abandon needless proxy type and get a smaller binary size - [ ] Conditional compilation so we can abandon needless proxy type and get a smaller binary size

View File

@ -43,7 +43,7 @@ dns://53
# global remote dns server (you can specify different dns server in rule file) # global remote dns server (you can specify different dns server in rule file)
dnsserver=8.8.8.8:53 dnsserver=8.8.8.8:53
# Create and mange ipset on linux based on destinations in rule files # Create and manage ipset on linux based on destinations in rule files
# - add ip/cidrs in rule files on startup # - add ip/cidrs in rule files on startup
# - add resolved ips for domains in rule files by dns forwarder server # - add resolved ips for domains in rule files by dns forwarder server
# Usually used in transparent proxy mode on linux # Usually used in transparent proxy mode on linux

View File

@ -8,8 +8,6 @@ import (
"net" "net"
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/shadowsocks/go-shadowsocks2/socks"
) )
const ( const (
@ -32,7 +30,7 @@ func NewRedirProxy(addr string, sDialer Dialer) (*RedirProxy, error) {
return s, nil return s, nil
} }
// ListenAndServe redirected requests as a server. // ListenAndServe .
func (s *RedirProxy) ListenAndServe() { func (s *RedirProxy) ListenAndServe() {
l, err := net.Listen("tcp", s.addr) l, err := net.Listen("tcp", s.addr)
if err != nil { if err != nil {
@ -84,7 +82,7 @@ func (s *RedirProxy) ListenAndServe() {
} }
// Get the original destination of a TCP connection. // Get the original destination of a TCP connection.
func getOrigDst(conn net.Conn, ipv6 bool) (socks.Addr, error) { func getOrigDst(conn net.Conn, ipv6 bool) (Addr, error) {
c, ok := conn.(*net.TCPConn) c, ok := conn.(*net.TCPConn)
if !ok { if !ok {
return nil, errors.New("only work with TCP connection") return nil, errors.New("only work with TCP connection")
@ -112,7 +110,7 @@ func getOrigDst(conn net.Conn, ipv6 bool) (socks.Addr, error) {
} }
// Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
func getorigdst(fd uintptr) (socks.Addr, error) { func getorigdst(fd uintptr) (Addr, error) {
raw := syscall.RawSockaddrInet4{} raw := syscall.RawSockaddrInet4{}
siz := unsafe.Sizeof(raw) 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 { if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
@ -120,7 +118,7 @@ func getorigdst(fd uintptr) (socks.Addr, error) {
} }
addr := make([]byte, 1+net.IPv4len+2) addr := make([]byte, 1+net.IPv4len+2)
addr[0] = socks.AtypIPv4 addr[0] = socks5IP4
copy(addr[1:1+net.IPv4len], raw.Addr[:]) copy(addr[1:1+net.IPv4len], raw.Addr[:])
port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian
addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1] addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1]
@ -129,7 +127,7 @@ func getorigdst(fd uintptr) (socks.Addr, error) {
// Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c // 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. // NOTE: I haven't tried yet but it should work since Linux 3.8.
func ipv6_getorigdst(fd uintptr) (socks.Addr, error) { func ipv6_getorigdst(fd uintptr) (Addr, error) {
raw := syscall.RawSockaddrInet6{} raw := syscall.RawSockaddrInet6{}
siz := unsafe.Sizeof(raw) 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 { if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
@ -137,7 +135,7 @@ func ipv6_getorigdst(fd uintptr) (socks.Addr, error) {
} }
addr := make([]byte, 1+net.IPv6len+2) addr := make([]byte, 1+net.IPv6len+2)
addr[0] = socks.AtypIPv6 addr[0] = socks5IP6
copy(addr[1:1+net.IPv6len], raw.Addr[:]) copy(addr[1:1+net.IPv6len], raw.Addr[:])
port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian
addr[1+net.IPv6len], addr[1+net.IPv6len+1] = port[0], port[1] addr[1+net.IPv6len], addr[1+net.IPv6len+1] = port[0], port[1]

View File

@ -15,7 +15,7 @@ func NewRedirProxy(addr string, sDialer Dialer) (*RedirProxy, error) {
return nil, errors.New("redir not supported on this os") return nil, errors.New("redir not supported on this os")
} }
// ListenAndServe redirected requests as a server. // ListenAndServe .
func (s *RedirProxy) ListenAndServe() { func (s *RedirProxy) ListenAndServe() {
log.Fatal("redir not supported on this os") log.Fatal("redir not supported on this os")
} }

View File

@ -77,7 +77,7 @@ func NewSOCKS5(addr, user, pass string, cDialer Dialer, sDialer Dialer) (*SOCKS5
return s, nil return s, nil
} }
// ListenAndServe connects to the address addr on the network net via the SOCKS5 proxy. // ListenAndServe .
func (s *SOCKS5) ListenAndServe() { func (s *SOCKS5) ListenAndServe() {
l, err := net.Listen("tcp", s.addr) l, err := net.Listen("tcp", s.addr)
if err != nil { if err != nil {

View File

@ -21,7 +21,7 @@ func NewTCPTun(addr, raddr string, sDialer Dialer) (*TCPTun, error) {
return s, nil return s, nil
} }
// ListenAndServe redirected requests as a server. // ListenAndServe .
func (s *TCPTun) ListenAndServe() { func (s *TCPTun) ListenAndServe() {
l, err := net.Listen("tcp", s.addr) l, err := net.Listen("tcp", s.addr)
if err != nil { if err != nil {

68
tproxy.go Normal file
View File

@ -0,0 +1,68 @@
// +build linux
package main
import (
"net"
"syscall"
)
type TProxy struct {
*Forwarder // as client
sDialer Dialer // dialer for server
}
// NewTProxy returns a tproxy.
func NewTProxy(addr string, sDialer Dialer) (*TProxy, error) {
s := &TProxy{
Forwarder: NewForwarder(addr, nil),
sDialer: sDialer,
}
return s, nil
}
// ListenAndServe .
func (s *TProxy) ListenAndServe() {
// go s.ListenAndServeTCP()
s.ListenAndServeUDP()
}
func (s *TProxy) ListenAndServeTCP() {
}
func (s *TProxy) ListenAndServeUDP() {
laddr, err := net.ResolveUDPAddr("udp", s.addr)
if err != nil {
logf("proxy-tproxy failed to resolve addr %s: %v", s.addr, err)
return
}
listener, err := net.ListenUDP("udp", laddr)
if err != nil {
logf("proxy-tproxy failed to listen on %s: %v", s.addr, err)
return
}
fd, err := listener.File()
if err != nil {
logf("proxy-tproxy failed to get file descriptor: %v", err)
return
}
defer fd.Close()
fileDescriptor := int(fd.Fd())
if err = syscall.SetsockoptInt(fileDescriptor, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
syscall.Close(fileDescriptor)
logf("proxy-tproxy failed to set socket option IP_TRANSPARENT: %v", err)
return
}
if err = syscall.SetsockoptInt(fileDescriptor, syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1); err != nil {
syscall.Close(fileDescriptor)
logf("proxy-tproxy failed to set socket option IP_RECVORIGDSTADDR: %v", err)
return
}
}

20
tproxy_other.go Normal file
View File

@ -0,0 +1,20 @@
// +build !linux
package main
import (
"errors"
"log"
)
type TProxy struct{}
// NewTProxy returns a tproxy.
func NewTProxy(addr string, sDialer Dialer) (*TProxy, error) {
return nil, errors.New("tproxy not supported on this os")
}
// ListenAndServe .
func (s *TProxy) ListenAndServe() {
log.Fatal("tproxy not supported on this os")
}

View File

@ -24,7 +24,7 @@ func NewUoTTun(addr, raddr string, sDialer Dialer) (*UoTTun, error) {
return s, nil return s, nil
} }
// ListenAndServe redirected requests as a server. // ListenAndServe .
func (s *UoTTun) ListenAndServe() { func (s *UoTTun) ListenAndServe() {
c, err := net.ListenPacket("udp", s.addr) c, err := net.ListenPacket("udp", s.addr)