eth0net.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. package netmgrd
  2. import (
  3. "fmt"
  4. "net"
  5. "os"
  6. "os/exec"
  7. "strconv"
  8. "strings"
  9. "syscall"
  10. "time"
  11. "github.com/sirupsen/logrus"
  12. "github.com/vishvananda/netlink"
  13. "hnyfkj.com.cn/rtu/linux/baseapp"
  14. )
  15. // 禁用所有4G网卡, 使其不可用
  16. func disable4GInterfaces() error {
  17. ifaces, err := net.Interfaces()
  18. if err != nil {
  19. return fmt.Errorf("获取网络接口列表失败: %w", err)
  20. }
  21. for _, iface := range ifaces {
  22. if iface.Name != "eth2" && iface.Name != "usb0" {
  23. continue
  24. }
  25. cmd := exec.Command("ip", "link", "set", "dev", iface.Name, "down")
  26. cmd.Stdout = baseapp.Logger.WriterLevel(logrus.InfoLevel)
  27. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.WarnLevel)
  28. if err := cmd.Run(); err != nil {
  29. return fmt.Errorf("关闭网口\"%s\"失败: %w", iface.Name, err)
  30. }
  31. }
  32. return nil
  33. }
  34. // 启动"eth0"网口, 使其变可用
  35. func enableEth0() error {
  36. cmd := exec.Command("ip", "link", "set", "dev", "eth0", "up")
  37. cmd.Stdout = baseapp.Logger.WriterLevel(logrus.InfoLevel)
  38. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.WarnLevel)
  39. if err := cmd.Run(); err != nil {
  40. return fmt.Errorf("启动网口\"eth0\"失败: %w", err)
  41. }
  42. return nil
  43. }
  44. // 启动DHCP客户端, 请求IP地址
  45. func dialupEth0() error {
  46. if err := enableEth0(); err != nil {
  47. return err
  48. }
  49. eth0pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
  50. cmd := exec.Command("udhcpc", "-b", "-i", "eth0", "-p", eth0pid)
  51. cmd.Stdout = baseapp.Logger.WriterLevel(logrus.InfoLevel)
  52. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.WarnLevel)
  53. if err := cmd.Run(); err != nil {
  54. return fmt.Errorf("\"eth0\"请求地址失败: %w", err)
  55. }
  56. return nil
  57. }
  58. // 检测"eth0"网口上的"udhcpc"后台进程是否正在运行, 只保持一个实例
  59. func udhcpcEth0Exists() (bool, error) {
  60. eth0pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
  61. data, err := os.ReadFile(eth0pid)
  62. if err != nil {
  63. return false, err
  64. }
  65. pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
  66. if err != nil {
  67. return false, err
  68. }
  69. err = syscall.Kill(pid, 0)
  70. if err == nil { // 存在
  71. return true, nil
  72. }
  73. if err == syscall.ESRCH { // 不存在
  74. return false, nil
  75. }
  76. return false, err
  77. }
  78. // 杀死"eth0"网口上的"udhcpc"进程(根据上次运行时它的PID-文件记录)
  79. func killEth0Udhcpc() error {
  80. eth0pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
  81. data, err := os.ReadFile(eth0pid)
  82. if err != nil {
  83. return err
  84. }
  85. pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
  86. if err != nil {
  87. return err
  88. }
  89. if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
  90. syscall.Kill(pid, syscall.SIGKILL)
  91. }
  92. return nil
  93. }
  94. // 强制杀死所有运行中的"udhcpc"进程,包括驻留在后台运行的(SIGKILL)
  95. func killAllUdhcpc() {
  96. entries, err := os.ReadDir("/proc")
  97. if err != nil {
  98. return
  99. }
  100. for _, entry := range entries {
  101. name := entry.Name()
  102. pid, err := strconv.Atoi(name)
  103. if err != nil {
  104. continue
  105. }
  106. comm, err := os.ReadFile("/proc/" + name + "/comm")
  107. if err != nil {
  108. continue
  109. }
  110. if strings.TrimSpace(string(comm)) == "udhcpc" {
  111. _ = syscall.Kill(pid, syscall.SIGKILL)
  112. } // if end
  113. } /// for end
  114. }
  115. // 运行"udhcpc"后, 获取"eth0"网口分配到的IPv4地址, 并校检其合法性
  116. func getEth0Addr() (ip, mask string, err error) {
  117. iface, err := net.InterfaceByName("eth0")
  118. if err != nil {
  119. return "", "", fmt.Errorf("找不到网络接口\"eth0\": %w", err)
  120. }
  121. addrs, err := iface.Addrs()
  122. if err != nil {
  123. return "", "", fmt.Errorf("获取\"eth0\"的地址失败: %w", err)
  124. }
  125. for _, addr := range addrs {
  126. ipNet, ok := addr.(*net.IPNet)
  127. if !ok {
  128. continue
  129. }
  130. ip4 := ipNet.IP.To4()
  131. if ip4 == nil {
  132. continue
  133. }
  134. return ip4.String(), net.IP(ipNet.Mask).String(), nil
  135. }
  136. return "", "", fmt.Errorf("在\"eth0\"上未找到有效的IPv4 地址")
  137. }
  138. // 定时检测"eth0"网卡上的"udhcpc"后台服务进程, 发现退出时自动拉起
  139. func monitorEth0Udhcpc(exitCh <-chan struct{}) {
  140. t := time.NewTicker(time.Duration(5) * time.Second)
  141. defer t.Stop()
  142. for {
  143. select {
  144. case <-t.C:
  145. bExists, _ := udhcpcEth0Exists()
  146. if !bExists { // 清场一次
  147. killAllUdhcpc()
  148. disable4GInterfaces()
  149. }
  150. if !bExists && dialupEth0() == nil { // 重新进场
  151. ip, mask, _ := getEth0Addr()
  152. baseapp.Logger.Warnf("[%s] \"eth0\"重新分配的地址: %s/%s!", MODULE_NAME, ip, mask)
  153. }
  154. case <-exitCh:
  155. return
  156. } // select end
  157. } // for end
  158. }
  159. func isInterfaceUp(name string) (bool, error) {
  160. link, err := netlink.LinkByName(name)
  161. if err != nil {
  162. return false, err
  163. }
  164. return link.Attrs().Flags&net.FlagUp != 0, nil
  165. }
  166. func waitEth0Carrier(timeoutMs int) (bool, error) {
  167. interval, elapsed := 50, 0
  168. for elapsed < timeoutMs {
  169. data, err := os.ReadFile("/sys/class/net/eth0/carrier")
  170. if err == nil && strings.TrimSpace(string(data)) == "1" {
  171. return true, nil
  172. }
  173. time.Sleep(time.Millisecond * time.Duration(interval))
  174. elapsed += interval
  175. }
  176. return false, fmt.Errorf("eth0 carrier not up after %d ms", timeoutMs)
  177. }
  178. func isEth0CableConnected() (bool, error) {
  179. if up, _ := isInterfaceUp("eth0"); !up {
  180. err := enableEth0()
  181. if err != nil {
  182. return false, err
  183. }
  184. }
  185. return waitEth0Carrier(2000)
  186. }
  187. func SetupEth0ForManagement(cidr string) error {
  188. link, err := netlink.LinkByName("eth0")
  189. if err != nil {
  190. return err
  191. }
  192. if err = netlink.LinkSetUp(link); err != nil {
  193. return err
  194. }
  195. addr, err := netlink.ParseAddr(cidr)
  196. if err != nil {
  197. return err
  198. }
  199. if err = netlink.AddrAdd(link, addr); err != nil && err != syscall.EEXIST {
  200. return err
  201. }
  202. return nil
  203. }