From d84873727f7679b2d782ecd27f3cc8ecd365457f Mon Sep 17 00:00:00 2001 From: Matt Layher Date: Tue, 14 Aug 2018 15:15:07 -0400 Subject: [PATCH] vendor: bump github.com/mdlayher/wifi and dependencies (#1045) Signed-off-by: Matt Layher --- vendor/github.com/mdlayher/genetlink/conn.go | 10 + .../mdlayher/genetlink/family_linux.go | 94 ++++---- .../github.com/mdlayher/netlink/attribute.go | 222 ++++++++++++++---- vendor/github.com/mdlayher/netlink/conn.go | 192 ++++++++++++--- .../github.com/mdlayher/netlink/conn_linux.go | 90 ++++++- .../mdlayher/netlink/conn_others.go | 53 +---- vendor/github.com/mdlayher/netlink/debug.go | 71 ++++++ vendor/github.com/mdlayher/netlink/doc.go | 20 ++ .../mdlayher/netlink/nlenc/endian.go | 16 ++ vendor/vendor.json | 22 +- 10 files changed, 608 insertions(+), 182 deletions(-) create mode 100644 vendor/github.com/mdlayher/netlink/debug.go create mode 100644 vendor/github.com/mdlayher/netlink/nlenc/endian.go diff --git a/vendor/github.com/mdlayher/genetlink/conn.go b/vendor/github.com/mdlayher/genetlink/conn.go index 27529829..019d43fd 100644 --- a/vendor/github.com/mdlayher/genetlink/conn.go +++ b/vendor/github.com/mdlayher/genetlink/conn.go @@ -67,6 +67,16 @@ func (c *Conn) SetBPF(filter []bpf.RawInstruction) error { return c.c.SetBPF(filter) } +// RemoveBPF removes a BPF filter from a Conn. +func (c *Conn) RemoveBPF() error { + return c.c.RemoveBPF() +} + +// SetOption enables or disables a netlink socket option for the Conn. +func (c *Conn) SetOption(option netlink.ConnOption, enable bool) error { + return c.c.SetOption(option, enable) +} + // Send sends a single Message to netlink, wrapping it in a netlink.Message // using the specified generic netlink family and flags. On success, Send // returns a copy of the netlink.Message with all parameters populated, for diff --git a/vendor/github.com/mdlayher/genetlink/family_linux.go b/vendor/github.com/mdlayher/genetlink/family_linux.go index 66fd4b10..9b8f0d6f 100644 --- a/vendor/github.com/mdlayher/genetlink/family_linux.go +++ b/vendor/github.com/mdlayher/genetlink/family_linux.go @@ -16,10 +16,6 @@ var ( // errInvalidFamilyVersion is returned when a family's version is greater // than an 8-bit integer. errInvalidFamilyVersion = errors.New("invalid family version attribute") - - // errInvalidMulticastGroupArray is returned when a multicast group array - // of attributes is malformed. - errInvalidMulticastGroupArray = errors.New("invalid multicast group attribute array") ) // getFamily retrieves a generic netlink family with the specified name. @@ -85,13 +81,8 @@ func (c *Conn) listFamilies() ([]Family, error) { func buildFamilies(msgs []Message) ([]Family, error) { families := make([]Family, 0, len(msgs)) for _, m := range msgs { - attrs, err := netlink.UnmarshalAttributes(m.Data) - if err != nil { - return nil, err - } - var f Family - if err := (&f).parseAttributes(attrs); err != nil { + if err := (&f).parseAttributes(m.Data); err != nil { return nil, err } @@ -101,66 +92,79 @@ func buildFamilies(msgs []Message) ([]Family, error) { return families, nil } -// parseAttributes parses netlink attributes into a Family's fields. -func (f *Family) parseAttributes(attrs []netlink.Attribute) error { - for _, a := range attrs { - switch a.Type { +// parseAttributes decodes netlink attributes into a Family's fields. +func (f *Family) parseAttributes(b []byte) error { + ad, err := netlink.NewAttributeDecoder(b) + if err != nil { + return err + } + + for ad.Next() { + switch ad.Type() { case unix.CTRL_ATTR_FAMILY_ID: - f.ID = nlenc.Uint16(a.Data) + f.ID = ad.Uint16() case unix.CTRL_ATTR_FAMILY_NAME: - f.Name = nlenc.String(a.Data) + f.Name = ad.String() case unix.CTRL_ATTR_VERSION: - v := nlenc.Uint32(a.Data) + v := ad.Uint32() if v > math.MaxUint8 { return errInvalidFamilyVersion } f.Version = uint8(v) case unix.CTRL_ATTR_MCAST_GROUPS: - groups, err := parseMulticastGroups(a.Data) - if err != nil { - return err - } - - f.Groups = groups + ad.Do(func(b []byte) error { + groups, err := parseMulticastGroups(b) + if err != nil { + return err + } + + f.Groups = groups + return nil + }) } } - return nil + return ad.Err() } // parseMulticastGroups parses an array of multicast group nested attributes // into a slice of MulticastGroups. func parseMulticastGroups(b []byte) ([]MulticastGroup, error) { - attrs, err := netlink.UnmarshalAttributes(b) + ad, err := netlink.NewAttributeDecoder(b) if err != nil { return nil, err } - groups := make([]MulticastGroup, 0, len(attrs)) - for i, a := range attrs { - // The type attribute is essentially an array index here; it starts - // at 1 and should increment for each new array element - if int(a.Type) != i+1 { - return nil, errInvalidMulticastGroupArray - } + var groups []MulticastGroup + for ad.Next() { + ad.Do(func(b []byte) error { + adi, err := netlink.NewAttributeDecoder(b) + if err != nil { + return err + } - nattrs, err := netlink.UnmarshalAttributes(a.Data) - if err != nil { - return nil, err - } + var g MulticastGroup + for adi.Next() { + switch adi.Type() { + case unix.CTRL_ATTR_MCAST_GRP_NAME: + g.Name = adi.String() + case unix.CTRL_ATTR_MCAST_GRP_ID: + g.ID = adi.Uint32() + } + } - var g MulticastGroup - for _, na := range nattrs { - switch na.Type { - case unix.CTRL_ATTR_MCAST_GRP_NAME: - g.Name = nlenc.String(na.Data) - case unix.CTRL_ATTR_MCAST_GRP_ID: - g.ID = nlenc.Uint32(na.Data) + if err := ad.Err(); err != nil { + return err } - } - groups = append(groups, g) + groups = append(groups, g) + return nil + }) + } + + if err := ad.Err(); err != nil { + return nil, err } return groups, nil diff --git a/vendor/github.com/mdlayher/netlink/attribute.go b/vendor/github.com/mdlayher/netlink/attribute.go index d06af475..2443c6ec 100644 --- a/vendor/github.com/mdlayher/netlink/attribute.go +++ b/vendor/github.com/mdlayher/netlink/attribute.go @@ -1,7 +1,9 @@ package netlink import ( + "encoding/binary" "errors" + "fmt" "github.com/mdlayher/netlink/nlenc" ) @@ -9,9 +11,6 @@ import ( var ( // errInvalidAttribute specifies if an Attribute's length is incorrect. errInvalidAttribute = errors.New("invalid attribute; length too short or too large") - // errInvalidAttributeFlags specifies if an Attribute's flag configuration is invalid. - // From a comment in Linux/include/uapi/linux/netlink.h, Nested and NetByteOrder are mutually exclusive. - errInvalidAttributeFlags = errors.New("invalid attribute; type cannot have both nested and net byte order flags") ) // An Attribute is a netlink attribute. Attributes are packed and unpacked @@ -25,48 +24,18 @@ type Attribute struct { // An arbitrary payload which is specified by Type. Data []byte - - // Whether the attribute's data contains nested attributes. Note that not - // all netlink families set this value. The programmer should consult - // documentation and inspect an attribute's data to determine if nested - // attributes are present. - Nested bool - - // Whether the attribute's data is in network (true) or native (false) byte order. - NetByteOrder bool } -// #define NLA_F_NESTED -const nlaNested uint16 = 0x8000 - -// #define NLA_F_NET_BYTE_ORDER -const nlaNetByteOrder uint16 = 0x4000 - -// Masks all bits except for Nested and NetByteOrder. -const nlaTypeMask = ^(nlaNested | nlaNetByteOrder) - // MarshalBinary marshals an Attribute into a byte slice. func (a Attribute) MarshalBinary() ([]byte, error) { if int(a.Length) < nlaHeaderLen { return nil, errInvalidAttribute } - if a.NetByteOrder && a.Nested { - return nil, errInvalidAttributeFlags - } - b := make([]byte, nlaAlign(int(a.Length))) nlenc.PutUint16(b[0:2], a.Length) - - switch { - case a.Nested: - nlenc.PutUint16(b[2:4], a.Type|nlaNested) - case a.NetByteOrder: - nlenc.PutUint16(b[2:4], a.Type|nlaNetByteOrder) - default: - nlenc.PutUint16(b[2:4], a.Type) - } + nlenc.PutUint16(b[2:4], a.Type) copy(b[nlaHeaderLen:], a.Data) @@ -80,22 +49,12 @@ func (a *Attribute) UnmarshalBinary(b []byte) error { } a.Length = nlenc.Uint16(b[0:2]) - - // Only hold the rightmost 14 bits in Type - a.Type = nlenc.Uint16(b[2:4]) & nlaTypeMask - - // Boolean flags extracted from the two leftmost bits of Type - a.Nested = (nlenc.Uint16(b[2:4]) & nlaNested) > 0 - a.NetByteOrder = (nlenc.Uint16(b[2:4]) & nlaNetByteOrder) > 0 + a.Type = nlenc.Uint16(b[2:4]) if nlaAlign(int(a.Length)) > len(b) { return errInvalidAttribute } - if a.NetByteOrder && a.Nested { - return errInvalidAttributeFlags - } - switch { // No length, no data case a.Length == 0: @@ -139,6 +98,9 @@ func MarshalAttributes(attrs []Attribute) ([]byte, error) { } // UnmarshalAttributes unpacks a slice of Attributes from a single byte slice. +// +// It is recommend to use the AttributeDecoder type where possible instead of calling +// UnmarshalAttributes and using package nlenc functions directly. func UnmarshalAttributes(b []byte) ([]Attribute, error) { var attrs []Attribute var i int @@ -164,3 +126,173 @@ func UnmarshalAttributes(b []byte) ([]Attribute, error) { return attrs, nil } + +// An AttributeDecoder provides a safe, iterator-like, API around attribute +// decoding. +// +// It is recommend to use an AttributeDecoder where possible instead of calling +// UnmarshalAttributes and using package nlenc functions directly. +// +// The Err method must be called after the Next method returns false to determine +// if any errors occurred during iteration. +type AttributeDecoder struct { + // ByteOrder defines a specific byte order to use when processing integer + // attributes. ByteOrder should be set immediately after creating the + // AttributeDecoder: before any attributes are parsed. + // + // If not set, the native byte order will be used. + ByteOrder binary.ByteOrder + + // The attributes being worked on, and the iterator index into the slice of + // attributes. + attrs []Attribute + i int + + // Any error encountered while decoding attributes. + err error +} + +// NewAttributeDecoder creates an AttributeDecoder that unpacks Attributes +// from b and prepares the decoder for iteration. +func NewAttributeDecoder(b []byte) (*AttributeDecoder, error) { + attrs, err := UnmarshalAttributes(b) + if err != nil { + return nil, err + } + + return &AttributeDecoder{ + // By default, use native byte order. + ByteOrder: nlenc.NativeEndian(), + + attrs: attrs, + }, nil +} + +// Next advances the decoder to the next netlink attribute. It returns false +// when no more attributes are present, or an error was encountered. +func (ad *AttributeDecoder) Next() bool { + if ad.err != nil { + // Hit an error, stop iteration. + return false + } + + ad.i++ + + if len(ad.attrs) < ad.i { + // No more attributes, stop iteration. + return false + } + + return true +} + +// Type returns the Attribute.Type field of the current netlink attribute +// pointed to by the decoder. +func (ad *AttributeDecoder) Type() uint16 { + return ad.attr().Type +} + +// attr returns the current Attribute pointed to by the decoder. +func (ad *AttributeDecoder) attr() Attribute { + return ad.attrs[ad.i-1] +} + +// data returns the Data field of the current Attribute pointed to by the decoder. +func (ad *AttributeDecoder) data() []byte { + return ad.attr().Data +} + +// Err returns the first error encountered by the decoder. +func (ad *AttributeDecoder) Err() error { + return ad.err +} + +// String returns the string representation of the current Attribute's data. +func (ad *AttributeDecoder) String() string { + if ad.err != nil { + return "" + } + + return nlenc.String(ad.data()) +} + +// Uint8 returns the uint8 representation of the current Attribute's data. +func (ad *AttributeDecoder) Uint8() uint8 { + if ad.err != nil { + return 0 + } + + b := ad.data() + if len(b) != 1 { + ad.err = fmt.Errorf("netlink: attribute %d is not a uint8; length: %d", ad.Type(), len(b)) + return 0 + } + + return uint8(b[0]) +} + +// Uint16 returns the uint16 representation of the current Attribute's data. +func (ad *AttributeDecoder) Uint16() uint16 { + if ad.err != nil { + return 0 + } + + b := ad.data() + if len(b) != 2 { + ad.err = fmt.Errorf("netlink: attribute %d is not a uint16; length: %d", ad.Type(), len(b)) + return 0 + } + + return ad.ByteOrder.Uint16(b) +} + +// Uint32 returns the uint32 representation of the current Attribute's data. +func (ad *AttributeDecoder) Uint32() uint32 { + if ad.err != nil { + return 0 + } + + b := ad.data() + if len(b) != 4 { + ad.err = fmt.Errorf("netlink: attribute %d is not a uint32; length: %d", ad.Type(), len(b)) + return 0 + } + + return ad.ByteOrder.Uint32(b) +} + +// Uint64 returns the uint64 representation of the current Attribute's data. +func (ad *AttributeDecoder) Uint64() uint64 { + if ad.err != nil { + return 0 + } + + b := ad.data() + if len(b) != 8 { + ad.err = fmt.Errorf("netlink: attribute %d is not a uint64; length: %d", ad.Type(), len(b)) + return 0 + } + + return ad.ByteOrder.Uint64(b) +} + +// Do is a general purpose function which allows access to the current data +// pointed to by the AttributeDecoder. +// +// Do can be used to allow parsing arbitrary data within the context of the +// decoder. Do is most useful when dealing with nested attributes, attribute +// arrays, or decoding arbitrary types (such as C structures) which don't fit +// cleanly into a typical unsigned integer value. +// +// The function fn should not retain any reference to the data b outside of the +// scope of the function. +func (ad *AttributeDecoder) Do(fn func(b []byte) error) { + if ad.err != nil { + return + } + + b := ad.data() + if err := fn(b); err != nil { + ad.err = err + } +} diff --git a/vendor/github.com/mdlayher/netlink/conn.go b/vendor/github.com/mdlayher/netlink/conn.go index 5b29fd92..ec396254 100644 --- a/vendor/github.com/mdlayher/netlink/conn.go +++ b/vendor/github.com/mdlayher/netlink/conn.go @@ -6,6 +6,7 @@ import ( "math/rand" "os" "sync/atomic" + "time" "golang.org/x/net/bpf" ) @@ -23,6 +24,7 @@ var ( errReadWriteCloserNotSupported = errors.New("raw read/write/closer not supported") errMulticastGroupsNotSupported = errors.New("multicast groups not supported") errBPFFiltersNotSupported = errors.New("BPF filters not supported") + errOptionsNotSupported = errors.New("options not supported") ) // A Conn is a connection to netlink. A Conn can be used to send and @@ -42,6 +44,9 @@ type Conn struct { // pid is the PID assigned by netlink. pid uint32 + + // d provides debugging capabilities for a Conn if not nil. + d *debugger } // A Socket is an operating-system specific implementation of netlink @@ -49,6 +54,7 @@ type Conn struct { type Socket interface { Close() error Send(m Message) error + SendMessages(m []Message) error Receive() ([]Message, error) } @@ -71,13 +77,31 @@ func Dial(family int, config *Config) (*Conn, error) { // NewConn is primarily useful for tests. Most applications should use // Dial instead. func NewConn(c Socket, pid uint32) *Conn { - seq := rand.Uint32() + // Seed the sequence number using a random number generator. + r := rand.New(rand.NewSource(time.Now().UnixNano())) + seq := r.Uint32() + + // Configure a debugger if arguments are set. + var d *debugger + if len(debugArgs) > 0 { + d = newDebugger(debugArgs) + } return &Conn{ sock: c, seq: &seq, pid: pid, + d: d, + } +} + +// debug executes fn with the debugger if the debugger is not nil. +func (c *Conn) debug(fn func(d *debugger)) { + if c.d == nil { + return } + + fn(c.d) } // Close closes the connection. @@ -109,6 +133,51 @@ func (c *Conn) Execute(m Message) ([]Message, error) { return replies, nil } +func (c *Conn) fixMsg(m *Message, ml int) { + if m.Header.Length == 0 { + m.Header.Length = uint32(nlmsgAlign(ml)) + } + + if m.Header.Sequence == 0 { + m.Header.Sequence = c.nextSequence() + } + + if m.Header.PID == 0 { + m.Header.PID = c.pid + } +} + +// SendMessages sends multiple Messages to netlink. The handling of +// m.Header.Length, Sequence and PID is the same as when calling Send. +func (c *Conn) SendMessages(messages []Message) ([]Message, error) { + for idx, m := range messages { + ml := nlmsgLength(len(m.Data)) + + // TODO(mdlayher): fine-tune this limit. + if ml > (1024 * 32) { + return nil, errors.New("netlink message data too large") + } + + c.fixMsg(&messages[idx], ml) + } + + c.debug(func(d *debugger) { + for _, m := range messages { + d.debugf(1, "send msgs: %+v", m) + } + }) + + if err := c.sock.SendMessages(messages); err != nil { + c.debug(func(d *debugger) { + d.debugf(1, "send msgs: err: %v", err) + }) + + return nil, err + } + + return messages, nil +} + // Send sends a single Message to netlink. In most cases, m.Header's Length, // Sequence, and PID fields should be set to 0, so they can be populated // automatically before the Message is sent. On success, Send returns a copy @@ -130,19 +199,17 @@ func (c *Conn) Send(m Message) (Message, error) { return Message{}, errors.New("netlink message data too large") } - if m.Header.Length == 0 { - m.Header.Length = uint32(nlmsgAlign(ml)) - } + c.fixMsg(&m, ml) - if m.Header.Sequence == 0 { - m.Header.Sequence = c.nextSequence() - } - - if m.Header.PID == 0 { - m.Header.PID = c.pid - } + c.debug(func(d *debugger) { + d.debugf(1, "send: %+v", m) + }) if err := c.sock.Send(m); err != nil { + c.debug(func(d *debugger) { + d.debugf(1, "send: err: %v", err) + }) + return Message{}, err } @@ -157,9 +224,19 @@ func (c *Conn) Send(m Message) (Message, error) { func (c *Conn) Receive() ([]Message, error) { msgs, err := c.receive() if err != nil { + c.debug(func(d *debugger) { + d.debugf(1, "recv: err: %v", err) + }) + return nil, err } + c.debug(func(d *debugger) { + for _, m := range msgs { + d.debugf(1, "recv: %+v", m) + } + }) + // When using nltest, it's possible for zero messages to be returned by receive. if len(msgs) == 0 { return msgs, nil @@ -177,37 +254,40 @@ func (c *Conn) Receive() ([]Message, error) { // receive is the internal implementation of Conn.Receive, which can be called // recursively to handle multi-part messages. func (c *Conn) receive() ([]Message, error) { - msgs, err := c.sock.Receive() - if err != nil { - return nil, err - } + var res []Message + for { + msgs, err := c.sock.Receive() + if err != nil { + return nil, err + } - // If this message is multi-part, we will need to perform an recursive call - // to continue draining the socket - var multi bool + // If this message is multi-part, we will need to perform an recursive call + // to continue draining the socket + var multi bool - for _, m := range msgs { - // Is this a multi-part message and is it not done yet? - if m.Header.Flags&HeaderFlagsMulti != 0 && m.Header.Type != HeaderTypeDone { - multi = true - } + for _, m := range msgs { + if err := checkMessage(m); err != nil { + return nil, err + } - if err := checkMessage(m); err != nil { - return nil, err + // Does this message indicate a multi-part message? + if m.Header.Flags&HeaderFlagsMulti == 0 { + // No, check the next messages. + continue + } + + // Does this message indicate the last message in a series of + // multi-part messages from a single read? + multi = m.Header.Type != HeaderTypeDone } - } - if !multi { - return msgs, nil - } + res = append(res, msgs...) - // More messages waiting - mmsgs, err := c.receive() - if err != nil { - return nil, err + if !multi { + // No more messages coming. + return res, nil + } } - - return append(msgs, mmsgs...), nil } // An fder is a Socket that supports retrieving its raw file descriptor. @@ -283,10 +363,11 @@ func (c *Conn) LeaveGroup(group uint32) error { return gc.LeaveGroup(group) } -// A bpfSetter is a Socket that supports setting BPF filters. +// A bpfSetter is a Socket that supports setting and removing BPF filters. type bpfSetter interface { Socket bpf.Setter + RemoveBPF() error } // SetBPF attaches an assembled BPF program to a Conn. @@ -299,6 +380,45 @@ func (c *Conn) SetBPF(filter []bpf.RawInstruction) error { return bc.SetBPF(filter) } +// RemoveBPF removes a BPF filter from a Conn. +func (c *Conn) RemoveBPF() error { + s, ok := c.sock.(bpfSetter) + if !ok { + return errBPFFiltersNotSupported + } + + return s.RemoveBPF() +} + +// A ConnOption is a boolean option that may be set for a Conn. +type ConnOption int + +// Possible ConnOption values. These constants are equivalent to the Linux +// setsockopt boolean options for netlink sockets. +const ( + PacketInfo ConnOption = iota + BroadcastError + NoENOBUFS + ListenAllNSID + CapAcknowledge +) + +// An optionSetter is a Socket that supports setting netlink options. +type optionSetter interface { + Socket + SetOption(option ConnOption, enable bool) error +} + +// SetOption enables or disables a netlink socket option for the Conn. +func (c *Conn) SetOption(option ConnOption, enable bool) error { + fc, ok := c.sock.(optionSetter) + if !ok { + return errOptionsNotSupported + } + + return fc.SetOption(option, enable) +} + // nextSequence atomically increments Conn's sequence number and returns // the incremented value. func (c *Conn) nextSequence() uint32 { diff --git a/vendor/github.com/mdlayher/netlink/conn_linux.go b/vendor/github.com/mdlayher/netlink/conn_linux.go index 2c9e38a1..691e30a1 100644 --- a/vendor/github.com/mdlayher/netlink/conn_linux.go +++ b/vendor/github.com/mdlayher/netlink/conn_linux.go @@ -94,6 +94,25 @@ func bind(s socket, config *Config) (*conn, uint32, error) { }, pid, nil } +// SendMessages serializes multiple Messages and sends them to netlink. +func (c *conn) SendMessages(messages []Message) error { + var buf []byte + for _, m := range messages { + b, err := m.MarshalBinary() + if err != nil { + return err + } + + buf = append(buf, b...) + } + + addr := &unix.SockaddrNetlink{ + Family: unix.AF_NETLINK, + } + + return c.s.Sendmsg(buf, nil, addr, 0) +} + // Send sends a single Message to netlink. func (c *conn) Send(m Message) error { b, err := m.MarshalBinary() @@ -112,7 +131,10 @@ func (c *conn) Send(m Message) error { func (c *conn) Receive() ([]Message, error) { b := make([]byte, os.Getpagesize()) for { - // Peek at the buffer to see how many bytes are available + // Peek at the buffer to see how many bytes are available. + // + // TODO(mdlayher): deal with OOB message data if available, such as + // when PacketInfo ConnOption is true. n, _, _, _, err := c.s.Recvmsg(b, nil, unix.MSG_PEEK) if err != nil { return nil, err @@ -204,6 +226,58 @@ func (c *conn) SetBPF(filter []bpf.RawInstruction) error { ) } +// RemoveBPF removes a BPF filter from a conn. +func (c *conn) RemoveBPF() error { + // dummy is ignored as argument to SO_DETACH_FILTER + // but SetSockopt requires it as an argument + var dummy uint32 + return c.s.SetSockopt( + unix.SOL_SOCKET, + unix.SO_DETACH_FILTER, + unsafe.Pointer(&dummy), + uint32(unsafe.Sizeof(dummy)), + ) +} + +// SetOption enables or disables a netlink socket option for the Conn. +func (c *conn) SetOption(option ConnOption, enable bool) error { + o, ok := linuxOption(option) + if !ok { + // Return the typical Linux error for an unknown ConnOption. + return unix.ENOPROTOOPT + } + + var v uint32 + if enable { + v = 1 + } + + return c.s.SetSockopt( + unix.SOL_NETLINK, + o, + unsafe.Pointer(&v), + uint32(unsafe.Sizeof(v)), + ) +} + +// linuxOption converts a ConnOption to its Linux value. +func linuxOption(o ConnOption) (int, bool) { + switch o { + case PacketInfo: + return unix.NETLINK_PKTINFO, true + case BroadcastError: + return unix.NETLINK_BROADCAST_ERROR, true + case NoENOBUFS: + return unix.NETLINK_NO_ENOBUFS, true + case ListenAllNSID: + return unix.NETLINK_LISTEN_ALL_NSID, true + case CapAcknowledge: + return unix.NETLINK_CAP_ACK, true + default: + return 0, false + } +} + // sysToHeader converts a syscall.NlMsghdr to a Header. func sysToHeader(r syscall.NlMsghdr) Header { // NB: the memory layout of Header and syscall.NlMsgHdr must be @@ -247,10 +321,20 @@ func newSysSocket(lockThread bool) *sysSocket { // But since this is very experimental, we'll leave it as a configurable at // this point. if lockThread { - // Never unlock the OS thread, so that the thread will terminate when - // the goroutine exits starting in Go 1.10: + // The intent is to never unlock the OS thread, so that the thread + // will terminate when the goroutine exits starting in Go 1.10: // https://go-review.googlesource.com/c/go/+/46038. + // + // However, due to recent instability and a potential bad interaction + // with the Go runtime for threads which are not unlocked, we have + // elected to temporarily unlock the thread: + // https://github.com/golang/go/issues/25128#issuecomment-410764489. + // + // If we ever allow a Conn to set its own network namespace, we must + // either ensure that the namespace is restored on exit here or that + // the thread is properly terminated at some point in the future. runtime.LockOSThread() + defer runtime.UnlockOSThread() } defer wg.Done() diff --git a/vendor/github.com/mdlayher/netlink/conn_others.go b/vendor/github.com/mdlayher/netlink/conn_others.go index de94a96f..447aaa5f 100644 --- a/vendor/github.com/mdlayher/netlink/conn_others.go +++ b/vendor/github.com/mdlayher/netlink/conn_others.go @@ -5,14 +5,12 @@ package netlink import ( "fmt" "runtime" - - "golang.org/x/net/bpf" ) var ( // errUnimplemented is returned by all functions on platforms that // cannot make use of netlink sockets. - errUnimplemented = fmt.Errorf("netlink sockets not implemented on %s/%s", + errUnimplemented = fmt.Errorf("netlink: not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) ) @@ -21,42 +19,13 @@ var _ Socket = &conn{} // A conn is the no-op implementation of a netlink sockets connection. type conn struct{} -// dial is the entry point for Dial. dial always returns an error. -func dial(family int, config *Config) (*conn, uint32, error) { - return nil, 0, errUnimplemented -} - -// Send always returns an error. -func (c *conn) Send(m Message) error { - return errUnimplemented -} - -// Receive always returns an error. -func (c *conn) Receive() ([]Message, error) { - return nil, errUnimplemented -} - -// Close always returns an error. -func (c *conn) Close() error { - return errUnimplemented -} - -// JoinGroup always returns an error. -func (c *conn) JoinGroup(group uint32) error { - return errUnimplemented -} - -// LeaveGroup always returns an error. -func (c *conn) LeaveGroup(group uint32) error { - return errUnimplemented -} - -// SetBPF always returns an error. -func (c *conn) SetBPF(filter []bpf.RawInstruction) error { - return errUnimplemented -} - -// newError always returns an error. -func newError(errno int) error { - return errUnimplemented -} +// All cross-platform functions and Socket methods are unimplemented outside +// of Linux. + +func dial(_ int, _ *Config) (*conn, uint32, error) { return nil, 0, errUnimplemented } +func newError(_ int) error { return errUnimplemented } + +func (c *conn) Send(_ Message) error { return errUnimplemented } +func (c *conn) SendMessages(_ []Message) error { return errUnimplemented } +func (c *conn) Receive() ([]Message, error) { return nil, errUnimplemented } +func (c *conn) Close() error { return errUnimplemented } diff --git a/vendor/github.com/mdlayher/netlink/debug.go b/vendor/github.com/mdlayher/netlink/debug.go new file mode 100644 index 00000000..3d2e05a8 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/debug.go @@ -0,0 +1,71 @@ +package netlink + +import ( + "fmt" + "log" + "os" + "strconv" + "strings" +) + +var ( + // Arguments used to create a debugger. + debugArgs []string +) + +func init() { + // Is netlink debugging enabled? + s := os.Getenv("NLDEBUG") + if s == "" { + return + } + + debugArgs = strings.Split(s, ",") +} + +// A debugger is used to provide debugging information about a netlink connection. +type debugger struct { + Log *log.Logger + Level int +} + +// newDebugger creates a debugger by parsing key=value arguments. +func newDebugger(args []string) *debugger { + d := &debugger{ + Log: log.New(os.Stderr, "nl: ", 0), + Level: 1, + } + + for _, a := range args { + kv := strings.Split(a, "=") + if len(kv) != 2 { + // Ignore malformed pairs and assume callers wants defaults. + continue + } + + switch kv[0] { + // Select the log level for the debugger. + case "level": + level, err := strconv.Atoi(kv[1]) + if err != nil { + panicf("netlink: invalid NLDEBUG level: %q", a) + } + + d.Level = level + } + } + + return d +} + +// debugf prints debugging information at the specified level, if d.Level is +// high enough to print the message. +func (d *debugger) debugf(level int, format string, v ...interface{}) { + if d.Level >= level { + d.Log.Printf(format, v...) + } +} + +func panicf(format string, a ...interface{}) { + panic(fmt.Sprintf(format, a...)) +} diff --git a/vendor/github.com/mdlayher/netlink/doc.go b/vendor/github.com/mdlayher/netlink/doc.go index 73e8c110..0768be23 100644 --- a/vendor/github.com/mdlayher/netlink/doc.go +++ b/vendor/github.com/mdlayher/netlink/doc.go @@ -1,2 +1,22 @@ // Package netlink provides low-level access to Linux netlink sockets. +// +// +// Debugging +// +// This package supports rudimentary netlink connection debugging support. +// To enable this, run your binary with the NLDEBUG environment variable set. +// Debugging information will be output to stderr with a prefix of "nl:". +// +// To use the debugging defaults, use: +// +// $ NLDEBUG=1 ./nlctl +// +// To configure individual aspects of the debugger, pass key/value options such +// as: +// +// $ NLDEBUG=level=1 ./nlctl +// +// Available key/value debugger options include: +// +// level=N: specify the debugging level (only "1" is currently supported) package netlink diff --git a/vendor/github.com/mdlayher/netlink/nlenc/endian.go b/vendor/github.com/mdlayher/netlink/nlenc/endian.go new file mode 100644 index 00000000..332f487b --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/nlenc/endian.go @@ -0,0 +1,16 @@ +package nlenc + +import ( + "encoding/binary" +) + +// NativeEndian returns the native byte order of this system. +func NativeEndian() binary.ByteOrder { + // Determine endianness by storing a uint16 in a byte slice. + b := Uint16Bytes(1) + if b[0] == 1 { + return binary.LittleEndian + } + + return binary.BigEndian +} diff --git a/vendor/vendor.json b/vendor/vendor.json index c8cad521..02667b6e 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -85,28 +85,28 @@ "versionExact": "v1.0.0" }, { - "checksumSHA1": "VZIJG8dML/XqZbL9bpeDNgkazcg=", + "checksumSHA1": "zLH8BV9kYzpqGB5PS4VDjADFvVM=", "path": "github.com/mdlayher/genetlink", - "revision": "76fecce4c787fb8eaa21a8755f722d67c53038e1", - "revisionTime": "2017-09-01T18:19:24Z" + "revision": "ca85b5a307448462b0aa7a07c67c0846bc12568f", + "revisionTime": "2018-07-28T17:03:40Z" }, { - "checksumSHA1": "S6NatJYh1aOFzSIs6Agp2R0ydtM=", + "checksumSHA1": "ybkJbYD6wyjdoPp/KncnDpCyYiU=", "path": "github.com/mdlayher/netlink", - "revision": "756e798fb38fac19fb2234d3acc32e902bc1af44", - "revisionTime": "2017-12-14T18:12:53Z" + "revision": "80a6f93efd374ddee4e0ea862ca0085ef42eed65", + "revisionTime": "2018-08-10T15:28:04Z" }, { - "checksumSHA1": "9nig0WuuiTICStI/8S+pIGqYksc=", + "checksumSHA1": "P7eEo2V7/kQEkt2ihW+26S39eEw=", "path": "github.com/mdlayher/netlink/nlenc", - "revision": "756e798fb38fac19fb2234d3acc32e902bc1af44", - "revisionTime": "2017-12-14T18:12:53Z" + "revision": "80a6f93efd374ddee4e0ea862ca0085ef42eed65", + "revisionTime": "2018-08-10T15:28:04Z" }, { "checksumSHA1": "Y7cjrOeOvA/ic+B8WCp2JyLEuvs=", "path": "github.com/mdlayher/wifi", - "revision": "9a2549315201616119128afe421d1601ef3506f9", - "revisionTime": "2018-06-15T12:49:15Z" + "revision": "efdf3f4195d9fc8b73013b3706fe626b7fb807d8", + "revisionTime": "2018-07-27T16:38:19Z" }, { "checksumSHA1": "VzutdH69PUqRqhrDVv6F91ebQd4=",