diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index a644582..b1c0202 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -14,10 +14,6 @@ jobs: uses: actions/setup-java@v1 with: java-version: 1.8 - - name: Setup GoLang - uses: actions/setup-go@v1 - with: - go-version: 1.13.x - name: Build with Gradle run: ./gradlew assembleRelease env: diff --git a/app/build.gradle b/app/build.gradle index 2312904..6bf03f3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "com.github.shadowsocks.plugin.gost" minSdkVersion 21 targetSdkVersion 29 - versionCode 2813 - versionName "2.8.1-3" + versionCode 2110 + versionName "2.11.0-1" } signingConfigs { releaseConfig { @@ -32,8 +32,8 @@ dependencies { task buildGoLibrary(type: Exec) { environment ([ANDROID_NDK_ROOT: android.ndkDirectory]) - commandLine ('sh', 'build.sh') - inputs.files 'build.sh' + commandLine ('sh', '../build.sh') + inputs.files '../build.sh' outputs.dir 'src/main/jniLibs' } diff --git a/app/build.sh b/app/build.sh deleted file mode 100644 index 1b535ae..0000000 --- a/app/build.sh +++ /dev/null @@ -1,27 +0,0 @@ -cd $( cd "$( dirname "$0" )" && pwd ) - -go version - -mkdir build - -cd build - -git clone https://github.com/xausky/gost.git - -cd gost - -CC=$(find $ANDROID_NDK_ROOT | grep 'armv7a-linux-androideabi21-clang$') \ -GOOS="android" GOARCH="arm" CGO_ENABLED="1" \ -go build -ldflags "-s -w" -a -o ../../src/main/jniLibs/armeabi-v7a/libgost-plugin.so ./cmd/gost - -CC=$(find $ANDROID_NDK_ROOT | grep 'aarch64-linux-android21-clang$') \ -GOOS="android" GOARCH="arm64" CGO_ENABLED="1" \ -go build -ldflags "-s -w" -a -o ../../src/main/jniLibs/arm64-v8a/libgost-plugin.so ./cmd/gost - -CC=$(find $ANDROID_NDK_ROOT | grep 'i686-linux-android21-clang$') \ -GOOS="android" GOARCH="386" CGO_ENABLED="1" \ -go build -ldflags "-s -w" -a -o ../../src/main/jniLibs/x86/libgost-plugin.so ./cmd/gost - -CC=$(find $ANDROID_NDK_ROOT | grep 'x86_64-linux-android21-clang$') \ -GOOS="android" GOARCH="amd64" CGO_ENABLED="1" \ -go build -ldflags "-s -w" -a -o ../../src/main/jniLibs/x86_64/libgost-plugin.so ./cmd/gost \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..69fb24f --- /dev/null +++ b/build.sh @@ -0,0 +1,46 @@ +set -e +GOST_VERSION=2.11.0 +GOLANG_VERSION=1.13.8 +cd $( cd "$( dirname "$0" )" && pwd ) +if [ ! -e build ] +then +mkdir build +fi +cd build +if [ ! -e go ] +then +curl "https://dl.google.com/go/go$GOLANG_VERSION.linux-amd64.tar.gz" -L -o go.tar.gz +tar -zxvf go.tar.gz +cd go +patch -p1 -r . < ../../go.patch +cd .. +fi +export PATH=$PWD/go/bin:$PATH +export GOROOT=$PWD/go +go version +if [ ! -e gost ] +then +curl "https://github.com/ginuerzh/gost/archive/v$GOST_VERSION.tar.gz" -L -o gost.tar.gz +tar -zxvf gost.tar.gz +mv gost-$GOST_VERSION gost +cd gost +patch -p1 -r . < ../../gost.patch +cd .. +fi +cd gost +echo $ANDROID_NDK_ROOT +CC=$(find $ANDROID_NDK_ROOT | grep 'armv7a-linux-androideabi21-clang$') \ +GOOS="android" GOARCH="arm" CGO_ENABLED="1" \ +go build -ldflags "-s -w" -a -o ../../app/src/main/jniLibs/armeabi-v7a/libgost-plugin.so ./cmd/gost + +CC=$(find $ANDROID_NDK_ROOT | grep 'aarch64-linux-android21-clang$') \ +GOOS="android" GOARCH="arm64" CGO_ENABLED="1" \ +go build -ldflags "-s -w" -a -o ../../app/src/main/jniLibs/arm64-v8a/libgost-plugin.so ./cmd/gost + +CC=$(find $ANDROID_NDK_ROOT | grep 'i686-linux-android21-clang$') \ +GOOS="android" GOARCH="386" CGO_ENABLED="1" \ +go build -ldflags "-s -w" -a -o ../../app/src/main/jniLibs/x86/libgost-plugin.so ./cmd/gost + +CC=$(find $ANDROID_NDK_ROOT | grep 'x86_64-linux-android21-clang$') \ +GOOS="android" GOARCH="amd64" CGO_ENABLED="1" \ +go build -ldflags "-s -w" -a -o ../../app/src/main/jniLibs/x86_64/libgost-plugin.so ./cmd/gost diff --git a/go.patch b/go.patch new file mode 100644 index 0000000..d0b59fc --- /dev/null +++ b/go.patch @@ -0,0 +1,52 @@ +diff -ru go-back/src/net/dial.go go/src/net/dial.go +--- go-back/src/net/dial.go 2020-03-14 14:55:07.506350800 +0800 ++++ go/src/net/dial.go 2020-03-14 14:38:30.995350900 +0800 +@@ -347,6 +347,8 @@ + return d.DialContext(context.Background(), network, address) + } + ++var DialContextDialerHook func(d *Dialer) ++ + // DialContext connects to the address on the named network using + // the provided context. + // +@@ -366,6 +368,9 @@ + // See func Dial for a description of the network and address + // parameters. + func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) { ++ if DialContextDialerHook != nil { ++ DialContextDialerHook(d) ++ } + if ctx == nil { + panic("nil context") + } +@@ -519,7 +524,6 @@ + // either the first successful connection, or the first error. + func (sd *sysDialer) dialSerial(ctx context.Context, ras addrList) (Conn, error) { + var firstErr error // The error from the first address is most relevant. +- + for i, ra := range ras { + select { + case <-ctx.Done(): +diff -ru go-back/src/net/udpsock.go go/src/net/udpsock.go +--- go-back/src/net/udpsock.go 2020-03-14 14:55:08.235708400 +0800 ++++ go/src/net/udpsock.go 2020-03-14 14:36:19.476741700 +0800 +@@ -219,6 +219,8 @@ + return c, nil + } + ++var ListenUDPListenConfigHook func(d *ListenConfig) ++ + // ListenUDP acts like ListenPacket for UDP networks. + // + // The network must be a UDP network name; see func Dial for details. +@@ -238,6 +240,9 @@ + laddr = &UDPAddr{} + } + sl := &sysListener{network: network, address: laddr.String()} ++ if ListenUDPListenConfigHook != nil { ++ ListenUDPListenConfigHook(&sl.ListenConfig) ++ } + c, err := sl.listenUDP(context.Background(), laddr) + if err != nil { + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err} diff --git a/gost.patch b/gost.patch new file mode 100644 index 0000000..2aafa7c --- /dev/null +++ b/gost.patch @@ -0,0 +1,212 @@ +diff -ruN gost.back/cmd/gost/main.go gost/cmd/gost/main.go +--- gost.back/cmd/gost/main.go 2020-03-14 15:01:10.651935500 +0800 ++++ gost/cmd/gost/main.go 2020-03-14 16:17:45.537385600 +0800 +@@ -8,10 +8,12 @@ + "net/http" + "os" + "runtime" ++ "strings" + + _ "net/http/pprof" + + "github.com/ginuerzh/gost" ++ "github.com/ginuerzh/gost/utils" + "github.com/go-log/log" + ) + +@@ -27,13 +29,25 @@ + + var ( + printVersion bool ++ fastOpen bool + ) ++ localHost := os.Getenv("SS_LOCAL_HOST") ++ localPort := os.Getenv("SS_LOCAL_PORT") ++ pluginOptions := os.Getenv("SS_PLUGIN_OPTIONS") ++ pluginOptions = strings.ReplaceAll(pluginOptions, "#SS_HOST", os.Getenv("SS_REMOTE_HOST")) ++ pluginOptions = strings.ReplaceAll(pluginOptions, "#SS_PORT", os.Getenv("SS_REMOTE_PORT")) ++ ++ os.Args = append(os.Args, "-L") ++ os.Args = append(os.Args, fmt.Sprintf("ss+tcp://rc4-md5:gost@[%s]:%s", localHost, localPort)) ++ os.Args = append(os.Args, strings.Split(pluginOptions, " ")...) + + flag.Var(&baseCfg.route.ChainNodes, "F", "forward address, can make a forward chain") + flag.Var(&baseCfg.route.ServeNodes, "L", "listen address, can listen on multiple ports (required)") + flag.StringVar(&configureFile, "C", "", "configure file") + flag.BoolVar(&baseCfg.Debug, "D", false, "enable debug log") +- flag.BoolVar(&printVersion, "V", false, "print version") ++ flag.BoolVar(&utils.VpnMode, "V", false, "VPN Mode") ++ flag.BoolVar(&fastOpen, "fast-open", false, "fast Open TCP") ++ flag.BoolVar(&printVersion, "PV", false, "print version") + if pprofEnabled { + flag.StringVar(&pprofAddr, "P", ":6060", "profiling HTTP server address") + } +@@ -45,6 +59,12 @@ + os.Exit(0) + } + ++ if localHost == "" || localPort == "" { ++ fmt.Fprintln(os.Stderr, "Can only be used in the shadowsocks plugin.") ++ os.Exit(1) ++ } ++ utils.Init() ++ + if configureFile != "" { + _, err := parseBaseConfig(configureFile) + if err != nil { +diff -ruN gost.back/utils/utils.go gost/utils/utils.go +--- gost.back/utils/utils.go 1970-01-01 08:00:00.000000000 +0800 ++++ gost/utils/utils.go 2020-03-14 16:16:52.766185200 +0800 +@@ -0,0 +1,7 @@ ++// +build !android ++ ++package utils ++ ++var VpnMode bool ++ ++func Init() {} +\ No newline at end of file +diff -ruN gost.back/utils/utils_android.go gost/utils/utils_android.go +--- gost.back/utils/utils_android.go 1970-01-01 08:00:00.000000000 +0800 ++++ gost/utils/utils_android.go 2020-03-14 16:16:30.964564900 +0800 +@@ -0,0 +1,140 @@ ++// +build android ++ ++package utils ++ ++/* ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ANCIL_FD_BUFFER(n) \ ++ struct { \ ++ struct cmsghdr h; \ ++ int fd[n]; \ ++ } ++ ++int ++ancil_send_fds_with_buffer(int sock, const int *fds, unsigned n_fds, void *buffer) ++{ ++ struct msghdr msghdr; ++ char nothing = '!'; ++ struct iovec nothing_ptr; ++ struct cmsghdr *cmsg; ++ int i; ++ ++ nothing_ptr.iov_base = ¬hing; ++ nothing_ptr.iov_len = 1; ++ msghdr.msg_name = NULL; ++ msghdr.msg_namelen = 0; ++ msghdr.msg_iov = ¬hing_ptr; ++ msghdr.msg_iovlen = 1; ++ msghdr.msg_flags = 0; ++ msghdr.msg_control = buffer; ++ msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds; ++ cmsg = CMSG_FIRSTHDR(&msghdr); ++ cmsg->cmsg_len = msghdr.msg_controllen; ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_RIGHTS; ++ for(i = 0; i < n_fds; i++) ++ ((int *)CMSG_DATA(cmsg))[i] = fds[i]; ++ return(sendmsg(sock, &msghdr, 0) >= 0 ? 0 : -1); ++} ++ ++int ++ancil_send_fd(int sock, int fd) ++{ ++ ANCIL_FD_BUFFER(1) buffer; ++ ++ return(ancil_send_fds_with_buffer(sock, &fd, 1, &buffer)); ++} ++ ++void ++set_timeout(int sock) ++{ ++ struct timeval tv; ++ tv.tv_sec = 3; ++ tv.tv_usec = 0; ++ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); ++ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); ++} ++ ++*/ ++import "C" ++ ++import ( ++ "context" ++ "log" ++ "net" ++ "syscall" ++) ++ ++var VpnMode bool ++ ++func ControlOnConnSetup(network string, address string, c syscall.RawConn) error { ++ if VpnMode { ++ fn := func(s uintptr) { ++ fd := int(s) ++ path := "protect_path" ++ ++ socket, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) ++ if err != nil { ++ log.Println(err) ++ return ++ } ++ ++ defer syscall.Close(socket) ++ ++ C.set_timeout(C.int(socket)) ++ ++ err = syscall.Connect(socket, &syscall.SockaddrUnix{Name: path}) ++ if err != nil { ++ log.Println(err) ++ return ++ } ++ ++ C.ancil_send_fd(C.int(socket), C.int(fd)) ++ ++ dummy := []byte{1} ++ n, err := syscall.Read(socket, dummy) ++ if err != nil { ++ log.Println(err) ++ return ++ } ++ if n != 1 { ++ log.Println("Failed to protect fd: ", fd) ++ return ++ } ++ } ++ ++ if err := c.Control(fn); err != nil { ++ return err ++ } ++ } ++ ++ return nil ++} ++ ++func Init() { ++ log.Printf("Android Utils Init. VpnMode: %v", VpnMode) ++ net.DefaultResolver = &net.Resolver{Dial: func(ctx context.Context, network, address string) (net.Conn, error) { ++ log.Printf("DefaultResolver address %v modify to %v", address, "119.29.29.29:53") ++ d := net.Dialer{} ++ return d.DialContext(ctx, network, "119.29.29.29:53") ++ }, PreferGo: true} ++ if VpnMode { ++ log.Printf("VpnMode Hook Init.") ++ net.ListenUDPListenConfigHook = func(c *net.ListenConfig) { ++ log.Printf("DialContextDialerHook %v", c) ++ c.Control = ControlOnConnSetup ++ } ++ net.DialContextDialerHook = func(d *net.Dialer) { ++ log.Printf("DialContextDialerHook %v", d) ++ d.Control = ControlOnConnSetup ++ } ++ } ++}