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