tun.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. //go:build android
  2. package main
  3. import "C"
  4. import (
  5. "core/platform"
  6. t "core/tun"
  7. "errors"
  8. "strconv"
  9. "sync"
  10. "sync/atomic"
  11. "syscall"
  12. "time"
  13. "github.com/metacubex/mihomo/component/dialer"
  14. "github.com/metacubex/mihomo/log"
  15. "golang.org/x/sync/semaphore"
  16. )
  17. var tunLock sync.Mutex
  18. var tun *t.Tun
  19. var runTime *time.Time
  20. type FdMap struct {
  21. m sync.Map
  22. }
  23. func (cm *FdMap) Store(key int64) {
  24. cm.m.Store(key, struct{}{})
  25. }
  26. func (cm *FdMap) Load(key int64) bool {
  27. _, ok := cm.m.Load(key)
  28. return ok
  29. }
  30. var fdMap FdMap
  31. //export startTUN
  32. func startTUN(fd C.int, port C.longlong) {
  33. i := int64(port)
  34. ServicePort = i
  35. if fd == 0 {
  36. tunLock.Lock()
  37. defer tunLock.Unlock()
  38. now := time.Now()
  39. runTime = &now
  40. SendMessage(Message{
  41. Type: StartedMessage,
  42. Data: strconv.FormatInt(runTime.UnixMilli(), 10),
  43. })
  44. return
  45. }
  46. initSocketHook()
  47. go func() {
  48. tunLock.Lock()
  49. defer tunLock.Unlock()
  50. if tun != nil {
  51. tun.Close()
  52. tun = nil
  53. }
  54. f := int(fd)
  55. gateway := "172.16.0.1/30"
  56. portal := "172.16.0.2"
  57. dns := "0.0.0.0"
  58. tempTun := &t.Tun{Closed: false, Limit: semaphore.NewWeighted(4)}
  59. closer, err := t.Start(f, gateway, portal, dns)
  60. if err != nil {
  61. log.Errorln("startTUN error: %v", err)
  62. tempTun.Close()
  63. }
  64. tempTun.Closer = closer
  65. tun = tempTun
  66. now := time.Now()
  67. runTime = &now
  68. SendMessage(Message{
  69. Type: StartedMessage,
  70. Data: strconv.FormatInt(runTime.UnixMilli(), 10),
  71. })
  72. }()
  73. }
  74. //export getRunTime
  75. func getRunTime() *C.char {
  76. if runTime == nil {
  77. return C.CString("")
  78. }
  79. return C.CString(strconv.FormatInt(runTime.UnixMilli(), 10))
  80. }
  81. //export stopTun
  82. func stopTun() {
  83. removeSocketHook()
  84. go func() {
  85. tunLock.Lock()
  86. defer tunLock.Unlock()
  87. runTime = nil
  88. if tun != nil {
  89. tun.Close()
  90. tun = nil
  91. }
  92. }()
  93. }
  94. var errBlocked = errors.New("blocked")
  95. //export setFdMap
  96. func setFdMap(fd C.long) {
  97. fdInt := int64(fd)
  98. go func() {
  99. fdMap.Store(fdInt)
  100. }()
  101. }
  102. type Fd struct {
  103. Id int64 `json:"id"`
  104. Value int64 `json:"value"`
  105. }
  106. func markSocket(fd Fd) {
  107. SendMessage(Message{
  108. Type: ProtectMessage,
  109. Data: fd,
  110. })
  111. }
  112. var fdCounter int64 = 0
  113. func initSocketHook() {
  114. dialer.DefaultSocketHook = func(network, address string, conn syscall.RawConn) error {
  115. if platform.ShouldBlockConnection() {
  116. return errBlocked
  117. }
  118. return conn.Control(func(fd uintptr) {
  119. if tun == nil {
  120. return
  121. }
  122. fdInt := int64(fd)
  123. timeout := time.After(100 * time.Millisecond)
  124. id := atomic.AddInt64(&fdCounter, 1)
  125. markSocket(Fd{
  126. Id: id,
  127. Value: fdInt,
  128. })
  129. for {
  130. select {
  131. case <-timeout:
  132. return
  133. default:
  134. exists := fdMap.Load(id)
  135. if exists {
  136. return
  137. }
  138. time.Sleep(10 * time.Millisecond)
  139. }
  140. }
  141. })
  142. }
  143. }
  144. func removeSocketHook() {
  145. dialer.DefaultSocketHook = nil
  146. }