src/pkg/syscall/netlink_linux.go - The Go Programming Language

Golang

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