Skip to content

Commit

Permalink
Switch to wireguard driver for a better windows support
Browse files Browse the repository at this point in the history
  • Loading branch information
kayrus committed Dec 9, 2020
1 parent fe51cd4 commit cd3f67c
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 452 deletions.
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ CMDDIR=$(shell pwd)/cmd/tun2socks
PROGRAM=tun2socks
GOOS:=$(shell go env GOOS)

BUILD_CMD="cd $(CMDDIR) && $(GOBUILD) -ldflags $(RELEASE_LDFLAGS) -o $(BUILDDIR)/$(PROGRAM)_$(GOOS) -v -tags '$(BUILD_TAGS)'"
ifeq "$(strip $(GOOS))" "windows"
SUFFIX=.exe
endif

BUILD_CMD="cd $(CMDDIR) && $(GOBUILD) -ldflags $(RELEASE_LDFLAGS) -o $(BUILDDIR)/$(PROGRAM)_$(GOOS)$(SUFFIX) -v -tags '$(BUILD_TAGS)'"

XBUILD_LINUX_CMD="cd $(BUILDDIR) && $(XGOCMD) -ldflags $(STATIC_RELEASE_LDFLAGS) -tags '$(BUILD_TAGS)' --targets=linux/* $(CMDDIR)"
XBUILD_OTHERS_CMD="cd $(BUILDDIR) && $(XGOCMD) -ldflags $(RELEASE_LDFLAGS) -tags '$(BUILD_TAGS)' --targets=darwin/*,windows/*,android/*,ios/* $(CMDDIR)"

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ Create a tunnel:
```sh
sudo tun2socks -proxyServer 127.0.0.1:1234 -routes 10.0.0.0/8,172.16.0.0/12 -exclude example.com,10.0.0.1 -loglevel debug
```

## Windows

Windows build requires a https://www.wintun.net dll located in the tun2socks executable path.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ go 1.13

require (
github.com/IBM/netaddr v1.4.0
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b
github.com/stretchr/testify v1.6.1 // indirect
github.com/vishvananda/netlink v1.1.0
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3
golang.zx2c4.com/wireguard v0.0.20201119-0.20201127121345-b6303091fc8c
)
9 changes: 7 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b h1:+y4hCMc/WKsDbAPsOQZgBSaSZ26uh2afyaWeVg/3s/c=
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand All @@ -15,18 +13,25 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7Zo
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7 h1:3uJsdck53FDIpWwLeAXlia9p4C8j0BO2xZrqzKpL0D8=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3 h1:kzM6+9dur93BcC2kVlYl34cHU+TYZLanmpSJHVMmL64=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.20201119-0.20201127121345-b6303091fc8c h1:9hQ0/h+C/WejiYNxvDeY/euDCfmMJBTlUb46+jHTmHs=
golang.zx2c4.com/wireguard v0.0.20201119-0.20201127121345-b6303091fc8c/go.mod h1:MLNavHGuHO1M5coT9hkHgdN8AoJHdUWLpsLKSeR63VE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
Expand Down
44 changes: 40 additions & 4 deletions routes/routes_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,54 @@ import (
"fmt"
"net"
"os/exec"
"regexp"
)

var re = regexp.MustCompile(`IfIndex\s+:\s+(\d+)`)
var ifIndex string

func getIfID(iface string) error {
args := []string{
"int",
"ipv4",
"show",
"interfaces",
iface,
}
v, err := exec.Command("netsh.exe", args...).Output()
if err != nil {
return fmt.Errorf("failed to find a %q interface index: %s, %s", iface, v, err)
}
if v := re.FindSubmatch(v); len(v) == 2 {
ifIndex = string(v[1])
return nil
}

return fmt.Errorf("failed to find a %q interface index: %s", iface, v)
}

func routeAdd(dst interface{}, gw net.IP, priority int, iface string) error {
if ifIndex == "" {
if err := getIfID(iface); err != nil {
return err
}
}

// an implementation of "replace"
routeDel(dst, gw, priority, iface)
d := getNet(dst)
args := []string{
"add",
d.IP.String(),
"mask",
net.IP(d.Mask).To4().String(),
gw.String(),
"metric",
fmt.Sprintf("%d", priority),
fmt.Sprintf("%d", priority+1),
"if",
ifIndex,
}
v, err := exec.Command("route", args...).Output()
v, err := exec.Command("route.exe", args...).Output()
if err != nil {
return fmt.Errorf("failed to add %s route to %s interface: %s: %s", dst, iface, v, err)
}
Expand All @@ -30,12 +63,15 @@ func routeDel(dst interface{}, gw net.IP, priority int, iface string) error {
args := []string{
"delete",
d.IP.String(),
"mask",
net.IP(d.Mask).To4().String(),
gw.String(),
"metric",
fmt.Sprintf("%d", priority),
fmt.Sprintf("%d", priority+1),
"if",
ifIndex,
}
v, err := exec.Command("route", args...).Output()
v, err := exec.Command("route.exe", args...).Output()
if err != nil {
return fmt.Errorf("failed to delete %s route from %s interface: %s: %s", dst, iface, v, err)
}
Expand Down
50 changes: 50 additions & 0 deletions tun/tun.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package tun

import (
"io"
"runtime"

"golang.zx2c4.com/wireguard/tun"
)

type tunnel struct {
tun.Device
}

func (t *tunnel) Read(b []byte) (int, error) {
if runtime.GOOS == "windows" {
return t.Device.Read(b, 0)
}
// unix.IFF_NO_PI is not set, therefore we receive packet information
n, err := t.Device.File().Read(b)
if n < 4 {
return 0, err
}
// shift slice to the left
return copy(b[:n-4], b[4:n]), nil
}

func (t *tunnel) Write(b []byte) (int, error) {
if runtime.GOOS == "windows" {
return t.Device.Write(b, 0)
}
return t.Device.Write(append(make([]byte, 4), b...), 4)
}

func (t *tunnel) Close() error {
return t.Device.Close()
}

func OpenTunDevice(name, addr, gw, mask string, dnsServers []string, persist bool) (io.ReadWriteCloser, error) {
tunDev, err := tun.CreateTUN(name, 1500)
if err != nil {
return nil, err
}

getName, err := tunDev.Name()
if err != nil {
return nil, err
}

return &tunnel{Device: tunDev}, setInterface(getName, addr, gw, mask, tunDev.(*tun.NativeTun))
}
66 changes: 15 additions & 51 deletions tun/tun_darwin.go
Original file line number Diff line number Diff line change
@@ -1,67 +1,31 @@
package tun

import (
"errors"
"fmt"
"io"
"net"
"os/exec"
"strconv"
"strings"

"github.com/songgao/water"
"github.com/eycorsican/go-tun2socks/routes"
"golang.zx2c4.com/wireguard/tun"
)

func isIPv4(ip net.IP) bool {
if ip.To4() != nil {
return true
}
return false
}

func isIPv6(ip net.IP) bool {
// To16() also valid for ipv4, ensure it's not an ipv4 address
if ip.To4() != nil {
return false
}
if ip.To16() != nil {
return true
func setInterface(name, addr, gw, mask string, tun *tun.NativeTun) error {
addrs, err := routes.ParseAddresses(addr, gw, mask)
if err != nil {
return err
}
return false
}

func OpenTunDevice(name, addr, gw, mask string, dnsServers []string, persist bool) (io.ReadWriteCloser, error) {
tunDev, err := water.New(water.Config{
DeviceType: water.TUN,
})
v, err := exec.Command("ifconfig", name, "mtu", "1500").Output()
if err != nil {
return nil, err
return fmt.Errorf("failed to set MTU: %s: %s", v, err)
}
name = tunDev.Name()
ip := net.ParseIP(addr)
if ip == nil {
return nil, errors.New("invalid IP address")
}

var params string
if isIPv4(ip) {
params = fmt.Sprintf("%s inet %s netmask %s %s", name, addr, mask, gw)
} else if isIPv6(ip) {
prefixlen, err := strconv.Atoi(mask)
if err != nil {
return nil, errors.New(fmt.Sprintf("parse IPv6 prefixlen failed: %v", err))
}
params = fmt.Sprintf("%s inet6 %s/%d", name, addr, prefixlen)
} else {
return nil, errors.New("invalid IP address")
v, err = exec.Command("ifconfig", name, "inet", addrs[0].String(), addrs[1].String()).Output()
if err != nil {
return fmt.Errorf("failed to set ip addr: %s: %s", v, err)
}

out, err := exec.Command("ifconfig", strings.Split(params, " ")...).Output()
v, err = exec.Command("ifconfig", name, "up").Output()
if err != nil {
if len(out) != 0 {
return nil, errors.New(fmt.Sprintf("%v, output: %s", err, out))
}
return nil, err
return fmt.Errorf("failed to bring up interface: %s: %s", v, err)
}
return tunDev, nil

return nil
}
20 changes: 2 additions & 18 deletions tun/tun_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,13 @@ package tun

import (
"fmt"
"io"

"github.com/eycorsican/go-tun2socks/routes"
"github.com/songgao/water"
"github.com/vishvananda/netlink"
"golang.zx2c4.com/wireguard/tun"
)

func OpenTunDevice(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 := water.New(cfg)
if err != nil {
return nil, err
}
name = tunDev.Name()

return tunDev, setInterface(name, addr, gw, mask)
}

func setInterface(name, addr, gw, mask string) error {
func setInterface(name, addr, gw, mask string, tun *tun.NativeTun) error {
link, err := netlink.LinkByName(name)
if err != nil {
return fmt.Errorf("failed to detect %s interface: %s", name, err)
Expand Down
Loading

0 comments on commit cd3f67c

Please sign in to comment.