如何使用go语言中的RTNETLINK套接字监视ip地址更改
我有以下代码,它应该使用RTNETLINK套接字监视网络更改。但是,当我为接口设置新IP地址时,“new Addr”或“Del Addr”不会显示。什么是可能的问题如何使用go语言中的RTNETLINK套接字监视ip地址更改,go,ip-address,netlink,Go,Ip Address,Netlink,我有以下代码,它应该使用RTNETLINK套接字监视网络更改。但是,当我为接口设置新IP地址时,“new Addr”或“Del Addr”不会显示。什么是可能的问题 package main import ( "fmt" "syscall" ) func main() { l, _ := ListenNetlink() for { msgs, err := l.ReadMsgs() if err != nil {
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\u IPV4\u IFADDR=0x5。但是,中定义的C语言中的模拟RTMGRP\u IPV4\u IFADDR
常量具有不同的值,如下所示:
#define RTMGRP_IPV4_IFADDR 0x10
groups := (1 << (syscall.RTNLGRP_LINK - 1)) |
(1 << (syscall.RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (syscall.RTNLGRP_IPV6_IFADDR - 1))
我是通过github.com提交的,我希望它能在即将发布的版本中得到修复
目前,您可以在代码中使用0x10
,而不是0x5
。它将完美地工作
结果证明它根本不是bug。他们没有从重新声明RTMGRP.*
常量变量组,也不想在功能中添加此项,因为syscall.go
已冻结。然而,他们建议使用RTNLGRP.*
,这也在中声明。然而,这两组常量变量在以下方面是不同的RTMGRP.*
组表示位值(即:RTMGRP.\u IPV4\u IFADDR=0x10
)并声明用于用户空间向后功能RTLNGRP_*
组表示位位置而不是位值(即:RTNLGRP_IPV4\u IFADDR=0x5
),可以通过以下方式将其转换为位值1我在syscall.go
文件中找到了bag。常量变量syscall.RTNLGRP\u IPV4\u IFADDR=0x5
。但是,中定义的C语言中的模拟RTMGRP\u IPV4\u IFADDR
常量具有不同的值,如下所示:
#define RTMGRP_IPV4_IFADDR 0x10
groups := (1 << (syscall.RTNLGRP_LINK - 1)) |
(1 << (syscall.RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (syscall.RTNLGRP_IPV6_IFADDR - 1))
我是通过github.com提交的,我希望它能在即将发布的版本中得到修复
目前,您可以在代码中使用0x10
,而不是0x5
。它将完美地工作
结果证明它根本不是bug。他们没有从重新声明
RTMGRP.*
常量变量组,也不想在功能中添加此项,因为syscall.go
已冻结。然而,他们建议使用RTNLGRP.*
,这也在中声明。然而,这两组常量变量在以下方面是不同的RTMGRP.*
组表示位值(即:RTMGRP.\u IPV4\u IFADDR=0x10
)并声明用于用户空间向后功能RTLNGRP_*
组表示位位置,而不是位值(即:RTNLGRP_IPV4\u IFADDR=0x5
),可以通过以下方式将其转换为位值1,根据接受的答案,修复它以将组更改为以下内容:
#define RTMGRP_IPV4_IFADDR 0x10
groups := (1 << (syscall.RTNLGRP_LINK - 1)) |
(1 << (syscall.RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (syscall.RTNLGRP_IPV6_IFADDR - 1))
groups:=(1根据接受的答案,修复它以将组更改为以下内容:
#define RTMGRP_IPV4_IFADDR 0x10
groups := (1 << (syscall.RTNLGRP_LINK - 1)) |
(1 << (syscall.RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (syscall.RTNLGRP_IPV6_IFADDR - 1))
groups:=(1以下是*BSD的等效代码:
package main
import (
"fmt"
"log"
"syscall"
)
func main() {
netlink, err := ListenNetlink()
if err != nil {
log.Printf("[ERR] Could not create netlink listener: %v", err)
return
}
for {
msgs, err := netlink.ReadMsgs()
if err != nil {
log.Printf("[ERR] Could not read netlink: %v", err)
}
for _, msg := range msgs {
if _, ok := msg.(*syscall.InterfaceAddrMessage); ok {
log.Printf("address change!")
}
}
}
}
type NetlinkListener struct {
fd int
}
func ListenNetlink() (*NetlinkListener, error) {
s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
if err != nil {
return nil, fmt.Errorf("socket: %s", err)
}
return &NetlinkListener{fd: s}, nil
}
func (l *NetlinkListener) ReadMsgs() ([]syscall.RoutingMessage, 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.ParseRoutingMessage(pkt[:n])
if err != nil {
return nil, fmt.Errorf("parse: %s", err)
}
return msgs, nil
}
以下是*BSD的等效代码:
package main
import (
"fmt"
"log"
"syscall"
)
func main() {
netlink, err := ListenNetlink()
if err != nil {
log.Printf("[ERR] Could not create netlink listener: %v", err)
return
}
for {
msgs, err := netlink.ReadMsgs()
if err != nil {
log.Printf("[ERR] Could not read netlink: %v", err)
}
for _, msg := range msgs {
if _, ok := msg.(*syscall.InterfaceAddrMessage); ok {
log.Printf("address change!")
}
}
}
}
type NetlinkListener struct {
fd int
}
func ListenNetlink() (*NetlinkListener, error) {
s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
if err != nil {
return nil, fmt.Errorf("socket: %s", err)
}
return &NetlinkListener{fd: s}, nil
}
func (l *NetlinkListener) ReadMsgs() ([]syscall.RoutingMessage, 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.ParseRoutingMessage(pkt[:n])
if err != nil {
return nil, fmt.Errorf("parse: %s", err)
}
return msgs, nil
}
更新示例应该是
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 := (1 << (syscall.RTNLGRP_LINK - 1)) |
(1 << (syscall.RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (syscall.RTNLGRP_IPV6_IFADDR - 1))
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
}
// rtm_scope is the distance to the destination:
//
// RT_SCOPE_UNIVERSE global route
// RT_SCOPE_SITE interior route in the
// local autonomous system
// RT_SCOPE_LINK route on this link
// RT_SCOPE_HOST route on the local host
// RT_SCOPE_NOWHERE destination doesn't exist
//
// The values between RT_SCOPE_UNIVERSE and RT_SCOPE_SITE are
// available to the user.
func IsRelevant(msg *syscall.IfAddrmsg) bool {
if msg.Scope == syscall.RT_SCOPE_UNIVERSE ||
msg.Scope == syscall.RT_SCOPE_SITE {
return true
}
return false
}
主程序包
进口(
“fmt”
“系统调用”
)
func main(){
l、 _u3;:=ListenNetlink()
为了{
msgs,err:=l.ReadMsgs()
如果错误!=零{
fmt.Println(“无法读取网络链接:%s”,错误)
}
对于u,m:=范围msgs{
如果是新地址(&m){
fmt.Println(“新地址”)
}
如果是IsDelAddr(&m){
格式打印(“删除地址”)
}
}
}
}
输入NetlinkListener结构{
fd int
sa*syscall.SockaddrNetlink
}
func ListenNetlink()(*NetlinkListener,错误){
组:=(1更新示例应为
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 := (1 << (syscall.RTNLGRP_LINK - 1)) |
(1 << (syscall.RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (syscall.RTNLGRP_IPV6_IFADDR - 1))
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
}
// rtm_scope is the distance to the destination:
//
// RT_SCOPE_UNIVERSE global route
// RT_SCOPE_SITE interior route in the
// local autonomous system
// RT_SCOPE_LINK route on this link
// RT_SCOPE_HOST route on the local host
// RT_SCOPE_NOWHERE destination doesn't exist
//
// The values between RT_SCOPE_UNIVERSE and RT_SCOPE_SITE are
// available to the user.
func IsRelevant(msg *syscall.IfAddrmsg) bool {
if msg.Scope == syscall.RT_SCOPE_UNIVERSE ||
msg.Scope == syscall.RT_SCOPE_SITE {
return true
}
return false
}
主程序包
进口(
“fmt”
“系统调用”
)
func main(){
l、 _u3;:=ListenNetlink()
为了{
msgs,err:=l.ReadMsgs()
如果错误!=零{
fmt.Println(“无法读取网络链接:%s”,错误)
}
对于u,m:=范围msgs{
如果是新地址(&m){
fmt.Println(“新地址”)
}
如果是IsDelAddr(&m){
格式打印(“删除地址”)
}
}
}
}
输入NetlinkListener结构{
fd int
sa*syscall.SockaddrNetlink
}
func ListenNetlink()(*NetlinkListener,错误){
组:=(1)谢谢你解答。你能相应地更新上面的示例代码吗?谢谢你解答。你能相应地更新上面的示例代码吗?谢谢你的示例。谢谢你的示例。达尔文/macOS的示例是什么样子的?@surlac上述代码在达尔文/macOS任何其他BSD'sh操作系统上工作Darwin/macOS的示例是什么?@surlac上面的代码适用于Darwin/macOS或任何其他BSD'sh操作系统