linux/net/netfilter/nf_queue.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/init.h>
   3#include <linux/module.h>
   4#include <linux/proc_fs.h>
   5#include <linux/skbuff.h>
   6#include <linux/netfilter.h>
   7#include <linux/seq_file.h>
   8#include <linux/rcupdate.h>
   9#include <net/protocol.h>
  10#include <net/netfilter/nf_queue.h>
  11
  12#include "nf_internals.h"
  13
  14/*
  15 * A queue handler may be registered for each protocol.  Each is protected by
  16 * long term mutex.  The handler must provide an an outfn() to accept packets
  17 * for queueing and must reinject all packets it receives, no matter what.
  18 */
  19static const struct nf_queue_handler *queue_handler[NFPROTO_NUMPROTO] __read_mostly;
  20
  21static DEFINE_MUTEX(queue_handler_mutex);
  22
  23/* return EBUSY when somebody else is registered, return EEXIST if the
  24 * same handler is registered, return 0 in case of success. */
  25int nf_register_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
  26{
  27        int ret;
  28
  29        if (pf >= ARRAY_SIZE(queue_handler))
  30                return -EINVAL;
  31
  32        mutex_lock(&queue_handler_mutex);
  33        if (queue_handler[pf] == qh)
  34                ret = -EEXIST;
  35        else if (queue_handler[pf])
  36                ret = -EBUSY;
  37        else {
  38                rcu_assign_pointer(queue_handler[pf], qh);
  39                ret = 0;
  40        }
  41        mutex_unlock(&queue_handler_mutex);
  42
  43        return ret;
  44}
  45EXPORT_SYMBOL(nf_register_queue_handler);
  46
  47/* The caller must flush their queue before this */
  48int nf_unregister_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
  49{
  50        if (pf >= ARRAY_SIZE(queue_handler))
  51                return -EINVAL;
  52
  53        mutex_lock(&queue_handler_mutex);
  54        if (queue_handler[pf] && queue_handler[pf] != qh) {
  55                mutex_unlock(&queue_handler_mutex);
  56                return -EINVAL;
  57        }
  58
  59        rcu_assign_pointer(queue_handler[pf], NULL);
  60        mutex_unlock(&queue_handler_mutex);
  61
  62        synchronize_rcu();
  63
  64        return 0;
  65}
  66EXPORT_SYMBOL(nf_unregister_queue_handler);
  67
  68void nf_unregister_queue_handlers(const struct nf_queue_handler *qh)
  69{
  70        u_int8_t pf;
  71
  72        mutex_lock(&queue_handler_mutex);
  73        for (pf = 0; pf < ARRAY_SIZE(queue_handler); pf++)  {
  74                if (queue_handler[pf] == qh)
  75                        rcu_assign_pointer(queue_handler[pf], NULL);
  76        }
  77        mutex_unlock(&queue_handler_mutex);
  78
  79        synchronize_rcu();
  80}
  81EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
  82
  83static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
  84{
  85        /* Release those devices we held, or Alexey will kill me. */
  86        if (entry->indev)
  87                dev_put(entry->indev);
  88        if (entry->outdev)
  89                dev_put(entry->outdev);
  90#ifdef CONFIG_BRIDGE_NETFILTER
  91        if (entry->skb->nf_bridge) {
  92                struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
  93
  94                if (nf_bridge->physindev)
  95                        dev_put(nf_bridge->physindev);
  96                if (nf_bridge->physoutdev)
  97                        dev_put(nf_bridge->physoutdev);
  98        }
  99#endif
 100        /* Drop reference to owner of hook which queued us. */
 101        module_put(entry->elem->owner);
 102}
 103
 104/*
 105 * Any packet that leaves via this function must come back
 106 * through nf_reinject().
 107 */
 108static int __nf_queue(struct sk_buff *skb,
 109                      struct list_head *elem,
 110                      u_int8_t pf, unsigned int hook,
 111                      struct net_device *indev,
 112                      struct net_device *outdev,
 113                      int (*okfn)(struct sk_buff *),
 114                      unsigned int queuenum)
 115{
 116        int status;
 117        struct nf_queue_entry *entry = NULL;
 118#ifdef CONFIG_BRIDGE_NETFILTER
 119        struct net_device *physindev;
 120        struct net_device *physoutdev;
 121#endif
 122        const struct nf_afinfo *afinfo;
 123        const struct nf_queue_handler *qh;
 124
 125        /* QUEUE == DROP if noone is waiting, to be safe. */
 126        rcu_read_lock();
 127
 128        qh = rcu_dereference(queue_handler[pf]);
 129        if (!qh)
 130                goto err_unlock;
 131
 132        afinfo = nf_get_afinfo(pf);
 133        if (!afinfo)
 134                goto err_unlock;
 135
 136        entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC);
 137        if (!entry)
 138                goto err_unlock;
 139
 140        *entry = (struct nf_queue_entry) {
 141                .skb    = skb,
 142                .elem   = list_entry(elem, struct nf_hook_ops, list),
 143                .pf     = pf,
 144                .hook   = hook,
 145                .indev  = indev,
 146                .outdev = outdev,
 147                .okfn   = okfn,
 148        };
 149
 150        /* If it's going away, ignore hook. */
 151        if (!try_module_get(entry->elem->owner)) {
 152                rcu_read_unlock();
 153                kfree(entry);
 154                return 0;
 155        }
 156
 157        /* Bump dev refs so they don't vanish while packet is out */
 158        if (indev)
 159                dev_hold(indev);
 160        if (outdev)
 161                dev_hold(outdev);
 162#ifdef CONFIG_BRIDGE_NETFILTER
 163        if (skb->nf_bridge) {
 164                physindev = skb->nf_bridge->physindev;
 165                if (physindev)
 166                        dev_hold(physindev);
 167                physoutdev = skb->nf_bridge->physoutdev;
 168                if (physoutdev)
 169                        dev_hold(physoutdev);
 170        }
 171#endif
 172        afinfo->saveroute(skb, entry);
 173        status = qh->outfn(entry, queuenum);
 174
 175        rcu_read_unlock();
 176
 177        if (status < 0) {
 178                nf_queue_entry_release_refs(entry);
 179                goto err;
 180        }
 181
 182        return 1;
 183
 184err_unlock:
 185        rcu_read_unlock();
 186err:
 187        kfree_skb(skb);
 188        kfree(entry);
 189        return 1;
 190}
 191
 192int nf_queue(struct sk_buff *skb,
 193             struct list_head *elem,
 194             u_int8_t pf, unsigned int hook,
 195             struct net_device *indev,
 196             struct net_device *outdev,
 197             int (*okfn)(struct sk_buff *),
 198             unsigned int queuenum)
 199{
 200        struct sk_buff *segs;
 201
 202        if (!skb_is_gso(skb))
 203                return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
 204                                  queuenum);
 205
 206        switch (pf) {
 207        case NFPROTO_IPV4:
 208                skb->protocol = htons(ETH_P_IP);
 209                break;
 210        case NFPROTO_IPV6:
 211                skb->protocol = htons(ETH_P_IPV6);
 212                break;
 213        }
 214
 215        segs = skb_gso_segment(skb, 0);
 216        kfree_skb(skb);
 217        if (IS_ERR(segs))
 218                return 1;
 219
 220        do {
 221                struct sk_buff *nskb = segs->next;
 222
 223                segs->next = NULL;
 224                if (!__nf_queue(segs, elem, pf, hook, indev, outdev, okfn,
 225                                queuenum))
 226                        kfree_skb(segs);
 227                segs = nskb;
 228        } while (segs);
 229        return 1;
 230}
 231
 232void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 233{
 234        struct sk_buff *skb = entry->skb;
 235        struct list_head *elem = &entry->elem->list;
 236        const struct nf_afinfo *afinfo;
 237
 238        rcu_read_lock();
 239
 240        nf_queue_entry_release_refs(entry);
 241
 242        /* Continue traversal iff userspace said ok... */
 243        if (verdict == NF_REPEAT) {
 244                elem = elem->prev;
 245                verdict = NF_ACCEPT;
 246        }
 247
 248        if (verdict == NF_ACCEPT) {
 249                afinfo = nf_get_afinfo(entry->pf);
 250                if (!afinfo || afinfo->reroute(skb, entry) < 0)
 251                        verdict = NF_DROP;
 252        }
 253
 254        if (verdict == NF_ACCEPT) {
 255        next_hook:
 256                verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook],
 257                                     skb, entry->hook,
 258                                     entry->indev, entry->outdev, &elem,
 259                                     entry->okfn, INT_MIN);
 260        }
 261
 262        switch (verdict & NF_VERDICT_MASK) {
 263        case NF_ACCEPT:
 264        case NF_STOP:
 265                local_bh_disable();
 266                entry->okfn(skb);
 267                local_bh_enable();
 268        case NF_STOLEN:
 269                break;
 270        case NF_QUEUE:
 271                if (!__nf_queue(skb, elem, entry->pf, entry->hook,
 272                                entry->indev, entry->outdev, entry->okfn,
 273                                verdict >> NF_VERDICT_BITS))
 274                        goto next_hook;
 275                break;
 276        default:
 277                kfree_skb(skb);
 278        }
 279        rcu_read_unlock();
 280        kfree(entry);
 281        return;
 282}
 283EXPORT_SYMBOL(nf_reinject);
 284
 285#ifdef CONFIG_PROC_FS
 286static void *seq_start(struct seq_file *seq, loff_t *pos)
 287{
 288        if (*pos >= ARRAY_SIZE(queue_handler))
 289                return NULL;
 290
 291        return pos;
 292}
 293
 294static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
 295{
 296        (*pos)++;
 297
 298        if (*pos >= ARRAY_SIZE(queue_handler))
 299                return NULL;
 300
 301        return pos;
 302}
 303
 304static void seq_stop(struct seq_file *s, void *v)
 305{
 306
 307}
 308
 309static int seq_show(struct seq_file *s, void *v)
 310{
 311        int ret;
 312        loff_t *pos = v;
 313        const struct nf_queue_handler *qh;
 314
 315        rcu_read_lock();
 316        qh = rcu_dereference(queue_handler[*pos]);
 317        if (!qh)
 318                ret = seq_printf(s, "%2lld NONE\n", *pos);
 319        else
 320                ret = seq_printf(s, "%2lld %s\n", *pos, qh->name);
 321        rcu_read_unlock();
 322
 323        return ret;
 324}
 325
 326static const struct seq_operations nfqueue_seq_ops = {
 327        .start  = seq_start,
 328        .next   = seq_next,
 329        .stop   = seq_stop,
 330        .show   = seq_show,
 331};
 332
 333static int nfqueue_open(struct inode *inode, struct file *file)
 334{
 335        return seq_open(file, &nfqueue_seq_ops);
 336}
 337
 338static const struct file_operations nfqueue_file_ops = {
 339        .owner   = THIS_MODULE,
 340        .open    = nfqueue_open,
 341        .read    = seq_read,
 342        .llseek  = seq_lseek,
 343        .release = seq_release,
 344};
 345#endif /* PROC_FS */
 346
 347
 348int __init netfilter_queue_init(void)
 349{
 350#ifdef CONFIG_PROC_FS
 351        if (!proc_create("nf_queue", S_IRUGO,
 352                         proc_net_netfilter, &nfqueue_file_ops))
 353                return -1;
 354#endif
 355        return 0;
 356}
 357
 358
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.