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