netlink: specify netlink packet direction for nlmon
authorDaniel Borkmann <dborkman@redhat.com>
Mon, 23 Dec 2013 13:35:56 +0000 (14:35 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 31 Dec 2013 19:31:43 +0000 (14:31 -0500)
In order to facilitate development for netlink protocol dissector,
fill the unused field skb->pkt_type of the cloned skb with a hint
of the address space of the new owner (receiver) socket in the
notion of "to kernel" resp. "to user".

At the time we invoke __netlink_deliver_tap_skb(), we already have
set the new skb owner via netlink_skb_set_owner_r(), so we can use
that for netlink_is_kernel() probing.

In normal PF_PACKET network traffic, this field denotes if the
packet is destined for us (PACKET_HOST), if it's broadcast
(PACKET_BROADCAST), etc.

As we only have 3 bit reserved, we can use the value (= 6) of
PACKET_FASTROUTE as it's _not used_ anywhere in the whole kernel
and not supported anywhere, and packets of such type were never
exposed to user space, so there are no overlapping users of such
kind. Thus, as wished, that seems the only way to make both
PACKET_* values non-overlapping and therefore device agnostic.

By using those two flags for netlink skbs on nlmon devices, they
can be made available and picked up via sll_pkttype (previously
unused in netlink context) in struct sockaddr_ll. We now have
these two directions:

 - PACKET_USER (= 6)    ->  to user space
 - PACKET_KERNEL (= 7)  ->  to kernel space

Partial `ip a` example strace for sa_family=AF_NETLINK with
detected nl msg direction:

syscall:                     direction:
sendto(3,  ...) = 40         /* to kernel */
recvmsg(3, ...) = 3404       /* to user */
recvmsg(3, ...) = 1120       /* to user */
recvmsg(3, ...) = 20         /* to user */
sendto(3,  ...) = 40         /* to kernel */
recvmsg(3, ...) = 168        /* to user */
recvmsg(3, ...) = 144        /* to user */
recvmsg(3, ...) = 20         /* to user */

Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: Jakub Zawadzki <darkjames-ws@darkjames.pl>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/if_packet.h
net/netlink/af_netlink.c

index e9d844c80c112f45a64935a3a6c963a91e579995..1988a02842cc539c20381c0fbe412e2ce4c7f30d 100644 (file)
@@ -26,8 +26,10 @@ struct sockaddr_ll {
 #define PACKET_MULTICAST       2               /* To group             */
 #define PACKET_OTHERHOST       3               /* To someone else      */
 #define PACKET_OUTGOING                4               /* Outgoing of any type */
-/* These ones are invisible by user level */
 #define PACKET_LOOPBACK                5               /* MC/BRD frame looped back */
+#define PACKET_USER            6               /* To user space        */
+#define PACKET_KERNEL          7               /* To kernel space      */
+/* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
 #define PACKET_FASTROUTE       6               /* Fastrouted frame     */
 
 /* Packet socket options */
index 56e09d8a55fdd79a84b58b3cbdc411347492dacc..3f75f1cd9eb3d203e41adc2646f57a880d56cd2d 100644 (file)
@@ -204,6 +204,8 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb,
        if (nskb) {
                nskb->dev = dev;
                nskb->protocol = htons((u16) sk->sk_protocol);
+               nskb->pkt_type = netlink_is_kernel(sk) ?
+                                PACKET_KERNEL : PACKET_USER;
 
                ret = dev_queue_xmit(nskb);
                if (unlikely(ret > 0))