netfilter: nft_meta: deal with PACKET_LOOPBACK in netdev family
authorLiping Zhang <zlpnobody@gmail.com>
Sat, 7 Jan 2017 13:33:55 +0000 (21:33 +0800)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 18 Jan 2017 19:32:43 +0000 (20:32 +0100)
After adding the following nft rule, then ping 224.0.0.1:
  # nft add rule netdev t c pkttype host counter

The warning complain message will be printed out again and again:
  WARNING: CPU: 0 PID: 10182 at net/netfilter/nft_meta.c:163 \
           nft_meta_get_eval+0x3fe/0x460 [nft_meta]
  [...]
  Call Trace:
  <IRQ>
  dump_stack+0x85/0xc2
  __warn+0xcb/0xf0
  warn_slowpath_null+0x1d/0x20
  nft_meta_get_eval+0x3fe/0x460 [nft_meta]
  nft_do_chain+0xff/0x5e0 [nf_tables]

So we should deal with PACKET_LOOPBACK in netdev family too. For ipv4,
convert it to PACKET_BROADCAST/MULTICAST according to the destination
address's type; For ipv6, convert it to PACKET_MULTICAST directly.

Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nft_meta.c

index 9a22b24346b8be7b6a135b27b1bc9b9e3de42e79..e1f5ca9b423b5ffda43ec5519d4c8832ce695899 100644 (file)
@@ -156,8 +156,34 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                case NFPROTO_IPV6:
                        *dest = PACKET_MULTICAST;
                        break;
+               case NFPROTO_NETDEV:
+                       switch (skb->protocol) {
+                       case htons(ETH_P_IP): {
+                               int noff = skb_network_offset(skb);
+                               struct iphdr *iph, _iph;
+
+                               iph = skb_header_pointer(skb, noff,
+                                                        sizeof(_iph), &_iph);
+                               if (!iph)
+                                       goto err;
+
+                               if (ipv4_is_multicast(iph->daddr))
+                                       *dest = PACKET_MULTICAST;
+                               else
+                                       *dest = PACKET_BROADCAST;
+
+                               break;
+                       }
+                       case htons(ETH_P_IPV6):
+                               *dest = PACKET_MULTICAST;
+                               break;
+                       default:
+                               WARN_ON_ONCE(1);
+                               goto err;
+                       }
+                       break;
                default:
-                       WARN_ON(1);
+                       WARN_ON_ONCE(1);
                        goto err;
                }
                break;