github.com/rafaeltorres324/go/src@v0.0.0-20210519164414-9fdf653a9838/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 := cloexecSocket(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 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. 140 type 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. 148 func 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 173 func 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 }