Skip to content
Permalink
Browse files
first commit
  • Loading branch information
Mahesh Jadhav authored and Mahesh Jadhav committed Dec 20, 2018
1 parent 0c98fd7 commit 897cd5022c49818ae56450f1cb64724ed02a527b
Show file tree
Hide file tree
Showing 8 changed files with 1,632 additions and 0 deletions.
@@ -0,0 +1,31 @@
package main

import (
"github.com/OceanOfLearning/conntrack-go/lib"
"fmt"
"golang.org/x/sys/unix"
"log"
"time"
)

func main(){
h,err := lib.NewHandle(unix.NETLINK_NETFILTER)
if err != nil {
log.Fatalln("failed to create Handle..ERROR:",err)
}
err = h.ConntrackTableFlush(lib.ConntrackTable)
if err != nil {
log.Fatalln("failed to flush conntrack table..ERROR:", err)
}
for {
flows, err := h.ConntrackTableList(lib.ConntrackTable, lib.InetFamily(unix.AF_INET))
if err == nil {
if len(flows) != 0 {
for _, flow := range flows {
fmt.Println(flow)
}
}
}
<-time.After(time.Millisecond * 50)
}
}
@@ -0,0 +1,129 @@
package lib

import (
"net"
"fmt"
"golang.org/x/sys/unix"
)

const (
// For Parsing Mark
TCP_PROTO = 6
UDP_PROTO = 17
)
var L4ProtoMap = map[uint8]string{
6: "tcp",
17: "udp",
}
type ConntrackTableType uint8
const (
ConntrackTable = ConntrackTableType(1)
ConntrackExpectTable = ConntrackTableType(2)
)

// InetFamily Family type
type InetFamily uint8

// 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 {
Bytes uint64
DstIP net.IP
DstPort uint16
Packets uint64
Protocol uint8
SrcIP net.IP
SrcPort uint16
}

type ConntrackFlow struct {
FamilyType uint8
Forward ipTuple
Reverse ipTuple
Mark uint32
}

func (s *ConntrackFlow) String() string {
// conntrack cmd output:
// udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0
return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=%d",
L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes,
s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes,
s.Mark)
}

type Handle struct {
sockets map[int]*SocketHandle
lookupByDump bool
}
func (h *Handle) newNetlinkRequest(proto, flags int) *NetlinkRequest {
// Do this so that package API still use nl package variable nextSeqNr
if h.sockets == nil {
return NewNetlinkRequest(proto, flags)
}
return &NetlinkRequest{
NlMsghdr: unix.NlMsghdr{
Len: uint32(unix.SizeofNlMsghdr),
Type: uint16(proto),
Flags: unix.NLM_F_REQUEST | uint16(flags),
},
Sockets: h.sockets,
}
}
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
}
func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
req := h.newConntrackRequest(table, unix.AF_INET, IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
_, err := req.Execute(unix.NETLINK_NETFILTER, 0)
return err
}
func (h *Handle) newConntrackRequest(table ConntrackTableType, family InetFamily, operation, flags int) *NetlinkRequest {
// Create the Netlink request object
req := h.newNetlinkRequest((int(table)<<8)|operation, flags)
// Add the netfilter header
msg := &Nfgenmsg{
NfgenFamily: uint8(family),
Version: NFNETLINK_V0,
ResId: 0,
}
req.AddData(msg)
return req
}

func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) ([][]byte, error) {
req := h.newConntrackRequest(table, family, IPCTNL_MSG_CT_GET, unix.NLM_F_DUMP)
return req.Execute(unix.NETLINK_NETFILTER, 0)
}

func NewHandle(nlFamilies ...int) (*Handle, error) {
return newHandle(None(), None(), nlFamilies...)
}
func newHandle(newNs, curNs NsHandle, nlFamilies ...int) (*Handle, error) {
h := &Handle{sockets: map[int]*SocketHandle{}}
fams := SupportedNlFamilies
if len(nlFamilies) != 0 {
fams = nlFamilies
}
for _, f := range fams {
s, err := GetNetlinkSocketAt(newNs, curNs, f)
if err != nil {
return nil, err
}
h.sockets[f] = &SocketHandle{Socket: s}
}
return h, nil
}
@@ -0,0 +1,208 @@
package lib

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 = 7
CTA_MARK = 8
CTA_COUNTERS_ORIG = 9
CTA_COUNTERS_REPLY = 10
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
)

// enum ctattr_counters {
// CTA_COUNTERS_UNSPEC,
// CTA_COUNTERS_PACKETS, /* 64bit counters */
// CTA_COUNTERS_BYTES, /* 64bit counters */
// CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */
// CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */
// CTA_COUNTERS_PAD,
// __CTA_COUNTERS_M
// };
// #define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
const (
CTA_COUNTERS_PACKETS = 1
CTA_COUNTERS_BYTES = 2
)

// /* 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)))[:]
}

0 comments on commit 897cd50

Please sign in to comment.