github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/syscall/netlink_linux.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Netlink sockets and messages 6 7 package syscall 8 9 import "unsafe" 10 11 // Round the length of a netlink message up to align it properly. 12 func nlmAlignOf(msglen int) int { 13 return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1) 14 } 15 16 // Round the length of a netlink route attribute up to align it 17 // properly. 18 func rtaAlignOf(attrlen int) int { 19 return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1) 20 } 21 22 // NetlinkRouteRequest represents a request message to receive routing 23 // and link states from the kernel. 24 type NetlinkRouteRequest struct { 25 Header NlMsghdr 26 Data RtGenmsg 27 } 28 29 func (rr *NetlinkRouteRequest) toWireFormat() []byte { 30 b := make([]byte, rr.Header.Len) 31 *(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len 32 *(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type 33 *(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags 34 *(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq 35 *(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid 36 b[16] = byte(rr.Data.Family) 37 return b 38 } 39 40 func newNetlinkRouteRequest(proto, seq, family int) []byte { 41 rr := &NetlinkRouteRequest{} 42 rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg) 43 rr.Header.Type = uint16(proto) 44 rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST 45 rr.Header.Seq = uint32(seq) 46 rr.Data.Family = uint8(family) 47 return rr.toWireFormat() 48 } 49 50 // NetlinkRIB returns routing information base, as known as RIB, which 51 // consists of network facility information, states and parameters. 52 func NetlinkRIB(proto, family int) ([]byte, error) { 53 s, err := Socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) 54 if err != nil { 55 return nil, err 56 } 57 defer Close(s) 58 lsa := &SockaddrNetlink{Family: AF_NETLINK} 59 if err := Bind(s, lsa); err != nil { 60 return nil, err 61 } 62 wb := newNetlinkRouteRequest(proto, 1, family) 63 if err := Sendto(s, wb, 0, lsa); err != nil { 64 return nil, err 65 } 66 var tab []byte 67 done: 68 for { 69 rb := make([]byte, Getpagesize()) 70 nr, _, err := Recvfrom(s, rb, 0) 71 if err != nil { 72 return nil, err 73 } 74 if nr < NLMSG_HDRLEN { 75 return nil, EINVAL 76 } 77 rb = rb[:nr] 78 tab = append(tab, rb...) 79 msgs, err := ParseNetlinkMessage(rb) 80 if err != nil { 81 return nil, err 82 } 83 for _, m := range msgs { 84 lsa, err := Getsockname(s) 85 if err != nil { 86 return nil, err 87 } 88 switch v := lsa.(type) { 89 case *SockaddrNetlink: 90 if m.Header.Seq != 1 || m.Header.Pid != v.Pid { 91 return nil, EINVAL 92 } 93 default: 94 return nil, EINVAL 95 } 96 if m.Header.Type == NLMSG_DONE { 97 break done 98 } 99 if m.Header.Type == NLMSG_ERROR { 100 return nil, EINVAL 101 } 102 } 103 } 104 return tab, nil 105 } 106 107 // NetlinkMessage represents a netlink message. 108 type NetlinkMessage struct { 109 Header NlMsghdr 110 Data []byte 111 } 112 113 // ParseNetlinkMessage parses b as an array of netlink messages and 114 // returns the slice containing the NetlinkMessage structures. 115 func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) { 116 var msgs []NetlinkMessage 117 for len(b) >= NLMSG_HDRLEN { 118 h, dbuf, dlen, err := netlinkMessageHeaderAndData(b) 119 if err != nil { 120 return nil, err 121 } 122 m := NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-NLMSG_HDRLEN]} 123 msgs = append(msgs, m) 124 b = b[dlen:] 125 } 126 return msgs, nil 127 } 128 129 func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) { 130 h := (*NlMsghdr)(unsafe.Pointer(&b[0])) 131 if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(b) { 132 return nil, nil, 0, EINVAL 133 } 134 return h, b[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil 135 } 136 137 // NetlinkRouteAttr represents a netlink route attribute. 138 type NetlinkRouteAttr struct { 139 Attr RtAttr 140 Value []byte 141 } 142 143 // ParseNetlinkRouteAttr parses m's payload as an array of netlink 144 // route attributes and returns the slice containing the 145 // NetlinkRouteAttr structures. 146 func ParseNetlinkRouteAttr(m *NetlinkMessage) ([]NetlinkRouteAttr, error) { 147 var b []byte 148 switch m.Header.Type { 149 case RTM_NEWLINK, RTM_DELLINK: 150 b = m.Data[SizeofIfInfomsg:] 151 case RTM_NEWADDR, RTM_DELADDR: 152 b = m.Data[SizeofIfAddrmsg:] 153 case RTM_NEWROUTE, RTM_DELROUTE: 154 b = m.Data[SizeofRtMsg:] 155 default: 156 return nil, EINVAL 157 } 158 var attrs []NetlinkRouteAttr 159 for len(b) >= SizeofRtAttr { 160 a, vbuf, alen, err := netlinkRouteAttrAndValue(b) 161 if err != nil { 162 return nil, err 163 } 164 ra := NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-SizeofRtAttr]} 165 attrs = append(attrs, ra) 166 b = b[alen:] 167 } 168 return attrs, nil 169 } 170 171 func netlinkRouteAttrAndValue(b []byte) (*RtAttr, []byte, int, error) { 172 a := (*RtAttr)(unsafe.Pointer(&b[0])) 173 if int(a.Len) < SizeofRtAttr || int(a.Len) > len(b) { 174 return nil, nil, 0, EINVAL 175 } 176 return a, b[SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil 177 }