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 7package syscall 8 9import "unsafe" 10 11// Round the length of a netlink message up to align it properly. 12func 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. 18func 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. 24type NetlinkRouteRequest struct { 25 Header NlMsghdr 26 Data RtGenmsg 27} 28 29func (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 40func 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. 52func 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()) 68done: 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. 109type 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. 116func 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 130func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) { 131 h := (*NlMsghdr)(unsafe.Pointer(&b[0])) 132 l := nlmAlignOf(int(h.Len)) 133 if int(h.Len) < NLMSG_HDRLEN || l > len(b) { 134 return nil, nil, 0, EINVAL 135 } 136 return h, b[NLMSG_HDRLEN:], l, nil 137} 138 139// NetlinkRouteAttr represents a netlink route attribute. 140type NetlinkRouteAttr struct { 141 Attr RtAttr 142 Value []byte 143} 144 145// ParseNetlinkRouteAttr parses m's payload as an array of netlink 146// route attributes and returns the slice containing the 147// NetlinkRouteAttr structures. 148func ParseNetlinkRouteAttr(m *NetlinkMessage) ([]NetlinkRouteAttr, error) { 149 var b []byte 150 switch m.Header.Type { 151 case RTM_NEWLINK, RTM_DELLINK: 152 b = m.Data[SizeofIfInfomsg:] 153 case RTM_NEWADDR, RTM_DELADDR: 154 b = m.Data[SizeofIfAddrmsg:] 155 case RTM_NEWROUTE, RTM_DELROUTE: 156 b = m.Data[SizeofRtMsg:] 157 default: 158 return nil, EINVAL 159 } 160 var attrs []NetlinkRouteAttr 161 for len(b) >= SizeofRtAttr { 162 a, vbuf, alen, err := netlinkRouteAttrAndValue(b) 163 if err != nil { 164 return nil, err 165 } 166 ra := NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-SizeofRtAttr]} 167 attrs = append(attrs, ra) 168 b = b[alen:] 169 } 170 return attrs, nil 171} 172 173func netlinkRouteAttrAndValue(b []byte) (*RtAttr, []byte, int, error) { 174 a := (*RtAttr)(unsafe.Pointer(&b[0])) 175 if int(a.Len) < SizeofRtAttr || int(a.Len) > len(b) { 176 return nil, nil, 0, EINVAL 177 } 178 return a, b[SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil 179} 180