netfilter: nft_meta: add pkttype support
authorAna Rey <anarey@gmail.com>
Wed, 6 Aug 2014 11:52:49 +0000 (13:52 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sun, 24 Aug 2014 12:06:39 +0000 (14:06 +0200)
Add pkttype support for ip, ipv6 and inet families of tables.

This allows you to fetch the meta packet type based on the link layer
information. The loopback traffic is a special case, the packet type
is guessed from the network layer header.

No special handling for bridge and arp since we're not going to see
such traffic in the loopback interface.

Joint work with Alvaro Neira Ayuso <alvaroneay@gmail.com>

Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com>
Signed-off-by: Ana Rey <anarey@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/uapi/linux/netfilter/nf_tables.h
net/netfilter/nft_meta.c

index 801bdd1e56e33b168b54705e0bfb8464e076f3b5..98144cdd8986038d9cc2f427aff71b310ad18e7e 100644 (file)
@@ -571,6 +571,7 @@ enum nft_exthdr_attributes {
  * @NFT_META_L4PROTO: layer 4 protocol number
  * @NFT_META_BRI_IIFNAME: packet input bridge interface name
  * @NFT_META_BRI_OIFNAME: packet output bridge interface name
+ * @NFT_META_PKTTYPE: packet type (skb->pkt_type), special handling for loopback
  */
 enum nft_meta_keys {
        NFT_META_LEN,
@@ -592,6 +593,7 @@ enum nft_meta_keys {
        NFT_META_L4PROTO,
        NFT_META_BRI_IIFNAME,
        NFT_META_BRI_OIFNAME,
+       NFT_META_PKTTYPE,
 };
 
 /**
index 852b178c6ae7fa2f7dbd6f7887404033da45971f..4f2862fc12c28c6a374d391b796f8bd285416553 100644 (file)
@@ -14,6 +14,9 @@
 #include <linux/netlink.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_tables.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <net/dst.h>
 #include <net/sock.h>
 #include <net/tcp_states.h> /* for TCP_TIME_WAIT */
@@ -124,6 +127,30 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                dest->data[0] = skb->secmark;
                break;
 #endif
+       case NFT_META_PKTTYPE:
+               if (skb->pkt_type != PACKET_LOOPBACK) {
+                       dest->data[0] = skb->pkt_type;
+                       break;
+               }
+
+               switch (pkt->ops->pf) {
+               case NFPROTO_IPV4:
+                       if (ipv4_is_multicast(ip_hdr(skb)->daddr))
+                               dest->data[0] = PACKET_MULTICAST;
+                       else
+                               dest->data[0] = PACKET_BROADCAST;
+                       break;
+               case NFPROTO_IPV6:
+                       if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
+                               dest->data[0] = PACKET_MULTICAST;
+                       else
+                               dest->data[0] = PACKET_BROADCAST;
+                       break;
+               default:
+                       WARN_ON(1);
+                       goto err;
+               }
+               break;
        default:
                WARN_ON(1);
                goto err;
@@ -195,6 +222,7 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
 #ifdef CONFIG_NETWORK_SECMARK
        case NFT_META_SECMARK:
 #endif
+       case NFT_META_PKTTYPE:
                break;
        default:
                return -EOPNOTSUPP;