From bd140cc3b5bd205f8ce315f7e10fb488f4a1c9a8 Mon Sep 17 00:00:00 2001 From: 100kgproxy <100kgproxy@protonmail.com> Date: Sat, 30 May 2020 07:02:47 +0800 Subject: [PATCH] add "sockPath" param to support directly use an exist tun device send by domain socket --- cmd/tun2socks/main.go | 33 +++++++++----- tun/tun_darwin.go | 4 ++ tun/tun_linux.go | 103 +++++++++++++++++++++++++++++++++++++++++- tun/tun_windows.go | 4 ++ 4 files changed, 130 insertions(+), 14 deletions(-) diff --git a/cmd/tun2socks/main.go b/cmd/tun2socks/main.go index db80143b..bc40e843 100644 --- a/cmd/tun2socks/main.go +++ b/cmd/tun2socks/main.go @@ -48,6 +48,7 @@ type CmdArgs struct { UdpTimeout *time.Duration LogLevel *string DnsFallback *bool + SockPath *string } type cmdFlag uint @@ -97,6 +98,7 @@ func main() { args.BlockOutsideDns = flag.Bool("blockOutsideDns", false, "Prevent DNS leaks by blocking plaintext DNS queries going out through non-TUN interface (may require admin privileges) (Windows only) ") args.ProxyType = flag.String("proxyType", "socks", "Proxy handler type") args.LogLevel = flag.String("loglevel", "info", "Logging level. (debug, info, warn, error, none)") + args.SockPath = flag.String("sockPath", "", "unix local socks path to send fd") flag.Parse() @@ -130,7 +132,14 @@ func main() { // Open the tun device. dnsServers := strings.Split(*args.TunDns, ",") - tunDev, err := tun.OpenTunDevice(*args.TunName, *args.TunAddr, *args.TunGw, *args.TunMask, dnsServers, *args.TunPersist) + + var tunDev io.ReadWriteCloser + var err error + if *args.SockPath != "" { + tunDev, err = tun.OpenTunDeviceByDomainSocket(*args.SockPath, *args.TunName, *args.TunAddr, *args.TunGw, *args.TunMask, dnsServers, *args.TunPersist) + } else { + tunDev, err = tun.OpenTunDevice(*args.TunName, *args.TunAddr, *args.TunGw, *args.TunMask, dnsServers, *args.TunPersist) + } if err != nil { log.Fatalf("failed to open tun device: %v", err) } @@ -141,9 +150,6 @@ func main() { } } - // Setup TCP/IP stack. - lwipWriter := core.NewLWIPStack().(io.Writer) - // Register TCP and UDP handlers to handle accepted connections. if creater, found := handlerCreater[*args.ProxyType]; found { creater() @@ -166,14 +172,17 @@ func main() { return tunDev.Write(data) }) - // Copy packets from tun device to lwip stack, it's the main loop. - go func() { - _, err := io.CopyBuffer(lwipWriter, tunDev, make([]byte, MTU)) - if err != nil { - log.Fatalf("copying data failed: %v", err) - } - }() - + if *args.SockPath == "" { + // Setup TCP/IP stack. + lwipWriter := core.NewLWIPStack().(io.Writer) + // Copy packets from tun device to lwip stack, it's the main loop. + go func() { + _, err := io.CopyBuffer(lwipWriter, tunDev, make([]byte, MTU)) + if err != nil { + log.Fatalf("copying data failed: %v", err) + } + }() + } log.Infof("Running tun2socks") osSignals := make(chan os.Signal, 1) diff --git a/tun/tun_darwin.go b/tun/tun_darwin.go index 68d63555..846cc5ad 100644 --- a/tun/tun_darwin.go +++ b/tun/tun_darwin.go @@ -65,3 +65,7 @@ func OpenTunDevice(name, addr, gw, mask string, dnsServers []string, persist boo } return tunDev, nil } + +func OpenTunDeviceByDomainSocket(sockpath, name, addr, gw, mask string, dnsServers []string, persist bool) (io.ReadWriteCloser, error) { + return nil,errors.New("no implement") +} \ No newline at end of file diff --git a/tun/tun_linux.go b/tun/tun_linux.go index f63e81e8..cb9a042e 100644 --- a/tun/tun_linux.go +++ b/tun/tun_linux.go @@ -1,9 +1,14 @@ package tun import ( - "io" - + "fmt" + "github.com/eycorsican/go-tun2socks/core" "github.com/songgao/water" + "io" + "net" + "os" + "syscall" + "time" ) func OpenTunDevice(name, addr, gw, mask string, dnsServers []string, persist bool) (io.ReadWriteCloser, error) { @@ -19,3 +24,97 @@ func OpenTunDevice(name, addr, gw, mask string, dnsServers []string, persist boo name = tunDev.Name() return tunDev, nil } + +func OpenTunDeviceByDomainSocket(sockpath, name, addr, gw, mask string, dnsServers []string, persist bool) (io.ReadWriteCloser, error) { + cfg := water.Config{ + DeviceType: water.TUN, + } + cfg.Name = name + cfg.Persist = persist + tunDev, err := openDevByDomainSocket(cfg, sockpath) + if err != nil { + return nil, err + } + return tunDev, nil +} + +//copied from https://golang.org/src/syscall/syscall_unix_test.go +func openDevByDomainSocket(config water.Config, sockpath string) (ifce *water.Interface, err error) { + //fmt.Println("sockpath=",sockpath) + + os.RemoveAll(sockpath) + l, err := net.Listen("unix", sockpath) + if err != nil { + //t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) + //return nil,errors.New(fmt.Sprintf("unexpected FileConn type; expected UnixConn, got %T", c)) + return nil,err + } + + itf := &water.Interface{ + + } + + go func() { + conn, err := l.Accept() + if err != nil { + fmt.Println(err) + return + } + uc, ok := conn.(*net.UnixConn) + if !ok { + fmt.Println(fmt.Sprintf("unexpected FileConn type; expected UnixConn, got %T", conn)) + } + buf := make([]byte, 32) // expect 1 byte + oob := make([]byte, 32) // expect 24 bytes + closeUnix := time.AfterFunc(15*time.Second, func() { + //t.Logf("timeout reading from unix socket") + uc.Close() + //return nil,errors.New("timeout reading from unix socket") + fmt.Println("timeout reading from unix socket") + }) + _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) + if err != nil { + //t.Fatalf("ReadMsgUnix: %v", err) + //return nil,errors.New(fmt.Sprintf("ReadMsgUnix: %v", err)) + fmt.Println("ReadMsgUnix: ", err) + return + } + closeUnix.Stop() + + scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) + if err != nil { + //t.Fatalf("ParseSocketControlMessage: %v", err) + //return nil,errors.New(fmt.Sprintf("ParseSocketControlMessage: %v", err)) + fmt.Println("ParseSocketControlMessage: ", err) + return + } + if len(scms) != 1 { + //t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) + //return nil,errors.New(fmt.Sprintf("expected 1 SocketControlMessage; got scms = %#v", scms)) + fmt.Println("expected 1 SocketControlMessage; got scms = ", scms) + return + } + scm := scms[0] + gotFds, err := syscall.ParseUnixRights(&scm) + if err != nil { + //t.Fatalf("syscall.ParseUnixRights: %v", err) + //return nil,errors.New(fmt.Sprintf("syscall.ParseUnixRights: %v", err)) + fmt.Println("syscall.ParseUnixRights: ", err) + return + } + if len(gotFds) != 1 { + //t.Fatalf("wanted 1 fd; got %#v", gotFds) + //return nil,errors.New(fmt.Sprintf("wanted 1 fd; got %#v", gotFds)) + fmt.Println("wanted 1 fd; got ", gotFds) + return + } + fdInt := gotFds[0] + + itf.ReadWriteCloser = os.NewFile(uintptr(fdInt), "tun0") + + lwipWriter := core.NewLWIPStack().(io.Writer) + io.CopyBuffer(lwipWriter, itf, make([]byte, 1500)) + }() + + return itf,nil +} diff --git a/tun/tun_windows.go b/tun/tun_windows.go index 97d640b5..4fd61808 100644 --- a/tun/tun_windows.go +++ b/tun/tun_windows.go @@ -389,3 +389,7 @@ func (dev *winTapDev) Close() error { sendStopMarker(dev.addr, dev.gw) return windows.Close(dev.fd) } + +func OpenTunDeviceByDomainSocket(sockpath, name, addr, gw, mask string, dnsServers []string, persist bool) (io.ReadWriteCloser, error) { + return nil,errors.New("not supported") +}