const struct expr *expr)
{
struct expr *dep = ctx->pdep->expr;
+ uint16_t l3proto;
+ uint8_t l4proto;
if (ctx->pbase != PROTO_BASE_NETWORK_HDR)
return true;
switch (family) {
case NFPROTO_INET:
- switch (dep->left->ops->type) {
- case EXPR_META:
- if (dep->left->meta.key == NFT_META_NFPROTO &&
- (mpz_get_uint16(dep->right->value) == NFPROTO_IPV4 ||
- mpz_get_uint16(dep->right->value) == NFPROTO_IPV6) &&
- expr->left->meta.key == NFT_META_L4PROTO &&
- mpz_get_uint8(expr->right->value) != IPPROTO_ICMP &&
- mpz_get_uint8(expr->right->value) != IPPROTO_ICMPV6)
- return false;
- break;
- case EXPR_PAYLOAD:
- if (dep->left->payload.base == PROTO_BASE_LL_HDR &&
- (mpz_get_uint16(dep->right->value) == ETH_P_IP ||
- mpz_get_uint16(dep->right->value) == ETH_P_IPV6) &&
- expr->left->meta.key == NFT_META_L4PROTO &&
- mpz_get_uint8(expr->right->value) != IPPROTO_ICMP &&
- mpz_get_uint8(expr->right->value) != IPPROTO_ICMPV6)
- return false;
- break;
- default:
- break;
- }
- break;
case NFPROTO_NETDEV:
case NFPROTO_BRIDGE:
- switch (dep->left->ops->type) {
- case EXPR_META:
- if (dep->left->meta.key == NFT_META_PROTOCOL &&
- (mpz_get_uint16(dep->right->value) == ETH_P_IP ||
- mpz_get_uint16(dep->right->value) == ETH_P_IPV6) &&
- expr->left->meta.key == NFT_META_L4PROTO &&
- mpz_get_uint8(expr->right->value) != IPPROTO_ICMP &&
- mpz_get_uint8(expr->right->value) != IPPROTO_ICMPV6)
- return false;
+ break;
+ default:
+ return true;
+ }
+
+ if (expr->left->meta.key != NFT_META_L4PROTO)
+ return true;
+
+ l3proto = mpz_get_uint16(dep->right->value);
+
+ switch (dep->left->ops->type) {
+ case EXPR_META:
+ if (dep->left->meta.key != NFT_META_NFPROTO)
+ return true;
+ break;
+ case EXPR_PAYLOAD:
+ if (dep->left->payload.base != PROTO_BASE_LL_HDR)
+ return true;
+
+ switch(l3proto) {
+ case ETH_P_IP:
+ l3proto = NFPROTO_IPV4;
break;
- case EXPR_PAYLOAD:
- if (dep->left->payload.base == PROTO_BASE_LL_HDR &&
- (mpz_get_uint16(dep->right->value) == ETH_P_IP ||
- mpz_get_uint16(dep->right->value) == ETH_P_IPV6) &&
- expr->left->meta.key == NFT_META_L4PROTO &&
- mpz_get_uint8(expr->right->value) != IPPROTO_ICMP &&
- mpz_get_uint8(expr->right->value) != IPPROTO_ICMPV6)
- return false;
+ case ETH_P_IPV6:
+ l3proto = NFPROTO_IPV6;
break;
default:
break;
}
break;
+ default:
+ break;
+ }
+
+ l4proto = mpz_get_uint8(expr->right->value);
+
+ switch (l4proto) {
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ break;
+ default:
+ return false;
}
+
+ if ((l3proto == NFPROTO_IPV4 && l4proto == IPPROTO_ICMPV6) ||
+ (l3proto == NFPROTO_IPV6 && l4proto == IPPROTO_ICMP))
+ return false;
+
return true;
}
--- /dev/null
+:output;type filter hook output priority 0
+
+*inet;test-inet;output
+
+# without nfproto specified, these should add an implicit dependency on
+# the likely l3 proto (i.e., IPv6 for icmpv6 and IPv4 for icmp)
+
+icmp type echo-request;ok
+icmpv6 type echo-request;ok
+
+# make sure only those nfproto matches are dropped if
+# the next statement would add it as a dependency anyway
+
+meta nfproto ipv4 icmp type echo-request;ok;icmp type echo-request
+meta nfproto ipv4 icmpv6 type echo-request;ok
+
+meta nfproto ipv6 icmp type echo-request;ok
+meta nfproto ipv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
--- /dev/null
+# icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "name": "icmp"
+ }
+ },
+ "right": "echo-request"
+ }
+ }
+]
+
+# icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "name": "icmpv6"
+ }
+ },
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv4 icmp type echo-request
+[
+ {
+ "match": {
+ "left": { "meta": "nfproto" },
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "name": "icmp"
+ }
+ },
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv4 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": { "meta": "nfproto" },
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "name": "icmpv6"
+ }
+ },
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv6 icmp type echo-request
+[
+ {
+ "match": {
+ "left": { "meta": "nfproto" },
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "name": "icmp"
+ }
+ },
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv6 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": { "meta": "nfproto" },
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "name": "icmpv6"
+ }
+ },
+ "right": "echo-request"
+ }
+ }
+]
+
--- /dev/null
+# meta nfproto ipv4 icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "name": "icmp"
+ }
+ },
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv6 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "name": "icmpv6"
+ }
+ },
+ "right": "echo-request"
+ }
+ }
+]
+
--- /dev/null
+# icmp type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmpv6 type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# meta nfproto ipv4 icmp type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta nfproto ipv4 icmpv6 type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# meta nfproto ipv6 icmp type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta nfproto ipv6 icmpv6 type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+