// SPDX-License-Identifier: GPL-2.0-only/* * This is a module which is used for queueing packets and communicating with * userspace via nfnetlink. * * (C) 2005 by Harald Welte <laforge@netfilter.org> * (C) 2007 by Patrick McHardy <kaber@trash.net> * * Based on the old ipv4-only ip_queue.c: * (C) 2000-2002 James Morris <jmorris@intercode.com.au> * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org> */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/notifier.h>#include <linux/netdevice.h>#include <linux/netfilter.h>#include <linux/proc_fs.h>#include <linux/netfilter_ipv4.h>#include <linux/netfilter_ipv6.h>#include <linux/netfilter_bridge.h>#include <linux/netfilter/nfnetlink.h>#include <linux/netfilter/nfnetlink_queue.h>#include <linux/netfilter/nf_conntrack_common.h>#include <linux/icmp.h>#include <linux/icmpv6.h>#include <linux/ip.h>#include <linux/list.h>#include <linux/sctp.h>#include <linux/cgroup-defs.h>#include <linux/rhashtable.h>#include <linux/jhash.h>#include <linux/tcp.h>#include <linux/udp.h>#include <net/gre.h>#include <net/gso.h>#include <net/sock.h>#include <net/tcp_states.h>#include <net/netfilter/nf_queue.h>#include <net/netns/generic.h> #include <linux/atomic.h> #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)#include "../bridge/br_private.h"#endif #if IS_ENABLED(CONFIG_NF_CONNTRACK)#include <net/netfilter/nf_conntrack.h>#endif #define NFQNL_QMAX_DEFAULT 1024#define NFQNL_HASH_MIN 8#define NFQNL_HASH_MAX 32768 /* We're using struct nlattr which has 16bit nla_len. Note that nla_len * includes the header length. Thus, the maximum packet length that we * support is 65531 bytes. We send truncated packets if the specified length * is larger than that. Userspace can check for presence of NFQA_CAP_LEN * attribute to detect truncation. */#define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN) struct nfqnl_instance { struct hlist_node hlist; /* global list of queues */ struct rhashtable nfqnl_packet_map; struct rcu_work rwork; u32 peer_portid; unsigned int queue_maxlen; unsigned int copy_range; unsigned int queue_dropped; unsigned int queue_user_dropped; u_int16_t queue_num; /* number of this queue */ u_int8_t copy_mode; u_int32_t flags; /* Set using NFQA_CFG_FLAGS *//* * Following fields are dirtied for each queued packet, * keep them in same cache line if possible. */ spinlock_t lock ____cacheline_aligned_in_smp; unsigned int queue_total; unsigned int id_sequence; /* 'sequence' of pkt ids */ struct list_head queue_list; /* packets in queue */}; typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); static struct workqueue_struct *nfq_cleanup_wq __read_mostly;static unsigned int nfnl_queue_net_id __read_mostly; #define INSTANCE_BUCKETS 16struct nfnl_queue_net { spinlock_t instances_lock; struct hlist_head instance_table[INSTANCE_BUCKETS];}; static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net){ return net_generic(net, nfnl_queue_net_id);} static inline u_int8_t instance_hashfn(u_int16_t queue_num){ return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;} static const struct rhashtable_params nfqnl_rhashtable_params = { .head_offset = offsetof(struct nf_queue_entry, hash_node), .key_offset = offsetof(struct nf_queue_entry, id), .key_len = sizeof(u32), .automatic_shrinking = true, .min_size = NFQNL_HASH_MIN, .max_size = NFQNL_HASH_MAX,}; static struct nfqnl_instance *instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num){ struct hlist_head *head; struct nfqnl_instance *inst; head = &q->instance_table[instance_hashfn(queue_num)]; hlist_for_each_entry_rcu(inst, head, hlist) { if (inst->queue_num == queue_num) return inst; } return NULL;} static struct nfqnl_instance *instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid){ struct nfqnl_instance *inst; unsigned int h; int err; inst = kzalloc_obj(*inst, GFP_KERNEL_ACCOUNT); if (!inst) return ERR_PTR(-ENOMEM); inst->queue_num = queue_num; inst->peer_portid = portid; inst->queue_maxlen = NFQNL_QMAX_DEFAULT; inst->copy_range = NFQNL_MAX_COPY_RANGE; inst->copy_mode = NFQNL_COPY_NONE; spin_lock_init(&inst->lock); INIT_LIST_HEAD(&inst->queue_list); err = rhashtable_init(&inst->nfqnl_packet_map, &nfqnl_rhashtable_params); if (err < 0) goto out_free; spin_lock(&q->instances_lock); if (instance_lookup(q, queue_num)) { err = -EEXIST; goto out_unlock; } if (!try_module_get(THIS_MODULE)) { err = -EAGAIN; goto out_unlock; } h = instance_hashfn(queue_num); hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]); spin_unlock(&q->instances_lock); return inst; out_unlock: spin_unlock(&q->instances_lock); rhashtable_destroy(&inst->nfqnl_packet_map);out_free: kfree(inst); return ERR_PTR(err);} static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data); static void instance_destroy_work(struct work_struct *work){ struct nfqnl_instance *inst; inst = container_of(to_rcu_work(work), struct nfqnl_instance, rwork); rcu_read_lock(); nfqnl_flush(inst, NULL, 0); rcu_read_unlock(); rhashtable_destroy(&inst->nfqnl_packet_map); kfree(inst); module_put(THIS_MODULE);} static void__instance_destroy(struct nfqnl_instance *inst){ hlist_del_rcu(&inst->hlist); INIT_RCU_WORK(&inst->rwork, instance_destroy_work); queue_rcu_work(nfq_cleanup_wq, &inst->rwork);} static voidinstance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst){ spin_lock(&q->instances_lock); __instance_destroy(inst); spin_unlock(&q->instances_lock);} static int__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry){ int err; err = rhashtable_insert_fast(&queue->nfqnl_packet_map, &entry->hash_node, nfqnl_rhashtable_params); if (unlikely(err)) return err; list_add_tail(&entry->list, &queue->queue_list); queue->queue_total++; return 0;} static void__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry){ rhashtable_remove_fast(&queue->nfqnl_packet_map, &entry->hash_node, nfqnl_rhashtable_params); list_del(&entry->list); queue->queue_total--;} static struct nf_queue_entry *find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id){ struct nf_queue_entry *entry; spin_lock_bh(&queue->lock); entry = rhashtable_lookup_fast(&queue->nfqnl_packet_map, &id, nfqnl_rhashtable_params); if (entry) __dequeue_entry(queue, entry); spin_unlock_bh(&queue->lock); return entry;} static unsigned int nf_iterate(struct sk_buff *skb, struct nf_hook_state *state, const struct nf_hook_entries *hooks, unsigned int *index){ const struct nf_hook_entry *hook; unsigned int verdict, i = *index; while (i < hooks->num_hook_entries) { hook = &hooks->hooks[i];repeat: verdict = nf_hook_entry_hookfn(hook, skb, state); if (verdict != NF_ACCEPT) { *index = i; if (verdict != NF_REPEAT) return verdict; goto repeat; } i++; } *index = i; return NF_ACCEPT;} static struct nf_hook_entries *nf_hook_entries_head(const struct net *net, u8 pf, u8 hooknum){ switch (pf) {#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE case NFPROTO_BRIDGE: return rcu_dereference(net->nf.hooks_bridge[hooknum]);#endif case NFPROTO_IPV4: return rcu_dereference(net->nf.hooks_ipv4[hooknum]); case NFPROTO_IPV6: return rcu_dereference(net->nf.hooks_ipv6[hooknum]); default: WARN_ON_ONCE(1); return NULL; } return NULL;} static int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry){#ifdef CONFIG_INET const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); if (entry->state.hook == NF_INET_LOCAL_OUT) { const struct iphdr *iph = ip_hdr(skb); if (!(iph->tos == rt_info->tos && skb->mark == rt_info->mark && iph->daddr == rt_info->daddr && iph->saddr == rt_info->saddr)) return ip_route_me_harder(entry->state.net, entry->state.sk, skb, RTN_UNSPEC); }#endif return 0;} static int nf_ip6_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry){ struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); if (entry->state.hook == NF_INET_LOCAL_OUT) { const struct ipv6hdr *iph = ipv6_hdr(skb); if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || skb->mark != rt_info->mark) return nf_ip6_route_me_harder(entry->state.net, entry->state.sk, skb); } return 0;} static int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry){ int ret = 0; switch (entry->state.pf) { case AF_INET: ret = nf_ip_reroute(skb, entry); break; case AF_INET6: ret = nf_ip6_reroute(skb, entry); break; } return ret;} /* caller must hold rcu read-side lock */static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict){ const struct nf_hook_entry *hook_entry; const struct nf_hook_entries *hooks; struct sk_buff *skb = entry->skb; const struct net *net; unsigned int i; int err; u8 pf; net = entry->state.net; pf = entry->state.pf; hooks = nf_hook_entries_head(net, pf, entry->state.hook); i = entry->hook_index; if (!hooks || i >= hooks->num_hook_entries) { kfree_skb_reason(skb, SKB_DROP_REASON_NETFILTER_DROP); nf_queue_entry_free(entry); return; } hook_entry = &hooks->hooks[i]; /* Continue traversal iff userspace said ok... */ if (verdict == NF_REPEAT) verdict = nf_hook_entry_hookfn(hook_entry, skb, &entry->state); if (verdict == NF_ACCEPT) { if (nf_reroute(skb, entry) < 0) verdict = NF_DROP; } if (verdict == NF_ACCEPT) {next_hook: ++i; verdict = nf_iterate(skb, &entry->state, hooks, &i); } switch (verdict & NF_VERDICT_MASK) { case NF_ACCEPT: case NF_STOP: local_bh_disable(); entry->state.okfn(entry->state.net, entry->state.sk, skb); local_bh_enable(); break; case NF_QUEUE: err = nf_queue(skb, &entry->state, i, verdict); if (err == 1) goto next_hook; break; case NF_STOLEN: break; default: kfree_skb(skb); } nf_queue_entry_free(entry);} /* return true if the entry has an unconfirmed conntrack attached that isn't owned by us * exclusively. */static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_unconfirmed){#if IS_ENABLED(CONFIG_NF_CONNTRACK) struct nf_conn *ct = (void *)skb_nfct(entry->skb); if (!ct || nf_ct_is_confirmed(ct)) return false; if (is_unconfirmed) *is_unconfirmed = true; /* in some cases skb_clone() can occur after initial conntrack * pickup, but conntrack assumes exclusive skb->_nfct ownership for * unconfirmed entries. * * This happens for br_netfilter and with ip multicast routing. * This can't be solved with serialization here because one clone * could have been queued for local delivery or could be transmitted * in parallel on another CPU. */ return refcount_read(&ct->ct_general.use) > 1;#endif return false;} static bool nf_bridge_port_valid(const struct net_device *dev){ if (!dev) return true; return netif_is_bridge_port(dev);} /* queued skbs leave rcu protection. We bump device refcount so that * the device cannot go away. However, while packet was out the port * could have been removed from the bridge. * * Ensure in+outdev are still part of a bridge at reinject time. * * The device rx_handler_data could even be pointing at data that is * not a net_bridge_port structure. */static bool nf_bridge_ports_valid(const struct nf_queue_entry *entry){#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (!nf_bridge_port_valid(entry->physin) || !nf_bridge_port_valid(entry->physout)) return false;#endif if (entry->state.pf != PF_BRIDGE) return true; if (!nf_bridge_port_valid(entry->state.in) || !nf_bridge_port_valid(entry->state.out)) return false; return true;} static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict){ const struct nf_ct_hook *ct_hook; if (!nf_bridge_ports_valid(entry)) verdict = NF_DROP; if (verdict == NF_ACCEPT || verdict == NF_REPEAT || verdict == NF_STOP) { unsigned int ct_verdict = verdict; rcu_read_lock(); ct_hook = rcu_dereference(nf_ct_hook); if (ct_hook) ct_verdict = ct_hook->update(entry->state.net, entry->skb); rcu_read_unlock();Lines 1–500 of 2210. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * This is a module which is used for queueing packets and communicating with * userspace via nfnetlink. * * (C) 2005 by Harald Welte <laforge@netfilter.org> * (C) 2007 by Patrick McHardy <kaber@trash.net> * * Based on the old ipv4-only ip_queue.c: * (C) 2000-2002 James Morris <jmorris@intercode.com.au> * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org> */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/notifier.h> #include <linux/netdevice.h> #include <linux/netfilter.h> #include <linux/proc_fs.h> #include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv6.h> #include <linux/netfilter_bridge.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_queue.h> #include <linux/netfilter/nf_conntrack_common.h> #include <linux/icmp.h> #include <linux/icmpv6.h> #include <linux/ip.h> #include <linux/list.h> #include <linux/sctp.h> #include <linux/cgroup-defs.h> #include <linux/rhashtable.h> #include <linux/jhash.h> #include <linux/tcp.h> #include <linux/udp.h> #include <net/gre.h> #include <net/gso.h> #include <net/sock.h> #include <net/tcp_states.h> #include <net/netfilter/nf_queue.h> #include <net/netns/generic.h> #include <linux/atomic.h> #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #include "../bridge/br_private.h" #endif #if IS_ENABLED(CONFIG_NF_CONNTRACK) #include <net/netfilter/nf_conntrack.h> #endif #define NFQNL_QMAX_DEFAULT 1024 #define NFQNL_HASH_MIN 8 #define NFQNL_HASH_MAX 32768 /* We're using struct nlattr which has 16bit nla_len. Note that nla_len * includes the header length. Thus, the maximum packet length that we * support is 65531 bytes. We send truncated packets if the specified length * is larger than that. Userspace can check for presence of NFQA_CAP_LEN * attribute to detect truncation. */ #define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN) struct nfqnl_instance { struct hlist_node hlist; /* global list of queues */ struct rhashtable nfqnl_packet_map; struct rcu_work rwork; u32 peer_portid; unsigned int queue_maxlen; unsigned int copy_range; unsigned int queue_dropped; unsigned int queue_user_dropped; u_int16_t queue_num; /* number of this queue */ u_int8_t copy_mode; u_int32_t flags; /* Set using NFQA_CFG_FLAGS */ /* * Following fields are dirtied for each queued packet, * keep them in same cache line if possible. */ spinlock_t lock ____cacheline_aligned_in_smp; unsigned int queue_total; unsigned int id_sequence; /* 'sequence' of pkt ids */ struct list_head queue_list; /* packets in queue */ }; typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); static struct workqueue_struct *nfq_cleanup_wq __read_mostly; static unsigned int nfnl_queue_net_id __read_mostly; #define INSTANCE_BUCKETS 16 struct nfnl_queue_net { spinlock_t instances_lock; struct hlist_head instance_table[INSTANCE_BUCKETS]; }; static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net) { return net_generic(net, nfnl_queue_net_id); } static inline u_int8_t instance_hashfn(u_int16_t queue_num) { return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS; } static const struct rhashtable_params nfqnl_rhashtable_params = { .head_offset = offsetof(struct nf_queue_entry, hash_node), .key_offset = offsetof(struct nf_queue_entry, id), .key_len = sizeof(u32), .automatic_shrinking = true, .min_size = NFQNL_HASH_MIN, .max_size = NFQNL_HASH_MAX, }; static struct nfqnl_instance * instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num) { struct hlist_head *head; struct nfqnl_instance *inst; head = &q->instance_table[instance_hashfn(queue_num)]; hlist_for_each_entry_rcu(inst, head, hlist) { if (inst->queue_num == queue_num) return inst; } return NULL; } static struct nfqnl_instance * instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid) { struct nfqnl_instance *inst; unsigned int h; int err; inst = kzalloc_obj(*inst, GFP_KERNEL_ACCOUNT); if (!inst) return ERR_PTR(-ENOMEM); inst->queue_num = queue_num; inst->peer_portid = portid; inst->queue_maxlen = NFQNL_QMAX_DEFAULT; inst->copy_range = NFQNL_MAX_COPY_RANGE; inst->copy_mode = NFQNL_COPY_NONE; spin_lock_init(&inst->lock); INIT_LIST_HEAD(&inst->queue_list); err = rhashtable_init(&inst->nfqnl_packet_map, &nfqnl_rhashtable_params); if (err < 0) goto out_free; spin_lock(&q->instances_lock); if (instance_lookup(q, queue_num)) { err = -EEXIST; goto out_unlock; } if (!try_module_get(THIS_MODULE)) { err = -EAGAIN; goto out_unlock; } h = instance_hashfn(queue_num); hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]); spin_unlock(&q->instances_lock); return inst; out_unlock: spin_unlock(&q->instances_lock); rhashtable_destroy(&inst->nfqnl_packet_map); out_free: kfree(inst); return ERR_PTR(err); } static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data); static void instance_destroy_work(struct work_struct *work) { struct nfqnl_instance *inst; inst = container_of(to_rcu_work(work), struct nfqnl_instance, rwork); rcu_read_lock(); nfqnl_flush(inst, NULL, 0); rcu_read_unlock(); rhashtable_destroy(&inst->nfqnl_packet_map); kfree(inst); module_put(THIS_MODULE); } static void __instance_destroy(struct nfqnl_instance *inst) { hlist_del_rcu(&inst->hlist); INIT_RCU_WORK(&inst->rwork, instance_destroy_work); queue_rcu_work(nfq_cleanup_wq, &inst->rwork); } static void instance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst) { spin_lock(&q->instances_lock); __instance_destroy(inst); spin_unlock(&q->instances_lock); } static int __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) { int err; err = rhashtable_insert_fast(&queue->nfqnl_packet_map, &entry->hash_node, nfqnl_rhashtable_params); if (unlikely(err)) return err; list_add_tail(&entry->list, &queue->queue_list); queue->queue_total++; return 0; } static void __dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) { rhashtable_remove_fast(&queue->nfqnl_packet_map, &entry->hash_node, nfqnl_rhashtable_params); list_del(&entry->list); queue->queue_total--; } static struct nf_queue_entry * find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) { struct nf_queue_entry *entry; spin_lock_bh(&queue->lock); entry = rhashtable_lookup_fast(&queue->nfqnl_packet_map, &id, nfqnl_rhashtable_params); if (entry) __dequeue_entry(queue, entry); spin_unlock_bh(&queue->lock); return entry; } static unsigned int nf_iterate(struct sk_buff *skb, struct nf_hook_state *state, const struct nf_hook_entries *hooks, unsigned int *index) { const struct nf_hook_entry *hook; unsigned int verdict, i = *index; while (i < hooks->num_hook_entries) { hook = &hooks->hooks[i]; repeat: verdict = nf_hook_entry_hookfn(hook, skb, state); if (verdict != NF_ACCEPT) { *index = i; if (verdict != NF_REPEAT) return verdict; goto repeat; } i++; } *index = i; return NF_ACCEPT; } static struct nf_hook_entries *nf_hook_entries_head(const struct net *net, u8 pf, u8 hooknum) { switch (pf) { #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE case NFPROTO_BRIDGE: return rcu_dereference(net->nf.hooks_bridge[hooknum]); #endif case NFPROTO_IPV4: return rcu_dereference(net->nf.hooks_ipv4[hooknum]); case NFPROTO_IPV6: return rcu_dereference(net->nf.hooks_ipv6[hooknum]); default: WARN_ON_ONCE(1); return NULL; } return NULL; } static int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry) { #ifdef CONFIG_INET const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); if (entry->state.hook == NF_INET_LOCAL_OUT) { const struct iphdr *iph = ip_hdr(skb); if (!(iph->tos == rt_info->tos && skb->mark == rt_info->mark && iph->daddr == rt_info->daddr && iph->saddr == rt_info->saddr)) return ip_route_me_harder(entry->state.net, entry->state.sk, skb, RTN_UNSPEC); } #endif return 0; } static int nf_ip6_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry) { struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); if (entry->state.hook == NF_INET_LOCAL_OUT) { const struct ipv6hdr *iph = ipv6_hdr(skb); if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || skb->mark != rt_info->mark) return nf_ip6_route_me_harder(entry->state.net, entry->state.sk, skb); } return 0; } static int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry) { int ret = 0; switch (entry->state.pf) { case AF_INET: ret = nf_ip_reroute(skb, entry); break; case AF_INET6: ret = nf_ip6_reroute(skb, entry); break; } return ret; } /* caller must hold rcu read-side lock */ static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) { const struct nf_hook_entry *hook_entry; const struct nf_hook_entries *hooks; struct sk_buff *skb = entry->skb; const struct net *net; unsigned int i; int err; u8 pf; net = entry->state.net; pf = entry->state.pf; hooks = nf_hook_entries_head(net, pf, entry->state.hook); i = entry->hook_index; if (!hooks || i >= hooks->num_hook_entries) { kfree_skb_reason(skb, SKB_DROP_REASON_NETFILTER_DROP); nf_queue_entry_free(entry); return; } hook_entry = &hooks->hooks[i]; /* Continue traversal iff userspace said ok... */ if (verdict == NF_REPEAT) verdict = nf_hook_entry_hookfn(hook_entry, skb, &entry->state); if (verdict == NF_ACCEPT) { if (nf_reroute(skb, entry) < 0) verdict = NF_DROP; } if (verdict == NF_ACCEPT) { next_hook: ++i; verdict = nf_iterate(skb, &entry->state, hooks, &i); } switch (verdict & NF_VERDICT_MASK) { case NF_ACCEPT: case NF_STOP: local_bh_disable(); entry->state.okfn(entry->state.net, entry->state.sk, skb); local_bh_enable(); break; case NF_QUEUE: err = nf_queue(skb, &entry->state, i, verdict); if (err == 1) goto next_hook; break; case NF_STOLEN: break; default: kfree_skb(skb); } nf_queue_entry_free(entry); } /* return true if the entry has an unconfirmed conntrack attached that isn't owned by us * exclusively. */ static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_unconfirmed) { #if IS_ENABLED(CONFIG_NF_CONNTRACK) struct nf_conn *ct = (void *)skb_nfct(entry->skb); if (!ct || nf_ct_is_confirmed(ct)) return false; if (is_unconfirmed) *is_unconfirmed = true; /* in some cases skb_clone() can occur after initial conntrack * pickup, but conntrack assumes exclusive skb->_nfct ownership for * unconfirmed entries. * * This happens for br_netfilter and with ip multicast routing. * This can't be solved with serialization here because one clone * could have been queued for local delivery or could be transmitted * in parallel on another CPU. */ return refcount_read(&ct->ct_general.use) > 1; #endif return false; } static bool nf_bridge_port_valid(const struct net_device *dev) { if (!dev) return true; return netif_is_bridge_port(dev); } /* queued skbs leave rcu protection. We bump device refcount so that * the device cannot go away. However, while packet was out the port * could have been removed from the bridge. * * Ensure in+outdev are still part of a bridge at reinject time. * * The device rx_handler_data could even be pointing at data that is * not a net_bridge_port structure. */ static bool nf_bridge_ports_valid(const struct nf_queue_entry *entry) { #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (!nf_bridge_port_valid(entry->physin) || !nf_bridge_port_valid(entry->physout)) return false; #endif if (entry->state.pf != PF_BRIDGE) return true; if (!nf_bridge_port_valid(entry->state.in) || !nf_bridge_port_valid(entry->state.out)) return false; return true; } static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) { const struct nf_ct_hook *ct_hook; if (!nf_bridge_ports_valid(entry)) verdict = NF_DROP; if (verdict == NF_ACCEPT || verdict == NF_REPEAT || verdict == NF_STOP) { unsigned int ct_verdict = verdict; rcu_read_lock(); ct_hook = rcu_dereference(nf_ct_hook); if (ct_hook) ct_verdict = ct_hook->update(entry->state.net, entry->skb); rcu_read_unlock();