netfilter: nft_reject_inet: allow to use reject from inet ingress
authorPablo Neira Ayuso <pablo@netfilter.org>
Sat, 31 Oct 2020 10:24:08 +0000 (11:24 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sun, 1 Nov 2020 11:52:17 +0000 (12:52 +0100)
Enhance validation to support for reject from inet ingress chains.

Note that, reject from inet ingress and netdev ingress differ.

Reject packets from inet ingress are sent through ip_local_out() since
inet reject emulates the IP layer receive path. So the reject packet
follows to classic IP output and postrouting paths.

The reject action from netdev ingress assumes the packet not yet entered
the IP layer, so the reject packet is sent through dev_queue_xmit().
Therefore, reject packets from netdev ingress do not follow the classic
IP output and postrouting paths.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/ipv4/netfilter/nf_reject_ipv4.c
net/ipv6/netfilter/nf_reject_ipv6.c
net/netfilter/nft_reject_inet.c

index 8ca99342879cf7873d34f45e24940438bfadd428..04e5e0bfd86a31738a2a3546b742439f4d0b8133 100644 (file)
@@ -246,7 +246,8 @@ void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
        if (!oth)
                return;
 
-       if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(oldskb))
+       if ((hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) &&
+           nf_reject_fill_skb_dst(oldskb) < 0)
                return;
 
        if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
@@ -315,7 +316,8 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook)
        if (iph->frag_off & htons(IP_OFFSET))
                return;
 
-       if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(skb_in))
+       if ((hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) &&
+           nf_reject_fill_skb_dst(skb_in) < 0)
                return;
 
        if (skb_csum_unnecessary(skb_in) || !nf_reject_verify_csum(proto)) {
index 8dcceda6c32a67ca6b063c7c2218fed7547acd29..aa35e6e37c1f418fe1bbb241e2d77f237494547d 100644 (file)
@@ -304,7 +304,7 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
        fl6.fl6_sport = otcph->dest;
        fl6.fl6_dport = otcph->source;
 
-       if (hook == NF_INET_PRE_ROUTING) {
+       if (hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) {
                nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false);
                if (!dst)
                        return;
@@ -402,7 +402,8 @@ void nf_send_unreach6(struct net *net, struct sk_buff *skb_in,
        if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL)
                skb_in->dev = net->loopback_dev;
 
-       if (hooknum == NF_INET_PRE_ROUTING && nf_reject6_fill_skb_dst(skb_in))
+       if ((hooknum == NF_INET_PRE_ROUTING || hooknum == NF_INET_INGRESS) &&
+           nf_reject6_fill_skb_dst(skb_in) < 0)
                return;
 
        icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0);
index ffd1aa1f957657a8c526118c1b462fd1896ebdf8..32f3ea398ddfbcacaf72bf9a41a62e6f1c249781 100644 (file)
@@ -58,6 +58,18 @@ static void nft_reject_inet_eval(const struct nft_expr *expr,
        regs->verdict.code = NF_DROP;
 }
 
+static int nft_reject_inet_validate(const struct nft_ctx *ctx,
+                                   const struct nft_expr *expr,
+                                   const struct nft_data **data)
+{
+       return nft_chain_validate_hooks(ctx->chain,
+                                       (1 << NF_INET_LOCAL_IN) |
+                                       (1 << NF_INET_FORWARD) |
+                                       (1 << NF_INET_LOCAL_OUT) |
+                                       (1 << NF_INET_PRE_ROUTING) |
+                                       (1 << NF_INET_INGRESS));
+}
+
 static struct nft_expr_type nft_reject_inet_type;
 static const struct nft_expr_ops nft_reject_inet_ops = {
        .type           = &nft_reject_inet_type,
@@ -65,7 +77,7 @@ static const struct nft_expr_ops nft_reject_inet_ops = {
        .eval           = nft_reject_inet_eval,
        .init           = nft_reject_init,
        .dump           = nft_reject_dump,
-       .validate       = nft_reject_validate,
+       .validate       = nft_reject_inet_validate,
 };
 
 static struct nft_expr_type nft_reject_inet_type __read_mostly = {