Home | History | Annotate | Download | only in syscall
      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 	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 }
    180