From b0b043a2804712bf93f1cb3a2ff486e9e3b3a984 Mon Sep 17 00:00:00 2001 From: nadoo <287492+nadoo@users.noreply.github.com> Date: Tue, 25 Jan 2022 11:16:24 +0800 Subject: [PATCH] tproxy: setsockopt in listener to suuport ipv6 --- .github/workflows/docker.yml | 2 +- proxy/tproxy/tproxy.go | 59 ++++++++++++------------------------ 2 files changed, 21 insertions(+), 40 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 373555f..84012f3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -11,7 +11,7 @@ on: env: DOCKERHUB_REPO: nadoo/glider GHCR_REPO: ghcr.io/nadoo/glider - PLATFORMS: linux/amd64,linux/arm64,linux/arm/v7 + PLATFORMS: linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6 jobs: publish: diff --git a/proxy/tproxy/tproxy.go b/proxy/tproxy/tproxy.go index b5c93e2..fda1fa5 100644 --- a/proxy/tproxy/tproxy.go +++ b/proxy/tproxy/tproxy.go @@ -1,14 +1,11 @@ package tproxy import ( - "bytes" "encoding/binary" "fmt" "net" "os" - "strconv" "syscall" - "unsafe" "golang.org/x/sys/unix" ) @@ -35,8 +32,16 @@ func ListenUDP(network string, laddr *net.UDPAddr) (*net.UDPConn, error) { return nil, &net.OpError{Op: "listen", Net: network, Source: nil, Addr: laddr, Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %s", err)} } - if err = syscall.SetsockoptInt(fileDescriptor, syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1); err != nil { - return nil, &net.OpError{Op: "listen", Net: network, Source: nil, Addr: laddr, Err: fmt.Errorf("set socket option: IP_RECVORIGDSTADDR: %s", err)} + if laddr.IP == nil || laddr.IP.To4() != nil { + if err = syscall.SetsockoptInt(fileDescriptor, syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1); err != nil { + return nil, &net.OpError{Op: "listen", Net: network, Source: nil, Addr: laddr, Err: fmt.Errorf("set socket option: IP_RECVORIGDSTADDR: %s", err)} + } + } + + if laddr.IP == nil || laddr.IP.To4() == nil { + if err = syscall.SetsockoptInt(fileDescriptor, syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1); err != nil { + return nil, &net.OpError{Op: "listen", Net: network, Source: nil, Addr: laddr, Err: fmt.Errorf("set socket option: IPV6_RECVORIGDSTADDR: %s", err)} + } } return listener, nil @@ -60,44 +65,20 @@ func ReadFromUDP(conn *net.UDPConn, b []byte) (int, *net.UDPAddr, *net.UDPAddr, return 0, nil, nil, fmt.Errorf("parsing socket control message: %s", err) } - var originalDst *net.UDPAddr for _, msg := range msgs { - if (msg.Header.Level == syscall.SOL_IP || msg.Header.Level == syscall.SOL_IPV6) && - msg.Header.Type == syscall.IP_RECVORIGDSTADDR { - originalDstRaw := &syscall.RawSockaddrInet4{} - if err = binary.Read(bytes.NewReader(msg.Data), binary.LittleEndian, originalDstRaw); err != nil { - return 0, nil, nil, fmt.Errorf("reading original destination address: %s", err) - } - - switch originalDstRaw.Family { - case syscall.AF_INET: - pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(originalDstRaw)) - p := (*[2]byte)(unsafe.Pointer(&pp.Port)) - originalDst = &net.UDPAddr{ - IP: net.IPv4(pp.Addr[0], pp.Addr[1], pp.Addr[2], pp.Addr[3]), - Port: int(p[0])<<8 + int(p[1]), - } - - case syscall.AF_INET6: - pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(originalDstRaw)) - p := (*[2]byte)(unsafe.Pointer(&pp.Port)) - originalDst = &net.UDPAddr{ - IP: net.IP(pp.Addr[:]), - Port: int(p[0])<<8 + int(p[1]), - Zone: strconv.Itoa(int(pp.Scope_id)), - } - - default: - return 0, nil, nil, fmt.Errorf("original destination is an unsupported network family") - } + if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR { + ip := net.IP(msg.Data[4:8]) + port := binary.BigEndian.Uint16(msg.Data[2:4]) + return n, addr, &net.UDPAddr{IP: ip, Port: int(port)}, nil + } + if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == unix.IPV6_RECVORIGDSTADDR { + ip := net.IP(msg.Data[8:24]) + port := binary.BigEndian.Uint16(msg.Data[2:4]) + return n, addr, &net.UDPAddr{IP: ip, Port: int(port)}, nil } } - if originalDst == nil { - return 0, nil, nil, fmt.Errorf("unable to obtain original destination: %s", err) - } - - return n, addr, originalDst, nil + return 0, nil, nil, fmt.Errorf("unable to obtain original destination: %s", err) } // ListenPacket acts like net.ListenPacket but the addr could be non-local.