func main() { sk := nlgo.NlSocketAlloc() if err := nlgo.GenlConnect(sk); err != nil { panic(err) } else if err := nlgo.GenlSendSimple(sk, nlgo.GENL_ID_CTRL, nlgo.CTRL_CMD_GETFAMILY, nlgo.CTRL_VERSION, syscall.NLM_F_DUMP); err != nil { panic(err) } nl80211 := nlgo.NlSocketAlloc() if err := nlgo.GenlConnect(nl80211); err != nil { panic(err) } data := make([]byte, syscall.Getpagesize()) if n, _, _, _, err := syscall.Recvmsg(sk.Fd, data, nil, 0); err != nil { panic(err) } else if msgs, err := syscall.ParseNetlinkMessage(data[:n]); err != nil { log.Print("X", err) } else { for _, msg := range msgs { genl := *(*nlgo.GenlMsghdr)(unsafe.Pointer(&msg.Data[0])) if msg.Header.Type == nlgo.GENL_ID_CTRL && genl.Cmd == nlgo.CTRL_CMD_NEWFAMILY { if attr, err := nlgo.CtrlPolicy.Parse(msg.Data[nlgo.GENL_HDRLEN:]); err != nil { log.Print(err) } else if amap, ok := attr.(nlgo.AttrMap); !ok { log.Print(attr) } else if value := amap.Get(nlgo.CTRL_ATTR_FAMILY_NAME).(nlgo.NulString); string(value) == "nl80211" { log.Printf("%v", attr) for _, g := range amap.Get(nlgo.CTRL_ATTR_MCAST_GROUPS).(nlgo.AttrSlice).Slice() { group := g.Value.(nlgo.AttrMap) pid := group.Get(nlgo.CTRL_ATTR_MCAST_GRP_ID).(nlgo.U32) if err := nlgo.NlSocketAddMembership(nl80211, int(pid)); err != nil { log.Print(err) } } } } else { log.Print("UNKNOWN") } } } nlgo.NlSocketFree(sk) for { if n, _, _, _, err := syscall.Recvmsg(nl80211.Fd, data, nil, 0); err != nil { panic(err) } else if msgs, err := syscall.ParseNetlinkMessage(data[:n]); err != nil { log.Print("Y", err) } else { for _, msg := range msgs { genl := (*nlgo.GenlMsghdr)(unsafe.Pointer(&msg.Data[0])) if attr, err := nlgo.Nl80211Policy.Parse(msg.Data[nlgo.GENL_HDRLEN:]); err != nil { log.Print("Z", err) } else { log.Printf("NL80211_CMD_%s attrs=%s", nlgo.NL80211_CMD_itoa[genl.Cmd], attr) } } } } }
func getDefaultRoute() (*syscall.NetlinkMessage, error) { dat, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC) if err != nil { return nil, err } msgs, msgErr := syscall.ParseNetlinkMessage(dat) if msgErr != nil { return nil, msgErr } rtmsg := syscall.RtMsg{} for _, m := range msgs { if m.Header.Type != syscall.RTM_NEWROUTE { continue } buf := bytes.NewBuffer(m.Data[:syscall.SizeofRtMsg]) if rerr := binary.Read(buf, binary.LittleEndian, &rtmsg); rerr != nil { continue } if rtmsg.Dst_len == 0 { // zero-length Dst_len implies default route return &m, nil } } return nil, errNoDefaultRoute }
func TestParseNetlinkMessage(t *testing.T) { for i, b := range [][]byte{ {103, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 5, 8, 0, 3, 0, 8, 0, 6, 0, 0, 0, 0, 1, 63, 0, 10, 0, 69, 16, 0, 59, 39, 82, 64, 0, 64, 6, 21, 89, 127, 0, 0, 1, 127, 0, 0, 1, 230, 228, 31, 144, 32, 186, 155, 211, 185, 151, 209, 179, 128, 24, 1, 86, 53, 119, 0, 0, 1, 1, 8, 10, 0, 17, 234, 12, 0, 17, 189, 126, 107, 106, 108, 107, 106, 13, 10, }, {106, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 3, 8, 0, 3, 0, 8, 0, 6, 0, 0, 0, 0, 1, 66, 0, 10, 0, 69, 0, 0, 62, 230, 255, 64, 0, 64, 6, 85, 184, 127, 0, 0, 1, 127, 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 65, 250, 60, 192, 97, 128, 24, 1, 86, 253, 21, 0, 0, 1, 1, 8, 10, 0, 51, 106, 89, 0, 51, 102, 198, 108, 104, 106, 108, 107, 104, 108, 107, 104, 10, }, {102, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 1, 8, 0, 3, 0, 8, 0, 6, 0, 0, 0, 0, 1, 62, 0, 10, 0, 69, 0, 0, 58, 231, 2, 64, 0, 64, 6, 85, 185, 127, 0, 0, 1, 127, 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 86, 250, 60, 192, 97, 128, 24, 1, 86, 104, 64, 0, 0, 1, 1, 8, 10, 0, 52, 198, 200, 0, 51, 135, 232, 101, 115, 97, 103, 103, 10, }, } { m, err := syscall.ParseNetlinkMessage(b) if err != syscall.EINVAL { t.Errorf("#%d: got %v; want EINVAL", i, err) } if m != nil { t.Errorf("#%d: got %v; want nil", i, m) } } }
// getNeighbors sends a request to netlink to retrieve all neighbors using // the specified address family. func getNeighbors(family Family) ([]*Neighbor, error) { // Request neighbors belonging to a specific family from netlink tab, err := syscall.NetlinkRIB(syscall.RTM_GETNEIGH, int(family)) if err != nil { return nil, os.NewSyscallError("netlink rib", err) } // Parse netlink information into individual messages msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { return nil, os.NewSyscallError("netlink message", err) } // Check messages for information var nn []*Neighbor for _, m := range msgs { // Ignore any messages which don't indicate a new neighbor if m.Header.Type != syscall.RTM_NEWNEIGH { continue } // Attempt to parse an individual neighbor from a message n, err := newNeighbor(&m) if err != nil { return nil, err } nn = append(nn, n) } return nn, nil }
func getIface(idx uint32) (*syscall.NetlinkMessage, error) { dat, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) if err != nil { return nil, err } msgs, msgErr := syscall.ParseNetlinkMessage(dat) if msgErr != nil { return nil, msgErr } ifaddrmsg := syscall.IfAddrmsg{} for _, m := range msgs { if m.Header.Type != syscall.RTM_NEWADDR { continue } buf := bytes.NewBuffer(m.Data[:syscall.SizeofIfAddrmsg]) if rerr := binary.Read(buf, binary.LittleEndian, &ifaddrmsg); rerr != nil { continue } if ifaddrmsg.Index == idx { return &m, nil } } return nil, errNoDefaultRoute }
// If the ifindex is zero, interfaceTable returns mappings of all // network interfaces. Otherwise it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, error) { // 如果ifindex为0,返回所有网络接口 tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) // 获得netlink rib if err != nil { return nil, os.NewSyscallError("netlinkrib", err) } msgs, err := syscall.ParseNetlinkMessage(tab) // 解析netlink信息 if err != nil { return nil, os.NewSyscallError("parsenetlinkmessage", err) } var ift []Interface loop: for _, m := range msgs { // 遍历获取的netlink信息 switch m.Header.Type { case syscall.NLMSG_DONE: break loop case syscall.RTM_NEWLINK: ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifim.Index) { attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, os.NewSyscallError("parsenetlinkrouteattr", err) } ift = append(ift, *newLink(ifim, attrs)) // 加入到Interface Slice中 if ifindex == int(ifim.Index) { break loop } } } } return ift, nil }
// If the ifindex is zero, interfaceTable returns mappings of all // network interfaces. Otheriwse it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, error) { tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) if err != nil { return nil, os.NewSyscallError("netlink rib", err) } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { return nil, os.NewSyscallError("netlink message", err) } var ift []Interface for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: goto done case syscall.RTM_NEWLINK: ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifim.Index) { attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, os.NewSyscallError("netlink routeattr", err) } ifi := newLink(ifim, attrs) ift = append(ift, ifi) } } } done: return ift, nil }
func (w *Watcher) readAllEvents() { buf := make([]byte, syscall.Getpagesize()) listener, _ := w.listener.(*netlinkListener) for { if w.isDone() { return } nr, _, err := syscall.Recvfrom(listener.sock, buf, 0) if err != nil { w.Error <- err continue } if nr < syscall.NLMSG_HDRLEN { w.Error <- syscall.EINVAL continue } msgs, _ := syscall.ParseNetlinkMessage(buf[:nr]) for _, m := range msgs { if m.Header.Type == syscall.NLMSG_DONE { w.handleEventAll(m.Data) } } } }
// If the ifindex is zero, interfaceAddrTable returns addresses // for all network interfaces. Otherwise it returns addresses // for a specific interface. func interfaceAddrTable(ifindex int) ([]Addr, os.Error) { var ( tab []byte e int err os.Error ifat []Addr msgs []syscall.NetlinkMessage ) tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) if e != 0 { return nil, os.NewSyscallError("netlink rib", e) } msgs, e = syscall.ParseNetlinkMessage(tab) if e != 0 { return nil, os.NewSyscallError("netlink message", e) } ifat, err = addrTable(msgs, ifindex) if err != nil { return nil, err } return ifat, nil }
func (nl *NetlinkSocket) RecvMessages(sz, sockflags int) ([]NetlinkMessage, error) { buf := make([]byte, sz) rsz, _, err := syscall.Recvfrom(nl.sfd, buf, sockflags) if err != nil { return nil, err } if rsz < syscall.NLMSG_HDRLEN { return nil, syscall.EINVAL } msgList, err := syscall.ParseNetlinkMessage(buf[:rsz]) if err != nil { return nil, err } ret := []NetlinkMessage{} for _, msg := range msgList { msg := NetlinkMessage(msg) logf("received: %+v\n", msg) ret = append(ret, msg) } return ret, nil }
func TestSocketPacketConn(t *testing.T) { s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_ROUTE) if err != nil { t.Fatal(err) } lsa := syscall.SockaddrNetlink{Family: syscall.AF_NETLINK} if err := syscall.Bind(s, &lsa); err != nil { syscall.Close(s) t.Fatal(err) } f := os.NewFile(uintptr(s), "netlink") c, err := SocketPacketConn(f, &netlinkAddr{}) f.Close() if err != nil { t.Fatal(err) } defer c.Close() const N = 3 var wg sync.WaitGroup wg.Add(2 * N) dst := &netlinkAddr{PID: 0} for i := 0; i < N; i++ { go func() { defer wg.Done() l := syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg b := make([]byte, l) *(*uint32)(unsafe.Pointer(&b[0:4][0])) = uint32(l) *(*uint16)(unsafe.Pointer(&b[4:6][0])) = uint16(syscall.RTM_GETLINK) *(*uint16)(unsafe.Pointer(&b[6:8][0])) = uint16(syscall.NLM_F_DUMP | syscall.NLM_F_REQUEST) *(*uint32)(unsafe.Pointer(&b[8:12][0])) = uint32(1) *(*uint32)(unsafe.Pointer(&b[12:16][0])) = uint32(0) b[16] = byte(syscall.AF_UNSPEC) if _, err := c.WriteTo(b, dst); err != nil { t.Error(err) return } }() } for i := 0; i < N; i++ { go func() { defer wg.Done() b := make([]byte, os.Getpagesize()) n, _, err := c.ReadFrom(b) if err != nil { t.Error(err) return } if _, err := syscall.ParseNetlinkMessage(b[:n]); err != nil { t.Error(err) return } }() } wg.Wait() }
func NewRtHub() (*RtHub, error) { self := &RtHub{ sock: NlSocketAlloc(), lock: &sync.Mutex{}, unilock: &sync.Mutex{}, multicast: make(map[uint32][]NetlinkListener), } if err := NlConnect(self.sock, syscall.NETLINK_ROUTE); err != nil { NlSocketFree(self.sock) return nil, err } go func() { for { buf := make([]byte, syscall.Getpagesize()) if n, _, err := syscall.Recvfrom(self.sock.Fd, buf, syscall.MSG_TRUNC); err != nil { if e, ok := err.(syscall.Errno); ok && e.Temporary() { continue } break } else if msgs, err := syscall.ParseNetlinkMessage(buf[:n]); err != nil { break } else { for _, msg := range msgs { multi := func() []NetlinkListener { self.lock.Lock() defer self.lock.Unlock() var ret []NetlinkListener for _, s := range self.multicast { ret = append(ret, s...) } return ret }() if msg.Header.Seq == self.uniseq { if self.unicast != nil { self.unicast.NetlinkListen(msg) } switch msg.Header.Type { case syscall.NLMSG_DONE, syscall.NLMSG_ERROR: self.unilock.Unlock() } } if msg.Header.Seq == 0 { for _, proc := range multi { proc.NetlinkListen(msg) } } } } } log.Print("rt hub loop exit") }() return self, nil }
func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) { rb := make([]byte, syscall.Getpagesize()) nr, _, err := syscall.Recvfrom(s.fd, rb, 0) if err != nil { return nil, err } if nr < syscall.NLMSG_HDRLEN { return nil, ErrShortResponse } rb = rb[:nr] return syscall.ParseNetlinkMessage(rb) }
// If the ifindex is zero, interfaceAddrTable returns addresses // for all network interfaces. Otherwise it returns addresses // for a specific interface. func interfaceAddrTable(ifindex int) ([]Addr, os.Error) { var ( tab []byte e int err os.Error ifat4 []Addr ifat6 []Addr msgs4 []syscall.NetlinkMessage msgs6 []syscall.NetlinkMessage ) tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET) if e != 0 { return nil, os.NewSyscallError("netlink rib", e) } msgs4, e = syscall.ParseNetlinkMessage(tab) if e != 0 { return nil, os.NewSyscallError("netlink message", e) } ifat4, err = addrTable(msgs4, ifindex) if err != nil { return nil, err } tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET6) if e != 0 { return nil, os.NewSyscallError("netlink rib", e) } msgs6, e = syscall.ParseNetlinkMessage(tab) if e != 0 { return nil, os.NewSyscallError("netlink message", e) } ifat6, err = addrTable(msgs6, ifindex) if err != nil { return nil, err } return append(ifat4, ifat6...), nil }
// genl_ctrl_probe_by_name is not exposed in the original libnl func GenlCtrlProbeByName(sk *NlSock, name string) (AttrMap, error) { if err := GenlSendSimple(sk, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, CTRL_VERSION, syscall.NLM_F_DUMP); err != nil { return AttrMap{}, err } var ret AttrMap err := func() error { for { buf := make([]byte, syscall.Getpagesize()) if nn, _, err := syscall.Recvfrom(sk.Fd, buf, syscall.MSG_TRUNC); err != nil { return err } else if nn > len(buf) { return NLE_MSG_TRUNC } else { buf = buf[:nn] } if msgs, err := syscall.ParseNetlinkMessage(buf); err != nil { return err } else { for _, msg := range msgs { switch msg.Header.Type { case GENL_ID_CTRL: genl := (*GenlMsghdr)(unsafe.Pointer(&msg.Data[0])) switch genl.Cmd { case CTRL_CMD_NEWFAMILY: if attrs, err := CtrlPolicy.Parse(msg.Data[GENL_HDRLEN:]); err != nil { return err } else if info, ok := attrs.(AttrMap); !ok { // shold not happen } else if value := info.Get(CTRL_ATTR_FAMILY_NAME); value == nil { // should not happen by kernel } else if string(value.(NulString)) == name { ret = info } default: return fmt.Errorf("unexpected command") } case syscall.NLMSG_DONE: return nil case syscall.NLMSG_ERROR: return fmt.Errorf("NlMsgerr=%s", (*syscall.NlMsgerr)(unsafe.Pointer(&msg.Data[0]))) default: return fmt.Errorf("unexpected NlMsghdr=%s", msg.Header) } } } } }() return ret, err }
// Receive receives one or more Messages from netlink. func (c *conn) Receive() ([]Message, error) { b := make([]byte, os.Getpagesize()) for { // Peek at the buffer to see how many bytes are available n, _, err := c.s.Recvfrom(b, syscall.MSG_PEEK) if err != nil { return nil, err } // Break when we can read all messages if n < len(b) { break } // Double in size if not enough bytes b = make([]byte, len(b)*2) } // Read out all available messages n, from, err := c.s.Recvfrom(b, 0) if err != nil { return nil, err } addr, ok := from.(*syscall.SockaddrNetlink) if !ok { return nil, errInvalidSockaddr } if addr.Family != syscall.AF_NETLINK { return nil, errInvalidFamily } raw, err := syscall.ParseNetlinkMessage(b[:n]) if err != nil { return nil, err } msgs := make([]Message, 0, len(raw)) for _, r := range raw { m := Message{ Header: sysToHeader(r.Header), Data: r.Data, } msgs = append(msgs, m) } return msgs, nil }
// If the ifindex is zero, interfaceAddrTable returns addresses // for all network interfaces. Otherwise it returns addresses // for a specific interface. func interfaceAddrTable(ifindex int) ([]Addr, error) { tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) if err != nil { return nil, os.NewSyscallError("netlink rib", err) } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { return nil, os.NewSyscallError("netlink message", err) } ifat, err := addrTable(msgs, ifindex) if err != nil { return nil, err } return ifat, nil }
func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) { if s.fd < 0 { return nil, fmt.Errorf("Receive called on a closed socket") } rb := make([]byte, syscall.Getpagesize()) nr, _, err := syscall.Recvfrom(s.fd, rb, 0) if err != nil { return nil, err } if nr < syscall.NLMSG_HDRLEN { return nil, fmt.Errorf("Got short response from netlink") } rb = rb[:nr] return syscall.ParseNetlinkMessage(rb) }
// This basic rtnetlink example lists up link interfaces. func Example() { sock := NlSocketAlloc() defer NlSocketFree(sock) if err := NlConnect(sock, syscall.NETLINK_ROUTE); err != nil { panic(err) } req := make([]byte, NLMSG_ALIGN(syscall.SizeofIfInfomsg)) if err := NlSendSimple(sock, syscall.RTM_GETLINK, syscall.NLM_F_DUMP, req); err != nil { panic(err) } func() { for { buf := make([]byte, syscall.Getpagesize()) if nn, _, err := syscall.Recvfrom(sock.Fd, buf, syscall.MSG_TRUNC); err != nil { panic(err) } else if nn > len(buf) { panic("out of recv buf") } else { buf = buf[:nn] } if msgs, err := syscall.ParseNetlinkMessage(buf); err != nil { panic(err) } else { for _, msg := range msgs { switch msg.Header.Type { case syscall.RTM_NEWLINK: ifinfo := (*syscall.IfInfomsg)(unsafe.Pointer(&msg.Data[0])) if attrs, err := RouteLinkPolicy.Parse(msg.Data[NLA_ALIGN(syscall.SizeofIfInfomsg):]); err != nil { panic(err) } else { log.Print("ifinfomsg=", ifinfo, " attrs=", attrs) } case syscall.NLMSG_DONE: return default: log.Print("unhandled msg", msg.Header) } } } } }() }
// If the ifi is nil, interfaceAddrTable returns addresses for all // network interfaces. Otherwise it returns addresses for a specific // interface. func interfaceAddrTable(ifi *Interface) ([]Addr, error) { tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) if err != nil { return nil, os.NewSyscallError("netlinkrib", err) } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { return nil, os.NewSyscallError("parsenetlinkmessage", err) } var ift []Interface if ifi == nil { var err error ift, err = interfaceTable(0) if err != nil { return nil, err } } ifat, err := addrTable(ift, ifi, msgs) if err != nil { return nil, err } return ifat, nil }
func find_gateway(ip_mask *net.IPNet) (ip net.IP, dev string, err error) { buf, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET) if err != nil { log.Println("Failed to open netlink:", err) return } msgs, err := syscall.ParseNetlinkMessage(buf) if err != nil { log.Println("Failed to parse nl msg:", err) return } var def route set := false var once sync.Once loop: for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: break loop case syscall.RTM_NEWROUTE: // a route enrty var r route rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0])) attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { // err is shadowed log.Println("Failed to parse nl rtattr:", err) return ip, dev, err } // parse a route entry for _, a := range attrs { switch a.Attr.Type { case syscall.RTA_DST: addr := a.Value _, r.dst, err = net.ParseCIDR(fmt.Sprintf("%d.%d.%d.%d/%d", addr[0], addr[1], addr[2], addr[3], rtmsg.Dst_len)) if err != nil { log.Println("Failed to parse ip addr:", err) return ip, dev, err } case syscall.RTA_GATEWAY: addr := a.Value r.gateway = net.IPv4(addr[0], addr[1], addr[2], addr[3]) case syscall.RTA_OIF: r.if_index = int(a.Value[0]) } } if r.dst == nil { once.Do(func() { def = r set = true }) } else { if r.dst.Contains(ip_mask.IP) { ifce, err := net.InterfaceByIndex(r.if_index) if err != nil { log.Println("Failed to get interface by index:", err) return ip, dev, err } return r.gateway, ifce.Name, nil } } } } if set { ifce, err := net.InterfaceByIndex(def.if_index) if err != nil { log.Println("Failed to get interface by index:", err) return ip, dev, err } return def.gateway, ifce.Name, nil } err = fmt.Errorf("Route not found.") return }
// New creates a new router object. The router returned by New currently does // not update its routes after construction... care should be taken for // long-running programs to call New() regularly to take into account any // changes to the routing table which have occurred since the last New() call. func New() (Router, error) { rtr := &router{} tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC) if err != nil { return nil, err } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { return nil, err } loop: for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: break loop case syscall.RTM_NEWROUTE: rt := (*routeInfoInMemory)(unsafe.Pointer(&m.Data[0])) routeInfo := rtInfo{} attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, err } switch rt.Family { case syscall.AF_INET: rtr.v4 = append(rtr.v4, &routeInfo) case syscall.AF_INET6: rtr.v6 = append(rtr.v6, &routeInfo) default: continue loop } for _, attr := range attrs { switch attr.Attr.Type { case syscall.RTA_DST: routeInfo.Dst = &net.IPNet{ IP: net.IP(attr.Value), Mask: net.CIDRMask(int(rt.DstLen), len(attr.Value)*8), } case syscall.RTA_SRC: routeInfo.Src = &net.IPNet{ IP: net.IP(attr.Value), Mask: net.CIDRMask(int(rt.SrcLen), len(attr.Value)*8), } case syscall.RTA_GATEWAY: routeInfo.Gateway = net.IP(attr.Value) case syscall.RTA_PREFSRC: routeInfo.PrefSrc = net.IP(attr.Value) case syscall.RTA_IIF: routeInfo.InputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0])) case syscall.RTA_OIF: routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0])) case syscall.RTA_PRIORITY: routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0])) } } } } sort.Sort(rtr.v4) sort.Sort(rtr.v6) ifaces, err := net.Interfaces() if err != nil { return nil, err } for i, iface := range ifaces { if i != iface.Index-1 { return nil, fmt.Errorf("out of order iface %d = %v", i, iface) } rtr.ifaces = append(rtr.ifaces, iface) var addrs ipAddrs ifaceAddrs, err := iface.Addrs() if err != nil { return nil, err } for _, addr := range ifaceAddrs { if inet, ok := addr.(*net.IPNet); ok { // Go has a nasty habit of giving you IPv4s as ::ffff:1.2.3.4 instead of 1.2.3.4. // We want to use mapped v4 addresses as v4 preferred addresses, never as v6 // preferred addresses. if v4 := inet.IP.To4(); v4 != nil { if addrs.v4 == nil { addrs.v4 = v4 } } else if addrs.v6 == nil { addrs.v6 = inet.IP } } } rtr.addrs = append(rtr.addrs, addrs) } return rtr, nil }
func MonitorIP() { // Create a Unix socket to listen for NetLink changes fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_ROUTE) if err != nil { fmt.Println("Error creating unix socket:", err) return } defer syscall.Close(fd) // Netlink options sn := syscall.SockaddrNetlink{ Pid: 0, // Pid 0 == KERNEL messages Groups: syscall.RTNLGRP_LINK | syscall.RTNLGRP_IPV4_IFADDR, // Broadcast groups } // Bind to the Socket err = syscall.Bind(fd, &sn) if err != nil { fmt.Println("Binding fd to socket failed") } // Infinite loop to keep listening for changes buff := make([]byte, syscall.Getpagesize()) for { n, _, err := syscall.Recvfrom(fd, buff, 0x00) if err != nil { fmt.Println("Error when receiving from the socket: ", err) } // Incorrect header length, ignore if n < syscall.NLMSG_HDRLEN { continue } msgs, err := syscall.ParseNetlinkMessage(buff[:n]) if err != nil { fmt.Println("Parsing netlink message failed") } // Loop over parsed Netlink messages for _, msg := range msgs { if msg.Header.Type == syscall.NLMSG_ERROR { fmt.Println("Netlink message error!") continue } // Ignore multipart messages if msg.Header.Type == syscall.NLMSG_DONE { continue } // Ignore neighbor messages if msg.Header.Type == syscall.RTM_DELNEIGH || msg.Header.Type == syscall.RTM_NEWNEIGH { continue } fmt.Printf("RECEIVED : %+v \n", msg) if msg.Header.Type == syscall.RTM_NEWLINK { ifMsg := syscall.IfInfomsg{ Family: msg.Data[0], // AF_UNSPEC (always) X__ifi_pad: msg.Data[1], // Reserved Type: binary.LittleEndian.Uint16(msg.Data[2:4]), Index: int32(binary.LittleEndian.Uint32(msg.Data[4:8])), Flags: binary.LittleEndian.Uint32(msg.Data[8:12]), Change: binary.LittleEndian.Uint32(msg.Data[12:16]), // Reserved for future use } // Check if the interface is "administratively" up if ifMsg.Flags&syscall.IFF_UP == 0 { continue } // Check if the interface is operationally up if ifMsg.Flags&syscall.IFF_RUNNING == 0 { continue } //nlAttrs, _ := syscall.ParseNetlinkRouteAttr(&msg) iface, _ := net.InterfaceByIndex(int(ifMsg.Index)) addrs, _ := iface.Addrs() //fmt.Printf("RTM_NEWLINK: %+v \n", ifMsg) //fmt.Printf("RTM_NEWLINK ATTRIBUTES: %+v \n", nlAttrs) //fmt.Printf("RTM_NEWLINK INTERFACE: %+v \n", iface) fmt.Printf("RTM_NEWLINK INTERFACE ADDRS: %+v \n", addrs) if len(addrs) > 0 { fmt.Printf("%s is now available at %s \n", iface.Name, addrs[0].(*net.IPNet).IP) } else { fmt.Printf("No address associated yet with %s \n", iface.Name) } } else { continue } } } }
func NewGenlHub() (*GenlHub, error) { self := &GenlHub{ sock: NlSocketAlloc(), lock: &sync.Mutex{}, familyIds: map[uint16]GenlFamily{ GENL_ID_CTRL: GenlFamilyCtrl, }, groupIds: map[uint32]GenlGroup{ GENL_ID_CTRL: GenlGroup{ Id: GENL_ID_CTRL, Family: "nlctrl", Name: "notify", }, }, unilock: &sync.Mutex{}, multicast: make(map[groupKey][]GenlListener), } if err := NlConnect(self.sock, syscall.NETLINK_GENERIC); err != nil { self.Close() return nil, err } if err := self.Add("nlctrl", "notify", self); err != nil { self.Close() return nil, err } if err := self.Async(GenlFamilyCtrl.DumpRequest(CTRL_CMD_GETFAMILY), self); err != nil { self.Close() return nil, err } go func() { for { buf := make([]byte, syscall.Getpagesize()) if bufN, _, err := syscall.Recvfrom(self.sock.Fd, buf, syscall.MSG_TRUNC); err != nil { if e, ok := err.(syscall.Errno); ok && e.Temporary() { continue } break } else if msgs, err := syscall.ParseNetlinkMessage(buf[:bufN]); err != nil { break } else { for _, msg := range msgs { self.lock.Lock() family := self.familyIds[msg.Header.Type] var multi []GenlListener for gkey, s := range self.multicast { if family.Name == gkey.Family { for _, n := range s { if uniq := func() bool { for _, m := range multi { if m == n { return false } } return true }(); uniq { multi = append(multi, n) } } } } self.lock.Unlock() gmsg := GenlMessage{ NetlinkMessage: msg, Family: family, } if msg.Header.Seq == self.uniseq { if self.unicast != nil { self.unicast.GenlListen(gmsg) } switch msg.Header.Type { case syscall.NLMSG_DONE, syscall.NLMSG_ERROR: self.unilock.Unlock() } } if msg.Header.Seq == 0 { for _, proc := range multi { proc.GenlListen(gmsg) } } } } } log.Print("genl hub loop exit") }() return self, nil }
func GetTaskStats(nlsk *nlgo.NlSock, p int) (t *Taskstats) { nlsk.Flags |= nlgo.NL_NO_AUTO_ACK const familyID = 22 m := &MSG{ Len: 8, Type: TASKSTATS_CMD_ATTR_PID, Pid: uint32(p), } hdr := (*[nlgo.SizeofGenlMsghdr]byte)(unsafe.Pointer(&nlgo.GenlMsghdr{ Cmd: TASKSTATS_CMD_GET, Version: 0, }))[:] req := ((*[8]byte)(unsafe.Pointer(m)))[:] length := 4 pad := ((length + 4 - 1) & (^3)) - length for i := 0; i < pad; i++ { req = append(req, 0) } hdr = append(hdr, req...) nlgo.NlSendSimple(nlsk, familyID, 1, hdr[:]) func() error { for { buf := make([]byte, 16384) if nn, _, err := syscall.Recvfrom(nlsk.Fd, buf, 0); err != nil { return err } else if nn > len(buf) { return nlgo.NLE_MSG_TRUNC } else { buf = buf[:nn] } if msgs, err := syscall.ParseNetlinkMessage(buf); err != nil { return err } else { for _, msg := range msgs { switch msg.Header.Type { case syscall.NLMSG_DONE: return nil case syscall.NLMSG_ERROR: return fmt.Errorf("NlMsgerr=%s", nlgo.NlMsgerr(msg)) case 22: genl := (*nlgo.GenlMsghdr)(unsafe.Pointer(&msg.Data[0])) _ = genl attrs := parse_attributes(msg.Data[nlgo.GENL_HDRLEN:]) for _, attr := range attrs { if attr.Type == TASKSTATS_TYPE_AGGR_PID { attrs = parse_attributes(attr.Data) break } } for _, attr := range attrs { if attr.Type == TASKSTATS_TYPE_STATS { _ = uint32(*(*uint32)(unsafe.Pointer(&attr.Data[248]))) t = (*Taskstats)(unsafe.Pointer(&attr.Data[0])) break } } return nil default: return fmt.Errorf("unexpected NlMsghdr=%s", msg.Header) } } } } }() // if err != nil { // fmt.Println(err, err.Error()) // } return }
// List all available routes on the system. func Routes() ([]*Route, error) { var routes []*Route rib, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC) if err != nil { return nil, fmt.Errorf("Could not retrieve RIB: %s", err) } msgs, err := syscall.ParseNetlinkMessage(rib) if err != nil { return nil, fmt.Errorf("Could not parse messages: %s") } for _, m := range msgs { if m.Header.Type == syscall.NLMSG_DONE { break } if m.Header.Type != syscall.RTM_NEWROUTE { continue } route := &Route{Default: true} rtmsg := (*rtmsg)(unsafe.Pointer(&m.Data[0])) attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, fmt.Errorf("Could not parse attr: %s", err) } for _, a := range attrs { switch a.Attr.Type { case syscall.RTA_SRC: route.SrcNet = &net.IPNet{ IP: net.IP(a.Value), Mask: net.CIDRMask( int(rtmsg.src_len), len(a.Value)*8, ), } case syscall.RTA_DST: route.DstNet = &net.IPNet{ IP: net.IP(a.Value), Mask: net.CIDRMask( int(rtmsg.dst_len), len(a.Value)*8, ), } route.Default = false case syscall.RTA_GATEWAY: route.Gateway = net.IP(a.Value) case syscall.RTA_OIF: oif := *(*uint32)(unsafe.Pointer(&a.Value[0])) iface, err := net.InterfaceByIndex(int(oif)) if err != nil { } route.Iface = iface case syscall.RTA_PRIORITY: } } routes = append(routes, route) } return routes, nil }
func NewGenlHub() (*GenlHub, error) { self := &GenlHub{ sock: NlSocketAlloc(), lock: &sync.Mutex{}, familyIds: map[uint16]GenlFamily{ GENL_ID_CTRL: GenlFamily{ Id: GENL_ID_CTRL, Name: "nlctrl", Version: 1, }, }, groupIds: map[uint32]GenlGroup{ GENL_ID_CTRL: GenlGroup{ Id: GENL_ID_CTRL, Family: "nlctrl", Name: "notify", }, }, unicast: make(map[uint32]chan GenlMessage), multicast: make(map[groupKey][]GenlListener), } if err := NlConnect(self.sock, syscall.NETLINK_GENERIC); err != nil { NlSocketFree(self.sock) return nil, err } go func() { feed := func(msg GenlMessage) { seq := msg.Header.Seq if seq == 0 { // multicast var listeners []GenlListener self.lock.Lock() if family, ok := self.familyIds[msg.Header.Type]; ok { for gkey, ls := range self.multicast { if gkey.Family == family.Name { for _, listener := range ls { if ok := func() bool { // remove duplicate for _, li := range listeners { if li == listener { return false } } return true }(); ok { listeners = append(listeners, listener) } } } } } else { log.Print("got unknown family message") } self.lock.Unlock() for _, listener := range listeners { listener.GenlListen(msg) } } else { self.lock.Lock() listener := self.unicast[seq] self.lock.Unlock() if listener != nil { listener <- msg mtype := msg.Header.Type if mtype == syscall.NLMSG_DONE || mtype == syscall.NLMSG_ERROR { // NlSock.Flags NL_NO_AUTO_ACK is 0 by default self.lock.Lock() delete(self.unicast, seq) self.lock.Unlock() close(listener) } } } } for { buf := make([]byte, syscall.Getpagesize()) if bufN, _, err := syscall.Recvfrom(self.sock.Fd, buf, syscall.MSG_TRUNC); err != nil { if e, ok := err.(syscall.Errno); ok && e.Temporary() { continue } feed(GenlMessage{Error: err}) return } else if bufN > len(buf) { feed(GenlMessage{Error: fmt.Errorf("msg trunc")}) return } else if msgs, err := syscall.ParseNetlinkMessage(buf[:bufN]); err != nil { feed(GenlMessage{Error: err}) return } else { for _, msg := range msgs { switch msg.Header.Type { default: feed(GenlMessage{ Header: msg.Header, Family: self.familyIds[msg.Header.Type].Name, Genl: (*GenlMsghdr)(unsafe.Pointer(&msg.Data[0])), Payload: msg.Data[GENL_HDRLEN:], }) case syscall.NLMSG_ERROR: err := *(*syscall.NlMsgerr)(unsafe.Pointer(&msg.Data[0])) feed(GenlMessage{ Header: msg.Header, Error: MsgError{In: err}, }) case syscall.NLMSG_DONE: feed(GenlMessage{ Header: msg.Header, Genl: nil, Payload: msg.Data, }) } } } } }() self.Add("nlctrl", "notify", self) if res, err := self.Request("nlctrl", CTRL_VERSION, CTRL_CMD_GETFAMILY, syscall.NLM_F_DUMP, nil, nil); err != nil { return nil, err } else { for _, r := range res { self.GenlListen(r) } } return self, nil }
func NewRtHub() (*RtHub, error) { self := &RtHub{ sock: NlSocketAlloc(), lock: &sync.Mutex{}, unicast: make(map[uint32]chan RtMessage), multicast: make(map[uint32][]RtListener), } if err := NlConnect(self.sock, syscall.NETLINK_ROUTE); err != nil { NlSocketFree(self.sock) return nil, err } go func() { for { var merr error var messages []syscall.NetlinkMessage var controls []syscall.SocketControlMessage buf := make([]byte, syscall.Getpagesize()) oob := make([]byte, syscall.Getpagesize()) if bufN, oobN, _, _, err := syscall.Recvmsg(self.sock.Fd, buf, oob, syscall.MSG_TRUNC); err != nil { if e, ok := err.(syscall.Errno); ok && e.Temporary() { continue } merr = err } else if bufN == 0 { break } else if bufN > len(buf) { merr = err } else if oobN > len(oob) { merr = err } else if msgs, err := syscall.ParseNetlinkMessage(buf[:bufN]); err != nil { merr = err } else if ctrls, err := syscall.ParseSocketControlMessage(oob[:oobN]); err != nil { merr = err } else { messages = msgs controls = ctrls } for _, message := range messages { msg := RtMessage{ Message: message, Controls: controls, Error: merr, } seq := message.Header.Seq mtype := message.Header.Type if seq == 0 { var listeners []RtListener self.lock.Lock() for _, s := range self.multicast { listeners = append(listeners, s...) } self.lock.Unlock() for _, listener := range listeners { listener.RtListen(msg) } } else { self.lock.Lock() listener := self.unicast[seq] self.lock.Unlock() if listener != nil { listener <- msg if mtype == syscall.NLMSG_DONE || mtype == syscall.NLMSG_ERROR { delete(self.unicast, seq) close(listener) } } } } } }() return self, nil }