Skip to content

Commit 3f75881

Browse files
feat(firewall): add connection tracking state matching support
1 parent de96cea commit 3f75881

File tree

3 files changed

+132
-0
lines changed

3 files changed

+132
-0
lines changed

apis/networking/v1beta1/firewall/match_types.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,23 @@ const (
5454
L4ProtoUDP L4Proto = "udp"
5555
)
5656

57+
// CtStateValue is the connection tracking state of the packet.
58+
// +kubebuilder:validation:Enum=new;established;related;untracked;invalid
59+
type CtStateValue string
60+
61+
const (
62+
// CtStateNew is the connection tracking state of the packet.
63+
CtStateNew CtStateValue = "new"
64+
// CtStateEstablished is the connection tracking state of the packet.
65+
CtStateEstablished CtStateValue = "established"
66+
// CtStateRelated is the connection tracking state of the packet.
67+
CtStateRelated CtStateValue = "related"
68+
// CtStateUntracked is the connection tracking state of the packet.
69+
CtStateUntracked CtStateValue = "untracked"
70+
// CtStateInvalid is the connection tracking state of the packet.
71+
CtStateInvalid CtStateValue = "invalid"
72+
)
73+
5774
// MatchIP is an IP to be matched.
5875
// +kubebuilder:object:generate=true
5976
type MatchIP struct {
@@ -92,6 +109,14 @@ type MatchProto struct {
92109
Value L4Proto `json:"value"`
93110
}
94111

112+
// MatchCtState is a connection tracking state to be matched.
113+
// +kubebuilder:object:generate=true
114+
type MatchCtState struct {
115+
// Value is the connection tracking state to be matched.
116+
// +kubebuilder:validation:MinItems=1
117+
Value []CtStateValue `json:"value"`
118+
}
119+
95120
// Match is a match to be applied to a rule.
96121
// +kubebuilder:object:generate=true
97122
type Match struct {
@@ -106,4 +131,6 @@ type Match struct {
106131
Proto *MatchProto `json:"proto,omitempty"`
107132
// Dev contains the options to match a device.
108133
Dev *MatchDev `json:"dev,omitempty"`
134+
// CtState contains the options to match a connection tracking state.
135+
CtState *MatchCtState `json:"ctstate,omitempty"`
109136
}

deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_firewallconfigurations.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,28 @@ spec:
112112
description: Match is a match to be applied
113113
to a rule.
114114
properties:
115+
ctstate:
116+
description: CtState contains the options
117+
to match a connection tracking state.
118+
properties:
119+
value:
120+
description: Value is the connection
121+
tracking state to be matched.
122+
items:
123+
description: CtStateValue is the connection
124+
tracking state of the packet.
125+
enum:
126+
- new
127+
- established
128+
- related
129+
- untracked
130+
- invalid
131+
type: string
132+
minItems: 1
133+
type: array
134+
required:
135+
- value
136+
type: object
115137
dev:
116138
description: Dev contains the options to
117139
match a device.
@@ -221,6 +243,28 @@ spec:
221243
description: Match is a match to be applied
222244
to a rule.
223245
properties:
246+
ctstate:
247+
description: CtState contains the options
248+
to match a connection tracking state.
249+
properties:
250+
value:
251+
description: Value is the connection
252+
tracking state to be matched.
253+
items:
254+
description: CtStateValue is the connection
255+
tracking state of the packet.
256+
enum:
257+
- new
258+
- established
259+
- related
260+
- untracked
261+
- invalid
262+
type: string
263+
minItems: 1
264+
type: array
265+
required:
266+
- value
267+
type: object
224268
dev:
225269
description: Dev contains the options to
226270
match a device.

pkg/firewall/utils/match.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ func applyMatch(m *firewallv1beta1.Match, rule *nftables.Rule) error {
5858
return err
5959
}
6060
}
61+
if m.CtState != nil {
62+
err = applyMatchCtState(m, rule, op)
63+
if err != nil {
64+
return err
65+
}
66+
}
6167
return nil
6268
}
6369

@@ -303,3 +309,58 @@ func ifname(n string) []byte {
303309
copy(b, n+"\x00")
304310
return b
305311
}
312+
313+
func applyMatchCtState(m *firewallv1beta1.Match, rule *nftables.Rule, op expr.CmpOp) error {
314+
var stateBits uint32
315+
316+
cmpOp := expr.CmpOpNeq
317+
if op == expr.CmpOpNeq {
318+
cmpOp = expr.CmpOpEq
319+
}
320+
321+
for _, state := range m.CtState.Value {
322+
bit, err := getCtStateBit(state)
323+
if err != nil {
324+
return err
325+
}
326+
stateBits |= bit
327+
}
328+
329+
rule.Exprs = append(rule.Exprs,
330+
&expr.Ct{
331+
Register: 1,
332+
SourceRegister: false,
333+
Key: expr.CtKeySTATE,
334+
},
335+
&expr.Bitwise{
336+
SourceRegister: 1,
337+
DestRegister: 1,
338+
Len: 4,
339+
Mask: binaryutil.NativeEndian.PutUint32(stateBits),
340+
Xor: []byte{0x0, 0x0, 0x0, 0x0},
341+
},
342+
&expr.Cmp{
343+
Op: cmpOp,
344+
Register: 1,
345+
Data: []byte{0, 0, 0, 0},
346+
},
347+
)
348+
return nil
349+
}
350+
351+
func getCtStateBit(state firewallv1beta1.CtStateValue) (uint32, error) {
352+
switch state {
353+
case firewallv1beta1.CtStateNew:
354+
return expr.CtStateBitNEW, nil
355+
case firewallv1beta1.CtStateEstablished:
356+
return expr.CtStateBitESTABLISHED, nil
357+
case firewallv1beta1.CtStateRelated:
358+
return expr.CtStateBitRELATED, nil
359+
case firewallv1beta1.CtStateInvalid:
360+
return expr.CtStateBitINVALID, nil
361+
case firewallv1beta1.CtStateUntracked:
362+
return expr.CtStateBitUNTRACKED, nil
363+
default:
364+
return 0, fmt.Errorf("invalid ctstate value %s", state)
365+
}
366+
}

0 commit comments

Comments
 (0)