2016-04-01 10 views
0

Ich habe folgenden Code, der Netzwerkänderungen mit RTNETLINK-Socket überwachen sollte. Allerdings, wenn ich neue IP-Adresse für die Schnittstelle "New Addr" oder "Del Addr" einstellen wird nicht angezeigt. Was kann mögliches Problem sein.Wie IP-Adressänderung mit RTNETLINK-Buchse in Go-Sprache zu überwachen

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 
} 

Antwort

0

Ich fand Tasche in syscall.go Datei. Konstante Variable syscall.RTNLGRP_IPV4_IFADDR=0x5. Jedoch Analog RTMGRP_IPV4_IFADDR Konstante in C-Sprache, die in rtnetlink.h source definierte anderen Wert als Folgendes:

#define RTMGRP_IPV4_IFADDR 0x10 

I vorgelegt issue durch github.com und ich hoffe, dass es in der kommenden Versionen behoben werden.

Für jetzt können Sie 0x10 in Ihrem Code anstelle von 0x5 verwenden. Es wird perfekt funktionieren.

Stellt sich heraus, dass es überhaupt kein Fehler ist. Sie haben die RTMGRP_* Konstantenvariablengruppe aus rtnetlink.h source nicht deklariert und möchten diese Funktion auch nicht hinzufügen, da syscall.go eingefroren ist. Jedoch schlagen sie vor, RTNLGRP_* zu verwenden, das auch in rtnetlink.h source erklärt wird. Diese zwei Gruppen von konstanten Variablen unterscheiden sich jedoch in folgender Weise. RTMGRP_* Gruppe repräsentiert Bit-Wert (d. H. RTMGRP_IPV4_IFADDR = 0x10) und für Benutzerraum rückwärts Fähigkeiten deklariert. RTLNGRP_* Die Gruppe repräsentiert die Bitposition und nicht den Bitwert (d. H. RTNLGRP_IPV4_IFADDR=0x5), der auf folgende Weise in den Bitwert übersetzt werden kann: 1 << (RTNLGRP_* - 1)