forked from platinasystems/conntrack-go
Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
first commit
- Loading branch information
Mahesh Jadhav
authored and
Mahesh Jadhav
committed
Dec 20, 2018
1 parent
0c98fd7
commit 897cd5022c49818ae56450f1cb64724ed02a527b
Showing
8 changed files
with
1,632 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)))[:] | ||
} |
Oops, something went wrong.