tunnel.go 13 KB

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