Skip to content

Commit

Permalink
feat: ✨ add ProxyTunnel to replace tun2socks
Browse files Browse the repository at this point in the history
  • Loading branch information
jyyi1 committed Aug 22, 2023
1 parent 60c800c commit 3e5ae25
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 22 deletions.
11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ go 1.20
require (
github.com/Jigsaw-Code/outline-sdk v0.0.2
github.com/Jigsaw-Code/outline-sdk/x v0.0.0-20230807220427-893de7fdc6b8
github.com/eycorsican/go-tun2socks v1.16.11
github.com/stretchr/testify v1.8.4
golang.org/x/sys v0.11.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eycorsican/go-tun2socks v1.16.11 // indirect
github.com/miekg/dns v1.1.54 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/shadowsocks/go-shadowsocks2 v0.1.5 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/tools v0.9.1 // indirect
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
19 changes: 10 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,29 @@ github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/shadowsocks/go-shadowsocks2 v0.1.5 h1:PDSQv9y2S85Fl7VBeOMF9StzeXZyK1HakRm86CUbr28=
github.com/shadowsocks/go-shadowsocks2 v0.1.5/go.mod h1:AGGpIoek4HRno4xzyFiAtLHkOpcoznZEkAccaI/rplM=
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/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60 h1:o4bs4seAAlSiZQAZbO6/RP5XBCZCooQS3Pgc0AUjWts=
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
18 changes: 18 additions & 0 deletions outline/client/backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Outline Client Backend

## Environment Preparation

```sh
go install golang.org/x/mobile/cmd/gomobile@latest
export GOBIN="$HOME/go/bin/" -- or your customized go binary folder
export PATH="$GOBIN:$PATH"
gomobile init
```

## Build

```sh
export ANDROID_HOME="$HOME/Android/Sdk"
gomobile clean
gomobile bind -target android ./outline/client/backend
```
50 changes: 50 additions & 0 deletions outline/client/backend/copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2023 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package backend

import (
"io"
"sync"
)

type Reader interface {
io.Reader
}

type Writer interface {
io.Writer
}

type AsyncCopyResult struct {
wg sync.WaitGroup
copied int64
err error
}

func CopyAsync(dest Writer, source Reader) *AsyncCopyResult {
w := &AsyncCopyResult{}
w.wg.Add(1)
go func() {
defer w.wg.Done()
buf := make([]byte, 1500)
w.copied, w.err = io.CopyBuffer(dest, source, buf)
}()
return w
}

func (w *AsyncCopyResult) Wait() (int64, error) {
w.wg.Wait()
return w.copied, w.err
}
77 changes: 77 additions & 0 deletions outline/client/backend/electron_legacy/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2023 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///go:build linux & windows

package electronlegacy

import (
"flag"
"log"
"os"
"os/signal"
"strings"
"syscall"

"github.com/Jigsaw-Code/outline-apps/outline/client/backend"
"github.com/eycorsican/go-tun2socks/tun"
)

var args struct {
// TUN device settings
tunAddr *string
tunGw *string
tunMask *string
tunName *string
tunDNS *string

// Proxy settings
proxyConfig *string
}

func main() {
args.tunAddr = flag.String("tunAddr", "10.0.85.2", "TUN interface IP address")
args.tunGw = flag.String("tunGw", "10.0.85.1", "TUN interface gateway")
args.tunMask = flag.String("tunMask", "255.255.255.0", "TUN interface network mask; prefixlen for IPv6")
args.tunDNS = flag.String("tunDNS", "1.1.1.1,9.9.9.9,208.67.222.222", "Comma-separated list of DNS resolvers for the TUN interface (Windows only)")
args.tunName = flag.String("tunName", "tun0", "TUN interface name")
args.proxyConfig = flag.String("config", "", "The Outline configuration in JSON format")
flag.Parse()

proxy, err := backend.NewProxyTunnel(*args.proxyConfig)
if err != nil {
log.Fatalf("Failed to create Outline ProxyTunnel: %v", err)
}
log.Println("Outline ProxyTunnel created")
defer proxy.Close() // not necessary, but no harm

dnsResolvers := strings.Split(*args.tunDNS, ",")
tunDev, err := tun.OpenTunDevice(*args.tunName, *args.tunAddr, *args.tunGw, *args.tunMask, dnsResolvers, true)
if err != nil {
log.Fatalf("Failed to open tun device: %v", err)
}
log.Println("Tun device opened")
defer tunDev.Close() // not necessary, but no harm

defer backend.CopyAsync(tunDev, proxy).Wait()
defer backend.CopyAsync(proxy, tunDev).Wait()

osSignals := make(chan os.Signal, 1)
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
sig := <-osSignals

log.Printf("Received signal: %v, terminating...", sig)
proxy.Close()
tunDev.Close()
}
30 changes: 30 additions & 0 deletions outline/client/backend/proxy_tunnel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2023 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package backend

import "github.com/Jigsaw-Code/outline-apps/outline/device"

// ProxyTunnel is an interface that will be exported by gomobile, and be used by Outline Client.
type ProxyTunnel struct {
*device.OutlineDevice
}

func NewProxyTunnel(configJSON string) (*ProxyTunnel, error) {
d, err := device.NewOutlineDevice(configJSON)
if err != nil {
return nil, err
}
return &ProxyTunnel{d}, nil
}
14 changes: 6 additions & 8 deletions outline/device/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ const (

// OutlineDevice delegates the TCP and UDP traffic from local machine to the remote Outline server.
type OutlineDevice struct {
t2s network.IPDevice
pp *outlinePacketProxy
sd transport.StreamDialer
// The tun2socks IP device
network.IPDevice

pp *outlinePacketProxy
sd transport.StreamDialer
}

// NewOutlineDevice creates a new [OutlineDevice] that can relay traffic to a remote Outline server.
Expand All @@ -51,17 +53,13 @@ func NewOutlineDevice(configJSON string) (d *OutlineDevice, err error) {
return nil, fmt.Errorf("failed to create UDP proxy: %w", err)
}

if d.t2s, err = lwip2transport.ConfigureDevice(d.sd, d.pp); err != nil {
if d.IPDevice, err = lwip2transport.ConfigureDevice(d.sd, d.pp); err != nil {
return nil, fmt.Errorf("failed to configure lwIP: %w", err)
}

return
}

func (d *OutlineDevice) Close() error {
return d.t2s.Close()
}

func (d *OutlineDevice) Refresh() error {
return d.pp.testConnectivityAndRefresh(connectivityTestDNSResolver, connectivityTestTargetDomain)
}

0 comments on commit 3e5ae25

Please sign in to comment.