mirror of
https://github.com/xjasonlyu/tun2socks.git
synced 2025-10-15 05:11:01 +08:00
freebsd/openbsd support (experimental)
This commit is contained in:
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
- 'assets/**'
|
- 'assets/**'
|
||||||
|
16
Makefile
16
Makefile
@@ -14,8 +14,12 @@ GO_BUILD = CGO_ENABLED=0 go build $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(
|
|||||||
|
|
||||||
PLATFORM_LIST = \
|
PLATFORM_LIST = \
|
||||||
darwin-amd64 \
|
darwin-amd64 \
|
||||||
|
freebsd-amd64 \
|
||||||
|
freebsd-arm64 \
|
||||||
linux-amd64 \
|
linux-amd64 \
|
||||||
linux-arm64 \
|
linux-arm64 \
|
||||||
|
openbsd-amd64 \
|
||||||
|
openbsd-arm64 \
|
||||||
|
|
||||||
.PHONY: all docker $(PLATFORM_LIST)
|
.PHONY: all docker $(PLATFORM_LIST)
|
||||||
|
|
||||||
@@ -27,12 +31,24 @@ docker:
|
|||||||
darwin-amd64:
|
darwin-amd64:
|
||||||
GOARCH=amd64 GOOS=darwin $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
GOARCH=amd64 GOOS=darwin $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
||||||
|
|
||||||
|
freebsd-amd64:
|
||||||
|
GOARCH=amd64 GOOS=freebsd $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
||||||
|
|
||||||
|
freebsd-arm64:
|
||||||
|
GOARCH=arm64 GOOS=freebsd $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
||||||
|
|
||||||
linux-amd64:
|
linux-amd64:
|
||||||
GOARCH=amd64 GOOS=linux $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
GOARCH=amd64 GOOS=linux $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
||||||
|
|
||||||
linux-arm64:
|
linux-arm64:
|
||||||
GOARCH=arm64 GOOS=linux $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
GOARCH=arm64 GOOS=linux $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
||||||
|
|
||||||
|
openbsd-amd64:
|
||||||
|
GOARCH=amd64 GOOS=openbsd $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
||||||
|
|
||||||
|
openbsd-arm64:
|
||||||
|
GOARCH=arm64 GOOS=openbsd $(GO_BUILD) -o $(DIR)/$(NAME)-$@
|
||||||
|
|
||||||
zip_releases=$(addsuffix .zip, $(PLATFORM_LIST))
|
zip_releases=$(addsuffix .zip, $(PLATFORM_LIST))
|
||||||
|
|
||||||
$(zip_releases): %.zip : %
|
$(zip_releases): %.zip : %
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
| Target | Minimum | Recommended |
|
| Target | Minimum | Recommended |
|
||||||
| :----- | :-----: | :---------: |
|
| :----- | :-----: | :---------: |
|
||||||
| System | linux darwin | linux |
|
| System | linux darwin freebsd openbsd | linux |
|
||||||
| Memory | >20MB | >128MB |
|
| Memory | >20MB | >128MB |
|
||||||
| CPU | amd64 arm64 | amd64 |
|
| CPU | amd64 arm64 | amd64 |
|
||||||
|
|
||||||
@@ -296,5 +296,5 @@ If you are sensitive to memory, please go back to [v1](https://github.com/xjason
|
|||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- [ ] Windows support
|
- [ ] Windows support
|
||||||
- [ ] FreeBSD support
|
- [x] FreeBSD support
|
||||||
- [ ] OpenBSD support
|
- [x] OpenBSD support
|
||||||
|
1
go.mod
1
go.mod
@@ -18,6 +18,7 @@ require (
|
|||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect
|
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect
|
||||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf
|
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf
|
||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
||||||
|
golang.zx2c4.com/wireguard v0.0.20200320
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20201107072535-9e848922ed33
|
gvisor.dev/gvisor v0.0.0-20201107072535-9e848922ed33
|
||||||
)
|
)
|
||||||
|
5
go.sum
5
go.sum
@@ -247,6 +247,7 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf
|
|||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
@@ -286,6 +287,7 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||||
@@ -334,6 +336,7 @@ golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM=
|
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM=
|
||||||
@@ -382,6 +385,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.zx2c4.com/wireguard v0.0.20200320 h1:1vE6zVeO7fix9cJX1Z9ZQ+ikPIIx7vIyU0o0tLDD88g=
|
||||||
|
golang.zx2c4.com/wireguard v0.0.20200320/go.mod h1:lDian4Sw4poJ04SgHh35nzMVwGSYlPumkdnHcucAQoY=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
@@ -13,11 +13,11 @@ import (
|
|||||||
"github.com/xjasonlyu/clash/component/dialer"
|
"github.com/xjasonlyu/clash/component/dialer"
|
||||||
"github.com/xjasonlyu/tun2socks/internal/api"
|
"github.com/xjasonlyu/tun2socks/internal/api"
|
||||||
"github.com/xjasonlyu/tun2socks/internal/core"
|
"github.com/xjasonlyu/tun2socks/internal/core"
|
||||||
"github.com/xjasonlyu/tun2socks/internal/dev"
|
|
||||||
"github.com/xjasonlyu/tun2socks/internal/dns"
|
"github.com/xjasonlyu/tun2socks/internal/dns"
|
||||||
"github.com/xjasonlyu/tun2socks/internal/proxy"
|
"github.com/xjasonlyu/tun2socks/internal/proxy"
|
||||||
"github.com/xjasonlyu/tun2socks/internal/tunnel"
|
"github.com/xjasonlyu/tun2socks/internal/tunnel"
|
||||||
"github.com/xjasonlyu/tun2socks/pkg/log"
|
"github.com/xjasonlyu/tun2socks/pkg/log"
|
||||||
|
"github.com/xjasonlyu/tun2socks/pkg/tun"
|
||||||
)
|
)
|
||||||
|
|
||||||
func bindToInterface(name string) {
|
func bindToInterface(name string) {
|
||||||
@@ -51,7 +51,7 @@ func Main(c *cli.Context) error {
|
|||||||
if c.IsSet("interface") {
|
if c.IsSet("interface") {
|
||||||
name := c.String("interface")
|
name := c.String("interface")
|
||||||
bindToInterface(name)
|
bindToInterface(name)
|
||||||
log.Infof("[IFCE] bind to interface: %s", name)
|
log.Infof("[DIALER] bind to interface: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.IsSet("api") { /* initiate API */
|
if c.IsSet("api") { /* initiate API */
|
||||||
@@ -71,16 +71,11 @@ func Main(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deviceURL := c.String("device")
|
deviceURL := c.String("device")
|
||||||
device, err := dev.Open(deviceURL)
|
device, err := tun.Open(deviceURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("open device %s: %w", deviceURL, err)
|
return fmt.Errorf("open device %s: %w", deviceURL, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer device.Close()
|
||||||
err := device.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("close device %s error: %v", deviceURL, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
proxyURL := c.String("proxy")
|
proxyURL := c.String("proxy")
|
||||||
if err := proxy.Register(proxyURL); err != nil {
|
if err := proxy.Register(proxyURL); err != nil {
|
||||||
@@ -90,7 +85,7 @@ func Main(c *cli.Context) error {
|
|||||||
if _, err := core.NewDefaultStack(device, tunnel.Add, tunnel.AddPacket); err != nil {
|
if _, err := core.NewDefaultStack(device, tunnel.Add, tunnel.AddPacket); err != nil {
|
||||||
return fmt.Errorf("initiate stack: %w", err)
|
return fmt.Errorf("initiate stack: %w", err)
|
||||||
}
|
}
|
||||||
log.Infof("[STACK] %s --> %s", device.String(), proxy.String())
|
log.Infof("[STACK] %s --> %s", deviceURL, proxyURL)
|
||||||
|
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
@@ -1,74 +0,0 @@
|
|||||||
package dev
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
||||||
|
|
||||||
"github.com/xjasonlyu/tun2socks/internal/dev/tun"
|
|
||||||
)
|
|
||||||
|
|
||||||
const defaultScheme = "tun"
|
|
||||||
|
|
||||||
type Device struct {
|
|
||||||
url *url.URL
|
|
||||||
io.Closer
|
|
||||||
stack.LinkEndpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
func Open(deviceURL string) (device *Device, err error) {
|
|
||||||
if !strings.Contains(deviceURL, "://") {
|
|
||||||
deviceURL = defaultScheme + "://" + deviceURL
|
|
||||||
}
|
|
||||||
|
|
||||||
var u *url.URL
|
|
||||||
if u, err = url.Parse(deviceURL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
ep stack.LinkEndpoint
|
|
||||||
c io.Closer
|
|
||||||
)
|
|
||||||
switch strings.ToLower(u.Scheme) {
|
|
||||||
case "tun":
|
|
||||||
name := u.Host
|
|
||||||
ep, c, err = tun.Open(name)
|
|
||||||
default:
|
|
||||||
err = errors.New("unsupported device type")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
device = &Device{
|
|
||||||
url: u,
|
|
||||||
Closer: c,
|
|
||||||
LinkEndpoint: ep,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes device.
|
|
||||||
func (d *Device) Close() error {
|
|
||||||
return d.Closer.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns name of device.
|
|
||||||
func (d *Device) Name() string {
|
|
||||||
return d.url.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns type of device.
|
|
||||||
func (d *Device) Type() string {
|
|
||||||
return strings.ToLower(d.url.Scheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns full URL string.
|
|
||||||
func (d *Device) String() string {
|
|
||||||
return d.url.String()
|
|
||||||
}
|
|
@@ -1,15 +0,0 @@
|
|||||||
// +build !darwin,!linux
|
|
||||||
|
|
||||||
package tun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Open(_ string) (stack.LinkEndpoint, io.Closer, error) {
|
|
||||||
return nil, nil, fmt.Errorf("operation was not supported on %s", runtime.GOOS)
|
|
||||||
}
|
|
@@ -1,57 +0,0 @@
|
|||||||
package tun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/songgao/water"
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
||||||
|
|
||||||
"github.com/xjasonlyu/tun2socks/pkg/link/rwc"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Open(name string) (ep stack.LinkEndpoint, c io.Closer, err error) {
|
|
||||||
config := water.Config{
|
|
||||||
DeviceType: water.TUN,
|
|
||||||
}
|
|
||||||
config.Name = name
|
|
||||||
|
|
||||||
var ifce *water.Interface
|
|
||||||
ifce, err = water.New(config)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var mtu uint32
|
|
||||||
mtu, err = getMTU(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ep, err = rwc.New(ifce, mtu)
|
|
||||||
c = ifce
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMTU(name string) (uint32, error) {
|
|
||||||
fd, err := unix.Socket(
|
|
||||||
unix.AF_INET,
|
|
||||||
unix.SOCK_DGRAM,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer unix.Close(fd)
|
|
||||||
|
|
||||||
ifr, err := unix.IoctlGetIfreqMTU(fd, name)
|
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("get MTU on %s: %w", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return uint32(ifr.MTU), nil
|
|
||||||
}
|
|
@@ -1,43 +0,0 @@
|
|||||||
package tun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/link/tun"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
||||||
)
|
|
||||||
|
|
||||||
type closeFunc func() error
|
|
||||||
|
|
||||||
func (f closeFunc) Close() error {
|
|
||||||
return f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Open(name string) (ep stack.LinkEndpoint, c io.Closer, err error) {
|
|
||||||
var fd int
|
|
||||||
fd, err = tun.Open(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var mtu uint32
|
|
||||||
mtu, err = rawfile.GetMTU(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ep, err = fdbased.New(&fdbased.Options{
|
|
||||||
FDs: []int{fd},
|
|
||||||
MTU: mtu,
|
|
||||||
EthernetHeader: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
c = closeFunc(func() error {
|
|
||||||
return syscall.Close(fd)
|
|
||||||
})
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
44
pkg/tun/tun.go
Normal file
44
pkg/tun/tun.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultScheme = "tun"
|
||||||
|
|
||||||
|
type Device interface {
|
||||||
|
stack.LinkEndpoint
|
||||||
|
|
||||||
|
Name() string // returns the current name
|
||||||
|
Close() error // stops and closes the tun
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open opens TUN Device with given URL.
|
||||||
|
func Open(rawURL string) (Device, error) {
|
||||||
|
if !strings.Contains(rawURL, "://") {
|
||||||
|
rawURL = defaultScheme + "://" + rawURL
|
||||||
|
}
|
||||||
|
|
||||||
|
var u *url.URL
|
||||||
|
u, err := url.Parse(rawURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ToLower(u.Scheme) != defaultScheme {
|
||||||
|
return nil, errors.New("unsupported TUN scheme")
|
||||||
|
}
|
||||||
|
|
||||||
|
var n uint64
|
||||||
|
if mtu := u.Query().Get("mtu"); mtu != "" {
|
||||||
|
n, _ = strconv.ParseUint(mtu, 10, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := u.Host
|
||||||
|
return CreateTUN(name, uint32(n))
|
||||||
|
}
|
12
pkg/tun/tun_default.go
Normal file
12
pkg/tun/tun_default.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// +build !darwin,!freebsd,!linux,!openbsd
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateTUN(_ string, _ uint32) (Device, error) {
|
||||||
|
return nil, fmt.Errorf("operation was not supported on %s", runtime.GOOS)
|
||||||
|
}
|
96
pkg/tun/tun_linux.go
Normal file
96
pkg/tun/tun_linux.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/link/tun"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
)
|
||||||
|
|
||||||
|
type linuxTun struct {
|
||||||
|
stack.LinkEndpoint
|
||||||
|
|
||||||
|
tunName string
|
||||||
|
tunFile *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTUN(name string, n uint32) (Device, error) {
|
||||||
|
fd, err := tun.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
if err := setMTU(name, n); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mtu uint32
|
||||||
|
if mtu, err = rawfile.GetMTU(name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ep stack.LinkEndpoint
|
||||||
|
if ep, err = fdbased.New(&fdbased.Options{
|
||||||
|
FDs: []int{fd},
|
||||||
|
MTU: mtu,
|
||||||
|
// TUN only
|
||||||
|
EthernetHeader: false,
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &linuxTun{
|
||||||
|
LinkEndpoint: ep,
|
||||||
|
tunName: name,
|
||||||
|
tunFile: os.NewFile(uintptr(fd), "tun"),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *linuxTun) Name() string {
|
||||||
|
return t.tunName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *linuxTun) Close() error {
|
||||||
|
return t.tunFile.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setMTU(name string, n uint32) error {
|
||||||
|
// open datagram socket
|
||||||
|
fd, err := unix.Socket(
|
||||||
|
unix.AF_INET,
|
||||||
|
unix.SOCK_DGRAM,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer unix.Close(fd)
|
||||||
|
|
||||||
|
const ifReqSize = unix.IFNAMSIZ + 64
|
||||||
|
|
||||||
|
// do ioctl call
|
||||||
|
var ifr [ifReqSize]byte
|
||||||
|
copy(ifr[:], name)
|
||||||
|
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = n
|
||||||
|
_, _, errno := unix.Syscall(
|
||||||
|
unix.SYS_IOCTL,
|
||||||
|
uintptr(fd),
|
||||||
|
uintptr(unix.SIOCSIFMTU),
|
||||||
|
uintptr(unsafe.Pointer(&ifr[0])),
|
||||||
|
)
|
||||||
|
|
||||||
|
if errno != 0 {
|
||||||
|
return errors.New("failed to set MTU of TUN device")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
69
pkg/tun/tun_unix.go
Normal file
69
pkg/tun/tun_unix.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// +build darwin freebsd openbsd
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.zx2c4.com/wireguard/tun"
|
||||||
|
|
||||||
|
"github.com/xjasonlyu/clash/common/pool"
|
||||||
|
"github.com/xjasonlyu/tun2socks/pkg/link/rwc"
|
||||||
|
)
|
||||||
|
|
||||||
|
const offset = 4
|
||||||
|
|
||||||
|
type unixTun struct {
|
||||||
|
*rwc.Endpoint
|
||||||
|
|
||||||
|
device tun.Device
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTUN(name string, n uint32) (Device, error) {
|
||||||
|
device, err := tun.CreateTUN(name, int(n))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mtu, err := device.MTU()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ut := &unixTun{
|
||||||
|
device: device,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ut.Endpoint, err = rwc.New(ut, uint32(mtu)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ut, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *unixTun) Read(packet []byte) (n int, err error) {
|
||||||
|
buf := pool.Get(offset + len(packet))
|
||||||
|
defer pool.Put(buf)
|
||||||
|
|
||||||
|
if n, err = t.device.Read(buf, offset); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(packet, buf[offset:offset+n])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *unixTun) Write(packet []byte) (int, error) {
|
||||||
|
buf := pool.Get(offset + len(packet))
|
||||||
|
defer pool.Put(buf)
|
||||||
|
|
||||||
|
copy(buf[offset:], packet)
|
||||||
|
return t.device.Write(buf[:offset+len(packet)], offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *unixTun) Name() string {
|
||||||
|
name, _ := t.device.Name()
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *unixTun) Close() error {
|
||||||
|
return t.device.Close()
|
||||||
|
}
|
Reference in New Issue
Block a user