fw: support for icmpv6 nftables in system rules

- Add support for all available nftables ICMPv6 types (ip6tables -m icmpv6 --help)
- Build nftables ICMPv6 rules
- Create a default outbound ICMPv6 echo-request/reply rule
  (currently outbound echo-request ICMPv6 is by default denied)

Signed-off-by: Nico Berlee <nico.berlee@on2it.net>
This commit is contained in:
Nico Berlee 2022-07-02 18:02:27 +02:00
parent 96fbc8536a
commit 5721ca9479
Failed to generate hash of commit
6 changed files with 89 additions and 6 deletions

View file

@ -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"
)

View file

@ -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)
}

View file

@ -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:

View file

@ -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

View file

@ -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{}
exprICMP, _ := exprs.NewExprProtocol(exprs.NFT_PROTO_ICMP)
switch icmpProtoVersion {
case exprs.NFT_PROTO_ICMP:
setType = nftables.TypeICMPType
case exprs.NFT_PROTO_ICMPv6:
setType = nftables.TypeICMP6Type
default:
return nil
}
exprICMP, _ := exprs.NewExprProtocol(icmpProtoVersion)
ICMPrule := []expr.Any{}
ICMPrule = append(ICMPrule, *exprICMP...)
@ -29,10 +39,15 @@ 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}...)
@ -40,7 +55,7 @@ func (n *Nft) buildICMPRule(table, family string, icmpOptions []*config.ExprValu
setElements = append(setElements,
[]nftables.SetElement{
{
Key: []byte{exprs.GetICMPType(icmp.Value)},
Key: []byte{icmpType},
},
}...)
case exprs.NFT_ICMP_CODE:

View file

@ -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",