tun device work fine
This commit is contained in:
11 files changed
+165
-50
No files matched your search
@@ -23,9 +23,9 @@ func main() {
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
if err := server.Start(os.Args[1]) ; err != nil {
|
||||
fmt.Println("[CONTROLLER] ERROR={"+ err.Error() +"}")
|
||||
|
||||
if err := server.Start(os.Args[1]); err != nil {
|
||||
fmt.Println("[CONTROLLER] ERROR={" + err.Error() + "}")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +52,12 @@ func LoadDefault() {
|
||||
Proxies: map[string]constant.Proxy{},
|
||||
}
|
||||
|
||||
global, _ := adapters.NewSelector("GLOBAL", make([]constant.Proxy, 0))
|
||||
reject := adapters.NewProxy(adapters.NewReject())
|
||||
direct := adapters.NewProxy(adapters.NewDirect())
|
||||
global, _ := adapters.NewSelector("GLOBAL", []constant.Proxy{direct})
|
||||
|
||||
defaultC.Proxies["DIRECT"] = adapters.NewProxy(adapters.NewDirect())
|
||||
defaultC.Proxies["REJECT"] = adapters.NewProxy(adapters.NewReject())
|
||||
defaultC.Proxies["DIRECT"] = direct
|
||||
defaultC.Proxies["REJECT"] = reject
|
||||
defaultC.Proxies["GLOBAL"] = adapters.NewProxy(global)
|
||||
|
||||
executor.ApplyConfig(defaultC, true)
|
||||
@@ -67,7 +69,7 @@ func LoadFromFile(path string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
executor.ApplyConfig(cfg, true)
|
||||
return nil
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
func handleProfileDefault(client *net.UnixConn) {
|
||||
profile.LoadDefault()
|
||||
|
||||
log.Infoln("Profile default loaded")
|
||||
|
||||
client.Close()
|
||||
}
|
||||
|
||||
@@ -46,5 +48,7 @@ func handleProfileReload(client *net.UnixConn) {
|
||||
binary.Write(client, binary.BigEndian, uint32(0))
|
||||
}
|
||||
|
||||
log.Infoln("Profile " + payload.Path + " loaded")
|
||||
|
||||
client.Close()
|
||||
}
|
||||
@@ -8,17 +8,21 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
commandPing = 0
|
||||
commandTunStart = 1
|
||||
commandTunStop = 2
|
||||
commandPing = 0
|
||||
commandTunStart = 1
|
||||
commandTunStop = 2
|
||||
commandProfileDefault = 3
|
||||
commandProfileReload = 4
|
||||
)
|
||||
|
||||
var handlers map[int]func(*net.UnixConn) = make(map[int]func(*net.UnixConn))
|
||||
|
||||
func init() {
|
||||
handlers[commandPing] = handlePing // ping.go
|
||||
handlers[commandTunStart] = handleTunStart // tun.go
|
||||
handlers[commandTunStop] = handleTunStop // tun.go
|
||||
handlers[commandPing] = handlePing // ping.go
|
||||
handlers[commandTunStart] = handleTunStart // tun.go
|
||||
handlers[commandTunStop] = handleTunStop // tun.go
|
||||
handlers[commandProfileDefault] = handleProfileDefault // profile.go
|
||||
handlers[commandProfileReload] = handleProfileReload // profile.go
|
||||
}
|
||||
|
||||
// Start local control server
|
||||
|
||||
@@ -15,9 +15,8 @@ const (
|
||||
|
||||
func handleTunStart(client *net.UnixConn) {
|
||||
buffer := make([]byte, unix.CmsgLen(4*1))
|
||||
data := make([]byte, 8)
|
||||
|
||||
_, noob, _, _, err := client.ReadMsgUnix(data, buffer)
|
||||
_, noob, _, _, err := client.ReadMsgUnix(nil, buffer)
|
||||
if err != nil {
|
||||
log.Warnln("Read tun socket failure, %s", err.Error())
|
||||
return
|
||||
@@ -35,9 +34,13 @@ func handleTunStart(client *net.UnixConn) {
|
||||
return
|
||||
}
|
||||
|
||||
mtu := binary.BigEndian.Uint32(data)
|
||||
var mtu uint32
|
||||
var end uint32
|
||||
|
||||
if binary.BigEndian.Uint32(data[4:]) != tunCommandEnd {
|
||||
binary.Read(client, binary.BigEndian, &mtu)
|
||||
binary.Read(client, binary.BigEndian, &end)
|
||||
|
||||
if end != tunCommandEnd {
|
||||
log.Warnln("Invalid tun command end")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,9 +1,108 @@
|
||||
package com.github.kr328.clash.core
|
||||
|
||||
import android.content.Context
|
||||
import java.io.File
|
||||
import android.net.LocalSocket
|
||||
import android.net.LocalSocketAddress
|
||||
import android.net.Uri
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.util.Log
|
||||
import org.json.JSONObject
|
||||
import java.io.*
|
||||
|
||||
class Clash(context: Context, clashDir: File, controllerPath: File) :
|
||||
class Clash(private val context: Context, clashDir: File, private val controllerPath: File) :
|
||||
ClashProcess(context, clashDir, controllerPath) {
|
||||
companion object {
|
||||
const val COMMAND_PING = 0
|
||||
const val COMMAND_TUN_START = 1
|
||||
const val COMMAND_TUN_STOP = 2
|
||||
const val COMMAND_PROFILE_DEFAULT = 3
|
||||
const val COMMAND_PROFILE_RELOAD = 4
|
||||
|
||||
const val PING_REPLY = 233
|
||||
}
|
||||
|
||||
private val cacheFile = context.cacheDir.resolve("config.yaml")
|
||||
|
||||
fun ping(): Boolean {
|
||||
try {
|
||||
return runControl(COMMAND_PING) {_, input, _ ->
|
||||
input.readInt() == PING_REPLY
|
||||
}
|
||||
}
|
||||
catch (e: IOException) {
|
||||
Log.w(TAG, "Clash ping failure", e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@Synchronized
|
||||
fun loadProfile(url: Uri) {
|
||||
synchronized(cacheFile) {
|
||||
context.contentResolver.openInputStream(url)?.use {
|
||||
it.copyTo(FileOutputStream(cacheFile))
|
||||
}
|
||||
|
||||
runControl(COMMAND_PROFILE_RELOAD) {_, input, output ->
|
||||
output.writeString(JSONObject().apply {
|
||||
put("path", cacheFile.absolutePath)
|
||||
}.toString())
|
||||
|
||||
val result = input.readString()
|
||||
if (result.isNotEmpty()) {
|
||||
throw IOException(JSONObject(result).getString("error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun startTunDevice(fd: FileDescriptor, mtu: Int) {
|
||||
runControl(COMMAND_TUN_START) { socket, _, output ->
|
||||
socket.setFileDescriptorsForSend(arrayOf(fd))
|
||||
socket.outputStream.write(0)
|
||||
socket.outputStream.flush()
|
||||
output.writeInt(mtu)
|
||||
output.writeInt(0x243)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R>runControl(command: Int, block: (LocalSocket, DataInputStream, DataOutputStream) -> R): R {
|
||||
val socket = LocalSocket()
|
||||
|
||||
socket.connect(LocalSocketAddress(controllerPath.absolutePath, LocalSocketAddress.Namespace.FILESYSTEM))
|
||||
|
||||
val input = DataInputStream(socket.inputStream)
|
||||
val output = DataOutputStream(socket.outputStream)
|
||||
|
||||
output.writeInt(command)
|
||||
|
||||
val result = block(socket, input, output)
|
||||
|
||||
try {
|
||||
input.close()
|
||||
output.close()
|
||||
|
||||
socket.close()
|
||||
}
|
||||
catch (ignore: IOException) {
|
||||
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun DataOutputStream.writeString(string: String) {
|
||||
this.writeInt(string.length)
|
||||
this.writeBytes(string)
|
||||
}
|
||||
|
||||
private fun DataInputStream.readString(): String {
|
||||
val len = this.readInt()
|
||||
val buffer = ByteArray(len)
|
||||
|
||||
this.read(buffer)
|
||||
|
||||
return String(buffer)
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import android.util.Log
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
abstract class ClashProcess(context: Context, clashDir: File, private val controllerPath: File) {
|
||||
abstract class ClashProcess(context: Context, clashDir: File, controllerPath: File) {
|
||||
companion object {
|
||||
private const val TAG = "ClashForAndroid"
|
||||
const val TAG = "ClashForAndroid"
|
||||
private const val CLASH_COMMAND = "\"{CLASH}\" \"{CONTROLLER}\" 2>&1"
|
||||
private val PID_PATTERN = Regex("PID=(\\d+)")
|
||||
private const val CONTROLLER_STATUS_PREFIX = "[CONTROLLER]"
|
||||
@@ -57,6 +57,8 @@ abstract class ClashProcess(context: Context, clashDir: File, private val contro
|
||||
|
||||
if ( error != null )
|
||||
throw IOException("Controller: $error")
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user