interfaces.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // Package network provides network-related utilities for LocalGo
  2. package network
  3. import (
  4. "errors"
  5. "fmt"
  6. "net"
  7. "strings"
  8. )
  9. // systemInterface is a network interface paired with its IPv4 addresses.
  10. // It exists so interface enumeration can be performed without netlink, which
  11. // the Android/Termux sandbox blocks (net.Interfaces() returns EPERM there).
  12. type systemInterface struct {
  13. net.Interface
  14. addrs []*net.IPNet
  15. }
  16. // systemInterfaces returns all system interfaces with their IPv4 addresses.
  17. // It uses netlink-based enumeration (net.Interfaces); on android it
  18. // transparently falls back to ioctl-based enumeration when netlink is
  19. // unavailable (see platformInterfaceFallback).
  20. func systemInterfaces() ([]systemInterface, error) {
  21. ifs, err := net.Interfaces()
  22. if err != nil {
  23. return platformInterfaceFallback(err)
  24. }
  25. out := make([]systemInterface, 0, len(ifs))
  26. for _, i := range ifs {
  27. addrs, err := i.Addrs()
  28. if err != nil {
  29. continue
  30. }
  31. si := systemInterface{Interface: i}
  32. for _, a := range addrs {
  33. if ipn, ok := a.(*net.IPNet); ok && ipn.IP.To4() != nil {
  34. si.addrs = append(si.addrs, ipn)
  35. }
  36. }
  37. out = append(out, si)
  38. }
  39. return out, nil
  40. }
  41. // systemInterfaceByName returns the interface with the given name, or an error.
  42. func systemInterfaceByName(name string) (*systemInterface, error) {
  43. ifs, err := systemInterfaces()
  44. if err != nil {
  45. return nil, err
  46. }
  47. for i := range ifs {
  48. if ifs[i].Name == name {
  49. return &ifs[i], nil
  50. }
  51. }
  52. return nil, fmt.Errorf("interface %q not found", name)
  53. }
  54. // EnumerateInterfaces returns all system interfaces. Unlike net.Interfaces,
  55. // this works even where netlink is blocked (e.g. Android/Termux).
  56. func EnumerateInterfaces() ([]net.Interface, error) {
  57. ifs, err := systemInterfaces()
  58. if err != nil {
  59. return nil, err
  60. }
  61. out := make([]net.Interface, 0, len(ifs))
  62. for _, i := range ifs {
  63. out = append(out, i.Interface)
  64. }
  65. return out, nil
  66. }
  67. // InterfaceByName returns the named system interface. Unlike net.InterfaceByName,
  68. // this works even where netlink is blocked (e.g. Android/Termux).
  69. func InterfaceByName(name string) (*net.Interface, error) {
  70. si, err := systemInterfaceByName(name)
  71. if err != nil {
  72. return nil, err
  73. }
  74. iface := si.Interface
  75. return &iface, nil
  76. }
  77. // GetLocalIP returns the primary non-loopback IP address of the machine
  78. func GetLocalIP() (string, error) {
  79. ifs, err := systemInterfaces()
  80. if err != nil {
  81. return "", err
  82. }
  83. for _, i := range ifs {
  84. if (i.Flags&net.FlagUp) == 0 || (i.Flags&net.FlagLoopback) != 0 {
  85. continue
  86. }
  87. for _, ipn := range i.addrs {
  88. if !ipn.IP.IsLoopback() {
  89. return ipn.IP.String(), nil
  90. }
  91. }
  92. }
  93. return "", errors.New("no suitable local IP address found")
  94. }
  95. // GetLocalIPAddresses returns a list of local IP addresses for all non-loopback interfaces
  96. func GetLocalIPAddresses() ([]net.IP, error) {
  97. var ips []net.IP
  98. ifs, err := systemInterfaces()
  99. if err != nil {
  100. return nil, err
  101. }
  102. for _, i := range ifs {
  103. // Skip down and loopback interfaces
  104. if (i.Flags&net.FlagUp) == 0 || (i.Flags&net.FlagLoopback) != 0 {
  105. continue
  106. }
  107. for _, ipn := range i.addrs {
  108. ips = append(ips, ipn.IP)
  109. }
  110. }
  111. return ips, nil
  112. }
  113. // GetInterfaceIPs returns all IP addresses for a specific network interface
  114. func GetInterfaceIPs(interfaceName string) ([]string, error) {
  115. iface, err := systemInterfaceByName(interfaceName)
  116. if err != nil {
  117. return nil, err
  118. }
  119. var ips []string
  120. for _, ipn := range iface.addrs {
  121. ips = append(ips, ipn.IP.String())
  122. }
  123. return ips, nil
  124. }
  125. // FormatAddress formats an IP address and port into a URL
  126. func FormatAddress(ip net.IP, port int, https bool) string {
  127. protocol := "http"
  128. if https {
  129. protocol = "https"
  130. }
  131. ipStr := ip.String()
  132. // Check if it's an IPv6 address
  133. if strings.Contains(ipStr, ":") {
  134. return fmt.Sprintf("%s://[%s]:%d", protocol, ipStr, port)
  135. }
  136. return fmt.Sprintf("%s://%s:%d", protocol, ipStr, port)
  137. }
  138. // GetPreferredOutboundIP gets the preferred IP address for outbound connections
  139. func GetPreferredOutboundIP() (net.IP, error) {
  140. // Connect to a public IP (no actual connection is made)
  141. conn, err := net.Dial("udp", "8.8.8.8:80")
  142. if err != nil {
  143. return nil, fmt.Errorf("failed to determine preferred outbound IP: %w", err)
  144. }
  145. defer conn.Close()
  146. // Get the local address
  147. localAddr := conn.LocalAddr().(*net.UDPAddr)
  148. return localAddr.IP, nil
  149. }
  150. // ParseCIDRRange parses a CIDR notation (e.g. "192.168.1.0/24") and returns
  151. // all usable host IPs in that range (network and broadcast addresses excluded).
  152. func ParseCIDRRange(cidr string) ([]net.IP, error) {
  153. _, ipnet, err := net.ParseCIDR(cidr)
  154. if err != nil {
  155. return nil, fmt.Errorf("invalid CIDR %q: %w", cidr, err)
  156. }
  157. ip4 := ipnet.IP.To4()
  158. if ip4 == nil {
  159. return nil, fmt.Errorf("CIDR %q is not an IPv4 range", cidr)
  160. }
  161. ones, bits := ipnet.Mask.Size()
  162. hostBits := bits - ones
  163. if hostBits < 2 || hostBits > 30 {
  164. return nil, fmt.Errorf("CIDR %q prefix length must be /8–/30", cidr)
  165. }
  166. base := uint32(ip4[0])<<24 | uint32(ip4[1])<<16 | uint32(ip4[2])<<8 | uint32(ip4[3])
  167. totalHosts := (1 << hostBits) - 2
  168. var ips []net.IP
  169. for i := 1; i <= totalHosts; i++ {
  170. addr := base + uint32(i)
  171. ips = append(ips, net.IPv4(byte(addr>>24), byte(addr>>16), byte(addr>>8), byte(addr)))
  172. }
  173. return ips, nil
  174. }
  175. // GetSubnetIPs returns all IP addresses in the same /24 subnet as the given IP
  176. func GetSubnetIPs(ip net.IP) []net.IP {
  177. ip4 := ip.To4()
  178. if ip4 == nil {
  179. return nil
  180. }
  181. var ips []net.IP
  182. // Assume /24 subnet for local discovery (most common)
  183. // Iterate 1-254
  184. for i := 1; i <= 254; i++ {
  185. // Create a copy of the base IP
  186. newIP := make(net.IP, len(ip4))
  187. copy(newIP, ip4)
  188. newIP[3] = byte(i)
  189. // Skip if it matches the original IP (optional, but scan logic might want to include self for testing)
  190. // Keeping self allows "finding" the local node which confirms scan is running.
  191. ips = append(ips, newIP)
  192. }
  193. return ips
  194. }
  195. // GetInterfaceIPNet returns the IPv4 network (IP + subnet mask) for the named interface.
  196. // Returns nil if the interface has no IPv4 address.
  197. func GetInterfaceIPNet(ifaceName string) (*net.IPNet, error) {
  198. iface, err := systemInterfaceByName(ifaceName)
  199. if err != nil {
  200. return nil, fmt.Errorf("interface %q: %w", ifaceName, err)
  201. }
  202. if len(iface.addrs) > 0 {
  203. return iface.addrs[0], nil
  204. }
  205. return nil, fmt.Errorf("interface %q has no IPv4 address", ifaceName)
  206. }
  207. // GetUsableSubnetIPsFromIP returns all usable host IPs in the subnet of the
  208. // interface that owns the given IP, respecting its actual netmask. Falls back
  209. // to a flat /24 scan if the interface cannot be determined.
  210. func GetUsableSubnetIPsFromIP(ip net.IP) ([]net.IP, error) {
  211. ipStr := ip.String()
  212. ifs, err := systemInterfaces()
  213. if err != nil {
  214. return GetSubnetIPs(ip), nil
  215. }
  216. for _, i := range ifs {
  217. if (i.Flags&net.FlagUp) == 0 || (i.Flags&net.FlagLoopback) != 0 {
  218. continue
  219. }
  220. for _, ipn := range i.addrs {
  221. if ipn.IP.String() == ipStr {
  222. return GetUsableSubnetIPs(i.Name)
  223. }
  224. }
  225. }
  226. return GetSubnetIPs(ip), nil
  227. }
  228. // GetUsableSubnetIPs returns all usable host IPs in the subnet of the named
  229. // interface, respecting its actual netmask. Subnets with more than 1022 hosts
  230. // (larger than /22) are capped at /22 to keep scanning practical. Network and
  231. // broadcast addresses are excluded.
  232. func GetUsableSubnetIPs(ifaceName string) ([]net.IP, error) {
  233. ipnet, err := GetInterfaceIPNet(ifaceName)
  234. if err != nil {
  235. return nil, err
  236. }
  237. ip4 := ipnet.IP.To4()
  238. if ip4 == nil {
  239. return nil, fmt.Errorf("interface %q has no IPv4 address", ifaceName)
  240. }
  241. ones, bits := ipnet.Mask.Size()
  242. hostBits := bits - ones
  243. // Cap at /22 for practical scanning (max 1022 usable hosts)
  244. effectiveMask := ipnet.Mask
  245. if hostBits > 10 {
  246. effectiveMask = net.CIDRMask(22, bits)
  247. hostBits = bits - 22
  248. }
  249. if hostBits < 2 {
  250. return nil, fmt.Errorf("interface %q subnet prefix /%d is too small for scanning", ifaceName, bits-hostBits)
  251. }
  252. maskBits := []byte{effectiveMask[0], effectiveMask[1], effectiveMask[2], effectiveMask[3]}
  253. base := uint32(ip4[0])<<24 | uint32(ip4[1])<<16 | uint32(ip4[2])<<8 | uint32(ip4[3])
  254. base &= uint32(maskBits[0])<<24 | uint32(maskBits[1])<<16 | uint32(maskBits[2])<<8 | uint32(maskBits[3])
  255. totalHosts := (1 << hostBits) - 2
  256. var ips []net.IP
  257. for i := 1; i <= totalHosts; i++ {
  258. addr := base + uint32(i)
  259. ips = append(ips, net.IPv4(byte(addr>>24), byte(addr>>16), byte(addr>>8), byte(addr)))
  260. }
  261. return ips, nil
  262. }