Forráskód Böngészése

Vendoring Netlink library

- Added conntrack support

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>
Flavio Crisciani 8 éve
szülő
commit
e88bc31afa

+ 1 - 1
vendor.conf

@@ -34,7 +34,7 @@ github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
 github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
 github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
 github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
-github.com/vishvananda/netlink c682914b0b231f6cad204a86e565551e51d387c0
+github.com/vishvananda/netlink 1e86b2bee5b6a7d377e4c02bb7f98209d6a7297c
 github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
 github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
 github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d

+ 13 - 0
vendor/github.com/vishvananda/netlink/addr_linux.go

@@ -27,6 +27,19 @@ func (h *Handle) AddrAdd(link Link, addr *Addr) error {
 	return h.addrHandle(link, addr, req)
 }
 
+// AddrReplace will replace (or, if not present, add) an IP address on a link device.
+// Equivalent to: `ip addr replace $addr dev $link`
+func AddrReplace(link Link, addr *Addr) error {
+	return pkgHandle.AddrReplace(link, addr)
+}
+
+// AddrReplace will replace (or, if not present, add) an IP address on a link device.
+// Equivalent to: `ip addr replace $addr dev $link`
+func (h *Handle) AddrReplace(link Link, addr *Addr) error {
+	req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK)
+	return h.addrHandle(link, addr, req)
+}
+
 // AddrDel will delete an IP address from a link device.
 // Equivalent to: `ip addr del $addr dev $link`
 func AddrDel(link Link, addr *Addr) error {

+ 344 - 0
vendor/github.com/vishvananda/netlink/conntrack_linux.go

@@ -0,0 +1,344 @@
+package netlink
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"net"
+	"syscall"
+
+	"github.com/vishvananda/netlink/nl"
+)
+
+// ConntrackTableType Conntrack table for the netlink operation
+type ConntrackTableType uint8
+
+const (
+	// ConntrackTable Conntrack table
+	// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK		 1
+	ConntrackTable = 1
+	// ConntrackExpectTable Conntrack expect table
+	// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK_EXP 2
+	ConntrackExpectTable = 2
+)
+
+const (
+	// backward compatibility with golang 1.6 which does not have io.SeekCurrent
+	seekCurrent = 1
+)
+
+// InetFamily Family type
+type InetFamily uint8
+
+//  -L [table] [options]          List conntrack or expectation table
+//  -G [table] parameters         Get conntrack or expectation
+
+//  -I [table] parameters         Create a conntrack or expectation
+//  -U [table] parameters         Update a conntrack
+//  -E [table] [options]          Show events
+
+//  -C [table]                    Show counter
+//  -S                            Show statistics
+
+// ConntrackTableList returns the flow list of a table of a specific family
+// conntrack -L [table] [options]          List conntrack or expectation table
+func ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
+	return pkgHandle.ConntrackTableList(table, family)
+}
+
+// ConntrackTableFlush flushes all the flows of a specified table
+// conntrack -F [table]            Flush table
+// The flush operation applies to all the family types
+func ConntrackTableFlush(table ConntrackTableType) error {
+	return pkgHandle.ConntrackTableFlush(table)
+}
+
+// ConntrackDeleteFilter deletes entries on the specified table on the base of the filter
+// conntrack -D [table] parameters         Delete conntrack or expectation
+func ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
+	return pkgHandle.ConntrackDeleteFilter(table, family, filter)
+}
+
+// ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
+// conntrack -L [table] [options]          List conntrack or expectation table
+func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
+	res, err := h.dumpConntrackTable(table, family)
+	if err != nil {
+		return nil, err
+	}
+
+	// Deserialize all the flows
+	var result []*ConntrackFlow
+	for _, dataRaw := range res {
+		result = append(result, parseRawData(dataRaw))
+	}
+
+	return result, nil
+}
+
+// ConntrackTableFlush flushes all the flows of a specified table using the netlink handle passed
+// conntrack -F [table]            Flush table
+// The flush operation applies to all the family types
+func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
+	req := h.newConntrackRequest(table, syscall.AF_INET, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK)
+	_, err := req.Execute(syscall.NETLINK_NETFILTER, 0)
+	return err
+}
+
+// ConntrackDeleteFilter deletes entries on the specified table on the base of the filter using the netlink handle passed
+// conntrack -D [table] parameters         Delete conntrack or expectation
+func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
+	res, err := h.dumpConntrackTable(table, family)
+	if err != nil {
+		return 0, err
+	}
+
+	var matched uint
+	for _, dataRaw := range res {
+		flow := parseRawData(dataRaw)
+		if match := filter.MatchConntrackFlow(flow); match {
+			req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK)
+			// skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already
+			req2.AddRawData(dataRaw[4:])
+			req2.Execute(syscall.NETLINK_NETFILTER, 0)
+			matched++
+		}
+	}
+
+	return matched, nil
+}
+
+func (h *Handle) newConntrackRequest(table ConntrackTableType, family InetFamily, operation, flags int) *nl.NetlinkRequest {
+	// Create the Netlink request object
+	req := h.newNetlinkRequest((int(table)<<8)|operation, flags)
+	// Add the netfilter header
+	msg := &nl.Nfgenmsg{
+		NfgenFamily: uint8(family),
+		Version:     nl.NFNETLINK_V0,
+		ResId:       0,
+	}
+	req.AddData(msg)
+	return req
+}
+
+func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) ([][]byte, error) {
+	req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, syscall.NLM_F_DUMP)
+	return req.Execute(syscall.NETLINK_NETFILTER, 0)
+}
+
+// The full conntrack flow structure is very complicated and can be found in the file:
+// http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h
+// For the time being, the structure below allows to parse and extract the base information of a flow
+type ipTuple struct {
+	SrcIP    net.IP
+	DstIP    net.IP
+	Protocol uint8
+	SrcPort  uint16
+	DstPort  uint16
+}
+
+type ConntrackFlow struct {
+	FamilyType uint8
+	Forward    ipTuple
+	Reverse    ipTuple
+}
+
+func (s *ConntrackFlow) String() string {
+	// conntrack cmd output:
+	// udp      17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001
+	return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d\tsrc=%s dst=%s sport=%d dport=%d",
+		nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
+		s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort,
+		s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort)
+}
+
+// This method parse the ip tuple structure
+// The message structure is the following:
+// <len, [CTA_IP_V4_SRC|CTA_IP_V6_SRC], 16 bytes for the IP>
+// <len, [CTA_IP_V4_DST|CTA_IP_V6_DST], 16 bytes for the IP>
+// <len, NLA_F_NESTED|nl.CTA_TUPLE_PROTO, 1 byte for the protocol, 3 bytes of padding>
+// <len, CTA_PROTO_SRC_PORT, 2 bytes for the source port, 2 bytes of padding>
+// <len, CTA_PROTO_DST_PORT, 2 bytes for the source port, 2 bytes of padding>
+func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) {
+	for i := 0; i < 2; i++ {
+		_, t, _, v := parseNfAttrTLV(reader)
+		switch t {
+		case nl.CTA_IP_V4_SRC, nl.CTA_IP_V6_SRC:
+			tpl.SrcIP = v
+		case nl.CTA_IP_V4_DST, nl.CTA_IP_V6_DST:
+			tpl.DstIP = v
+		}
+	}
+	// Skip the next 4 bytes  nl.NLA_F_NESTED|nl.CTA_TUPLE_PROTO
+	reader.Seek(4, seekCurrent)
+	_, t, _, v := parseNfAttrTLV(reader)
+	if t == nl.CTA_PROTO_NUM {
+		tpl.Protocol = uint8(v[0])
+	}
+	// Skip some padding 3 bytes
+	reader.Seek(3, seekCurrent)
+	for i := 0; i < 2; i++ {
+		_, t, _ := parseNfAttrTL(reader)
+		switch t {
+		case nl.CTA_PROTO_SRC_PORT:
+			parseBERaw16(reader, &tpl.SrcPort)
+		case nl.CTA_PROTO_DST_PORT:
+			parseBERaw16(reader, &tpl.DstPort)
+		}
+		// Skip some padding 2 byte
+		reader.Seek(2, seekCurrent)
+	}
+}
+
+func parseNfAttrTLV(r *bytes.Reader) (isNested bool, attrType, len uint16, value []byte) {
+	isNested, attrType, len = parseNfAttrTL(r)
+
+	value = make([]byte, len)
+	binary.Read(r, binary.BigEndian, &value)
+	return isNested, attrType, len, value
+}
+
+func parseNfAttrTL(r *bytes.Reader) (isNested bool, attrType, len uint16) {
+	binary.Read(r, nl.NativeEndian(), &len)
+	len -= nl.SizeofNfattr
+
+	binary.Read(r, nl.NativeEndian(), &attrType)
+	isNested = (attrType & nl.NLA_F_NESTED) == nl.NLA_F_NESTED
+	attrType = attrType & (nl.NLA_F_NESTED - 1)
+
+	return isNested, attrType, len
+}
+
+func parseBERaw16(r *bytes.Reader, v *uint16) {
+	binary.Read(r, binary.BigEndian, v)
+}
+
+func parseRawData(data []byte) *ConntrackFlow {
+	s := &ConntrackFlow{}
+	// First there is the Nfgenmsg header
+	// consume only the family field
+	reader := bytes.NewReader(data)
+	binary.Read(reader, nl.NativeEndian(), &s.FamilyType)
+
+	// skip rest of the Netfilter header
+	reader.Seek(3, seekCurrent)
+	// The message structure is the following:
+	// <len, NLA_F_NESTED|CTA_TUPLE_ORIG> 4 bytes
+	// <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
+	// flow information of the forward flow
+	// <len, NLA_F_NESTED|CTA_TUPLE_REPLY> 4 bytes
+	// <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
+	// flow information of the reverse flow
+	for reader.Len() > 0 {
+		nested, t, l := parseNfAttrTL(reader)
+		if nested && t == nl.CTA_TUPLE_ORIG {
+			if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
+				parseIpTuple(reader, &s.Forward)
+			}
+		} else if nested && t == nl.CTA_TUPLE_REPLY {
+			if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
+				parseIpTuple(reader, &s.Reverse)
+
+				// Got all the useful information stop parsing
+				break
+			} else {
+				// Header not recognized skip it
+				reader.Seek(int64(l), seekCurrent)
+			}
+		}
+	}
+
+	return s
+}
+
+// Conntrack parameters and options:
+//   -n, --src-nat ip                      source NAT ip
+//   -g, --dst-nat ip                      destination NAT ip
+//   -j, --any-nat ip                      source or destination NAT ip
+//   -m, --mark mark                       Set mark
+//   -c, --secmark secmark                 Set selinux secmark
+//   -e, --event-mask eventmask            Event mask, eg. NEW,DESTROY
+//   -z, --zero                            Zero counters while listing
+//   -o, --output type[,...]               Output format, eg. xml
+//   -l, --label label[,...]               conntrack labels
+
+// Common parameters and options:
+//   -s, --src, --orig-src ip              Source address from original direction
+//   -d, --dst, --orig-dst ip              Destination address from original direction
+//   -r, --reply-src ip            Source addres from reply direction
+//   -q, --reply-dst ip            Destination address from reply direction
+//   -p, --protonum proto          Layer 4 Protocol, eg. 'tcp'
+//   -f, --family proto            Layer 3 Protocol, eg. 'ipv6'
+//   -t, --timeout timeout         Set timeout
+//   -u, --status status           Set status, eg. ASSURED
+//   -w, --zone value              Set conntrack zone
+//   --orig-zone value             Set zone for original direction
+//   --reply-zone value            Set zone for reply direction
+//   -b, --buffer-size             Netlink socket buffer size
+//   --mask-src ip                 Source mask address
+//   --mask-dst ip                 Destination mask address
+
+// Filter types
+type ConntrackFilterType uint8
+
+const (
+	ConntrackOrigSrcIP = iota // -orig-src ip   Source address from original direction
+	ConntrackOrigDstIP        // -orig-dst ip   Destination address from original direction
+	ConntrackNatSrcIP         // -src-nat ip    Source NAT ip
+	ConntrackNatDstIP         // -dst-nat ip    Destination NAT ip
+	ConntrackNatAnyIP         // -any-nat ip    Source or destination NAT ip
+)
+
+type ConntrackFilter struct {
+	ipFilter map[ConntrackFilterType]net.IP
+}
+
+// AddIP adds an IP to the conntrack filter
+func (f *ConntrackFilter) AddIP(tp ConntrackFilterType, ip net.IP) error {
+	if f.ipFilter == nil {
+		f.ipFilter = make(map[ConntrackFilterType]net.IP)
+	}
+	if _, ok := f.ipFilter[tp]; ok {
+		return errors.New("Filter attribute already present")
+	}
+	f.ipFilter[tp] = ip
+	return nil
+}
+
+// MatchConntrackFlow applies the filter to the flow and returns true if the flow matches the filter
+// false otherwise
+func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
+	if len(f.ipFilter) == 0 {
+		// empty filter always not match
+		return false
+	}
+
+	match := true
+	// -orig-src ip   Source address from original direction
+	if elem, found := f.ipFilter[ConntrackOrigSrcIP]; found {
+		match = match && elem.Equal(flow.Forward.SrcIP)
+	}
+
+	// -orig-dst ip   Destination address from original direction
+	if elem, found := f.ipFilter[ConntrackOrigDstIP]; match && found {
+		match = match && elem.Equal(flow.Forward.DstIP)
+	}
+
+	// -src-nat ip    Source NAT ip
+	if elem, found := f.ipFilter[ConntrackNatSrcIP]; match && found {
+		match = match && elem.Equal(flow.Reverse.SrcIP)
+	}
+
+	// -dst-nat ip    Destination NAT ip
+	if elem, found := f.ipFilter[ConntrackNatDstIP]; match && found {
+		match = match && elem.Equal(flow.Reverse.DstIP)
+	}
+
+	// -any-nat ip    Source or destination NAT ip
+	if elem, found := f.ipFilter[ConntrackNatAnyIP]; match && found {
+		match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP))
+	}
+
+	return match
+}

+ 53 - 0
vendor/github.com/vishvananda/netlink/conntrack_unspecified.go

@@ -0,0 +1,53 @@
+// +build !linux
+
+package netlink
+
+// ConntrackTableType Conntrack table for the netlink operation
+type ConntrackTableType uint8
+
+// InetFamily Family type
+type InetFamily uint8
+
+// ConntrackFlow placeholder
+type ConntrackFlow struct{}
+
+// ConntrackFilter placeholder
+type ConntrackFilter struct{}
+
+// ConntrackTableList returns the flow list of a table of a specific family
+// conntrack -L [table] [options]          List conntrack or expectation table
+func ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
+	return nil, ErrNotImplemented
+}
+
+// ConntrackTableFlush flushes all the flows of a specified table
+// conntrack -F [table]            Flush table
+// The flush operation applies to all the family types
+func ConntrackTableFlush(table ConntrackTableType) error {
+	return ErrNotImplemented
+}
+
+// ConntrackDeleteFilter deletes entries on the specified table on the base of the filter
+// conntrack -D [table] parameters         Delete conntrack or expectation
+func ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
+	return 0, ErrNotImplemented
+}
+
+// ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
+// conntrack -L [table] [options]          List conntrack or expectation table
+func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
+	return nil, ErrNotImplemented
+}
+
+// ConntrackTableFlush flushes all the flows of a specified table using the netlink handle passed
+// conntrack -F [table]            Flush table
+// The flush operation applies to all the family types
+func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
+	return ErrNotImplemented
+}
+
+// ConntrackDeleteFilter deletes entries on the specified table on the base of the filter using the netlink handle passed
+// conntrack -D [table] parameters         Delete conntrack or expectation
+func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
+	return 0, ErrNotImplemented
+}

+ 40 - 1
vendor/github.com/vishvananda/netlink/filter.go

@@ -1,6 +1,10 @@
 package netlink
 
-import "fmt"
+import (
+	"fmt"
+
+	"github.com/vishvananda/netlink/nl"
+)
 
 type Filter interface {
 	Attrs() *FilterAttrs
@@ -180,11 +184,46 @@ func NewMirredAction(redirIndex int) *MirredAction {
 	}
 }
 
+// Constants used in TcU32Sel.Flags.
+const (
+	TC_U32_TERMINAL  = nl.TC_U32_TERMINAL
+	TC_U32_OFFSET    = nl.TC_U32_OFFSET
+	TC_U32_VAROFFSET = nl.TC_U32_VAROFFSET
+	TC_U32_EAT       = nl.TC_U32_EAT
+)
+
+// Sel of the U32 filters that contains multiple TcU32Key. This is the copy
+// and the frontend representation of nl.TcU32Sel. It is serialized into canonical
+// nl.TcU32Sel with the appropriate endianness.
+type TcU32Sel struct {
+	Flags    uint8
+	Offshift uint8
+	Nkeys    uint8
+	Pad      uint8
+	Offmask  uint16
+	Off      uint16
+	Offoff   int16
+	Hoff     int16
+	Hmask    uint32
+	Keys     []TcU32Key
+}
+
+// TcU32Key contained of Sel in the U32 filters. This is the copy and the frontend
+// representation of nl.TcU32Key. It is serialized into chanonical nl.TcU32Sel
+// with the appropriate endianness.
+type TcU32Key struct {
+	Mask    uint32
+	Val     uint32
+	Off     int32
+	OffMask int32
+}
+
 // U32 filters on many packet related properties
 type U32 struct {
 	FilterAttrs
 	ClassId    uint32
 	RedirIndex int
+	Sel        *TcU32Sel
 	Actions    []Action
 }
 

+ 40 - 5
vendor/github.com/vishvananda/netlink/filter_linux.go

@@ -6,6 +6,7 @@ import (
 	"errors"
 	"fmt"
 	"syscall"
+	"unsafe"
 
 	"github.com/vishvananda/netlink/nl"
 )
@@ -128,12 +129,34 @@ func (h *Handle) FilterAdd(filter Filter) error {
 
 	options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
 	if u32, ok := filter.(*U32); ok {
-		// match all
-		sel := nl.TcU32Sel{
-			Nkeys: 1,
-			Flags: nl.TC_U32_TERMINAL,
+		// Convert TcU32Sel into nl.TcU32Sel as it is without copy.
+		sel := (*nl.TcU32Sel)(unsafe.Pointer(u32.Sel))
+		if sel == nil {
+			// match all
+			sel = &nl.TcU32Sel{
+				Nkeys: 1,
+				Flags: nl.TC_U32_TERMINAL,
+			}
+			sel.Keys = append(sel.Keys, nl.TcU32Key{})
+		}
+
+		if native != networkOrder {
+			// Copy Tcu32Sel.
+			cSel := sel
+			keys := make([]nl.TcU32Key, cap(sel.Keys))
+			copy(keys, sel.Keys)
+			cSel.Keys = keys
+			sel = cSel
+
+			// Handle the endianness of attributes
+			sel.Offmask = native.Uint16(htons(sel.Offmask))
+			sel.Hmask = native.Uint32(htonl(sel.Hmask))
+			for _, key := range sel.Keys {
+				key.Mask = native.Uint32(htonl(key.Mask))
+				key.Val = native.Uint32(htonl(key.Val))
+			}
 		}
-		sel.Keys = append(sel.Keys, nl.TcU32Key{})
+		sel.Nkeys = uint8(len(sel.Keys))
 		nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
 		if u32.ClassId != 0 {
 			nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(u32.ClassId))
@@ -425,6 +448,16 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
 		case nl.TCA_U32_SEL:
 			detailed = true
 			sel := nl.DeserializeTcU32Sel(datum.Value)
+			u32.Sel = (*TcU32Sel)(unsafe.Pointer(sel))
+			if native != networkOrder {
+				// Handle the endianness of attributes
+				u32.Sel.Offmask = native.Uint16(htons(sel.Offmask))
+				u32.Sel.Hmask = native.Uint32(htonl(sel.Hmask))
+				for _, key := range u32.Sel.Keys {
+					key.Mask = native.Uint32(htonl(key.Mask))
+					key.Val = native.Uint32(htonl(key.Val))
+				}
+			}
 			// only parse if we have a very basic redirect
 			if sel.Flags&nl.TC_U32_TERMINAL == 0 || sel.Nkeys != 1 {
 				return detailed, nil
@@ -443,6 +476,8 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
 					u32.RedirIndex = int(action.Ifindex)
 				}
 			}
+		case nl.TCA_U32_CLASSID:
+			u32.ClassId = native.Uint32(datum.Value)
 		}
 	}
 	return detailed, nil

+ 189 - 0
vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go

@@ -0,0 +1,189 @@
+package nl
+
+import "unsafe"
+
+// Track the message sizes for the correct serialization/deserialization
+const (
+	SizeofNfgenmsg      = 4
+	SizeofNfattr        = 4
+	SizeofNfConntrack   = 376
+	SizeofNfctTupleHead = 52
+)
+
+var L4ProtoMap = map[uint8]string{
+	6:  "tcp",
+	17: "udp",
+}
+
+// All the following constants are coming from:
+// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink_conntrack.h
+
+// enum cntl_msg_types {
+// 	IPCTNL_MSG_CT_NEW,
+// 	IPCTNL_MSG_CT_GET,
+// 	IPCTNL_MSG_CT_DELETE,
+// 	IPCTNL_MSG_CT_GET_CTRZERO,
+// 	IPCTNL_MSG_CT_GET_STATS_CPU,
+// 	IPCTNL_MSG_CT_GET_STATS,
+// 	IPCTNL_MSG_CT_GET_DYING,
+// 	IPCTNL_MSG_CT_GET_UNCONFIRMED,
+//
+// 	IPCTNL_MSG_MAX
+// };
+const (
+	IPCTNL_MSG_CT_GET    = 1
+	IPCTNL_MSG_CT_DELETE = 2
+)
+
+// #define NFNETLINK_V0	0
+const (
+	NFNETLINK_V0 = 0
+)
+
+// #define NLA_F_NESTED (1 << 15)
+const (
+	NLA_F_NESTED = (1 << 15)
+)
+
+// enum ctattr_type {
+// 	CTA_UNSPEC,
+// 	CTA_TUPLE_ORIG,
+// 	CTA_TUPLE_REPLY,
+// 	CTA_STATUS,
+// 	CTA_PROTOINFO,
+// 	CTA_HELP,
+// 	CTA_NAT_SRC,
+// #define CTA_NAT	CTA_NAT_SRC	/* backwards compatibility */
+// 	CTA_TIMEOUT,
+// 	CTA_MARK,
+// 	CTA_COUNTERS_ORIG,
+// 	CTA_COUNTERS_REPLY,
+// 	CTA_USE,
+// 	CTA_ID,
+// 	CTA_NAT_DST,
+// 	CTA_TUPLE_MASTER,
+// 	CTA_SEQ_ADJ_ORIG,
+// 	CTA_NAT_SEQ_ADJ_ORIG	= CTA_SEQ_ADJ_ORIG,
+// 	CTA_SEQ_ADJ_REPLY,
+// 	CTA_NAT_SEQ_ADJ_REPLY	= CTA_SEQ_ADJ_REPLY,
+// 	CTA_SECMARK,		/* obsolete */
+// 	CTA_ZONE,
+// 	CTA_SECCTX,
+// 	CTA_TIMESTAMP,
+// 	CTA_MARK_MASK,
+// 	CTA_LABELS,
+// 	CTA_LABELS_MASK,
+// 	__CTA_MAX
+// };
+const (
+	CTA_TUPLE_ORIG  = 1
+	CTA_TUPLE_REPLY = 2
+	CTA_STATUS      = 3
+	CTA_TIMEOUT     = 8
+	CTA_MARK        = 9
+	CTA_PROTOINFO   = 4
+)
+
+// enum ctattr_tuple {
+// 	CTA_TUPLE_UNSPEC,
+// 	CTA_TUPLE_IP,
+// 	CTA_TUPLE_PROTO,
+// 	CTA_TUPLE_ZONE,
+// 	__CTA_TUPLE_MAX
+// };
+// #define CTA_TUPLE_MAX (__CTA_TUPLE_MAX - 1)
+const (
+	CTA_TUPLE_IP    = 1
+	CTA_TUPLE_PROTO = 2
+)
+
+// enum ctattr_ip {
+// 	CTA_IP_UNSPEC,
+// 	CTA_IP_V4_SRC,
+// 	CTA_IP_V4_DST,
+// 	CTA_IP_V6_SRC,
+// 	CTA_IP_V6_DST,
+// 	__CTA_IP_MAX
+// };
+// #define CTA_IP_MAX (__CTA_IP_MAX - 1)
+const (
+	CTA_IP_V4_SRC = 1
+	CTA_IP_V4_DST = 2
+	CTA_IP_V6_SRC = 3
+	CTA_IP_V6_DST = 4
+)
+
+// enum ctattr_l4proto {
+// 	CTA_PROTO_UNSPEC,
+// 	CTA_PROTO_NUM,
+// 	CTA_PROTO_SRC_PORT,
+// 	CTA_PROTO_DST_PORT,
+// 	CTA_PROTO_ICMP_ID,
+// 	CTA_PROTO_ICMP_TYPE,
+// 	CTA_PROTO_ICMP_CODE,
+// 	CTA_PROTO_ICMPV6_ID,
+// 	CTA_PROTO_ICMPV6_TYPE,
+// 	CTA_PROTO_ICMPV6_CODE,
+// 	__CTA_PROTO_MAX
+// };
+// #define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1)
+const (
+	CTA_PROTO_NUM      = 1
+	CTA_PROTO_SRC_PORT = 2
+	CTA_PROTO_DST_PORT = 3
+)
+
+// enum ctattr_protoinfo {
+// 	CTA_PROTOINFO_UNSPEC,
+// 	CTA_PROTOINFO_TCP,
+// 	CTA_PROTOINFO_DCCP,
+// 	CTA_PROTOINFO_SCTP,
+// 	__CTA_PROTOINFO_MAX
+// };
+// #define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1)
+const (
+	CTA_PROTOINFO_TCP = 1
+)
+
+// enum ctattr_protoinfo_tcp {
+// 	CTA_PROTOINFO_TCP_UNSPEC,
+// 	CTA_PROTOINFO_TCP_STATE,
+// 	CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
+// 	CTA_PROTOINFO_TCP_WSCALE_REPLY,
+// 	CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
+// 	CTA_PROTOINFO_TCP_FLAGS_REPLY,
+// 	__CTA_PROTOINFO_TCP_MAX
+// };
+// #define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1)
+const (
+	CTA_PROTOINFO_TCP_STATE           = 1
+	CTA_PROTOINFO_TCP_WSCALE_ORIGINAL = 2
+	CTA_PROTOINFO_TCP_WSCALE_REPLY    = 3
+	CTA_PROTOINFO_TCP_FLAGS_ORIGINAL  = 4
+	CTA_PROTOINFO_TCP_FLAGS_REPLY     = 5
+)
+
+// /* General form of address family dependent message.
+//  */
+// struct nfgenmsg {
+// 	__u8  nfgen_family;		/* AF_xxx */
+// 	__u8  version;		/* nfnetlink version */
+// 	__be16    res_id;		/* resource id */
+// };
+type Nfgenmsg struct {
+	NfgenFamily uint8
+	Version     uint8
+	ResId       uint16 // big endian
+}
+
+func (msg *Nfgenmsg) Len() int {
+	return SizeofNfgenmsg
+}
+
+func DeserializeNfgenmsg(b []byte) *Nfgenmsg {
+	return (*Nfgenmsg)(unsafe.Pointer(&b[0:SizeofNfgenmsg][0]))
+}
+
+func (msg *Nfgenmsg) Serialize() []byte {
+	return (*(*[SizeofNfgenmsg]byte)(unsafe.Pointer(msg)))[:]
+}

+ 15 - 1
vendor/github.com/vishvananda/netlink/nl/nl_linux.go

@@ -24,7 +24,7 @@ const (
 )
 
 // SupportedNlFamilies contains the list of netlink families this netlink package supports
-var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM}
+var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM, syscall.NETLINK_NETFILTER}
 
 var nextSeqNr uint32
 
@@ -321,6 +321,7 @@ func (a *RtAttr) Serialize() []byte {
 type NetlinkRequest struct {
 	syscall.NlMsghdr
 	Data    []NetlinkRequestData
+	RawData []byte
 	Sockets map[int]*SocketHandle
 }
 
@@ -332,6 +333,8 @@ func (req *NetlinkRequest) Serialize() []byte {
 		dataBytes[i] = data.Serialize()
 		length = length + len(dataBytes[i])
 	}
+	length += len(req.RawData)
+
 	req.Len = uint32(length)
 	b := make([]byte, length)
 	hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
@@ -343,6 +346,10 @@ func (req *NetlinkRequest) Serialize() []byte {
 			next = next + 1
 		}
 	}
+	// Add the raw data if any
+	if len(req.RawData) > 0 {
+		copy(b[next:length], req.RawData)
+	}
 	return b
 }
 
@@ -352,6 +359,13 @@ func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
 	}
 }
 
+// AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization
+func (req *NetlinkRequest) AddRawData(data []byte) {
+	if data != nil {
+		req.RawData = append(req.RawData, data...)
+	}
+}
+
 // Execute the request against a the given sockType.
 // Returns a list of netlink messages in serialized format, optionally filtered
 // by resType.