diff --git a/buildSrc/src/main/java/GolangBindTask.kt b/buildSrc/src/main/java/GolangBindTask.kt new file mode 100644 index 0000000..3b7ba2f --- /dev/null +++ b/buildSrc/src/main/java/GolangBindTask.kt @@ -0,0 +1,138 @@ +import org.apache.tools.ant.taskdefs.condition.Os +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.tasks.TaskAction +import java.io.File +import java.io.FileReader +import java.io.FileWriter +import java.util.* +import kotlin.concurrent.thread + +open class GolangBindTask : DefaultTask() { + companion object { + private val STUB_GO_MOD_CONTENT = """ + module github.com/kr328/cfa-bind + + require ( + github.com/kr328/cfa v0.0.0 // redirect + github.com/Dreamacro/clash v0.0.0 // redirect + ) + + replace github.com/kr328/cfa v0.0.0 => {SOURCE_PATH} + replace github.com/Dreamacro/clash v0.0.0 => {SOURCE_PATH}/clash + """.trimIndent() + private val STUB_GO_FILE_CONTENT = """ + package main + + import "github.com/kr328/cfa/bridge" + + func main() {} + """.trimIndent() + } + + val javaOutput: File + get() { + return project.buildDir.resolve("intermediates/go_output/generate_java") + } + val nativeOutput: File + get() { + return project.buildDir.resolve("intermediates/go_output/native_library") + } + private val goBuildPath: File + get() { + return project.buildDir.resolve("intermediates/go_build") + } + private val goPath: File + get() { + return goBuildPath.resolve("go_path") + } + private val goBindPath: File + get() { + return goBuildPath.resolve("go_bind_path") + } + private val sourcePath: File + get() { + return project.file("src/main/golang") + } + private val properties by lazy { + FileReader(project.rootProject.file("local.properties")).use { + Properties().apply { load(it) } + } + } + private val environment = mutableMapOf() + + init { + + } + + @TaskAction + fun process() { + environment.put("GOPATH", goPath.absolutePath) + environment.put("ANDROID_HOME", findAndroidSdkPath().absolutePath) + environment.put("ANDROID_NDK_HOME", findAndroidNdkPath().absolutePath) + + if ( Os.isFamily(Os.FAMILY_WINDOWS) ) + environment.put("Path", System.getenv("Path") + ";" + goPath.resolve("bin")) + else + environment.put("PATH", System.getenv("PATH") + ":" + goPath.resolve("bin")) + + goBindPath.deleteRecursively() + goBindPath.mkdirs() + + "go get golang.org/x/mobile/cmd/gomobile".exec() + + FileWriter(goBindPath.resolve("go.mod")).use { + it.write(STUB_GO_MOD_CONTENT.replace("{SOURCE_PATH}", sourcePath.absolutePath)) + } + FileWriter(goBindPath.resolve("main.go")).use { + it.write(STUB_GO_FILE_CONTENT) + } + + "go mod vendor".exec(goBindPath) + + goBindPath.resolve("vendor") + .copyRecursively(goPath.resolve("src"), overwrite = true) + + "gomobile init".exec(goBuildPath) + "gomobile bind -target=android github.com/kr328/cfa/bridge".exec(goBuildPath) + } + + private fun findAndroidNdkPath(): File { + return properties.getProperty("ndk.dir")?.let { File(it) }?.takeIf { it.exists() } + ?: throw GradleException("Android NDK not found.") + } + + private fun findAndroidSdkPath(): File { + return properties.getProperty("sdk.dir")?.let { File(it) }?.takeIf { it.exists() } + ?: throw GradleException("Android SDK not found.") + } + + private fun String.exec(pwd: File = File(".")) { + val process = with (ProcessBuilder()) { + if ( Os.isFamily(Os.FAMILY_WINDOWS) ) + command("cmd.exe", "/c", this@exec) + else + command("bash", "-c", this@exec) + + environment().putAll(environment) + directory(pwd) + + redirectErrorStream(true) + + start() + } + + process.inputStream.copyTo(System.out) + println() + + if ( process.waitFor() != 0 ) + throw GradleException("Run command $this failure") + } + + private fun String.exe(): String { + return if ( Os.isFamily(Os.FAMILY_WINDOWS) ) + "$this.exe" + else + this + } +} \ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle index 1740143..f3a71e3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -42,20 +42,6 @@ dependencies { } afterEvaluate { - def compileArch = ["arm64-v8a", "x86_64"] - def options = new GolangBuildOptions(file("src/main/golang"), file("$buildDir/intermediates/native_output"), "23") - - def ts = compileArch.stream().map { abi -> - tasks.register("golangBuildFor" + abi.replace("-", "").replace("_", ""), GolangBuildTask.class) { - setOptions options, abi - } - }.toArray() - - for ( task in tasks ) { - if ( task.name.contains("JniLib") ) - task.dependsOn(ts) - } - def ds = tasks.register("downloadMMDB", MMDBDowloadTask.class) { onlyIf { System.currentTimeMillis() - file("$buildDir/intermediates/cache/Country.tar.gz").lastModified() > 24 * 3600 * 1000L @@ -89,6 +75,8 @@ afterEvaluate { if ( task.name.contains("generate") && task.name.contains("Assets") ) task.dependsOn(es) } + + tasks.register("golangBind", GolangBindTask.class) } repositories { diff --git a/core/src/main/golang/bridge/callback.go b/core/src/main/golang/bridge/callback.go new file mode 100644 index 0000000..ae4773b --- /dev/null +++ b/core/src/main/golang/bridge/callback.go @@ -0,0 +1,12 @@ +package bridge + +type Callback interface { +} + +var callback Callback = defaultCallback{} + +func SetCallback(cb Callback) { + callback = cb +} + +type defaultCallback struct{} diff --git a/core/src/main/golang/bridge/profiles.go b/core/src/main/golang/bridge/profiles.go new file mode 100644 index 0000000..1e12cc6 --- /dev/null +++ b/core/src/main/golang/bridge/profiles.go @@ -0,0 +1,11 @@ +package bridge + +import "github.com/kr328/cfa/profile" + +func LoadProfileFile(path string) { + profile.LoadFromFile(path) +} + +func LoadProfileDefault() { + profile.LoadDefault() +} diff --git a/core/src/main/golang/go.mod b/core/src/main/golang/go.mod index 236db9d..f0053a4 100644 --- a/core/src/main/golang/go.mod +++ b/core/src/main/golang/go.mod @@ -5,6 +5,7 @@ go 1.13 require ( github.com/Dreamacro/clash v0.0.0 // local github.com/google/go-cmp v0.3.1 // indirect + golang.org/x/mobile v0.0.0-20191210151939-1a1fef82734d // indirect golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 ) diff --git a/core/src/main/golang/go.sum b/core/src/main/golang/go.sum index cb075b6..9676285 100644 --- a/core/src/main/golang/go.sum +++ b/core/src/main/golang/go.sum @@ -1,3 +1,5 @@ +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Dreamacro/clash v0.16.0 h1:ZvV9apOrDHC0s5ff4YCHTRANd/XyOuLWvpyLWOkwS6U= github.com/Dreamacro/clash v0.16.0/go.mod h1:4ZBtABBmIGqISniBtu9fpYORrE5mKqIP8SMCTrNNVNY= github.com/Dreamacro/go-shadowsocks2 v0.1.3 h1:1ffY/q4e3o+MnztYgIq1iZiX1BWoWQ6D3AIO1kkb8bc= @@ -55,6 +57,7 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= @@ -62,11 +65,23 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1 h1:anGSYQpPhQwXlwsu5wmfq0nWkCNaMEMUwAv13Y92hd8= golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20191210151939-1a1fef82734d h1:LlA9R5JFi974qK4gm9FRK1+qSkduxnQKcrimdzcidyc= +golang.org/x/mobile v0.0.0-20191210151939-1a1fef82734d/go.mod h1:p895TfNkDgPEmEQrNiOtIl3j98d/tGU95djDj7NfyjQ= +golang.org/x/mod v0.1.0 h1:sfUMP1Gu8qASkorDVjnMuvgJzwFbTZSeXFiGBYAVdl4= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -89,12 +104,18 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190909214602-067311248421 h1:NmmWqJbt02YJHmp4A4gBXvsXXIzzixjzE1y6PKUyIjk= +golang.org/x/tools v0.0.0-20190909214602-067311248421/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/eapache/channels.v1 v1.1.0 h1:5bGAyKKvyCTWjSj7mhefG6Lc68VyN4MH1v8/7OoeeB4= gopkg.in/eapache/channels.v1 v1.1.0/go.mod h1:BHIBujSvu9yMTrTYbTCjDD43gUhtmaOtTWDe7sTv1js= diff --git a/core/src/main/golang/main.go b/core/src/main/golang/main.go index 68c3f66..06ab7d0 100644 --- a/core/src/main/golang/main.go +++ b/core/src/main/golang/main.go @@ -1,45 +1 @@ package main - -import ( - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/Dreamacro/clash/constant" - - "github.com/kr328/cfa/profile" - "github.com/kr328/cfa/server" -) - -func main() { - if len(os.Args) != 2 { - fmt.Println("Invalid argument") - return - } - - // Redirect stderr to stdout - os.Stderr = os.Stdout - - if cwd, err := os.Getwd(); err == nil { - constant.SetHomeDir(cwd) - } else { - return - } - - if err := server.Start(os.Args[1]); err != nil { - fmt.Println("[CONTROLLER] ERROR={" + err.Error() + "}") - return - } - - fmt.Println("[PID]", os.Getpid()) - fmt.Println("[CONTROLLER] STARTED") - - profile.LoadDefault() - - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - <-sigCh - - return -} diff --git a/core/src/main/golang/tun/tun.go b/core/src/main/golang/tun/tun.go index 2a1a780..3712023 100644 --- a/core/src/main/golang/tun/tun.go +++ b/core/src/main/golang/tun/tun.go @@ -2,9 +2,9 @@ package tun import ( "fmt" + "net" "strconv" - "github.com/Dreamacro/clash/dns" T "github.com/Dreamacro/clash/proxy/tun" ) @@ -13,6 +13,8 @@ type handler struct { } const dnsServerAddress = "172.19.0.2:53" +const gatewayAddress = "172.19.0.1/30" +const fakeInterface = "172.19.0.2" var ( dnsHijacking bool = false @@ -23,13 +25,19 @@ var ( func StartTunProxy(fd, mtu int) error { StopTunProxy() - adapter, err := T.NewTunProxy("fd://" + strconv.Itoa(fd) + "?mtu=" + strconv.Itoa(mtu)) + ip, network, _ := net.ParseCIDR(gatewayAddress) + + network.IP = ip.To4() + + fakeInterface := net.ParseIP(fakeInterface).To4() + + adapter, err := T.NewTunProxy("fd://"+strconv.Itoa(fd)+"?mtu="+strconv.Itoa(mtu), *network, fakeInterface) if err != nil { return err } instance = &handler{ - tunAdapter: &adapter, + tunAdapter: adapter, } ResetDnsRedirect() @@ -52,12 +60,11 @@ func ResetDnsRedirect() { return } - if dnsHijacking { - (*instance.tunAdapter).ReCreateDNSServer(dns.DefaultResolver, "0.0.0.0:53") - } else { - (*instance.tunAdapter).ReCreateDNSServer(dns.DefaultResolver, dnsServerAddress) - } - + // if dnsHijacking { + // (*instance.tunAdapter).ReCreateDNSServer(dns.DefaultResolver, "0.0.0.0:53") + // } else { + // (*instance.tunAdapter).ReCreateDNSServer(dns.DefaultResolver, dnsServerAddress) + // } } func SetDnsHijacking(enabled bool) { diff --git a/service/src/main/java/com/github/kr328/clash/service/TunService.kt b/service/src/main/java/com/github/kr328/clash/service/TunService.kt index 2c28946..4bfc754 100644 --- a/service/src/main/java/com/github/kr328/clash/service/TunService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/TunService.kt @@ -15,7 +15,7 @@ class TunService : VpnService(), IClashEventObserver { companion object { // from https://github.com/shadowsocks/shadowsocks-android/blob/master/core/src/main/java/com/github/shadowsocks/bg/VpnService.kt private const val VPN_MTU = 1500 - private const val PRIVATE_VLAN_DNS = "172.19.0.2" // sync with tun/tun.go/dnsServerAddress + private const val PRIVATE_VLAN_DNS = "114.114.114.114" // sync with tun/tun.go/dnsServerAddress private const val PRIVATE_VLAN4_CLIENT = "172.19.0.1" private const val PRIVATE_VLAN6_CLIENT = "fdfe:dcba:9876::1" }