go - go语言中如何使用RTNETLINK socket监控ip地址变化

标签 go ip-address netlink

我有以下代码,应该使用 RTNETLINK 套接字监视网络变化。但是,当我为接口(interface)设置新 IP 地址时,“New Addr”或“Del Addr”没有显示。可能是什么问题。

package main

import (
    "fmt"
    "syscall"
)

func main() {
    l, _ := ListenNetlink()

    for {
        msgs, err := l.ReadMsgs()
        if err != nil {
            fmt.Println("Could not read netlink: %s", err)
        }

        for _, m := range msgs {
            if IsNewAddr(&m) {
                fmt.Println("New Addr")
            }

            if IsDelAddr(&m) {
                fmt.Println("Del Addr")
            }
        }
    }
}

type NetlinkListener struct {
    fd int
    sa *syscall.SockaddrNetlink
}

func ListenNetlink() (*NetlinkListener, error) {
    groups := syscall.RTNLGRP_LINK |
        syscall.RTNLGRP_IPV4_IFADDR |
        syscall.RTNLGRP_IPV6_IFADDR

    s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM,
        syscall.NETLINK_ROUTE)
    if err != nil {
        return nil, fmt.Errorf("socket: %s", err)
    }

    saddr := &syscall.SockaddrNetlink{
        Family: syscall.AF_NETLINK,
        Pid:    uint32(0),
        Groups: uint32(groups),
    }

    err = syscall.Bind(s, saddr)
    if err != nil {
        return nil, fmt.Errorf("bind: %s", err)
    }

    return &NetlinkListener{fd: s, sa: saddr}, nil
}

func (l *NetlinkListener) ReadMsgs() ([]syscall.NetlinkMessage, error) {
    defer func() {
        recover()
    }()

    pkt := make([]byte, 2048)

    n, err := syscall.Read(l.fd, pkt)
    if err != nil {
        return nil, fmt.Errorf("read: %s", err)
    }

    msgs, err := syscall.ParseNetlinkMessage(pkt[:n])
    if err != nil {
        return nil, fmt.Errorf("parse: %s", err)
    }

    return msgs, nil
}

func IsNewAddr(msg *syscall.NetlinkMessage) bool {
    if msg.Header.Type == syscall.RTM_NEWADDR {
        return true
    }

    return false
}

func IsDelAddr(msg *syscall.NetlinkMessage) bool {
    if msg.Header.Type == syscall.RTM_DELADDR {
        return true
    }

    return false
}

func IsRelevant(msg *syscall.IfAddrmsg) bool {
    if msg.Scope == syscall.RT_SCOPE_UNIVERSE ||
        msg.Scope == syscall.RT_SCOPE_SITE {
        return true
    }

    return false
}

最佳答案

我在 syscall.go 找到了包文件。常数变量 syscall.RTNLGRP_IPV4_IFADDR=0x5 .然而模拟RTMGRP_IPV4_IFADDR rtnetlink.h source中定义的C语言常量具有以下不同的值:

#define RTMGRP_IPV4_IFADDR 0x10

我提交了 issue通过 github.com,我希望它会在即将发布的版本中得到修复。

现在你可以使用0x10在你的代码中安装了 0x5 .它将完美运行。

事实证明它根本不是错误。他们没有重新申报RTMGRP_*来自 rtnetlink.h source 的常量变量组自syscall.go 以来也不想在功能中添加此功能被卡住。但是他们建议使用 RTNLGRP_*这也在 rtnetlink.h source 中声明.然而,这两组常量变量在以下方面有所不同。 RTMGRP_* group 表示位值(即:RTMGRP_IPV4_IFADDR = 0x10)并为用户空间向后功能声明。 RTLNGRP_* group 表示位位置而不是位值(即: RTNLGRP_IPV4_IFADDR=0x5 ),可以通过以下方式将其转换为位值 1 << (RTNLGRP_* - 1)

关于go - go语言中如何使用RTNETLINK socket监控ip地址变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36347807/

相关文章:

database - 键/值数据库的二级索引

go - 在 golang 的单独端口中公开 Prometheus 指标

image - 是否可以找到图像来源的 IP?

python - 如何在 Python 中检查 ip 是否在网络中?

android - 无法在 Android 上原生使用 'libnl'。无法使用 `genl_ctrl_resolve()` 获取 nl80211 驱动程序

c++ - netlink 接口(interface) stat goto 交叉初始化错误

go - 如何使用反射获取 slice 数据?

go - 优雅地关闭 Gorilla 服务器

java - 检查字符串是Java中的主机名还是IP地址

Linux netlink 多播路由更新