diff options
Diffstat (limited to 'src/syscall/netlink_linux.go')
| -rw-r--r-- | src/syscall/netlink_linux.go | 178 | 
1 files changed, 178 insertions, 0 deletions
| diff --git a/src/syscall/netlink_linux.go b/src/syscall/netlink_linux.go new file mode 100644 index 000000000..1b73dce82 --- /dev/null +++ b/src/syscall/netlink_linux.go @@ -0,0 +1,178 @@ +// Copyright 2011 The Go Authors.  All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Netlink sockets and messages + +package syscall + +import "unsafe" + +// Round the length of a netlink message up to align it properly. +func nlmAlignOf(msglen int) int { +	return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1) +} + +// Round the length of a netlink route attribute up to align it +// properly. +func rtaAlignOf(attrlen int) int { +	return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1) +} + +// NetlinkRouteRequest represents a request message to receive routing +// and link states from the kernel. +type NetlinkRouteRequest struct { +	Header NlMsghdr +	Data   RtGenmsg +} + +func (rr *NetlinkRouteRequest) toWireFormat() []byte { +	b := make([]byte, rr.Header.Len) +	*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len +	*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type +	*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags +	*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq +	*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid +	b[16] = byte(rr.Data.Family) +	return b +} + +func newNetlinkRouteRequest(proto, seq, family int) []byte { +	rr := &NetlinkRouteRequest{} +	rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg) +	rr.Header.Type = uint16(proto) +	rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST +	rr.Header.Seq = uint32(seq) +	rr.Data.Family = uint8(family) +	return rr.toWireFormat() +} + +// NetlinkRIB returns routing information base, as known as RIB, which +// consists of network facility information, states and parameters. +func NetlinkRIB(proto, family int) ([]byte, error) { +	s, err := Socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) +	if err != nil { +		return nil, err +	} +	defer Close(s) +	lsa := &SockaddrNetlink{Family: AF_NETLINK} +	if err := Bind(s, lsa); err != nil { +		return nil, err +	} +	wb := newNetlinkRouteRequest(proto, 1, family) +	if err := Sendto(s, wb, 0, lsa); err != nil { +		return nil, err +	} +	var tab []byte +	rbNew := make([]byte, Getpagesize()) +done: +	for { +		rb := rbNew +		nr, _, err := Recvfrom(s, rb, 0) +		if err != nil { +			return nil, err +		} +		if nr < NLMSG_HDRLEN { +			return nil, EINVAL +		} +		rb = rb[:nr] +		tab = append(tab, rb...) +		msgs, err := ParseNetlinkMessage(rb) +		if err != nil { +			return nil, err +		} +		for _, m := range msgs { +			lsa, err := Getsockname(s) +			if err != nil { +				return nil, err +			} +			switch v := lsa.(type) { +			case *SockaddrNetlink: +				if m.Header.Seq != 1 || m.Header.Pid != v.Pid { +					return nil, EINVAL +				} +			default: +				return nil, EINVAL +			} +			if m.Header.Type == NLMSG_DONE { +				break done +			} +			if m.Header.Type == NLMSG_ERROR { +				return nil, EINVAL +			} +		} +	} +	return tab, nil +} + +// NetlinkMessage represents a netlink message. +type NetlinkMessage struct { +	Header NlMsghdr +	Data   []byte +} + +// ParseNetlinkMessage parses b as an array of netlink messages and +// returns the slice containing the NetlinkMessage structures. +func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) { +	var msgs []NetlinkMessage +	for len(b) >= NLMSG_HDRLEN { +		h, dbuf, dlen, err := netlinkMessageHeaderAndData(b) +		if err != nil { +			return nil, err +		} +		m := NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-NLMSG_HDRLEN]} +		msgs = append(msgs, m) +		b = b[dlen:] +	} +	return msgs, nil +} + +func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) { +	h := (*NlMsghdr)(unsafe.Pointer(&b[0])) +	if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(b) { +		return nil, nil, 0, EINVAL +	} +	return h, b[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil +} + +// NetlinkRouteAttr represents a netlink route attribute. +type NetlinkRouteAttr struct { +	Attr  RtAttr +	Value []byte +} + +// ParseNetlinkRouteAttr parses m's payload as an array of netlink +// route attributes and returns the slice containing the +// NetlinkRouteAttr structures. +func ParseNetlinkRouteAttr(m *NetlinkMessage) ([]NetlinkRouteAttr, error) { +	var b []byte +	switch m.Header.Type { +	case RTM_NEWLINK, RTM_DELLINK: +		b = m.Data[SizeofIfInfomsg:] +	case RTM_NEWADDR, RTM_DELADDR: +		b = m.Data[SizeofIfAddrmsg:] +	case RTM_NEWROUTE, RTM_DELROUTE: +		b = m.Data[SizeofRtMsg:] +	default: +		return nil, EINVAL +	} +	var attrs []NetlinkRouteAttr +	for len(b) >= SizeofRtAttr { +		a, vbuf, alen, err := netlinkRouteAttrAndValue(b) +		if err != nil { +			return nil, err +		} +		ra := NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-SizeofRtAttr]} +		attrs = append(attrs, ra) +		b = b[alen:] +	} +	return attrs, nil +} + +func netlinkRouteAttrAndValue(b []byte) (*RtAttr, []byte, int, error) { +	a := (*RtAttr)(unsafe.Pointer(&b[0])) +	if int(a.Len) < SizeofRtAttr || int(a.Len) > len(b) { +		return nil, nil, 0, EINVAL +	} +	return a, b[SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil +} | 
