device.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package aerotun
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "net"
  6. "os"
  7. "os/exec"
  8. "syscall"
  9. "unsafe"
  10. )
  11. type VirtualDevice interface {
  12. Read(buf []byte) (int, error)
  13. Write(buf []byte) (int, error)
  14. Close() error
  15. Name() string
  16. }
  17. // CreateDevice creates either a native Linux TUN device, or falls back to a high-speed
  18. // veth pair with AF_PACKET raw socket if running in an unprivileged container without /dev/net/tun.
  19. func CreateDevice(name string, mtu int, localCIDR string) (VirtualDevice, error) {
  20. if mtu <= 0 {
  21. mtu = DefaultMTU
  22. }
  23. if _, err := os.Stat("/dev/net/tun"); err == nil {
  24. dev, err := createNativeTun(name, mtu, localCIDR)
  25. if err == nil {
  26. return dev, nil
  27. }
  28. }
  29. // Universal container / Proxmox LXC fallback:
  30. return createVethTun(name, mtu, localCIDR)
  31. }
  32. // ---------------------------------------------------------------------------
  33. // 1. Native Linux TUN Implementation (/dev/net/tun)
  34. // ---------------------------------------------------------------------------
  35. type nativeTun struct {
  36. file *os.File
  37. name string
  38. }
  39. func createNativeTun(name string, mtu int, localCIDR string) (*nativeTun, error) {
  40. fd, err := syscall.Open("/dev/net/tun", syscall.O_RDWR, 0)
  41. if err != nil {
  42. return nil, err
  43. }
  44. type ifreq struct {
  45. name [16]byte
  46. flags uint16
  47. _pad [22]byte
  48. }
  49. var ifr ifreq
  50. copy(ifr.name[:], name)
  51. // IFF_TUN = 0x0001, IFF_NO_PI = 0x1000
  52. ifr.flags = 0x0001 | 0x1000
  53. _, _, errno := syscall.Syscall(
  54. syscall.SYS_IOCTL,
  55. uintptr(fd),
  56. uintptr(0x400454ca), // TUNSETIFF
  57. uintptr(unsafe.Pointer(&ifr)),
  58. )
  59. if errno != 0 {
  60. _ = syscall.Close(fd)
  61. return nil, errno
  62. }
  63. // Configure MTU and IP
  64. _ = exec.Command("ip", "link", "set", name, "mtu", fmt.Sprintf("%d", mtu)).Run()
  65. _ = exec.Command("ip", "link", "set", name, "up").Run()
  66. if localCIDR != "" {
  67. _ = exec.Command("ip", "addr", "add", localCIDR, "dev", name).Run()
  68. }
  69. return &nativeTun{
  70. file: os.NewFile(uintptr(fd), name),
  71. name: name,
  72. }, nil
  73. }
  74. func (t *nativeTun) Read(buf []byte) (int, error) {
  75. return t.file.Read(buf)
  76. }
  77. func (t *nativeTun) Write(buf []byte) (int, error) {
  78. return t.file.Write(buf)
  79. }
  80. func (t *nativeTun) Close() error {
  81. err := t.file.Close()
  82. _ = exec.Command("ip", "link", "delete", t.name).Run()
  83. return err
  84. }
  85. func (t *nativeTun) Name() string {
  86. return t.name
  87. }
  88. // ---------------------------------------------------------------------------
  89. // 2. High-Performance Container Fallback (VETH + AF_PACKET)
  90. // ---------------------------------------------------------------------------
  91. type vethTun struct {
  92. name string
  93. epName string
  94. sockFd int
  95. ifIndex int
  96. hwAddr [6]byte
  97. epHwAddr [6]byte
  98. packetBuf [2048]byte
  99. }
  100. func createVethTun(name string, mtu int, localCIDR string) (*vethTun, error) {
  101. epName := fmt.Sprintf("%s_ep", name)
  102. if len(epName) > 15 {
  103. epName = epName[:15]
  104. }
  105. // Clean up any stale interfaces
  106. _ = exec.Command("ip", "link", "delete", name).Run()
  107. _ = exec.Command("ip", "link", "delete", epName).Run()
  108. // 1. Create veth pair
  109. out, err := exec.Command("ip", "link", "add", name, "type", "veth", "peer", "name", epName).CombinedOutput()
  110. if err != nil {
  111. return nil, fmt.Errorf("failed to create veth pair %s: %s: %w", name, string(out), err)
  112. }
  113. // 2. Set Point-to-Point / ARP off behavior
  114. _ = exec.Command("ip", "link", "set", name, "arp", "off").Run()
  115. _ = exec.Command("ip", "link", "set", epName, "arp", "off").Run()
  116. _ = exec.Command("ip", "link", "set", name, "mtu", fmt.Sprintf("%d", mtu)).Run()
  117. _ = exec.Command("ip", "link", "set", epName, "mtu", fmt.Sprintf("%d", mtu)).Run()
  118. _ = exec.Command("ip", "link", "set", name, "up").Run()
  119. _ = exec.Command("ip", "link", "set", epName, "up").Run()
  120. // 3. Assign IP to main device
  121. if localCIDR != "" {
  122. _ = exec.Command("ip", "addr", "add", localCIDR, "dev", name).Run()
  123. }
  124. // 4. Get endpoint interface index
  125. epIface, err := net.InterfaceByName(epName)
  126. if err != nil {
  127. _ = exec.Command("ip", "link", "delete", name).Run()
  128. return nil, fmt.Errorf("failed to lookup %s: %w", epName, err)
  129. }
  130. // 5. Open AF_PACKET raw socket bound to endpoint
  131. // htons(ETH_P_ALL) = 0x0300
  132. const ethPAll = 0x0300
  133. sockFd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(htons(syscall.ETH_P_ALL)))
  134. if err != nil {
  135. _ = exec.Command("ip", "link", "delete", name).Run()
  136. return nil, fmt.Errorf("failed to open raw AF_PACKET socket: %w", err)
  137. }
  138. addr := syscall.SockaddrLinklayer{
  139. Protocol: htons(syscall.ETH_P_ALL),
  140. Ifindex: epIface.Index,
  141. }
  142. if err := syscall.Bind(sockFd, &addr); err != nil {
  143. _ = syscall.Close(sockFd)
  144. _ = exec.Command("ip", "link", "delete", name).Run()
  145. return nil, fmt.Errorf("failed to bind raw socket to %s: %w", epName, err)
  146. }
  147. dev := &vethTun{
  148. name: name,
  149. epName: epName,
  150. sockFd: sockFd,
  151. ifIndex: epIface.Index,
  152. }
  153. if len(epIface.HardwareAddr) >= 6 {
  154. copy(dev.epHwAddr[:], epIface.HardwareAddr[:6])
  155. }
  156. if mainIface, err := net.InterfaceByName(name); err == nil && len(mainIface.HardwareAddr) >= 6 {
  157. copy(dev.hwAddr[:], mainIface.HardwareAddr[:6])
  158. }
  159. return dev, nil
  160. }
  161. func (v *vethTun) Read(buf []byte) (int, error) {
  162. for {
  163. n, _, err := syscall.Recvfrom(v.sockFd, v.packetBuf[:], 0)
  164. if err != nil {
  165. return 0, err
  166. }
  167. if n <= 14 {
  168. continue // Too small for ethernet frame
  169. }
  170. // Ethernet frame header: [Dst MAC (6)][Src MAC (6)][EtherType (2)]
  171. etherType := binary.BigEndian.Uint16(v.packetBuf[12:14])
  172. // Check for IPv4 (0x0800) or IPv6 (0x86DD)
  173. if etherType != 0x0800 && etherType != 0x86DD {
  174. continue // Ignore ARP, STP, etc.
  175. }
  176. ipPayload := v.packetBuf[14:n]
  177. copied := copy(buf, ipPayload)
  178. return copied, nil
  179. }
  180. }
  181. func (v *vethTun) Write(buf []byte) (int, error) {
  182. if len(buf) == 0 {
  183. return 0, nil
  184. }
  185. // Build raw Ethernet frame to inject into endpoint
  186. frameLen := 14 + len(buf)
  187. var frame []byte
  188. if frameLen <= len(v.packetBuf) {
  189. frame = v.packetBuf[:frameLen]
  190. } else {
  191. frame = make([]byte, frameLen)
  192. }
  193. // Dst MAC: main interface, Src MAC: endpoint
  194. copy(frame[0:6], v.hwAddr[:])
  195. copy(frame[6:12], v.epHwAddr[:])
  196. // Detect IP version
  197. var etherType uint16 = 0x0800 // IPv4 default
  198. if (buf[0] >> 4) == 6 {
  199. etherType = 0x86DD // IPv6
  200. }
  201. binary.BigEndian.PutUint16(frame[12:14], etherType)
  202. copy(frame[14:], buf)
  203. addr := syscall.SockaddrLinklayer{
  204. Protocol: htons(etherType),
  205. Ifindex: v.ifIndex,
  206. Halen: 6,
  207. }
  208. copy(addr.Addr[:], v.hwAddr[:])
  209. err := syscall.Sendto(v.sockFd, frame, 0, &addr)
  210. if err != nil {
  211. return 0, err
  212. }
  213. return len(buf), nil
  214. }
  215. func (v *vethTun) Close() error {
  216. _ = syscall.Close(v.sockFd)
  217. _ = exec.Command("ip", "link", "delete", v.name).Run()
  218. return nil
  219. }
  220. func (v *vethTun) Name() string {
  221. return v.name
  222. }
  223. func htons(n uint16) uint16 {
  224. return (n<<8)&0xff00 | (n>>8)&0x00ff
  225. }