linux/net/netfilter/nf_queue.c
<<
>>
Prefs
   1/*
   2 * Rusty Russell (C)2000 -- This code is GPL.
   3 * Patrick McHardy (c) 2006-2012
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/slab.h>
   8#include <linux/init.h>
   9#include <linux/module.h>
  10#include <linux/proc_fs.h>
  11#include <linux/skbuff.h>
  12#include <linux/netfilter.h>
  13#include <linux/seq_file.h>
  14#include <linux/rcupdate.h>
  15#include <net/protocol.h>
  16#include <net/netfilter/nf_queue.h>
  17#include <net/dst.h>
  18
  19#include "nf_internals.h"
  20
  21/*
  22 * Hook for nfnetlink_queue to register its queue handler.
  23 * We do this so that most of the NFQUEUE code can be modular.
  24 *
  25 * Once the queue is registered it must reinject all packets it
  26 * receives, no matter what.
  27 */
  28static const struct nf_queue_handler __rcu *queue_handler __read_mostly;
  29
  30/* return EBUSY when somebody else is registered, return EEXIST if the
  31 * same handler is registered, return 0 in case of success. */
  32void nf_register_queue_handler(const struct nf_queue_handler *qh)
  33{
  34        /* should never happen, we only have one queueing backend in kernel */
  35        WARN_ON(rcu_access_pointer(queue_handler));
  36        rcu_assign_pointer(queue_handler, qh);
  37}
  38EXPORT_SYMBOL(nf_register_queue_handler);
  39
  40/* The caller must flush their queue before this */
  41void nf_unregister_queue_handler(void)
  42{
  43        RCU_INIT_POINTER(queue_handler, NULL);
  44        synchronize_rcu();
  45}
  46EXPORT_SYMBOL(nf_unregister_queue_handler);
  47
  48void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
  49{
  50        /* Release those devices we held, or Alexey will kill me. */
  51        if (entry->indev)
  52                dev_put(entry->indev);
  53        if (entry->outdev)
  54                dev_put(entry->outdev);
  55#ifdef CONFIG_BRIDGE_NETFILTER
  56        if (entry->skb->nf_bridge) {
  57                struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
  58
  59                if (nf_bridge->physindev)
  60                        dev_put(nf_bridge->physindev);
  61                if (nf_bridge->physoutdev)
  62                        dev_put(nf_bridge->physoutdev);
  63        }
  64#endif
  65        /* Drop reference to owner of hook which queued us. */
  66        module_put(entry->elem->owner);
  67}
  68EXPORT_SYMBOL_GPL(nf_queue_entry_release_refs);
  69
  70/* Bump dev refs so they don't vanish while packet is out */
  71bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
  72{
  73        if (!try_module_get(entry->elem->owner))
  74                return false;
  75
  76        if (entry->indev)
  77                dev_hold(entry->indev);
  78        if (entry->outdev)
  79                dev_hold(entry->outdev);
  80#ifdef CONFIG_BRIDGE_NETFILTER
  81        if (entry->skb->nf_bridge) {
  82                struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
  83                struct net_device *physdev;
  84
  85                physdev = nf_bridge->physindev;
  86                if (physdev)
  87                        dev_hold(physdev);
  88                physdev = nf_bridge->physoutdev;
  89                if (physdev)
  90                        dev_hold(physdev);
  91        }
  92#endif
  93
  94        return true;
  95}
  96EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
  97
  98/*
  99 * Any packet that leaves via this function must come back
 100 * through nf_reinject().
 101 */
 102int nf_queue(struct sk_buff *skb,
 103                      struct nf_hook_ops *elem,
 104                      u_int8_t pf, unsigned int hook,
 105                      struct net_device *indev,
 106                      struct net_device *outdev,
 107                      int (*okfn)(struct sk_buff *),
 108                      unsigned int queuenum)
 109{
 110        int status = -ENOENT;
 111        struct nf_queue_entry *entry = NULL;
 112        const struct nf_afinfo *afinfo;
 113        const struct nf_queue_handler *qh;
 114
 115        /* QUEUE == DROP if no one is waiting, to be safe. */
 116        rcu_read_lock();
 117
 118        qh = rcu_dereference(queue_handler);
 119        if (!qh) {
 120                status = -ESRCH;
 121                goto err_unlock;
 122        }
 123
 124        afinfo = nf_get_afinfo(pf);
 125        if (!afinfo)
 126                goto err_unlock;
 127
 128        entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC);
 129        if (!entry) {
 130                status = -ENOMEM;
 131                goto err_unlock;
 132        }
 133
 134        *entry = (struct nf_queue_entry) {
 135                .skb    = skb,
 136                .elem   = elem,
 137                .pf     = pf,
 138                .hook   = hook,
 139                .indev  = indev,
 140                .outdev = outdev,
 141                .okfn   = okfn,
 142                .size   = sizeof(*entry) + afinfo->route_key_size,
 143        };
 144
 145        if (!nf_queue_entry_get_refs(entry)) {
 146                status = -ECANCELED;
 147                goto err_unlock;
 148        }
 149        skb_dst_force(skb);
 150        afinfo->saveroute(skb, entry);
 151        status = qh->outfn(entry, queuenum);
 152
 153        rcu_read_unlock();
 154
 155        if (status < 0) {
 156                nf_queue_entry_release_refs(entry);
 157                goto err;
 158        }
 159
 160        return 0;
 161
 162err_unlock:
 163        rcu_read_unlock();
 164err:
 165        kfree(entry);
 166        return status;
 167}
 168
 169void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 170{
 171        struct sk_buff *skb = entry->skb;
 172        struct nf_hook_ops *elem = entry->elem;
 173        const struct nf_afinfo *afinfo;
 174        int err;
 175
 176        rcu_read_lock();
 177
 178        nf_queue_entry_release_refs(entry);
 179
 180        /* Continue traversal iff userspace said ok... */
 181        if (verdict == NF_REPEAT) {
 182                elem = list_entry(elem->list.prev, struct nf_hook_ops, list);
 183                verdict = NF_ACCEPT;
 184        }
 185
 186        if (verdict == NF_ACCEPT) {
 187                afinfo = nf_get_afinfo(entry->pf);
 188                if (!afinfo || afinfo->reroute(skb, entry) < 0)
 189                        verdict = NF_DROP;
 190        }
 191
 192        if (verdict == NF_ACCEPT) {
 193        next_hook:
 194                verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook],
 195                                     skb, entry->hook,
 196                                     entry->indev, entry->outdev, &elem,
 197                                     entry->okfn, INT_MIN);
 198        }
 199
 200        switch (verdict & NF_VERDICT_MASK) {
 201        case NF_ACCEPT:
 202        case NF_STOP:
 203                local_bh_disable();
 204                entry->okfn(skb);
 205                local_bh_enable();
 206                break;
 207        case NF_QUEUE:
 208                err = nf_queue(skb, elem, entry->pf, entry->hook,
 209                                entry->indev, entry->outdev, entry->okfn,
 210                                verdict >> NF_VERDICT_QBITS);
 211                if (err < 0) {
 212                        if (err == -ECANCELED)
 213                                goto next_hook;
 214                        if (err == -ESRCH &&
 215                           (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
 216                                goto next_hook;
 217                        kfree_skb(skb);
 218                }
 219                break;
 220        case NF_STOLEN:
 221                break;
 222        default:
 223                kfree_skb(skb);
 224        }
 225        rcu_read_unlock();
 226        kfree(entry);
 227}
 228EXPORT_SYMBOL(nf_reinject);
 229
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.