tunnel.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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) target() *net.UDPAddr {
  146. t.mu.RLock()
  147. defer t.mu.RUnlock()
  148. return t.remoteAddr
  149. }
  150. func (t *TunnelRunner) send(flags byte, payload []byte, target *net.UDPAddr, session sessionID) error {
  151. if t.secure != nil {
  152. var packet [64]byte
  153. var nonce [24]byte
  154. if target == nil {
  155. return errSession
  156. }
  157. b, err := t.secure.sealInto(packet[:0], &nonce, flags, payload)
  158. if err != nil {
  159. return err
  160. }
  161. n, err := t.udpConn.WriteToUDP(b, target)
  162. if err == nil {
  163. atomic.AddUint64(&t.wireBytesOut, uint64(n))
  164. }
  165. return err
  166. }
  167. if target == nil {
  168. return errSession
  169. }
  170. b, err := t.protocol.seal(flags, payload, session)
  171. if err != nil {
  172. return err
  173. }
  174. n, err := t.udpConn.WriteToUDP(b, target)
  175. if err == nil {
  176. atomic.AddUint64(&t.wireBytesOut, uint64(n))
  177. }
  178. return err
  179. }
  180. func (t *TunnelRunner) sendControl(flags byte, target *net.UDPAddr, session sessionID) error {
  181. payload := make([]byte, 2)
  182. binary.BigEndian.PutUint16(payload, uint16(t.effectiveMTU.Load()))
  183. return t.send(flags, payload, target, session)
  184. }
  185. func (t *TunnelRunner) txLoop() {
  186. if t.secure != nil {
  187. t.txLoopSecure()
  188. return
  189. }
  190. buf := make([]byte, maxPacketSize)
  191. var comp *adaptiveCompressor
  192. if t.cfg.Compression {
  193. comp = newAdaptiveCompressor(maxPacketSize)
  194. }
  195. for {
  196. n, err := t.dev.Read(buf)
  197. if err != nil {
  198. select {
  199. case <-t.stopChan:
  200. return
  201. default:
  202. }
  203. t.setError(fmt.Errorf("interface read: %w", err))
  204. time.Sleep(10 * time.Millisecond)
  205. continue
  206. }
  207. if n == 0 {
  208. continue
  209. }
  210. if n > int(t.effectiveMTU.Load()) || !validIPPacket(buf[:n]) {
  211. atomic.AddUint64(&t.droppedPackets, 1)
  212. t.setError(fmt.Errorf("invalid or oversized interface packet (%d bytes, MTU %d)", n, t.effectiveMTU.Load()))
  213. continue
  214. }
  215. payload := buf[:n]
  216. flags := byte(0)
  217. if comp != nil {
  218. if compressed, ok := comp.Compress(payload); ok {
  219. payload = compressed
  220. flags = FlagCompressedLZ4
  221. }
  222. }
  223. if err := t.send(flags, payload, t.target(), zeroSession); err != nil {
  224. atomic.AddUint64(&t.droppedPackets, 1)
  225. if !errors.Is(err, errSession) {
  226. t.setError(fmt.Errorf("UDP send: %w", err))
  227. }
  228. continue
  229. }
  230. atomic.AddUint64(&t.txBytes, uint64(n))
  231. atomic.AddUint64(&t.rawBytesOut, uint64(n))
  232. atomic.AddUint64(&t.packetsTx, 1)
  233. if flags == FlagCompressedLZ4 {
  234. atomic.AddUint64(&t.compressedPackets, 1)
  235. atomic.AddUint64(&t.savedBytes, uint64(n-len(payload)))
  236. } else {
  237. atomic.AddUint64(&t.rawPackets, 1)
  238. }
  239. }
  240. }
  241. func (t *TunnelRunner) rxLoop() {
  242. if t.secure != nil {
  243. t.rxLoopSecure()
  244. return
  245. }
  246. buf := make([]byte, maxPacketSize)
  247. decomp := make([]byte, maxPacketSize)
  248. for {
  249. n, src, err := t.udpConn.ReadFromUDP(buf)
  250. if err != nil {
  251. select {
  252. case <-t.stopChan:
  253. return
  254. default:
  255. }
  256. t.setError(err)
  257. continue
  258. }
  259. // A client pins its configured endpoint; servers support authenticated roaming.
  260. if t.cfg.Mode == "client" && !udpAddrsEqual(t.target(), src) {
  261. continue
  262. }
  263. payload, flags, sender, _, err := t.protocol.open(buf[:n])
  264. if err != nil {
  265. if errors.Is(err, errReplay) {
  266. atomic.AddUint64(&t.replayDrops, 1)
  267. } else {
  268. atomic.AddUint64(&t.authFailures, 1)
  269. }
  270. continue
  271. }
  272. atomic.AddUint64(&t.wireBytesIn, uint64(n))
  273. if flags == flagHello {
  274. if err := t.sendControl(flagAck, src, sender); err != nil {
  275. t.setError(err)
  276. }
  277. continue
  278. }
  279. // A replayable HELLO must not change MTU or connection state. Only
  280. // packets bound to our current boot/session may change the dataplane.
  281. previousMTU := t.effectiveMTU.Load()
  282. if flags == flagAck || flags == flagConfirm || flags == FlagKeepalive {
  283. if err := t.adjustMTU(src.IP, int(binary.BigEndian.Uint16(payload))); err != nil {
  284. t.setError(err)
  285. continue
  286. }
  287. }
  288. t.mu.Lock()
  289. t.remoteAddr = src
  290. t.lastHandshake = time.Now()
  291. t.mu.Unlock()
  292. if flags == flagAck {
  293. if err := t.sendControl(flagConfirm, src, sender); err != nil {
  294. t.setError(err)
  295. }
  296. continue
  297. }
  298. if flags == FlagKeepalive || flags == flagConfirm {
  299. // Propagate a lower underlay/path MTU immediately, including when
  300. // it was discovered only after receiving the final confirmation.
  301. if t.effectiveMTU.Load() < previousMTU {
  302. if err := t.sendControl(FlagKeepalive, src, sender); err != nil {
  303. t.setError(err)
  304. }
  305. }
  306. continue
  307. }
  308. if flags == FlagCompressedLZ4 {
  309. size, err := lz4.UncompressBlock(payload, decomp[:int(t.effectiveMTU.Load())])
  310. if err != nil || size == 0 {
  311. atomic.AddUint64(&t.droppedPackets, 1)
  312. continue
  313. }
  314. payload = decomp[:size]
  315. }
  316. if len(payload) > int(t.effectiveMTU.Load()) || !validIPPacket(payload) {
  317. atomic.AddUint64(&t.droppedPackets, 1)
  318. continue
  319. }
  320. wrote, err := t.dev.Write(payload)
  321. if err != nil || wrote != len(payload) {
  322. atomic.AddUint64(&t.droppedPackets, 1)
  323. t.setError(fmt.Errorf("interface write: %d/%d bytes, %v", wrote, len(payload), err))
  324. continue
  325. }
  326. atomic.AddUint64(&t.rxBytes, uint64(wrote))
  327. atomic.AddUint64(&t.rawBytesIn, uint64(wrote))
  328. atomic.AddUint64(&t.packetsRx, 1)
  329. }
  330. }
  331. func (t *TunnelRunner) keepaliveLoop() {
  332. if t.secure != nil {
  333. t.keepaliveSecure()
  334. return
  335. }
  336. // Initiate immediately, then retry quickly until the peer is authenticated.
  337. ticker := time.NewTicker(2 * time.Second)
  338. defer ticker.Stop()
  339. lastSent := time.Time{}
  340. for {
  341. target := t.target()
  342. t.mu.RLock()
  343. connected := !t.lastHandshake.IsZero() && time.Since(t.lastHandshake) < peerTimeout
  344. t.mu.RUnlock()
  345. if target != nil && (!connected || time.Since(lastSent) >= 20*time.Second) {
  346. flags := byte(flagHello)
  347. if connected {
  348. flags = FlagKeepalive
  349. }
  350. if err := t.sendControl(flags, target, zeroSession); err != nil {
  351. t.setError(err)
  352. }
  353. lastSent = time.Now()
  354. }
  355. select {
  356. case <-t.stopChan:
  357. return
  358. case <-ticker.C:
  359. }
  360. }
  361. }
  362. func validIPPacket(b []byte) bool {
  363. if len(b) < 20 {
  364. return false
  365. }
  366. if b[0]>>4 == 4 {
  367. ihl := int(b[0]&15) * 4
  368. return ihl >= 20 && len(b) >= ihl && int(b[2])<<8|int(b[3]) == len(b)
  369. }
  370. if b[0]>>4 == 6 {
  371. return len(b) >= 40 && (int(b[4])<<8|int(b[5]))+40 == len(b)
  372. }
  373. return false
  374. }
  375. func (t *TunnelRunner) GetTelemetry() TunnelInstance {
  376. t.mu.RLock()
  377. inst := t.cfg
  378. if _, ok := t.dev.(*nativeTun); ok {
  379. inst.Backend = "tun"
  380. } else {
  381. inst.Backend = "veth"
  382. }
  383. if t.secure != nil {
  384. inst.Handshakes = t.secure.handshakes.Load()
  385. }
  386. inst.MTU = int(t.effectiveMTU.Load())
  387. inst.ConfiguredMTU = t.configuredMTU
  388. inst.Running = !t.closed
  389. inst.Connected = inst.Running && !t.lastHandshake.IsZero() && time.Since(t.lastHandshake) < peerTimeout
  390. inst.ActivePeerEndpoint = ""
  391. if inst.Connected && t.remoteAddr != nil {
  392. inst.ActivePeerEndpoint = t.remoteAddr.String()
  393. }
  394. inst.LastHandshake = "Never"
  395. if !t.lastHandshake.IsZero() {
  396. inst.LastHandshake = time.Since(t.lastHandshake).Truncate(time.Second).String() + " ago"
  397. }
  398. if t.secure != nil {
  399. session := t.secure.sessions.Load().current
  400. if session == nil || time.Since(session.born) > secureRejectAfter {
  401. inst.Connected = false
  402. inst.ActivePeerEndpoint = ""
  403. }
  404. }
  405. inst.LastError = t.lastError
  406. t.mu.RUnlock()
  407. inst.RxBytes = atomic.LoadUint64(&t.rxBytes)
  408. inst.TxBytes = atomic.LoadUint64(&t.txBytes)
  409. inst.RawBytesIn = atomic.LoadUint64(&t.rawBytesIn)
  410. inst.RawBytesOut = atomic.LoadUint64(&t.rawBytesOut)
  411. inst.WireBytesIn = atomic.LoadUint64(&t.wireBytesIn)
  412. inst.WireBytesOut = atomic.LoadUint64(&t.wireBytesOut)
  413. inst.SavedBytes = atomic.LoadUint64(&t.savedBytes)
  414. inst.PacketsRx = atomic.LoadUint64(&t.packetsRx)
  415. inst.PacketsTx = atomic.LoadUint64(&t.packetsTx)
  416. inst.CompressedPackets = atomic.LoadUint64(&t.compressedPackets)
  417. inst.RawPackets = atomic.LoadUint64(&t.rawPackets)
  418. inst.DroppedPackets = atomic.LoadUint64(&t.droppedPackets)
  419. inst.AuthFailures = atomic.LoadUint64(&t.authFailures)
  420. inst.ReplayDrops = atomic.LoadUint64(&t.replayDrops)
  421. if t.secure != nil {
  422. 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)}
  423. }
  424. inst.CompressionRatio = "1.00x (0% saved)"
  425. if inst.RawBytesOut > inst.WireBytesOut && inst.WireBytesOut > 0 {
  426. inst.CompressionRatio = fmt.Sprintf("%.2fx (%.1f%% saved)", float64(inst.RawBytesOut)/float64(inst.WireBytesOut), (1-float64(inst.WireBytesOut)/float64(inst.RawBytesOut))*100)
  427. }
  428. return inst
  429. }
  430. func GenerateSecureKey() (string, error) {
  431. key := make([]byte, 32)
  432. if _, err := rand.Read(key); err != nil {
  433. return "", err
  434. }
  435. return fmt.Sprintf("%x", key), nil
  436. }
  437. func udpAddrsEqual(a, b *net.UDPAddr) bool {
  438. return a != nil && b != nil && a.IP.Equal(b.IP) && a.Port == b.Port && a.Zone == b.Zone
  439. }