eth0net.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. // 只保留需要使用的"eth0"网卡
  16. func disableEthBut0() error {
  17. ifaces, err := net.Interfaces()
  18. if err != nil {
  19. return fmt.Errorf("获取网络接口列表失败: %w", err)
  20. }
  21. for _, iface := range ifaces {
  22. if !strings.HasPrefix(iface.Name, "eth") || iface.Name == "eth0" {
  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. // 启动DHCP客户端, 请求IP地址
  35. func dialupEth0() error {
  36. cmd1 := exec.Command("ip", "link", "set", "dev", "eth0", "up")
  37. cmd1.Stdout = baseapp.Logger.WriterLevel(logrus.DebugLevel)
  38. cmd1.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
  39. if err := cmd1.Run(); err != nil {
  40. return fmt.Errorf("启动网口\"eth0\"失败: %w", err)
  41. }
  42. eth2pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
  43. cmd2 := exec.Command("udhcpc", "-b", "-i", "eth0", "-p", eth2pid)
  44. cmd2.Stdout = baseapp.Logger.WriterLevel(logrus.DebugLevel)
  45. cmd2.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
  46. if err := cmd2.Run(); err != nil {
  47. return fmt.Errorf("\"eth0\"请求地址失败: %w", err)
  48. }
  49. return nil
  50. }
  51. // 检测"eth0"网口上的"udhcpc"后台进程是否正在运行, 只保持一个实例
  52. func udhcpcEth0Exists() (bool, error) {
  53. eth2pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
  54. data, err := os.ReadFile(eth2pid)
  55. if err != nil {
  56. return false, err
  57. }
  58. pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
  59. if err != nil {
  60. return false, err
  61. }
  62. err = syscall.Kill(pid, 0)
  63. if err == nil { // 存在
  64. return true, nil
  65. }
  66. if err == syscall.ESRCH { // 不存在
  67. return false, nil
  68. }
  69. return false, err
  70. }
  71. // 杀死"eth0"网口上的"udhcpc"进程(根据上次运行时它的PID-文件记录)
  72. func KillEth0Udhcpc() error {
  73. eth2pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
  74. data, err := os.ReadFile(eth2pid)
  75. if err != nil {
  76. return err
  77. }
  78. pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
  79. if err != nil {
  80. return err
  81. }
  82. if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
  83. syscall.Kill(pid, syscall.SIGKILL)
  84. }
  85. return nil
  86. }
  87. // 强制杀死所有运行中的"udhcpc"进程,包括驻留在后台运行的(SIGKILL)
  88. func killAllUdhcpc() {
  89. cmd := exec.Command("sh", "-c", `ps | grep '[u]dhcpc' | awk '{print $1}'`)
  90. output, err := cmd.Output()
  91. if err != nil {
  92. return // 没找到也不是错误
  93. }
  94. pids := strings.FieldsSeq(string(output))
  95. for pidStr := range pids {
  96. pid, err := strconv.Atoi(pidStr)
  97. if err != nil {
  98. continue
  99. }
  100. if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
  101. syscall.Kill(pid, syscall.SIGKILL)
  102. }
  103. }
  104. }
  105. // 运行"udhcpc"后, 获取"eth0"网口分配到的IPv4地址, 并校检其合法性
  106. func getEth0Addr() (ip, mask string, err error) {
  107. iface, err := net.InterfaceByName("eth0")
  108. if err != nil {
  109. return "", "", fmt.Errorf("找不到网络接口\"eth0\": %w", err)
  110. }
  111. addrs, err := iface.Addrs()
  112. if err != nil {
  113. return "", "", fmt.Errorf("获取\"eth0\"的地址失败: %w", err)
  114. }
  115. for _, addr := range addrs {
  116. ipNet, ok := addr.(*net.IPNet)
  117. if !ok {
  118. continue
  119. }
  120. ip4 := ipNet.IP.To4()
  121. if ip4 == nil {
  122. continue
  123. }
  124. if ip4.IsPrivate() { // 判断得到IP地址是否合法
  125. return ip4.String(), net.IP(ipNet.Mask).String(), nil
  126. } else {
  127. return "", "", fmt.Errorf("分配给\"eth0\"的地址\"%s\"无效", ip4.String())
  128. }
  129. }
  130. return "", "", fmt.Errorf("在\"eth0\"上未找到有效的IPv4 地址")
  131. }
  132. // 定时检测"eth0"网卡上的"udhcpc"后台服务进程, 发现退出时自动拉起
  133. func MonitorEth0Udhcpc(exitCh <-chan struct{}) {
  134. t := time.NewTicker(time.Duration(5) * time.Second)
  135. defer t.Stop()
  136. for {
  137. select {
  138. case <-t.C:
  139. bExists, _ := udhcpcEth0Exists()
  140. if !bExists { // 清场一次
  141. killAllUdhcpc()
  142. disableEthBut0()
  143. }
  144. if !bExists && dialupEth0() == nil { // 重新进场
  145. ip, mask, _ := getEth0Addr()
  146. baseapp.Logger.Warnf("[%s] \"eth0\"重新分配的地址: %s/%s!", MODULE_NAME, ip, mask)
  147. }
  148. case <-exitCh:
  149. return
  150. } // select end
  151. } // for end
  152. }
  153. func IsEth0CableConnected() (bool, error) {
  154. if data, err := os.ReadFile("/sys/class/net/eth0/carrier"); err == nil {
  155. return strings.TrimSpace(string(data)) == "1", nil
  156. }
  157. link, err := netlink.LinkByName("eth0")
  158. if err != nil {
  159. return false, err
  160. }
  161. return link.Attrs().OperState == netlink.OperUp, nil
  162. }