From 8e846fe6f84d357371008bab30a6812d512edbbd Mon Sep 17 00:00:00 2001 From: Shelikhoo Date: Thu, 7 Sep 2017 06:55:15 +0800 Subject: [PATCH] Added UDP TPROXY Transmit Support --- proxy/dokodemo/dokodemo.go | 16 +++++- transport/internet/udp/sourceForgeSender.go | 55 +++++++++++++++++++ .../internet/udp/sourceForgeSender_bad.go | 12 ++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 transport/internet/udp/sourceForgeSender.go create mode 100644 transport/internet/udp/sourceForgeSender_bad.go diff --git a/proxy/dokodemo/dokodemo.go b/proxy/dokodemo/dokodemo.go index 5b031aa25..faecbe12e 100644 --- a/proxy/dokodemo/dokodemo.go +++ b/proxy/dokodemo/dokodemo.go @@ -7,6 +7,8 @@ import ( "runtime" "time" + gonet "net" + "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" "v2ray.com/core/app/log" @@ -16,6 +18,7 @@ import ( "v2ray.com/core/common/signal" "v2ray.com/core/proxy" "v2ray.com/core/transport/internet" + "v2ray.com/core/transport/internet/udp" ) type DokodemoDoor struct { @@ -88,7 +91,18 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in if network == net.Network_TCP { writer = buf.NewWriter(conn) } else { - writer = buf.NewSequentialWriter(conn) + //if we are in TPROXY mode, use linux's udp forging functionality + if !d.config.FollowRedirect { + writer = buf.NewSequentialWriter(conn) + } else { + srca := gonet.UDPAddr{IP: dest.Address.IP(), Port: int(dest.Port.Value())} + origsend, err := udp.TransmitSocket(&srca, conn.RemoteAddr()) + if err != nil { + return err + } + writer = buf.NewSequentialWriter(origsend) + } + } if err := buf.Copy(inboundRay.InboundOutput(), writer, buf.UpdateActivity(timer)); err != nil { diff --git a/transport/internet/udp/sourceForgeSender.go b/transport/internet/udp/sourceForgeSender.go new file mode 100644 index 000000000..31d03a9e8 --- /dev/null +++ b/transport/internet/udp/sourceForgeSender.go @@ -0,0 +1,55 @@ +// +build linux + +package udp + +import ( + "net" + "os" + "syscall" +) + +//Currently, Only IPv4 Forge is supported +func TransmitSocket(src net.Addr, dst net.Addr) (net.Conn, error) { + var fd int + var err error + fd, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) + if err != nil { + return nil, err + } + err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + if err != nil { + return nil, err + } + + err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1) + if err != nil { + return nil, err + } + + ip := src.(*net.UDPAddr).IP.To4() + var ip2 [4]byte + copy(ip2[:], ip) + srcaddr := syscall.SockaddrInet4{} + srcaddr.Addr = ip2 + srcaddr.Port = src.(*net.UDPAddr).Port + err = syscall.Bind(fd, &srcaddr) + if err != nil { + return nil, err + } + ipd := dst.(*net.UDPAddr).IP.To4() + var ip2d [4]byte + copy(ip2d[:], ipd) + dstaddr := syscall.SockaddrInet4{} + dstaddr.Addr = ip2d + dstaddr.Port = dst.(*net.UDPAddr).Port + err = syscall.Connect(fd, &dstaddr) + if err != nil { + return nil, err + } + fdf := os.NewFile(uintptr(fd), "/dev/udp/") + c, err := net.FileConn(fdf) + if err != nil { + return nil, err + } + return c, nil +} diff --git a/transport/internet/udp/sourceForgeSender_bad.go b/transport/internet/udp/sourceForgeSender_bad.go new file mode 100644 index 000000000..dadd40234 --- /dev/null +++ b/transport/internet/udp/sourceForgeSender_bad.go @@ -0,0 +1,12 @@ +// +build !linux + +package udp + +import ( + "errors" + "net" +) + +func TransmitionSocket(src net.Addr, dst net.Addr) (net.Conn, error) { + return nil, errors.New("Using an Linux only functionality on an non-Linux OS.") +}