mirror of
https://github.com/weaveworks/scope.git
synced 2026-05-03 15:58:57 +00:00
Import conntrack library
This commit is contained in:
committed by
Bryan Boreham
parent
e55086a5d3
commit
853196f6d1
23
probe/endpoint/conntrack/LICENSE
Normal file
23
probe/endpoint/conntrack/LICENSE
Normal file
@@ -0,0 +1,23 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 typetypetype
|
||||
Copyright (c) 2017 josephglanville
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
303
probe/endpoint/conntrack/conntrack.go
Normal file
303
probe/endpoint/conntrack/conntrack.go
Normal file
@@ -0,0 +1,303 @@
|
||||
package conntrack
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Layer3 struct {
|
||||
SrcIP net.IP
|
||||
DstIP net.IP
|
||||
}
|
||||
|
||||
type Layer4 struct {
|
||||
SrcPort uint16
|
||||
DstPort uint16
|
||||
Proto uint8
|
||||
}
|
||||
|
||||
type Meta struct {
|
||||
Layer3
|
||||
Layer4
|
||||
}
|
||||
|
||||
type Flow struct {
|
||||
MsgType NfConntrackMsg
|
||||
Original Meta
|
||||
Reply Meta
|
||||
State TCPState
|
||||
ID uint32
|
||||
}
|
||||
|
||||
type nfgenmsg struct {
|
||||
Family uint8 /* AF_xxx */
|
||||
Version uint8 /* nfnetlink version */
|
||||
ResID uint16 /* resource id */
|
||||
}
|
||||
|
||||
const (
|
||||
sizeofGenmsg = uint32(unsafe.Sizeof(nfgenmsg{}))
|
||||
)
|
||||
|
||||
type ConntrackListReq struct {
|
||||
Header syscall.NlMsghdr
|
||||
Body nfgenmsg
|
||||
}
|
||||
|
||||
func (c *ConntrackListReq) toWireFormat() []byte {
|
||||
// adapted from syscall/NetlinkRouteRequest.toWireFormat
|
||||
b := make([]byte, c.Header.Len)
|
||||
*(*uint32)(unsafe.Pointer(&b[0:4][0])) = c.Header.Len
|
||||
*(*uint16)(unsafe.Pointer(&b[4:6][0])) = c.Header.Type
|
||||
*(*uint16)(unsafe.Pointer(&b[6:8][0])) = c.Header.Flags
|
||||
*(*uint32)(unsafe.Pointer(&b[8:12][0])) = c.Header.Seq
|
||||
*(*uint32)(unsafe.Pointer(&b[12:16][0])) = c.Header.Pid
|
||||
b[16] = byte(c.Body.Family)
|
||||
b[17] = byte(c.Body.Version)
|
||||
*(*uint16)(unsafe.Pointer(&b[18:20][0])) = c.Body.ResID
|
||||
return b
|
||||
}
|
||||
|
||||
func connectNetfilter(bufferSize int, groups uint32) (int, *syscall.SockaddrNetlink, error) {
|
||||
s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_NETFILTER)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
lsa := &syscall.SockaddrNetlink{
|
||||
Family: syscall.AF_NETLINK,
|
||||
Groups: groups,
|
||||
}
|
||||
if err := syscall.Bind(s, lsa); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if bufferSize > 0 {
|
||||
if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_RCVBUFFORCE, bufferSize); err != nil {
|
||||
if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bufferSize); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return s, lsa, nil
|
||||
}
|
||||
|
||||
// Established lists all established TCP connections.
|
||||
func Established(bufferSize int) ([]Flow, error) {
|
||||
s, lsa, err := connectNetfilter(bufferSize, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer syscall.Close(s)
|
||||
|
||||
var flows []Flow
|
||||
msg := ConntrackListReq{
|
||||
Header: syscall.NlMsghdr{
|
||||
Len: syscall.NLMSG_HDRLEN + sizeofGenmsg,
|
||||
Type: (NFNL_SUBSYS_CTNETLINK << 8) | uint16(IpctnlMsgCtGet),
|
||||
Flags: syscall.NLM_F_REQUEST | syscall.NLM_F_DUMP,
|
||||
Pid: 0,
|
||||
Seq: 0,
|
||||
},
|
||||
Body: nfgenmsg{
|
||||
Family: syscall.AF_INET,
|
||||
Version: NFNETLINK_V0,
|
||||
ResID: 0,
|
||||
},
|
||||
}
|
||||
wb := msg.toWireFormat()
|
||||
if err := syscall.Sendto(s, wb, 0, lsa); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
readMsgs(s, func(c Flow) {
|
||||
if c.MsgType != NfctMsgUpdate {
|
||||
return
|
||||
}
|
||||
flows = append(flows, c)
|
||||
})
|
||||
return flows, nil
|
||||
}
|
||||
|
||||
// Follow gives a channel with all changes.
|
||||
func Follow(bufferSize int) (<-chan Flow, func(), error) {
|
||||
s, _, err := connectNetfilter(bufferSize, NF_NETLINK_CONNTRACK_NEW|NF_NETLINK_CONNTRACK_UPDATE|NF_NETLINK_CONNTRACK_DESTROY)
|
||||
stop := func() {
|
||||
syscall.Close(s)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, stop, err
|
||||
}
|
||||
|
||||
res := make(chan Flow, 1)
|
||||
go func() {
|
||||
defer syscall.Close(s)
|
||||
if err := readMsgs(s, func(c Flow) {
|
||||
res <- c
|
||||
}); err != nil {
|
||||
close(res)
|
||||
return
|
||||
}
|
||||
}()
|
||||
return res, stop, nil
|
||||
}
|
||||
|
||||
func readMsgs(s int, cb func(Flow)) error {
|
||||
for {
|
||||
// TODO(jpg): Re-use the receive buffer.
|
||||
// Will require copying any byte slices we will take pointers to
|
||||
rb := make([]byte, syscall.Getpagesize())
|
||||
nr, _, err := syscall.Recvfrom(s, rb, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgs, err := syscall.ParseNetlinkMessage(rb[:nr])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, msg := range msgs {
|
||||
if err := nfnlIsError(msg.Header); err != nil {
|
||||
}
|
||||
if nflnSubsysID(msg.Header.Type) != NFNL_SUBSYS_CTNETLINK {
|
||||
return fmt.Errorf(
|
||||
"unexpected subsys_id: %d\n",
|
||||
nflnSubsysID(msg.Header.Type),
|
||||
)
|
||||
}
|
||||
flow, err := parsePayload(msg.Data[sizeofGenmsg:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Disregard non-TCP flows for now
|
||||
if flow.Original.Proto != syscall.IPPROTO_TCP {
|
||||
continue
|
||||
}
|
||||
|
||||
// Taken from conntrack/parse.c:__parse_message_type
|
||||
switch CntlMsgTypes(nflnMsgType(msg.Header.Type)) {
|
||||
case IpctnlMsgCtNew:
|
||||
flow.MsgType = NfctMsgUpdate
|
||||
if msg.Header.Flags&(syscall.NLM_F_CREATE|syscall.NLM_F_EXCL) > 0 {
|
||||
flow.MsgType = NfctMsgNew
|
||||
}
|
||||
case IpctnlMsgCtDelete:
|
||||
flow.MsgType = NfctMsgDestroy
|
||||
}
|
||||
|
||||
cb(*flow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parsePayload(b []byte) (*Flow, error) {
|
||||
// Adapted from libnetfilter_conntrack/src/conntrack/parse_mnl.c
|
||||
flow := &Flow{}
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return flow, err
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrType(attr.Typ) {
|
||||
case CtaTupleOrig:
|
||||
parseTuple(attr.Msg, &flow.Original)
|
||||
case CtaTupleReply:
|
||||
parseTuple(attr.Msg, &flow.Reply)
|
||||
case CtaProtoinfo:
|
||||
parseProtoinfo(attr.Msg, flow)
|
||||
case CtaId:
|
||||
flow.ID = binary.BigEndian.Uint32(attr.Msg)
|
||||
}
|
||||
}
|
||||
return flow, nil
|
||||
}
|
||||
|
||||
func parseTuple(b []byte, meta *Meta) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrTuple(attr.Typ) {
|
||||
case CtaTupleUnspec:
|
||||
case CtaTupleIp:
|
||||
if err := parseIP(attr.Msg, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
case CtaTupleProto:
|
||||
parseProto(attr.Msg, meta)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseIP(b []byte, meta *Meta) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
// TODO(jpg) IPv6 support
|
||||
switch CtattrIp(attr.Typ) {
|
||||
case CtaIpV4Src:
|
||||
meta.SrcIP = net.IP(attr.Msg) // TODO: copy so we can reuse the buffer?
|
||||
case CtaIpV4Dst:
|
||||
meta.DstIP = net.IP(attr.Msg) // TODO: copy so we can reuse the buffer?
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseProto(b []byte, meta *Meta) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrL4proto(attr.Typ) {
|
||||
case CtaProtoNum:
|
||||
meta.Proto = uint8(attr.Msg[0])
|
||||
case CtaProtoSrcPort:
|
||||
meta.SrcPort = binary.BigEndian.Uint16(attr.Msg)
|
||||
case CtaProtoDstPort:
|
||||
meta.DstPort = binary.BigEndian.Uint16(attr.Msg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseProtoinfo(b []byte, flow *Flow) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrProtoinfo(attr.Typ) {
|
||||
case CtaProtoinfoTcp:
|
||||
if err := parseProtoinfoTCP(attr.Msg, flow); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
// we're not interested in other protocols
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseProtoinfoTCP(b []byte, flow *Flow) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrProtoinfoTcp(attr.Typ) {
|
||||
case CtaProtoinfoTcpState:
|
||||
flow.State = TCPState(attr.Msg[0])
|
||||
default:
|
||||
// we're not interested in other protocols
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
206
probe/endpoint/conntrack/const.go
Normal file
206
probe/endpoint/conntrack/const.go
Normal file
@@ -0,0 +1,206 @@
|
||||
package conntrack
|
||||
|
||||
const (
|
||||
// #defined in libnfnetlink/include/libnfnetlink/linux_nfnetlink.h
|
||||
NFNL_SUBSYS_CTNETLINK = 1
|
||||
NFNETLINK_V0 = 0
|
||||
|
||||
// #defined in libnfnetlink/include/libnfnetlink/linux_nfnetlink_compat.h
|
||||
NF_NETLINK_CONNTRACK_NEW = 0x00000001
|
||||
NF_NETLINK_CONNTRACK_UPDATE = 0x00000002
|
||||
NF_NETLINK_CONNTRACK_DESTROY = 0x00000004
|
||||
|
||||
// #defined in libnfnetlink/include/libnfnetlink/libnfnetlink.h
|
||||
NLA_F_NESTED = uint16(1 << 15)
|
||||
NLA_F_NET_BYTEORDER = uint16(1 << 14)
|
||||
NLA_TYPE_MASK = ^(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
|
||||
)
|
||||
|
||||
type NfConntrackMsg int
|
||||
|
||||
const (
|
||||
NfctMsgUnknown NfConntrackMsg = 0
|
||||
NfctMsgNew NfConntrackMsg = 1 << 0
|
||||
NfctMsgUpdate NfConntrackMsg = 1 << 1
|
||||
NfctMsgDestroy NfConntrackMsg = 1 << 2
|
||||
)
|
||||
|
||||
// Taken from libnetfilter_conntrack/src/conntrack/snprintf.c
|
||||
type TCPState uint8
|
||||
|
||||
const (
|
||||
TCPStateNone = iota
|
||||
TCPStateSynSent
|
||||
TCPStateSynRecv
|
||||
TCPStateEstablished
|
||||
TCPStateFinWait
|
||||
TCPStateCloseWait
|
||||
TCPStateLastAck
|
||||
TCPStateTimeWait
|
||||
TCPStateClose
|
||||
TCPStateListen
|
||||
TCPStateMax
|
||||
TCPStateIgnore
|
||||
)
|
||||
|
||||
func (s TCPState) String() string {
|
||||
return map[TCPState]string{
|
||||
TCPStateNone: "NONE",
|
||||
TCPStateSynSent: "SYN_SENT",
|
||||
TCPStateSynRecv: "SYN_RECV",
|
||||
TCPStateEstablished: "ESTABLISHED",
|
||||
TCPStateFinWait: "FIN_WAIT",
|
||||
TCPStateCloseWait: "CLOSE_WAIT",
|
||||
TCPStateLastAck: "LAST_ACK",
|
||||
TCPStateTimeWait: "TIME_WAIT",
|
||||
TCPStateClose: "CLOSE",
|
||||
TCPStateListen: "LISTEN",
|
||||
TCPStateMax: "MAX",
|
||||
TCPStateIgnore: "IGNORE",
|
||||
}[s]
|
||||
}
|
||||
|
||||
// Taken from libnetfilter_conntrack: git://git.netfilter.org/libnetfilter_conntrack
|
||||
// include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h
|
||||
|
||||
type CtattrType int
|
||||
|
||||
const (
|
||||
CtaUnspec CtattrType = 0
|
||||
CtaTupleOrig CtattrType = 1
|
||||
CtaTupleReply CtattrType = 2
|
||||
CtaStatus CtattrType = 3
|
||||
CtaProtoinfo CtattrType = 4
|
||||
CtaHelp CtattrType = 5
|
||||
CtaNatSrc CtattrType = 6
|
||||
CtaTimeout CtattrType = 7
|
||||
CtaMark CtattrType = 8
|
||||
CtaCountersOrig CtattrType = 9
|
||||
CtaCountersReply CtattrType = 10
|
||||
CtaUse CtattrType = 11
|
||||
CtaId CtattrType = 12
|
||||
CtaNatDst CtattrType = 13
|
||||
CtaTupleMaster CtattrType = 14
|
||||
CtaNatSeqAdjOrig CtattrType = 15
|
||||
CtaNatSeqAdjReply CtattrType = 16
|
||||
CtaSecmark CtattrType = 17
|
||||
CtaZone CtattrType = 18
|
||||
CtaSecctx CtattrType = 19
|
||||
CtaTimestamp CtattrType = 20
|
||||
CtaMarkMask CtattrType = 21
|
||||
CtaLabels CtattrType = 22
|
||||
CtaLabelsMask CtattrType = 23
|
||||
CtaMax CtattrType = 24
|
||||
)
|
||||
|
||||
type CtattrTuple int
|
||||
|
||||
const (
|
||||
CtaTupleUnspec CtattrTuple = 0
|
||||
CtaTupleIp CtattrTuple = 1
|
||||
CtaTupleProto CtattrTuple = 2
|
||||
CtaTupleMax CtattrTuple = 3
|
||||
)
|
||||
|
||||
type CtattrIp int
|
||||
|
||||
const (
|
||||
CtaIpUnspec CtattrIp = 0
|
||||
CtaIpV4Src CtattrIp = 1
|
||||
CtaIpV4Dst CtattrIp = 2
|
||||
CtaIpV6Src CtattrIp = 3
|
||||
CtaIpV6Dst CtattrIp = 4
|
||||
CtaIpMax CtattrIp = 5
|
||||
)
|
||||
|
||||
type CtattrL4proto int
|
||||
|
||||
const (
|
||||
CtaProtoUnspec CtattrL4proto = 0
|
||||
CtaProtoNum CtattrL4proto = 1
|
||||
CtaProtoSrcPort CtattrL4proto = 2
|
||||
CtaProtoDstPort CtattrL4proto = 3
|
||||
CtaProtoIcmpId CtattrL4proto = 4
|
||||
CtaProtoIcmpType CtattrL4proto = 5
|
||||
CtaProtoIcmpCode CtattrL4proto = 6
|
||||
CtaProtoIcmpv6Id CtattrL4proto = 7
|
||||
CtaProtoIcmpv6Type CtattrL4proto = 8
|
||||
CtaProtoIcmpv6Code CtattrL4proto = 9
|
||||
CtaProtoMax CtattrL4proto = 10
|
||||
)
|
||||
|
||||
type CtattrProtoinfo int
|
||||
|
||||
const (
|
||||
CtaProtoinfoUnspec CtattrProtoinfo = 0
|
||||
CtaProtoinfoTcp CtattrProtoinfo = 1
|
||||
CtaProtoinfoDccp CtattrProtoinfo = 2
|
||||
CtaProtoinfoSctp CtattrProtoinfo = 3
|
||||
CtaProtoinfoMax CtattrProtoinfo = 4
|
||||
)
|
||||
|
||||
type CtattrProtoinfoTcp int
|
||||
|
||||
const (
|
||||
CtaProtoinfoTcpUnspec CtattrProtoinfoTcp = 0
|
||||
CtaProtoinfoTcpState CtattrProtoinfoTcp = 1
|
||||
CtaProtoinfoTcpWscaleOriginal CtattrProtoinfoTcp = 2
|
||||
CtaProtoinfoTcpWscaleReply CtattrProtoinfoTcp = 3
|
||||
CtaProtoinfoTcpFlagsOriginal CtattrProtoinfoTcp = 4
|
||||
CtaProtoinfoTcpFlagsReply CtattrProtoinfoTcp = 5
|
||||
CtaProtoinfoTcpMax CtattrProtoinfoTcp = 6
|
||||
)
|
||||
|
||||
type NfConntrackAttrGrp int
|
||||
|
||||
const (
|
||||
AttrGrpOrigIpv4 NfConntrackAttrGrp = 0
|
||||
AttrGrpReplIpv4 NfConntrackAttrGrp = 1
|
||||
AttrGrpOrigIpv6 NfConntrackAttrGrp = 2
|
||||
AttrGrpReplIpv6 NfConntrackAttrGrp = 3
|
||||
AttrGrpOrigPort NfConntrackAttrGrp = 4
|
||||
AttrGrpReplPort NfConntrackAttrGrp = 5
|
||||
AttrGrpIcmp NfConntrackAttrGrp = 6
|
||||
AttrGrpMasterIpv4 NfConntrackAttrGrp = 7
|
||||
AttrGrpMasterIpv6 NfConntrackAttrGrp = 8
|
||||
AttrGrpMasterPort NfConntrackAttrGrp = 9
|
||||
AttrGrpOrigCounters NfConntrackAttrGrp = 10
|
||||
AttrGrpReplCounters NfConntrackAttrGrp = 11
|
||||
AttrGrpOrigAddrSrc NfConntrackAttrGrp = 12
|
||||
AttrGrpOrigAddrDst NfConntrackAttrGrp = 13
|
||||
AttrGrpReplAddrSrc NfConntrackAttrGrp = 14
|
||||
AttrGrpReplAddrDst NfConntrackAttrGrp = 15
|
||||
AttrGrpMax NfConntrackAttrGrp = 16
|
||||
)
|
||||
|
||||
type NfConntrackQuery int
|
||||
|
||||
const (
|
||||
NfctQCreate NfConntrackQuery = 0
|
||||
NfctQUpdate NfConntrackQuery = 1
|
||||
NfctQDestroy NfConntrackQuery = 2
|
||||
NfctQGet NfConntrackQuery = 3
|
||||
NfctQFlush NfConntrackQuery = 4
|
||||
NfctQDump NfConntrackQuery = 5
|
||||
NfctQDumpReset NfConntrackQuery = 6
|
||||
NfctQCreateUpdate NfConntrackQuery = 7
|
||||
NfctQDumpFilter NfConntrackQuery = 8
|
||||
NfctQDumpFilterReset NfConntrackQuery = 9
|
||||
)
|
||||
|
||||
// Taken from libnetfilter_conntrack: git://git.netfilter.org/libnetfilter_conntrack
|
||||
// include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h
|
||||
|
||||
type CntlMsgTypes int
|
||||
|
||||
const (
|
||||
IpctnlMsgCtNew CntlMsgTypes = 0
|
||||
IpctnlMsgCtGet CntlMsgTypes = 1
|
||||
IpctnlMsgCtDelete CntlMsgTypes = 2
|
||||
IpctnlMsgCtGetCtrzero CntlMsgTypes = 3
|
||||
IpctnlMsgCtGetStatsCpu CntlMsgTypes = 4
|
||||
IpctnlMsgCtGetStats CntlMsgTypes = 5
|
||||
IpctnlMsgCtGetDying CntlMsgTypes = 6
|
||||
IpctnlMsgCtGetUnconfirmed CntlMsgTypes = 7
|
||||
IpctnlMsgMax CntlMsgTypes = 8
|
||||
)
|
||||
33
probe/endpoint/conntrack/netlink.go
Normal file
33
probe/endpoint/conntrack/netlink.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package conntrack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// NFNL_MSG_TYPE
|
||||
func nflnMsgType(x uint16) uint8 {
|
||||
return uint8(x & 0x00ff)
|
||||
}
|
||||
|
||||
// NFNL_SUBSYS_ID
|
||||
func nflnSubsysID(x uint16) uint8 {
|
||||
return uint8((x & 0xff00) >> 8)
|
||||
}
|
||||
|
||||
// from src/libnfnetlink.c
|
||||
func nfnlIsError(hdr syscall.NlMsghdr) error {
|
||||
if hdr.Type == syscall.NLMSG_ERROR {
|
||||
return errors.New("NLMSG_ERROR")
|
||||
}
|
||||
if hdr.Type == syscall.NLMSG_DONE && hdr.Flags&syscall.NLM_F_MULTI > 0 {
|
||||
return errors.New("Done!")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Round the length of a netlink route attribute up to align it
|
||||
// properly.
|
||||
func rtaAlignOf(attrlen int) int {
|
||||
return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
|
||||
}
|
||||
43
probe/endpoint/conntrack/netlink_attr.go
Normal file
43
probe/endpoint/conntrack/netlink_attr.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package conntrack
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const attrHdrLength = 4
|
||||
|
||||
type Attr struct {
|
||||
Msg []byte
|
||||
Typ int
|
||||
IsNested bool
|
||||
IsNetByteorder bool
|
||||
}
|
||||
|
||||
func parseAttrs(b []byte) ([]Attr, error) {
|
||||
var attrs []Attr
|
||||
for len(b) >= attrHdrLength {
|
||||
var attr Attr
|
||||
attr, b = parseAttr(b)
|
||||
attrs = append(attrs, attr)
|
||||
}
|
||||
if len(b) != 0 {
|
||||
return nil, errors.New("leftover attr bytes")
|
||||
}
|
||||
return attrs, nil
|
||||
}
|
||||
|
||||
func parseAttr(b []byte) (Attr, []byte) {
|
||||
l := binary.LittleEndian.Uint16(b[0:2])
|
||||
// length is header + payload
|
||||
l -= uint16(attrHdrLength)
|
||||
|
||||
typ := binary.LittleEndian.Uint16(b[2:4])
|
||||
attr := Attr{
|
||||
Msg: b[attrHdrLength : attrHdrLength+int(l)],
|
||||
Typ: int(typ & NLA_TYPE_MASK),
|
||||
IsNested: typ&NLA_F_NESTED > 0,
|
||||
IsNetByteorder: typ&NLA_F_NET_BYTEORDER > 0,
|
||||
}
|
||||
return attr, b[rtaAlignOf(attrHdrLength+int(l)):]
|
||||
}
|
||||
Reference in New Issue
Block a user