Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fw: support for icmpv6 nftables in system rules #689

Merged
merged 1 commit into from
Jul 2, 2022
Merged
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
4 changes: 4 additions & 0 deletions daemon/firewall/nftables/exprs/enums.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,8 @@ const (
ICMP_ROUTER_SOLICITATION = "router-solicitation"
ICMP_ADDRESS_MASK_REQUEST = "address-mask-request"
ICMP_ADDRESS_MASK_REPLY = "address-mask-reply"

ICMP_PACKET_TOO_BIG = "packet-too-big"
ICMP_NEIGHBOUR_SOLICITATION = "neighbour-solicitation"
ICMP_NEIGHBOUR_ADVERTISEMENT = "neighbour-advertisement"
)
10 changes: 10 additions & 0 deletions daemon/firewall/nftables/exprs/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ func NewExprProtocol(proto string) (*[]expr.Any, error) {
},
}, nil

case NFT_PROTO_ICMPv6:
return &[]expr.Any{
&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: []byte{unix.IPPROTO_ICMPV6},
},
}, nil

default:
return nil, fmt.Errorf("Not valid protocol rule, invalid or not supported protocol: %s", proto)
}
Expand Down
29 changes: 29 additions & 0 deletions daemon/firewall/nftables/exprs/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,35 @@ func GetICMPType(icmpType string) uint8 {
return 0
}

// GetICMPv6Type returns an ICMPv6 type code
func GetICMPv6Type(icmpType string) uint8 {
switch icmpType {
case ICMP_DEST_UNREACHABLE:
return layers.ICMPv6TypeDestinationUnreachable
case ICMP_PACKET_TOO_BIG:
return layers.ICMPv6TypePacketTooBig
case ICMP_TIME_EXCEEDED:
return layers.ICMPv6TypeTimeExceeded
case ICMP_PARAMETER_PROBLEM:
return layers.ICMPv6TypeParameterProblem
case ICMP_ECHO_REQUEST:
return layers.ICMPv6TypeEchoRequest
case ICMP_ECHO_REPLY:
return layers.ICMPv6TypeEchoReply
case ICMP_ROUTER_SOLICITATION:
return layers.ICMPv6TypeRouterSolicitation
case ICMP_ROUTER_ADVERTISEMENT:
return layers.ICMPv6TypeRouterAdvertisement
case ICMP_NEIGHBOUR_SOLICITATION:
return layers.ICMPv6TypeNeighborSolicitation
case ICMP_NEIGHBOUR_ADVERTISEMENT:
return layers.ICMPv6TypeNeighborAdvertisement
case ICMP_REDIRECT:
return layers.ICMPv6TypeRedirect
}
return 0
}

func getICMPv6RejectCode(reason string) uint8 {
switch reason {
case ICMP_HOST_UNREACHABLE, ICMP_NET_UNREACHABLE, ICMP_NO_ROUTE:
Expand Down
2 changes: 1 addition & 1 deletion daemon/firewall/nftables/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (n *Nft) parseExpression(table, chain, family string, expression *config.Ex
exprList = append(exprList, *exprIP...)

case exprs.NFT_PROTO_ICMP, exprs.NFT_PROTO_ICMPv6:
exprICMP := n.buildICMPRule(table, family, expression.Statement.Values)
exprICMP := n.buildICMPRule(table, family, expression.Statement.Name, expression.Statement.Values)
if exprICMP == nil {
log.Warning("%s icmp statement error", logTag)
return nil
Expand Down
25 changes: 20 additions & 5 deletions daemon/firewall/nftables/rule_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,25 @@ import (

// rules examples: https://github.com/google/nftables/blob/master/nftables_test.go

func (n *Nft) buildICMPRule(table, family string, icmpOptions []*config.ExprValues) *[]expr.Any {
func (n *Nft) buildICMPRule(table, family string, icmpProtoVersion string, icmpOptions []*config.ExprValues) *[]expr.Any {
tbl := getTable(table, family)
if tbl == nil {
return nil
}
offset := uint32(0)
setType := nftables.TypeICMPType
icmpType := uint8(0)
setType := nftables.SetDatatype{}

switch icmpProtoVersion {
case exprs.NFT_PROTO_ICMP:
setType = nftables.TypeICMPType
case exprs.NFT_PROTO_ICMPv6:
setType = nftables.TypeICMP6Type
default:
return nil
}

exprICMP, _ := exprs.NewExprProtocol(exprs.NFT_PROTO_ICMP)
exprICMP, _ := exprs.NewExprProtocol(icmpProtoVersion)
ICMPrule := []expr.Any{}
ICMPrule = append(ICMPrule, *exprICMP...)

Expand All @@ -29,18 +39,23 @@ func (n *Nft) buildICMPRule(table, family string, icmpOptions []*config.ExprValu
for _, icmp := range icmpOptions {
switch icmp.Key {
case exprs.NFT_ICMP_TYPE:
if exprs.NFT_PROTO_ICMPv6 == icmpProtoVersion {
icmpType = exprs.GetICMPv6Type(icmp.Value)
} else {
icmpType = exprs.GetICMPType(icmp.Value)
}
exprCmp := &expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: []byte{exprs.GetICMPType(icmp.Value)},
Data: []byte{icmpType},
}
ICMPtemp = append(ICMPtemp, []expr.Any{exprCmp}...)

// fill setElements. If there're more than 1 icmp type we'll use it later
setElements = append(setElements,
[]nftables.SetElement{
{
Key: []byte{exprs.GetICMPType(icmp.Value)},
Key: []byte{icmpType},
},
}...)
case exprs.NFT_ICMP_CODE:
Expand Down
25 changes: 25 additions & 0 deletions daemon/system-fw.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,31 @@
"Target": "accept",
"TargetParameters": ""
},
{
"Enabled": true,
"Position": 0,
"Description": "Allow ICMPv6",
"Expressions": [
{
"Statement": {
"Op": "",
"Name": "icmpv6",
"Values": [
{
"Key": "type",
"Value": "echo-request"
},
{
"Key": "type",
"Value": "echo-reply"
}
]
}
}
],
"Target": "accept",
"TargetParameters": ""
},
{
"Enabled": false,
"Position": "0",
Expand Down