@@ -149,20 +149,26 @@ type ConntrackFlow struct {
149149 TimeStart uint64
150150 TimeStop uint64
151151 TimeOut uint32
152+ Labels []byte
152153}
153154
154155func (s * ConntrackFlow ) String () string {
155156 // conntrack cmd output:
156- // 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
157+ // 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
157158 // start=2019-07-26 01:26:21.557800506 +0000 UTC stop=1970-01-01 00:00:00 +0000 UTC timeout=30(sec)
158159 start := time .Unix (0 , int64 (s .TimeStart ))
159160 stop := time .Unix (0 , int64 (s .TimeStop ))
160161 timeout := int32 (s .TimeOut )
161- return fmt .Sprintf ("%s\t %d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\t src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=0x%x start=%v stop=%v timeout=%d(sec) " ,
162+ res := fmt .Sprintf ("%s\t %d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\t src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=0x%x " ,
162163 nl .L4ProtoMap [s .Forward .Protocol ], s .Forward .Protocol ,
163164 s .Forward .SrcIP .String (), s .Forward .DstIP .String (), s .Forward .SrcPort , s .Forward .DstPort , s .Forward .Packets , s .Forward .Bytes ,
164165 s .Reverse .SrcIP .String (), s .Reverse .DstIP .String (), s .Reverse .SrcPort , s .Reverse .DstPort , s .Reverse .Packets , s .Reverse .Bytes ,
165- s .Mark , start , stop , timeout )
166+ s .Mark )
167+ if len (s .Labels ) > 0 {
168+ res += fmt .Sprintf ("labels=0x%x " , s .Labels )
169+ }
170+ res += fmt .Sprintf ("start=%v stop=%v timeout=%d(sec)" , start , stop , timeout )
171+ return res
166172}
167173
168174// This method parse the ip tuple structure
@@ -306,6 +312,12 @@ func parseConnectionMark(r *bytes.Reader) (mark uint32) {
306312 return
307313}
308314
315+ func parseConnectionLabels (r * bytes.Reader ) (label []byte ) {
316+ label = make ([]byte , 16 ) // netfilter defines 128 bit labels value
317+ binary .Read (r , nl .NativeEndian (), & label )
318+ return
319+ }
320+
309321func parseRawData (data []byte ) * ConntrackFlow {
310322 s := & ConntrackFlow {}
311323 // First there is the Nfgenmsg header
@@ -351,6 +363,8 @@ func parseRawData(data []byte) *ConntrackFlow {
351363 switch t {
352364 case nl .CTA_MARK :
353365 s .Mark = parseConnectionMark (reader )
366+ case nl .CTA_LABELS :
367+ s .Labels = parseConnectionLabels (reader )
354368 case nl .CTA_TIMEOUT :
355369 s .TimeOut = parseTimeOut (reader )
356370 case nl .CTA_STATUS , nl .CTA_USE , nl .CTA_ID :
@@ -406,6 +420,8 @@ const (
406420 ConntrackReplyAnyIP // Match source or destination reply IP
407421 ConntrackOrigSrcPort // --orig-port-src port Source port in original direction
408422 ConntrackOrigDstPort // --orig-port-dst port Destination port in original direction
423+ ConntrackMatchLabels // --label label1,label2 Labels used in entry
424+ ConntrackUnmatchLabels // --label label1,label2 Labels not used in entry
409425 ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP
410426 ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP
411427 ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instead ConntrackReplyAnyIP
@@ -421,6 +437,7 @@ type ConntrackFilter struct {
421437 ipNetFilter map [ConntrackFilterType ]* net.IPNet
422438 portFilter map [ConntrackFilterType ]uint16
423439 protoFilter uint8
440+ labelFilter map [ConntrackFilterType ][][]byte
424441}
425442
426443// AddIPNet adds a IP subnet to the conntrack filter
@@ -474,10 +491,34 @@ func (f *ConntrackFilter) AddProtocol(proto uint8) error {
474491 return nil
475492}
476493
494+ // AddLabels adds the provided list (zero or more) of labels to the conntrack filter
495+ // ConntrackFilterType here can be either:
496+ // 1) ConntrackMatchLabels: This matches every flow that has a label value (len(flow.Labels) > 0)
497+ // against the list of provided labels. If `flow.Labels` contains ALL the provided labels
498+ // it is considered a match. This can be used when you want to match flows that contain
499+ // one or more labels.
500+ // 2) ConntrackUnmatchLabels: This matches every flow that has a label value (len(flow.Labels) > 0)
501+ // against the list of provided labels. If `flow.Labels` does NOT contain ALL the provided labels
502+ // it is considered a match. This can be used when you want to match flows that don't contain
503+ // one or more labels.
504+ func (f * ConntrackFilter ) AddLabels (tp ConntrackFilterType , labels [][]byte ) error {
505+ if len (labels ) == 0 {
506+ return errors .New ("Invalid length for provided labels" )
507+ }
508+ if f .labelFilter == nil {
509+ f .labelFilter = make (map [ConntrackFilterType ][][]byte )
510+ }
511+ if _ , ok := f .labelFilter [tp ]; ok {
512+ return errors .New ("Filter attribute already present" )
513+ }
514+ f .labelFilter [tp ] = labels
515+ return nil
516+ }
517+
477518// MatchConntrackFlow applies the filter to the flow and returns true if the flow matches the filter
478519// false otherwise
479520func (f * ConntrackFilter ) MatchConntrackFlow (flow * ConntrackFlow ) bool {
480- if len (f .ipNetFilter ) == 0 && len (f .portFilter ) == 0 && f .protoFilter == 0 {
521+ if len (f .ipNetFilter ) == 0 && len (f .portFilter ) == 0 && f .protoFilter == 0 && len ( f . labelFilter ) == 0 {
481522 // empty filter always not match
482523 return false
483524 }
@@ -531,6 +572,29 @@ func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
531572 }
532573 }
533574
575+ // Label filter
576+ if len (f .labelFilter ) > 0 {
577+ if len (flow .Labels ) > 0 {
578+ // --label label1,label2 in conn entry;
579+ // every label passed should be contained in flow.Labels for a match to be true
580+ if elem , found := f .labelFilter [ConntrackMatchLabels ]; match && found {
581+ for _ , label := range elem {
582+ match = match && (bytes .Contains (flow .Labels , label ))
583+ }
584+ }
585+ // --label label1,label2 in conn entry;
586+ // every label passed should be not contained in flow.Labels for a match to be true
587+ if elem , found := f .labelFilter [ConntrackUnmatchLabels ]; match && found {
588+ for _ , label := range elem {
589+ match = match && ! (bytes .Contains (flow .Labels , label ))
590+ }
591+ }
592+ } else {
593+ // flow doesn't contain labels, so it doesn't contain or notContain any provided matches
594+ match = false
595+ }
596+ }
597+
534598 return match
535599}
536600
0 commit comments