Files
MWClash/core/tun.go

162 lines
2.4 KiB
Go
Raw Normal View History

2024-04-30 23:38:49 +08:00
//go:build android
package main
import "C"
import (
"core/platform"
2024-04-30 23:38:49 +08:00
t "core/tun"
"errors"
2024-04-30 23:38:49 +08:00
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/log"
"golang.org/x/sync/semaphore"
2024-07-13 16:36:08 +08:00
"strconv"
2024-04-30 23:38:49 +08:00
"sync"
"sync/atomic"
2024-04-30 23:38:49 +08:00
"syscall"
"time"
)
var tunLock sync.Mutex
var tun *t.Tun
2024-07-13 16:36:08 +08:00
var runTime *time.Time
2024-04-30 23:38:49 +08:00
type FdMap struct {
m sync.Map
}
func (cm *FdMap) Store(key int64) {
2024-07-01 20:57:24 +08:00
cm.m.Store(key, struct{}{})
}
func (cm *FdMap) Load(key int64) bool {
_, ok := cm.m.Load(key)
2024-07-01 20:57:24 +08:00
return ok
}
var fdMap FdMap
2024-04-30 23:38:49 +08:00
//export startTUN
2024-07-13 16:36:08 +08:00
func startTUN(fd C.int, port C.longlong) {
i := int64(port)
ServicePort = i
2024-06-06 22:04:29 +08:00
go func() {
2024-06-16 19:04:33 +08:00
tunLock.Lock()
2024-06-06 22:04:29 +08:00
defer tunLock.Unlock()
2024-04-30 23:38:49 +08:00
2024-06-06 22:04:29 +08:00
if tun != nil {
tun.Close()
tun = nil
}
2024-07-13 16:36:08 +08:00
2024-06-06 22:04:29 +08:00
f := int(fd)
gateway := "172.16.0.1/30"
portal := "172.16.0.2"
dns := "0.0.0.0"
2024-04-30 23:38:49 +08:00
2024-06-06 22:04:29 +08:00
tempTun := &t.Tun{Closed: false, Limit: semaphore.NewWeighted(4)}
2024-04-30 23:38:49 +08:00
2024-06-06 22:04:29 +08:00
closer, err := t.Start(f, gateway, portal, dns)
2024-04-30 23:38:49 +08:00
2024-06-06 22:04:29 +08:00
if err != nil {
log.Errorln("startTUN error: %v", err)
tempTun.Close()
}
2024-04-30 23:38:49 +08:00
2024-06-06 22:04:29 +08:00
tempTun.Closer = closer
2024-04-30 23:38:49 +08:00
2024-06-06 22:04:29 +08:00
tun = tempTun
2024-07-13 16:36:08 +08:00
now := time.Now()
runTime = &now
SendMessage(Message{
Type: StartedMessage,
Data: strconv.FormatInt(runTime.UnixMilli(), 10),
})
2024-06-06 22:04:29 +08:00
}()
2024-04-30 23:38:49 +08:00
}
2024-07-13 16:36:08 +08:00
//export getRunTime
func getRunTime() *C.char {
if runTime == nil {
return C.CString("")
}
return C.CString(strconv.FormatInt(runTime.UnixMilli(), 10))
}
2024-04-30 23:38:49 +08:00
//export stopTun
func stopTun() {
2024-06-06 22:04:29 +08:00
go func() {
2024-06-16 19:04:33 +08:00
tunLock.Lock()
2024-06-06 22:04:29 +08:00
defer tunLock.Unlock()
2024-07-13 16:36:08 +08:00
runTime = nil
2024-06-06 22:04:29 +08:00
if tun != nil {
tun.Close()
tun = nil
}
}()
2024-04-30 23:38:49 +08:00
}
var errBlocked = errors.New("blocked")
//export setFdMap
func setFdMap(fd C.long) {
fdInt := int64(fd)
go func() {
fdMap.Store(fdInt)
}()
}
2024-07-13 16:36:08 +08:00
type Fd struct {
Id int64 `json:"id"`
Value int64 `json:"value"`
}
func markSocket(fd Fd) {
SendMessage(Message{
Type: ProtectMessage,
Data: fd,
})
}
var fdCounter int64 = 0
2024-04-30 23:38:49 +08:00
func init() {
dialer.DefaultSocketHook = func(network, address string, conn syscall.RawConn) error {
if platform.ShouldBlockConnection() {
return errBlocked
}
2024-04-30 23:38:49 +08:00
return conn.Control(func(fd uintptr) {
if tun == nil {
return
}
fdInt := int64(fd)
timeout := time.After(100 * time.Millisecond)
id := atomic.AddInt64(&fdCounter, 1)
2024-07-13 16:36:08 +08:00
markSocket(Fd{
Id: id,
Value: fdInt,
})
for {
select {
case <-timeout:
return
default:
exists := fdMap.Load(id)
if exists {
return
}
time.Sleep(10 * time.Millisecond)
}
}
2024-04-30 23:38:49 +08:00
})
}
}