configreader.go 5.6 KB

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