diff --git a/conntrack_linux.go b/conntrack_linux.go index 67b92e2..eaa77e9 100644 --- a/conntrack_linux.go +++ b/conntrack_linux.go @@ -146,6 +146,7 @@ type ConntrackFlow struct { Forward ipTuple Reverse ipTuple Mark uint32 + Zone uint16 TimeStart uint64 TimeStop uint64 TimeOut uint32 @@ -154,7 +155,7 @@ type ConntrackFlow struct { 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 labels=0x00000000050012ac4202010000000000 + // 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 labels=0x00000000050012ac4202010000000000 zone=100 // start=2019-07-26 01:26:21.557800506 +0000 UTC stop=1970-01-01 00:00:00 +0000 UTC timeout=30(sec) start := time.Unix(0, int64(s.TimeStart)) stop := time.Unix(0, int64(s.TimeStop)) @@ -167,6 +168,9 @@ func (s *ConntrackFlow) String() string { if len(s.Labels) > 0 { res += fmt.Sprintf("labels=0x%x ", s.Labels) } + if s.Zone != 0 { + res += fmt.Sprintf("zone=%d ", s.Zone) + } res += fmt.Sprintf("start=%v stop=%v timeout=%d(sec)", start, stop, timeout) return res } @@ -318,6 +322,12 @@ func parseConnectionLabels(r *bytes.Reader) (label []byte) { return } +func parseConnectionZone(r *bytes.Reader) (zone uint16) { + parseBERaw16(r, &zone) + r.Seek(2, seekCurrent) + return +} + func parseRawData(data []byte) *ConntrackFlow { s := &ConntrackFlow{} // First there is the Nfgenmsg header @@ -369,6 +379,8 @@ func parseRawData(data []byte) *ConntrackFlow { s.TimeOut = parseTimeOut(reader) case nl.CTA_STATUS, nl.CTA_USE, nl.CTA_ID: skipNfAttrValue(reader, l) + case nl.CTA_ZONE: + s.Zone = parseConnectionZone(reader) default: skipNfAttrValue(reader, l) } @@ -413,18 +425,18 @@ func parseRawData(data []byte) *ConntrackFlow { type ConntrackFilterType uint8 const ( - ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction - ConntrackOrigDstIP // -orig-dst ip Destination address from original direction - ConntrackReplySrcIP // --reply-src ip Reply Source IP - ConntrackReplyDstIP // --reply-dst ip Reply Destination IP - ConntrackReplyAnyIP // Match source or destination reply IP - ConntrackOrigSrcPort // --orig-port-src port Source port in original direction - ConntrackOrigDstPort // --orig-port-dst port Destination port in original direction - ConntrackMatchLabels // --label label1,label2 Labels used in entry - ConntrackUnmatchLabels // --label label1,label2 Labels not used in entry - ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP - ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP - ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instead ConntrackReplyAnyIP + ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction + ConntrackOrigDstIP // -orig-dst ip Destination address from original direction + ConntrackReplySrcIP // --reply-src ip Reply Source IP + ConntrackReplyDstIP // --reply-dst ip Reply Destination IP + ConntrackReplyAnyIP // Match source or destination reply IP + ConntrackOrigSrcPort // --orig-port-src port Source port in original direction + ConntrackOrigDstPort // --orig-port-dst port Destination port in original direction + ConntrackMatchLabels // --label label1,label2 Labels used in entry + ConntrackUnmatchLabels // --label label1,label2 Labels not used in entry + ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP + ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP + ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instead ConntrackReplyAnyIP ) type CustomConntrackFilter interface { @@ -438,6 +450,7 @@ type ConntrackFilter struct { portFilter map[ConntrackFilterType]uint16 protoFilter uint8 labelFilter map[ConntrackFilterType][][]byte + zoneFilter *uint16 } // AddIPNet adds a IP subnet to the conntrack filter @@ -493,14 +506,14 @@ func (f *ConntrackFilter) AddProtocol(proto uint8) error { // AddLabels adds the provided list (zero or more) of labels to the conntrack filter // ConntrackFilterType here can be either: -// 1) ConntrackMatchLabels: This matches every flow that has a label value (len(flow.Labels) > 0) -// against the list of provided labels. If `flow.Labels` contains ALL the provided labels -// it is considered a match. This can be used when you want to match flows that contain -// one or more labels. -// 2) ConntrackUnmatchLabels: This matches every flow that has a label value (len(flow.Labels) > 0) -// against the list of provided labels. If `flow.Labels` does NOT contain ALL the provided labels -// it is considered a match. This can be used when you want to match flows that don't contain -// one or more labels. +// 1. ConntrackMatchLabels: This matches every flow that has a label value (len(flow.Labels) > 0) +// against the list of provided labels. If `flow.Labels` contains ALL the provided labels +// it is considered a match. This can be used when you want to match flows that contain +// one or more labels. +// 2. ConntrackUnmatchLabels: This matches every flow that has a label value (len(flow.Labels) > 0) +// against the list of provided labels. If `flow.Labels` does NOT contain ALL the provided labels +// it is considered a match. This can be used when you want to match flows that don't contain +// one or more labels. func (f *ConntrackFilter) AddLabels(tp ConntrackFilterType, labels [][]byte) error { if len(labels) == 0 { return errors.New("Invalid length for provided labels") @@ -515,10 +528,19 @@ func (f *ConntrackFilter) AddLabels(tp ConntrackFilterType, labels [][]byte) err return nil } +// AddZone adds a zone to the conntrack filter +func (f *ConntrackFilter) AddZone(zone uint16) error { + if f.zoneFilter != nil { + return errors.New("Filter attribute already present") + } + f.zoneFilter = &zone + 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.ipNetFilter) == 0 && len(f.portFilter) == 0 && f.protoFilter == 0 && len(f.labelFilter) == 0 { + if len(f.ipNetFilter) == 0 && len(f.portFilter) == 0 && f.protoFilter == 0 && len(f.labelFilter) == 0 && f.zoneFilter == nil { // empty filter always not match return false } @@ -529,6 +551,11 @@ func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool { return false } + // Conntrack zone filter + if f.zoneFilter != nil && *f.zoneFilter != flow.Zone { + return false + } + match := true // IP conntrack filter diff --git a/conntrack_test.go b/conntrack_test.go index 2945093..111d93e 100644 --- a/conntrack_test.go +++ b/conntrack_test.go @@ -381,6 +381,7 @@ func TestConntrackFilter(t *testing.T) { Protocol: 6, }, Labels: []byte{0, 0, 0, 0, 3, 4, 61, 141, 207, 170, 2, 0, 0, 0, 0, 0}, + Zone: 200, }, ConntrackFlow{ FamilyType: unix.AF_INET6, @@ -398,6 +399,7 @@ func TestConntrackFilter(t *testing.T) { DstPort: 1000, Protocol: 132, }, + Zone: 200, }) // Empty filter @@ -755,6 +757,16 @@ func TestConntrackFilter(t *testing.T) { t.Fatalf("Error, there should be only 1 match, v4:%d, v6:%d", v4Match, v6Match) } + filterV4 = &ConntrackFilter{} + err = filterV4.AddZone(200) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + filterV6 = &ConntrackFilter{} + v4Match, v6Match = applyFilter(flowList, filterV4, filterV6) + if v4Match != 2 || v6Match != 0 { + t.Fatalf("Error, there should be only 1 match, v4:%d, v6:%d", v4Match, v6Match) + } } func TestParseRawData(t *testing.T) { @@ -943,13 +955,16 @@ func TestParseRawData(t *testing.T) { /* >>>> CTA_COUNTERS_BYTES */ 12, 0, 2, 0, 0, 0, 0, 0, 0, 0, 7, 66, + /* >> CTA_ZONE */ + 8, 0, 18, 0, + 0, 100, 0, 0, /* >> nested CTA_TIMESTAMP */ 16, 0, 20, 128, /* >>>> CTA_TIMESTAMP_START */ 12, 0, 1, 0, 22, 134, 80, 175, 134, 10, 182, 221}, expConntrackFlow: "tcp\t6 src=192.168.0.10 dst=192.168.77.73 sport=42625 dport=3333 packets=11 bytes=1914\t" + - "src=192.168.77.73 dst=192.168.0.10 sport=3333 dport=42625 packets=10 bytes=1858 mark=0x5 " + + "src=192.168.77.73 dst=192.168.0.10 sport=3333 dport=42625 packets=10 bytes=1858 mark=0x5 zone=100 " + "start=2021-06-07 13:43:50.511990493 +0000 UTC stop=1970-01-01 00:00:00 +0000 UTC timeout=152(sec)", }, } diff --git a/nl/conntrack_linux.go b/nl/conntrack_linux.go index 8659cd1..eb3e1c1 100644 --- a/nl/conntrack_linux.go +++ b/nl/conntrack_linux.go @@ -88,6 +88,7 @@ const ( CTA_COUNTERS_REPLY = 10 CTA_USE = 11 CTA_ID = 12 + CTA_ZONE = 18 CTA_TIMESTAMP = 20 CTA_LABELS = 22 )