...

Source file src/syscall/netlink_linux.go

     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	

View as plain text