|
@@ -1 +1,172 @@
|
|
|
package netmgrd
|
|
package netmgrd
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "net"
|
|
|
|
|
+ "os"
|
|
|
|
|
+ "os/exec"
|
|
|
|
|
+ "strconv"
|
|
|
|
|
+ "strings"
|
|
|
|
|
+ "syscall"
|
|
|
|
|
+ "time"
|
|
|
|
|
+
|
|
|
|
|
+ "github.com/sirupsen/logrus"
|
|
|
|
|
+ "hnyfkj.com.cn/rtu/linux/baseapp"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+// 只保留需要使用的"eth0"网卡
|
|
|
|
|
+func disableEthBut0() error {
|
|
|
|
|
+ ifaces, err := net.Interfaces()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("获取网络接口列表失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, iface := range ifaces {
|
|
|
|
|
+ if !strings.HasPrefix(iface.Name, "eth") || iface.Name == "eth0" {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ cmd := exec.Command("ip", "link", "set", "dev", iface.Name, "down")
|
|
|
|
|
+ cmd.Stdout = baseapp.Logger.WriterLevel(logrus.DebugLevel)
|
|
|
|
|
+ cmd.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
|
|
|
|
|
+ if err := cmd.Run(); err != nil {
|
|
|
|
|
+ return fmt.Errorf("关闭网口\"%s\"失败: %w", iface.Name, err)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 启动DHCP客户端, 请求IP地址
|
|
|
|
|
+func dialupEth0() error {
|
|
|
|
|
+ cmd1 := exec.Command("ip", "link", "set", "dev", "eth0", "up")
|
|
|
|
|
+ cmd1.Stdout = baseapp.Logger.WriterLevel(logrus.DebugLevel)
|
|
|
|
|
+ cmd1.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
|
|
|
|
|
+ if err := cmd1.Run(); err != nil {
|
|
|
|
|
+ return fmt.Errorf("启动网口\"eth0\"失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ eth2pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
|
|
|
|
|
+ cmd2 := exec.Command("udhcpc", "-b", "-i", "eth0", "-p", eth2pid)
|
|
|
|
|
+ cmd2.Stdout = baseapp.Logger.WriterLevel(logrus.DebugLevel)
|
|
|
|
|
+ cmd2.Stderr = baseapp.Logger.WriterLevel(logrus.ErrorLevel)
|
|
|
|
|
+ if err := cmd2.Run(); err != nil {
|
|
|
|
|
+ return fmt.Errorf("\"eth0\"请求地址失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 检测"eth0"网口上的"udhcpc"后台进程是否正在运行, 只保持一个实例
|
|
|
|
|
+func udhcpcEth0Exists() (bool, error) {
|
|
|
|
|
+ eth2pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
|
|
|
|
|
+ data, err := os.ReadFile(eth2pid)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return false, err
|
|
|
|
|
+ }
|
|
|
|
|
+ pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return false, err
|
|
|
|
|
+ }
|
|
|
|
|
+ err = syscall.Kill(pid, 0)
|
|
|
|
|
+ if err == nil { // 存在
|
|
|
|
|
+ return true, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ if err == syscall.ESRCH { // 不存在
|
|
|
|
|
+ return false, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ return false, err
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 杀死"eth0"网口上的"udhcpc"进程(根据上次运行时它的PID-文件记录)
|
|
|
|
|
+func KillEth0Udhcpc() error {
|
|
|
|
|
+ eth2pid := baseapp.RUN_DIR + "/udhcpc.eth0.pid"
|
|
|
|
|
+ data, err := os.ReadFile(eth2pid)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
|
|
|
|
|
+ syscall.Kill(pid, syscall.SIGKILL)
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 强制杀死所有运行中的"udhcpc"进程,包括驻留在后台运行的(SIGKILL)
|
|
|
|
|
+func killAllUdhcpc() {
|
|
|
|
|
+ cmd := exec.Command("sh", "-c", `ps | grep '[u]dhcpc' | awk '{print $1}'`)
|
|
|
|
|
+ output, err := cmd.Output()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return // 没找到也不是错误
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pids := strings.FieldsSeq(string(output))
|
|
|
|
|
+ for pidStr := range pids {
|
|
|
|
|
+ pid, err := strconv.Atoi(pidStr)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
|
|
|
|
|
+ syscall.Kill(pid, syscall.SIGKILL)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 运行"udhcpc"后, 获取"eth0"网口分配到的IPv4地址, 并校检其合法性
|
|
|
|
|
+func getEth0Addr() (ip, mask string, err error) {
|
|
|
|
|
+ iface, err := net.InterfaceByName("eth0")
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return "", "", fmt.Errorf("找不到网络接口\"eth0\": %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ addrs, err := iface.Addrs()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return "", "", fmt.Errorf("获取\"eth0\"的地址失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, addr := range addrs {
|
|
|
|
|
+ ipNet, ok := addr.(*net.IPNet)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ip4 := ipNet.IP.To4()
|
|
|
|
|
+ if ip4 == nil {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ip4.IsPrivate() { // 判断得到IP地址是否合法
|
|
|
|
|
+ return ip4.String(), net.IP(ipNet.Mask).String(), nil
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return "", "", fmt.Errorf("分配给\"eth0\"的地址\"%s\"无效", ip4.String())
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return "", "", fmt.Errorf("在\"eth0\"上未找到有效的IPv4 地址")
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 定时检测"eth0"网卡上的"udhcpc"后台服务进程, 发现退出时自动拉起
|
|
|
|
|
+func MonitorEth0Udhcpc(exitCh <-chan struct{}) {
|
|
|
|
|
+ t := time.NewTicker(time.Duration(5) * time.Second)
|
|
|
|
|
+ defer t.Stop()
|
|
|
|
|
+
|
|
|
|
|
+ for {
|
|
|
|
|
+ select {
|
|
|
|
|
+ case <-t.C:
|
|
|
|
|
+ bExists, _ := udhcpcEth0Exists()
|
|
|
|
|
+ if !bExists { // 清场一次
|
|
|
|
|
+ killAllUdhcpc()
|
|
|
|
|
+ disableEthBut0()
|
|
|
|
|
+ }
|
|
|
|
|
+ if !bExists && dialupEth0() == nil { // 重新进场
|
|
|
|
|
+ ip, mask, _ := getEth0Addr()
|
|
|
|
|
+ baseapp.Logger.Warnf("[%s] \"eth0\"重新分配的地址: %s/%s!", MODULE_NAME, ip, mask)
|
|
|
|
|
+ }
|
|
|
|
|
+ case <-exitCh:
|
|
|
|
|
+ return
|
|
|
|
|
+ } // select end
|
|
|
|
|
+ } // for end
|
|
|
|
|
+}
|