tunnel.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. package aerotun
  2. import (
  3. "crypto/rand"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "log"
  8. "net"
  9. "net/netip"
  10. "sync"
  11. "sync/atomic"
  12. "time"
  13. "github.com/pierrec/lz4/v4"
  14. )
  15. const peerTimeout = 65 * time.Second
  16. type TunnelRunner struct {
  17. secure *secureProtocol
  18. allowed []netip.Prefix
  19. effectiveMTU atomic.Int64
  20. mu sync.RWMutex
  21. cfg TunnelInstance
  22. dev VirtualDevice
  23. udpConn *net.UDPConn
  24. protocol *protocolState
  25. remoteAddr *net.UDPAddr
  26. stopChan chan struct{}
  27. closed bool
  28. wg sync.WaitGroup
  29. routes routeManager
  30. lastHandshake time.Time
  31. lastError string
  32. rxBytes, txBytes, rawBytesIn, rawBytesOut, wireBytesIn, wireBytesOut uint64
  33. savedBytes, packetsRx, packetsTx, compressedPackets, rawPackets uint64
  34. droppedPackets, authFailures, replayDrops uint64
  35. }
  36. func NewTunnelRunner(cfg TunnelInstance) (*TunnelRunner, error) {
  37. if err := validateConfig(&cfg); err != nil {
  38. return nil, err
  39. }
  40. var remote *net.UDPAddr
  41. var err error
  42. if cfg.RemoteEndpoint != "" {
  43. remote, err = net.ResolveUDPAddr("udp", cfg.RemoteEndpoint)
  44. if err != nil {
  45. return nil, fmt.Errorf("resolve remote endpoint: %w", err)
  46. }
  47. if remote.IP == nil || remote.IP.IsUnspecified() || remote.IP.IsMulticast() {
  48. return nil, fmt.Errorf("remote endpoint must be a unicast IP")
  49. }
  50. }
  51. var p *protocolState
  52. var secure *secureProtocol
  53. if cfg.Protocol == 3 {
  54. secure, err = newSecureProtocol(cfg)
  55. } else {
  56. p, err = newProtocol(cfg.PSK)
  57. }
  58. if err != nil {
  59. return nil, err
  60. }
  61. if remote != nil {
  62. cfg.MTU, err = underlayMTUForHeader(cfg.MTU, remote.IP, packetHeaderSize(cfg.Protocol))
  63. if err != nil {
  64. return nil, err
  65. }
  66. }
  67. if local, _, _ := net.ParseCIDR(cfg.LocalAddress); local.To4() == nil && cfg.MTU < 1280 {
  68. return nil, fmt.Errorf("underlay cannot carry IPv6 tunnel MTU 1280")
  69. }
  70. dev, err := CreateDevice(cfg.Name, cfg.MTU, cfg.LocalAddress)
  71. if err != nil {
  72. return nil, fmt.Errorf("create interface: %w", err)
  73. }
  74. if err = configurePeer(dev, cfg); err != nil {
  75. _ = dev.Close()
  76. return nil, err
  77. }
  78. conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: cfg.ListenPort})
  79. if err != nil {
  80. _ = dev.Close()
  81. return nil, fmt.Errorf("bind UDP: %w", err)
  82. }
  83. bufferSize := 4 << 20
  84. if cfg.Protocol == 3 {
  85. bufferSize = 1 << 20
  86. }
  87. _ = conn.SetReadBuffer(bufferSize)
  88. _ = conn.SetWriteBuffer(bufferSize)
  89. runner := &TunnelRunner{secure: secure, cfg: cfg, dev: dev, udpConn: conn, protocol: p, remoteAddr: remote, stopChan: make(chan struct{}), routes: routeManager{run: runIP}}
  90. for _, p := range cfg.AllowedIPs {
  91. prefix, _ := netip.ParsePrefix(p)
  92. runner.allowed = append(runner.allowed, prefix.Masked())
  93. }
  94. runner.effectiveMTU.Store(int64(cfg.MTU))
  95. return runner, nil
  96. }
  97. func (t *TunnelRunner) Start() error {
  98. if t.cfg.DefaultRoute {
  99. if err := t.routes.install(t.cfg.Name, t.remoteAddr.IP); err != nil {
  100. return err
  101. }
  102. }
  103. t.wg.Add(3)
  104. go func() { defer t.wg.Done(); t.txLoop() }()
  105. go func() { defer t.wg.Done(); t.rxLoop() }()
  106. go func() { defer t.wg.Done(); t.keepaliveLoop() }()
  107. log.Printf("[AeroTUN] %s started: protocol v%d, UDP %s, MTU %d", t.cfg.Name, t.cfg.Protocol, t.udpConn.LocalAddr(), t.cfg.MTU)
  108. return nil
  109. }
  110. func (t *TunnelRunner) Stop() {
  111. t.mu.Lock()
  112. if t.closed {
  113. t.mu.Unlock()
  114. return
  115. }
  116. t.closed = true
  117. close(t.stopChan)
  118. t.mu.Unlock()
  119. _ = t.udpConn.Close()
  120. _ = t.dev.Close()
  121. t.wg.Wait()
  122. t.routes.cleanup()
  123. }
  124. func (t *TunnelRunner) setError(err error) {
  125. t.mu.Lock()
  126. t.lastError = err.Error()
  127. t.mu.Unlock()
  128. }
  129. func (t *TunnelRunner) target() *net.UDPAddr {
  130. t.mu.RLock()
  131. defer t.mu.RUnlock()
  132. return t.remoteAddr
  133. }
  134. func (t *TunnelRunner) send(flags byte, payload []byte, target *net.UDPAddr, session sessionID) error {
  135. if t.secure != nil {
  136. var packet [64]byte
  137. var nonce [24]byte
  138. if target == nil {
  139. return errSession
  140. }
  141. b, err := t.secure.sealInto(packet[:0], &nonce, flags, payload)
  142. if err != nil {
  143. return err
  144. }
  145. n, err := t.udpConn.WriteToUDP(b, target)
  146. if err == nil {
  147. atomic.AddUint64(&t.wireBytesOut, uint64(n))
  148. }
  149. return err
  150. }
  151. if target == nil {
  152. return errSession
  153. }
  154. b, err := t.protocol.seal(flags, payload, session)
  155. if err != nil {
  156. return err
  157. }
  158. n, err := t.udpConn.WriteToUDP(b, target)
  159. if err == nil {
  160. atomic.AddUint64(&t.wireBytesOut, uint64(n))
  161. }
  162. return err
  163. }
  164. func (t *TunnelRunner) sendControl(flags byte, target *net.UDPAddr, session sessionID) error {
  165. payload := make([]byte, 2)
  166. binary.BigEndian.PutUint16(payload, uint16(t.effectiveMTU.Load()))
  167. return t.send(flags, payload, target, session)
  168. }
  169. func (t *TunnelRunner) txLoop() {
  170. if t.secure != nil {
  171. t.txLoopSecure()
  172. return
  173. }
  174. buf := make([]byte, maxPacketSize)
  175. comp := make([]byte, lz4.CompressBlockBound(maxPacketSize))
  176. for {
  177. n, err := t.dev.Read(buf)
  178. if err != nil {
  179. select {
  180. case <-t.stopChan:
  181. return
  182. default:
  183. }
  184. t.setError(fmt.Errorf("interface read: %w", err))
  185. time.Sleep(10 * time.Millisecond)
  186. continue
  187. }
  188. if n == 0 {
  189. continue
  190. }
  191. if n > int(t.effectiveMTU.Load()) || !validIPPacket(buf[:n]) {
  192. atomic.AddUint64(&t.droppedPackets, 1)
  193. t.setError(fmt.Errorf("invalid or oversized interface packet (%d bytes, MTU %d)", n, t.effectiveMTU.Load()))
  194. continue
  195. }
  196. payload := buf[:n]
  197. flags := byte(0)
  198. if t.cfg.Compression && n > 40 {
  199. size, err := lz4.CompressBlock(payload, comp, nil)
  200. if err == nil && size > 0 && size < n-16 {
  201. payload = comp[:size]
  202. flags = FlagCompressedLZ4
  203. }
  204. }
  205. if err := t.send(flags, payload, t.target(), zeroSession); err != nil {
  206. atomic.AddUint64(&t.droppedPackets, 1)
  207. if !errors.Is(err, errSession) {
  208. t.setError(fmt.Errorf("UDP send: %w", err))
  209. }
  210. continue
  211. }
  212. atomic.AddUint64(&t.txBytes, uint64(n))
  213. atomic.AddUint64(&t.rawBytesOut, uint64(n))
  214. atomic.AddUint64(&t.packetsTx, 1)
  215. if flags == FlagCompressedLZ4 {
  216. atomic.AddUint64(&t.compressedPackets, 1)
  217. atomic.AddUint64(&t.savedBytes, uint64(n-len(payload)))
  218. } else {
  219. atomic.AddUint64(&t.rawPackets, 1)
  220. }
  221. }
  222. }
  223. func (t *TunnelRunner) rxLoop() {
  224. if t.secure != nil {
  225. t.rxLoopSecure()
  226. return
  227. }
  228. buf := make([]byte, maxPacketSize)
  229. decomp := make([]byte, maxPacketSize)
  230. for {
  231. n, src, err := t.udpConn.ReadFromUDP(buf)
  232. if err != nil {
  233. select {
  234. case <-t.stopChan:
  235. return
  236. default:
  237. }
  238. t.setError(err)
  239. continue
  240. }
  241. // A client pins its configured endpoint; servers support authenticated roaming.
  242. if t.cfg.Mode == "client" && !udpAddrsEqual(t.target(), src) {
  243. continue
  244. }
  245. payload, flags, sender, _, err := t.protocol.open(buf[:n])
  246. if err != nil {
  247. if errors.Is(err, errReplay) {
  248. atomic.AddUint64(&t.replayDrops, 1)
  249. } else {
  250. atomic.AddUint64(&t.authFailures, 1)
  251. }
  252. continue
  253. }
  254. atomic.AddUint64(&t.wireBytesIn, uint64(n))
  255. if flags == flagHello {
  256. if err := t.sendControl(flagAck, src, sender); err != nil {
  257. t.setError(err)
  258. }
  259. continue
  260. }
  261. // A replayable HELLO must not change MTU or connection state. Only
  262. // packets bound to our current boot/session may change the dataplane.
  263. previousMTU := t.effectiveMTU.Load()
  264. if flags == flagAck || flags == flagConfirm || flags == FlagKeepalive {
  265. if err := t.adjustMTU(src.IP, int(binary.BigEndian.Uint16(payload))); err != nil {
  266. t.setError(err)
  267. continue
  268. }
  269. }
  270. t.mu.Lock()
  271. t.remoteAddr = src
  272. t.lastHandshake = time.Now()
  273. t.mu.Unlock()
  274. if flags == flagAck {
  275. if err := t.sendControl(flagConfirm, src, sender); err != nil {
  276. t.setError(err)
  277. }
  278. continue
  279. }
  280. if flags == FlagKeepalive || flags == flagConfirm {
  281. // Propagate a lower underlay/path MTU immediately, including when
  282. // it was discovered only after receiving the final confirmation.
  283. if t.effectiveMTU.Load() < previousMTU {
  284. if err := t.sendControl(FlagKeepalive, src, sender); err != nil {
  285. t.setError(err)
  286. }
  287. }
  288. continue
  289. }
  290. if flags == FlagCompressedLZ4 {
  291. size, err := lz4.UncompressBlock(payload, decomp[:int(t.effectiveMTU.Load())])
  292. if err != nil || size == 0 {
  293. atomic.AddUint64(&t.droppedPackets, 1)
  294. continue
  295. }
  296. payload = decomp[:size]
  297. }
  298. if len(payload) > int(t.effectiveMTU.Load()) || !validIPPacket(payload) {
  299. atomic.AddUint64(&t.droppedPackets, 1)
  300. continue
  301. }
  302. wrote, err := t.dev.Write(payload)
  303. if err != nil || wrote != len(payload) {
  304. atomic.AddUint64(&t.droppedPackets, 1)
  305. t.setError(fmt.Errorf("interface write: %d/%d bytes, %v", wrote, len(payload), err))
  306. continue
  307. }
  308. atomic.AddUint64(&t.rxBytes, uint64(wrote))
  309. atomic.AddUint64(&t.rawBytesIn, uint64(wrote))
  310. atomic.AddUint64(&t.packetsRx, 1)
  311. }
  312. }
  313. func (t *TunnelRunner) keepaliveLoop() {
  314. if t.secure != nil {
  315. t.keepaliveSecure()
  316. return
  317. }
  318. // Initiate immediately, then retry quickly until the peer is authenticated.
  319. ticker := time.NewTicker(2 * time.Second)
  320. defer ticker.Stop()
  321. lastSent := time.Time{}
  322. for {
  323. target := t.target()
  324. t.mu.RLock()
  325. connected := !t.lastHandshake.IsZero() && time.Since(t.lastHandshake) < peerTimeout
  326. t.mu.RUnlock()
  327. if target != nil && (!connected || time.Since(lastSent) >= 20*time.Second) {
  328. flags := byte(flagHello)
  329. if connected {
  330. flags = FlagKeepalive
  331. }
  332. if err := t.sendControl(flags, target, zeroSession); err != nil {
  333. t.setError(err)
  334. }
  335. lastSent = time.Now()
  336. }
  337. select {
  338. case <-t.stopChan:
  339. return
  340. case <-ticker.C:
  341. }
  342. }
  343. }
  344. func validIPPacket(b []byte) bool {
  345. if len(b) < 20 {
  346. return false
  347. }
  348. if b[0]>>4 == 4 {
  349. ihl := int(b[0]&15) * 4
  350. return ihl >= 20 && len(b) >= ihl && int(b[2])<<8|int(b[3]) == len(b)
  351. }
  352. if b[0]>>4 == 6 {
  353. return len(b) >= 40 && (int(b[4])<<8|int(b[5]))+40 == len(b)
  354. }
  355. return false
  356. }
  357. func (t *TunnelRunner) GetTelemetry() TunnelInstance {
  358. t.mu.RLock()
  359. inst := t.cfg
  360. if _, ok := t.dev.(*nativeTun); ok {
  361. inst.Backend = "tun"
  362. } else {
  363. inst.Backend = "veth"
  364. }
  365. if t.secure != nil {
  366. inst.Handshakes = t.secure.handshakes.Load()
  367. }
  368. inst.MTU = int(t.effectiveMTU.Load())
  369. inst.Running = !t.closed
  370. inst.Connected = inst.Running && !t.lastHandshake.IsZero() && time.Since(t.lastHandshake) < peerTimeout
  371. inst.ActivePeerEndpoint = ""
  372. if inst.Connected && t.remoteAddr != nil {
  373. inst.ActivePeerEndpoint = t.remoteAddr.String()
  374. }
  375. inst.LastHandshake = "Never"
  376. if !t.lastHandshake.IsZero() {
  377. inst.LastHandshake = time.Since(t.lastHandshake).Truncate(time.Second).String() + " ago"
  378. }
  379. if t.secure != nil {
  380. session := t.secure.sessions.Load().current
  381. if session == nil || time.Since(session.born) > secureRejectAfter {
  382. inst.Connected = false
  383. inst.ActivePeerEndpoint = ""
  384. }
  385. }
  386. inst.LastError = t.lastError
  387. t.mu.RUnlock()
  388. inst.RxBytes = atomic.LoadUint64(&t.rxBytes)
  389. inst.TxBytes = atomic.LoadUint64(&t.txBytes)
  390. inst.RawBytesIn = atomic.LoadUint64(&t.rawBytesIn)
  391. inst.RawBytesOut = atomic.LoadUint64(&t.rawBytesOut)
  392. inst.WireBytesIn = atomic.LoadUint64(&t.wireBytesIn)
  393. inst.WireBytesOut = atomic.LoadUint64(&t.wireBytesOut)
  394. inst.SavedBytes = atomic.LoadUint64(&t.savedBytes)
  395. inst.PacketsRx = atomic.LoadUint64(&t.packetsRx)
  396. inst.PacketsTx = atomic.LoadUint64(&t.packetsTx)
  397. inst.CompressedPackets = atomic.LoadUint64(&t.compressedPackets)
  398. inst.RawPackets = atomic.LoadUint64(&t.rawPackets)
  399. inst.DroppedPackets = atomic.LoadUint64(&t.droppedPackets)
  400. inst.AuthFailures = atomic.LoadUint64(&t.authFailures)
  401. inst.ReplayDrops = atomic.LoadUint64(&t.replayDrops)
  402. inst.CompressionRatio = "1.00x (0% saved)"
  403. if inst.RawBytesOut > inst.WireBytesOut && inst.WireBytesOut > 0 {
  404. inst.CompressionRatio = fmt.Sprintf("%.2fx (%.1f%% saved)", float64(inst.RawBytesOut)/float64(inst.WireBytesOut), (1-float64(inst.WireBytesOut)/float64(inst.RawBytesOut))*100)
  405. }
  406. return inst
  407. }
  408. func GenerateSecureKey() (string, error) {
  409. key := make([]byte, 32)
  410. if _, err := rand.Read(key); err != nil {
  411. return "", err
  412. }
  413. return fmt.Sprintf("%x", key), nil
  414. }
  415. func udpAddrsEqual(a, b *net.UDPAddr) bool {
  416. return a != nil && b != nil && a.IP.Equal(b.IP) && a.Port == b.Port && a.Zone == b.Zone
  417. }