configreader.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. package configreader
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "os"
  7. "os/exec"
  8. "path/filepath"
  9. "strings"
  10. "networktool/internal/model"
  11. "gopkg.in/yaml.v3"
  12. )
  13. type Service struct{}
  14. type configuredInterfaceValues struct {
  15. DHCP4 bool
  16. IP string
  17. Prefix int
  18. Gateway string
  19. DNS []string
  20. }
  21. func New() *Service { return &Service{} }
  22. func (s *Service) Read(interfaceName string) (model.InterfaceConfig, error) {
  23. iface, err := net.InterfaceByName(interfaceName)
  24. if err != nil {
  25. return model.InterfaceConfig{}, err
  26. }
  27. config := model.InterfaceConfig{Interface: interfaceName, DNS: []string{}}
  28. configured := readConfiguredInterfaceValues(interfaceName)
  29. config.Dhcp4 = configured.DHCP4
  30. config.IP = configured.IP
  31. config.Prefix = configured.Prefix
  32. config.Gateway = configured.Gateway
  33. if configured.DNS != nil {
  34. config.DNS = configured.DNS
  35. }
  36. if config.Dhcp4 || config.IP == "" {
  37. ip, prefix := readInterfaceIPv4(iface)
  38. if ip != "" {
  39. config.IP = ip
  40. config.Prefix = prefix
  41. }
  42. }
  43. if config.Dhcp4 || config.Gateway == "" {
  44. config.Gateway = readGateway(interfaceName)
  45. }
  46. if config.Dhcp4 || len(config.DNS) == 0 {
  47. config.DNS = readDNS()
  48. }
  49. return config, nil
  50. }
  51. func readInterfaceIPv4(iface *net.Interface) (string, int) {
  52. addrs, err := iface.Addrs()
  53. if err != nil {
  54. return "", 0
  55. }
  56. for _, addr := range addrs {
  57. ipNet, ok := addr.(*net.IPNet)
  58. if !ok || ipNet.IP.To4() == nil {
  59. continue
  60. }
  61. prefix, _ := ipNet.Mask.Size()
  62. return ipNet.IP.String(), prefix
  63. }
  64. return "", 0
  65. }
  66. func readGateway(interfaceName string) string {
  67. cmd := exec.Command("ip", "route", "show", "dev", interfaceName)
  68. output, err := cmd.Output()
  69. if err != nil {
  70. return ""
  71. }
  72. for _, line := range strings.Split(string(output), "\n") {
  73. line = strings.TrimSpace(line)
  74. if !strings.HasPrefix(line, "default via ") {
  75. continue
  76. }
  77. parts := strings.Fields(line)
  78. if len(parts) >= 3 {
  79. return parts[2]
  80. }
  81. }
  82. return ""
  83. }
  84. func readDNS() []string {
  85. file, err := os.Open("/etc/resolv.conf")
  86. if err != nil {
  87. return []string{}
  88. }
  89. defer file.Close()
  90. result := make([]string, 0, 2)
  91. scanner := bufio.NewScanner(file)
  92. for scanner.Scan() {
  93. line := strings.TrimSpace(scanner.Text())
  94. if !strings.HasPrefix(line, "nameserver ") {
  95. continue
  96. }
  97. parts := strings.Fields(line)
  98. if len(parts) >= 2 {
  99. result = append(result, parts[1])
  100. }
  101. }
  102. return result
  103. }
  104. func readConfiguredInterfaceValues(interfaceName string) configuredInterfaceValues {
  105. files, err := filepath.Glob("/etc/netplan/*.yaml")
  106. if err != nil || len(files) == 0 {
  107. return configuredInterfaceValues{}
  108. }
  109. for _, filePath := range files {
  110. data, err := os.ReadFile(filePath)
  111. if err != nil {
  112. continue
  113. }
  114. var raw map[string]any
  115. if err := yaml.Unmarshal(data, &raw); err != nil {
  116. continue
  117. }
  118. values, ok := findInterfaceValues(raw, interfaceName)
  119. if ok {
  120. return values
  121. }
  122. }
  123. return configuredInterfaceValues{}
  124. }
  125. func findInterfaceValues(raw map[string]any, interfaceName string) (configuredInterfaceValues, bool) {
  126. network, ok := raw["network"].(map[string]any)
  127. if !ok {
  128. return configuredInterfaceValues{}, false
  129. }
  130. ethernets, ok := network["ethernets"].(map[string]any)
  131. if !ok {
  132. return configuredInterfaceValues{}, false
  133. }
  134. entry, ok := ethernets[interfaceName].(map[string]any)
  135. if !ok {
  136. return configuredInterfaceValues{}, false
  137. }
  138. values := configuredInterfaceValues{}
  139. if dhcp4, ok := entry["dhcp4"].(bool); ok {
  140. values.DHCP4 = dhcp4
  141. }
  142. addresses, ok := entry["addresses"].([]any)
  143. if ok {
  144. for _, item := range addresses {
  145. text, ok := item.(string)
  146. if !ok || strings.TrimSpace(text) == "" {
  147. continue
  148. }
  149. ip, ipNet, err := net.ParseCIDR(text)
  150. if err != nil || ip == nil || ip.To4() == nil {
  151. continue
  152. }
  153. prefix, _ := ipNet.Mask.Size()
  154. values.IP = ip.String()
  155. values.Prefix = prefix
  156. break
  157. }
  158. }
  159. if nameservers, ok := entry["nameservers"].(map[string]any); ok {
  160. values.DNS = anyToStringSlice(nameservers["addresses"])
  161. }
  162. if routes, ok := entry["routes"].([]any); ok {
  163. for _, item := range routes {
  164. route, ok := item.(map[string]any)
  165. if !ok {
  166. continue
  167. }
  168. to, _ := route["to"].(string)
  169. via, _ := route["via"].(string)
  170. if strings.TrimSpace(to) == "default" && strings.TrimSpace(via) != "" {
  171. values.Gateway = strings.TrimSpace(via)
  172. break
  173. }
  174. }
  175. }
  176. if values.Gateway == "" {
  177. if gateway4, ok := entry["gateway4"].(string); ok {
  178. values.Gateway = strings.TrimSpace(gateway4)
  179. }
  180. }
  181. return values, values.DHCP4 || values.IP != "" || values.Gateway != "" || len(values.DNS) > 0
  182. }
  183. func anyToStringSlice(value any) []string {
  184. switch typed := value.(type) {
  185. case []string:
  186. return append([]string(nil), typed...)
  187. case []any:
  188. result := make([]string, 0, len(typed))
  189. for _, item := range typed {
  190. text, ok := item.(string)
  191. if ok && strings.TrimSpace(text) != "" {
  192. result = append(result, text)
  193. }
  194. }
  195. return result
  196. default:
  197. return []string{}
  198. }
  199. }
  200. func MustRead(interfaceName string) model.InterfaceConfig {
  201. config, err := New().Read(interfaceName)
  202. if err != nil {
  203. panic(fmt.Sprintf("read interface config failed: %v", err))
  204. }
  205. return config
  206. }