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 rbNew := make([]byte, Getpagesize()) 68 done: 69 for { 70 rb := rbNew 71 nr, _, err := Recvfrom(s, rb, 0) 72 if err != nil { 73 return nil, err 74 } 75 if nr < NLMSG_HDRLEN { 76 return nil, EINVAL 77 } 78 rb = rb[:nr] 79 tab = append(tab, rb...) 80 msgs, err := ParseNetlinkMessage(rb) 81 if err != nil { 82 return nil, err 83 } 84 for _, m := range msgs { 85 lsa, err := Getsockname(s) 86 if err != nil { 87 return nil, err 88 } 89 switch v := lsa.(type) { 90 case *SockaddrNetlink: 91 if m.Header.Seq != 1 || m.Header.Pid != v.Pid { 92 return nil, EINVAL 93 } 94 default: 95 return nil, EINVAL 96 } 97 if m.Header.Type == NLMSG_DONE { 98 break done 99 } 100 if m.Header.Type == NLMSG_ERROR { 101 return nil, EINVAL 102 } 103 } 104 } 105 return tab, nil 106 } 107 108 // NetlinkMessage represents a netlink message. 109 type NetlinkMessage struct { 110 Header NlMsghdr 111 Data []byte 112 } 113 114 // ParseNetlinkMessage parses b as an array of netlink messages and 115 // returns the slice containing the NetlinkMessage structures. 116 func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) { 117 var msgs []NetlinkMessage 118 for len(b) >= NLMSG_HDRLEN { 119 h, dbuf, dlen, err := netlinkMessageHeaderAndData(b) 120 if err != nil { 121 return nil, err 122 } 123 m := NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-NLMSG_HDRLEN]} 124 msgs = append(msgs, m) 125 b = b[dlen:] 126 } 127 return msgs, nil 128 } 129 130 func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) { 131 h := (*NlMsghdr)(unsafe.Pointer(&b[0])) 132 if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(b) { 133 return nil, nil, 0, EINVAL 134 } 135 return h, b[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil 136 } 137 138 // NetlinkRouteAttr represents a netlink route attribute. 139 type NetlinkRouteAttr struct { 140 Attr RtAttr 141 Value []byte 142 } 143 144 // ParseNetlinkRouteAttr parses m's payload as an array of netlink 145 // route attributes and returns the slice containing the 146 // NetlinkRouteAttr structures. 147 func ParseNetlinkRouteAttr(m *NetlinkMessage) ([]NetlinkRouteAttr, error) { 148 var b []byte 149 switch m.Header.Type { 150 case RTM_NEWLINK, RTM_DELLINK: 151 b = m.Data[SizeofIfInfomsg:] 152 case RTM_NEWADDR, RTM_DELADDR: 153 b = m.Data[SizeofIfAddrmsg:] 154 case RTM_NEWROUTE, RTM_DELROUTE: 155 b = m.Data[SizeofRtMsg:] 156 default: 157 return nil, EINVAL 158 } 159 var attrs []NetlinkRouteAttr 160 for len(b) >= SizeofRtAttr { 161 a, vbuf, alen, err := netlinkRouteAttrAndValue(b) 162 if err != nil { 163 return nil, err 164 } 165 ra := NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-SizeofRtAttr]} 166 attrs = append(attrs, ra) 167 b = b[alen:] 168 } 169 return attrs, nil 170 } 171 172 func netlinkRouteAttrAndValue(b []byte) (*RtAttr, []byte, int, error) { 173 a := (*RtAttr)(unsafe.Pointer(&b[0])) 174 if int(a.Len) < SizeofRtAttr || int(a.Len) > len(b) { 175 return nil, nil, 0, EINVAL 176 } 177 return a, b[SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil 178 } 179