tunnel.go 14 KB

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