Commit 0d7308c0 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

af_packet: Introduce egress hook



Add egress hook for AF_PACKET sockets that have the PACKET_QDISC_BYPASS
socket option set to on, which allows packets to escape without being
filtered in the egress path.

This patch only updates the AF_PACKET path, it does not update
dev_direct_xmit() so the XDP infrastructure has a chance to bypass
Netfilter.

[lukas: acquire rcu_read_lock, fix typos, rebase]
Signed-off-by: default avatarLukas Wunner <lukas@wunner.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 42df6e1d
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@
#endif
#include <linux/bpf.h>
#include <net/compat.h>
#include <linux/netfilter_netdev.h>

#include "internal.h"

@@ -241,8 +242,42 @@ struct packet_skb_cb {
static void __fanout_unlink(struct sock *sk, struct packet_sock *po);
static void __fanout_link(struct sock *sk, struct packet_sock *po);

#ifdef CONFIG_NETFILTER_EGRESS
static noinline struct sk_buff *nf_hook_direct_egress(struct sk_buff *skb)
{
	struct sk_buff *next, *head = NULL, *tail;
	int rc;

	rcu_read_lock();
	for (; skb != NULL; skb = next) {
		next = skb->next;
		skb_mark_not_on_list(skb);

		if (!nf_hook_egress(skb, &rc, skb->dev))
			continue;

		if (!head)
			head = skb;
		else
			tail->next = skb;

		tail = skb;
	}
	rcu_read_unlock();

	return head;
}
#endif

static int packet_direct_xmit(struct sk_buff *skb)
{
#ifdef CONFIG_NETFILTER_EGRESS
	if (nf_hook_egress_active()) {
		skb = nf_hook_direct_egress(skb);
		if (!skb)
			return NET_XMIT_DROP;
	}
#endif
	return dev_direct_xmit(skb, packet_pick_tx_queue(skb));
}