eth0net.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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.DebugLevel)
  27. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
  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.DebugLevel)
  38. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
  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.DebugLevel)
  52. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
  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. cmd := exec.Command("sh", "-c", `ps | grep '[u]dhcpc' | awk '{print $1}'`)
  97. output, err := cmd.Output()
  98. if err != nil {
  99. return // 没找到也不是错误
  100. }
  101. pids := strings.FieldsSeq(string(output))
  102. for pidStr := range pids {
  103. pid, err := strconv.Atoi(pidStr)
  104. if err != nil {
  105. continue
  106. }
  107. if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
  108. syscall.Kill(pid, syscall.SIGKILL)
  109. }
  110. }
  111. }
  112. // 运行"udhcpc"后, 获取"eth0"网口分配到的IPv4地址, 并校检其合法性
  113. func getEth0Addr() (ip, mask string, err error) {
  114. iface, err := net.InterfaceByName("eth0")
  115. if err != nil {
  116. return "", "", fmt.Errorf("找不到网络接口\"eth0\": %w", err)
  117. }
  118. addrs, err := iface.Addrs()
  119. if err != nil {
  120. return "", "", fmt.Errorf("获取\"eth0\"的地址失败: %w", err)
  121. }
  122. for _, addr := range addrs {
  123. ipNet, ok := addr.(*net.IPNet)
  124. if !ok {
  125. continue
  126. }
  127. ip4 := ipNet.IP.To4()
  128. if ip4 == nil {
  129. continue
  130. }
  131. return ip4.String(), net.IP(ipNet.Mask).String(), nil
  132. }
  133. return "", "", fmt.Errorf("在\"eth0\"上未找到有效的IPv4 地址")
  134. }
  135. // 定时检测"eth0"网卡上的"udhcpc"后台服务进程, 发现退出时自动拉起
  136. func monitorEth0Udhcpc(exitCh <-chan struct{}) {
  137. t := time.NewTicker(time.Duration(5) * time.Second)
  138. defer t.Stop()
  139. for {
  140. select {
  141. case <-t.C:
  142. bExists, _ := udhcpcEth0Exists()
  143. if !bExists { // 清场一次
  144. killAllUdhcpc()
  145. disable4GInterfaces()
  146. }
  147. if !bExists && dialupEth0() == nil { // 重新进场
  148. ip, mask, _ := getEth0Addr()
  149. baseapp.Logger.Warnf("[%s] \"eth0\"重新分配的地址: %s/%s!", MODULE_NAME, ip, mask)
  150. }
  151. case <-exitCh:
  152. return
  153. } // select end
  154. } // for end
  155. }
  156. func isInterfaceUp(name string) (bool, error) {
  157. link, err := netlink.LinkByName(name)
  158. if err != nil {
  159. return false, err
  160. }
  161. return link.Attrs().Flags&net.FlagUp != 0, nil
  162. }
  163. func waitEth0Carrier(timeoutMs int) (bool, error) {
  164. interval, elapsed := 50, 0
  165. for elapsed < timeoutMs {
  166. data, err := os.ReadFile("/sys/class/net/eth0/carrier")
  167. if err == nil && strings.TrimSpace(string(data)) == "1" {
  168. return true, nil
  169. }
  170. time.Sleep(time.Millisecond * time.Duration(interval))
  171. elapsed += interval
  172. }
  173. return false, fmt.Errorf("eth0 carrier not up after %d ms", timeoutMs)
  174. }
  175. func isEth0CableConnected() (bool, error) {
  176. if up, _ := isInterfaceUp("eth0"); !up {
  177. err := enableEth0()
  178. if err != nil {
  179. return false, err
  180. }
  181. }
  182. return waitEth0Carrier(2000)
  183. }