当前位置: 首页 > 面试题库 >

如何使用Go语言中的RTNETLINK套接字监视IP地址更改

阮炯
2023-03-14
问题内容

我有以下代码,应使用RTNETLINK套接字监视网络更改。但是,当我为接口“ New Addr”或“ Del
Addr”设置新的IP地址时,不会显示。可能是什么问题。

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_IFADDRrtnetlink.h源代码中定义的C语言中的模拟常量具有不同的值,如下所示:

#define RTMGRP_IPV4_IFADDR 0x10

我通过github.com
提交了问题,希望在以后的版本中可以解决。

现在,您可以0x10在插入的代码中使用0x5。它将完美运行。

事实证明这根本不是bug。他们没有RTMGRP_*rtnetlink.h源中重新声明常量变量组,并且由于syscall.go冻结而也不想在功能中添加此变量。但是他们建议使用source中RTNLGRP_*也声明的方法。但是,这两组常量变量在以下方面有所不同。组代表位值(即:),并声明为用于用户空间后退功能。组代表位位置而不是位值(即:),可以通过以下方式将其转换为位值rtnetlink.hRTMGRP_*``RTMGRP_IPV4_IFADDR = 0x10``RTLNGRP_*``RTNLGRP_IPV4_IFADDR=0x5``1 << (RTNLGRP_* - 1)



 类似资料:
  • 问题内容: 我想获取启动程序的计算机的IP地址,然后将其发送到客户端,但是我总是得到0.0.0.1而不是真实的IP地址(例如127.0.0.1)。 我目前可以获取端口,但无法获取IP地址。 我怎么才能得到它? 最好的解决方案是能够使用。这是我目前正在做的事情: 编辑: 我知道我的思维方式走错了路。所以我的问题是:获得自己的IP地址的最佳方法是什么? 问题答案: 当您将套接字设为0.0.0.0时,这

  • 问题内容: 我有一个Go程序,在其上托管了一个简单的HTTP服务,因此我可以通过该指令将我的公共主机连接到它,作为反向代理来满足我的网站请求的一部分。一切都很好,在那里没有问题。 我想将Go程序转换为在Unix域套接字而不是本地TCP套接字上承载HTTP服务,以提高安全性并减少TCP不必要的协议开销。 问题 :问题在于,即使程序终止后,Unix域套接字也无法重用。第二次(以及之后的每一次)我运行G

  • 问题内容: 我想获取计算机的IP地址。我使用了下面的代码,但是返回了。 我想获取IP地址(例如),而不是回送地址。 问题答案: 您需要遍历所有网络接口 播放(取自util / helper.go)

  • 问题内容: 我如何获得我的IP地址(最好是格式)? 问题答案: 此示例代码列出了计算机上存在的所有IPv4网络接口的接口名称(例如或)以及当前分配的IP地址:

  • 在Java建立TCP连接时,需要创建套接字。我使用下面的构造函数来创建套接字。公共套接字(InetAddress address,int port,InetAddress localAddr,int localPort)抛出IOException 根据Java API,localAddress应该是有效的InetAddress或null。当我提供作为本地地址时,在本地计算机(如和远程计算机)上建立

  • 问题内容: 我正在使用python和CherryPy创建一个大约2个人使用的简单内部网站。我将内置的Web服务器与CherryPy.quickstart一起使用,并且从未弄乱过配置文件。我最近更换了机器,所以我安装了最新的Python和cherrypy,当我运行该站点时,可以从localhost:8080访问它,但不能通过IP或Windows机器名访问它。可能是机器配置不同,也可能是CherryP