Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions apis/networking/v1beta1/firewall/match_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ const (
L4ProtoUDP L4Proto = "udp"
)

// CtStateValue is the connection tracking state of the packet.
// +kubebuilder:validation:Enum=new;established;related;untracked;invalid
type CtStateValue string

const (
// CtStateNew is the connection tracking state of the packet.
CtStateNew CtStateValue = "new"
// CtStateEstablished is the connection tracking state of the packet.
CtStateEstablished CtStateValue = "established"
// CtStateRelated is the connection tracking state of the packet.
CtStateRelated CtStateValue = "related"
// CtStateUntracked is the connection tracking state of the packet.
CtStateUntracked CtStateValue = "untracked"
// CtStateInvalid is the connection tracking state of the packet.
CtStateInvalid CtStateValue = "invalid"
)

// MatchIP is an IP to be matched.
// +kubebuilder:object:generate=true
type MatchIP struct {
Expand Down Expand Up @@ -92,6 +109,14 @@ type MatchProto struct {
Value L4Proto `json:"value"`
}

// MatchCtState is a connection tracking state to be matched.
// +kubebuilder:object:generate=true
type MatchCtState struct {
// Value is the connection tracking state to be matched.
// +kubebuilder:validation:MinItems=1
Value []CtStateValue `json:"value"`
}

// Match is a match to be applied to a rule.
// +kubebuilder:object:generate=true
type Match struct {
Expand All @@ -106,4 +131,6 @@ type Match struct {
Proto *MatchProto `json:"proto,omitempty"`
// Dev contains the options to match a device.
Dev *MatchDev `json:"dev,omitempty"`
// CtState contains the options to match a connection tracking state.
CtState *MatchCtState `json:"ctstate,omitempty"`
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,28 @@ spec:
description: Match is a match to be applied
to a rule.
properties:
ctstate:
description: CtState contains the options
to match a connection tracking state.
properties:
value:
description: Value is the connection
tracking state to be matched.
items:
description: CtStateValue is the connection
tracking state of the packet.
enum:
- new
- established
- related
- untracked
- invalid
type: string
minItems: 1
type: array
required:
- value
type: object
dev:
description: Dev contains the options to
match a device.
Expand Down Expand Up @@ -221,6 +243,28 @@ spec:
description: Match is a match to be applied
to a rule.
properties:
ctstate:
description: CtState contains the options
to match a connection tracking state.
properties:
value:
description: Value is the connection
tracking state to be matched.
items:
description: CtStateValue is the connection
tracking state of the packet.
enum:
- new
- established
- related
- untracked
- invalid
type: string
minItems: 1
type: array
required:
- value
type: object
dev:
description: Dev contains the options to
match a device.
Expand Down
61 changes: 61 additions & 0 deletions pkg/firewall/utils/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ func applyMatch(m *firewallv1beta1.Match, rule *nftables.Rule) error {
return err
}
}
if m.CtState != nil {
err = applyMatchCtState(m, rule, op)
if err != nil {
return err
}
}
return nil
}

Expand Down Expand Up @@ -303,3 +309,58 @@ func ifname(n string) []byte {
copy(b, n+"\x00")
return b
}

func applyMatchCtState(m *firewallv1beta1.Match, rule *nftables.Rule, op expr.CmpOp) error {
var stateBits uint32

cmpOp := expr.CmpOpNeq
if op == expr.CmpOpNeq {
cmpOp = expr.CmpOpEq
}

for _, state := range m.CtState.Value {
bit, err := getCtStateBit(state)
if err != nil {
return err
}
stateBits |= bit
}

rule.Exprs = append(rule.Exprs,
&expr.Ct{
Register: 1,
SourceRegister: false,
Key: expr.CtKeySTATE,
},
&expr.Bitwise{
SourceRegister: 1,
DestRegister: 1,
Len: 4,
Mask: binaryutil.NativeEndian.PutUint32(stateBits),
Xor: []byte{0x0, 0x0, 0x0, 0x0},
},
&expr.Cmp{
Op: cmpOp,
Register: 1,
Data: []byte{0, 0, 0, 0},
},
)
return nil
}

func getCtStateBit(state firewallv1beta1.CtStateValue) (uint32, error) {
switch state {
case firewallv1beta1.CtStateNew:
return expr.CtStateBitNEW, nil
case firewallv1beta1.CtStateEstablished:
return expr.CtStateBitESTABLISHED, nil
case firewallv1beta1.CtStateRelated:
return expr.CtStateBitRELATED, nil
case firewallv1beta1.CtStateInvalid:
return expr.CtStateBitINVALID, nil
case firewallv1beta1.CtStateUntracked:
return expr.CtStateBitUNTRACKED, nil
default:
return 0, fmt.Errorf("invalid ctstate value %s", state)
}
}