linux-old/net/ipv4/netfilter/ipt_ULOG.c
<<
>>
Prefs
   1/*
   2 * netfilter module for userspace packet logging daemons
   3 *
   4 * (C) 2000-2004 by Harald Welte <laforge@netfilter.org>
   5 *
   6 * 2000/09/22 ulog-cprange feature added
   7 * 2001/01/04 in-kernel queue as proposed by Sebastian Zander 
   8 *                                              <zander@fokus.gmd.de>
   9 * 2001/01/30 per-rule nlgroup conflicts with global queue. 
  10 *            nlgroup now global (sysctl)
  11 * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
  12 *            module loadtime -HW
  13 * 2002/07/07 remove broken nflog_rcv() function -HW
  14 * 2002/08/29 fix shifted/unshifted nlgroup bug -HW
  15 * 2002/10/30 fix uninitialized mac_len field - <Anders K. Pedersen>
  16 * 2004/10/25 fix erroneous calculation of 'len' parameter to NLMSG_PUT
  17 *            resulting in bogus 'error during NLMSG_PUT' messages.
  18 *
  19 * Released under the terms of the GPL
  20 *
  21 * This module accepts two parameters: 
  22 * 
  23 * nlbufsiz:
  24 *   The parameter specifies how big the buffer for each netlink multicast
  25 * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
  26 * get accumulated in the kernel until they are sent to userspace. It is
  27 * NOT possible to allocate more than 128kB, and it is strongly discouraged,
  28 * because atomically allocating 128kB inside the network rx softirq is not
  29 * reliable. Please also keep in mind that this buffer size is allocated for
  30 * each nlgroup you are using, so the total kernel memory usage increases
  31 * by that factor.
  32 *
  33 * flushtimeout:
  34 *   Specify, after how many clock ticks (intel: 100 per second) the queue
  35 * should be flushed even if it is not full yet.
  36 *
  37 * ipt_ULOG.c,v 1.22 2002/10/30 09:07:31 laforge Exp
  38 */
  39
  40#include <linux/module.h>
  41#include <linux/version.h>
  42#include <linux/config.h>
  43#include <linux/spinlock.h>
  44#include <linux/socket.h>
  45#include <linux/skbuff.h>
  46#include <linux/kernel.h>
  47#include <linux/timer.h>
  48#include <linux/netlink.h>
  49#include <linux/netdevice.h>
  50#include <linux/mm.h>
  51#include <linux/socket.h>
  52#include <linux/netfilter_ipv4/ip_tables.h>
  53#include <linux/netfilter_ipv4/ipt_ULOG.h>
  54#include <linux/netfilter_ipv4/lockhelp.h>
  55#include <net/sock.h>
  56#include <linux/bitops.h>
  57
  58MODULE_LICENSE("GPL");
  59MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
  60MODULE_DESCRIPTION("IP tables userspace logging module");
  61
  62#define ULOG_NL_EVENT           111             /* Harald's favorite number */
  63#define ULOG_MAXNLGROUPS        32              /* numer of nlgroups */
  64
  65#if 0
  66#define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ":" \
  67                                       format, ## args)
  68#else
  69#define DEBUGP(format, args...)
  70#endif
  71
  72#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0)
  73
  74static unsigned int nlbufsiz = 4096;
  75MODULE_PARM(nlbufsiz, "i");
  76MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
  77
  78static unsigned int flushtimeout = 10 * HZ;
  79MODULE_PARM(flushtimeout, "i");
  80MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
  81
  82/* global data structures */
  83
  84typedef struct {
  85        unsigned int qlen;              /* number of nlmsgs' in the skb */
  86        struct nlmsghdr *lastnlh;       /* netlink header of last msg in skb */
  87        struct sk_buff *skb;            /* the pre-allocated skb */
  88        struct timer_list timer;        /* the timer function */
  89} ulog_buff_t;
  90
  91static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS];      /* array of buffers */
  92
  93static struct sock *nflognl;    /* our socket */
  94DECLARE_LOCK(ulog_lock);        /* spinlock */
  95
  96/* send one ulog_buff_t to userspace */
  97static void ulog_send(unsigned int nlgroupnum)
  98{
  99        ulog_buff_t *ub = &ulog_buffers[nlgroupnum];
 100
 101        if (timer_pending(&ub->timer)) {
 102                DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
 103                del_timer(&ub->timer);
 104        }
 105
 106        /* last nlmsg needs NLMSG_DONE */
 107        if (ub->qlen > 1)
 108                ub->lastnlh->nlmsg_type = NLMSG_DONE;
 109
 110        NETLINK_CB(ub->skb).dst_groups = (1 << nlgroupnum);
 111        DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
 112                ub->qlen, nlgroupnum);
 113        netlink_broadcast(nflognl, ub->skb, 0, (1 << nlgroupnum), GFP_ATOMIC);
 114
 115        ub->qlen = 0;
 116        ub->skb = NULL;
 117        ub->lastnlh = NULL;
 118
 119}
 120
 121
 122/* timer function to flush queue in flushtimeout time */
 123static void ulog_timer(unsigned long data)
 124{
 125        DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");
 126
 127        /* lock to protect against somebody modifying our structure
 128         * from ipt_ulog_target at the same time */
 129        LOCK_BH(&ulog_lock);
 130        ulog_send(data);
 131        UNLOCK_BH(&ulog_lock);
 132}
 133
 134struct sk_buff *ulog_alloc_skb(unsigned int size)
 135{
 136        struct sk_buff *skb;
 137
 138        /* alloc skb which should be big enough for a whole
 139         * multipart message. WARNING: has to be <= 131000
 140         * due to slab allocator restrictions */
 141
 142        skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
 143        if (!skb) {
 144                PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
 145                        nlbufsiz);
 146
 147                /* try to allocate only as much as we need for 
 148                 * current packet */
 149
 150                skb = alloc_skb(size, GFP_ATOMIC);
 151                if (!skb)
 152                        PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
 153        }
 154
 155        return skb;
 156}
 157
 158static unsigned int ipt_ulog_target(struct sk_buff **pskb,
 159                                    unsigned int hooknum,
 160                                    const struct net_device *in,
 161                                    const struct net_device *out,
 162                                    const void *targinfo, void *userinfo)
 163{
 164        ulog_buff_t *ub;
 165        ulog_packet_msg_t *pm;
 166        size_t size, copy_len;
 167        struct nlmsghdr *nlh;
 168        struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
 169
 170        /* ffs == find first bit set, necessary because userspace
 171         * is already shifting groupnumber, but we need unshifted.
 172         * ffs() returns [1..32], we need [0..31] */
 173        unsigned int groupnum = ffs(loginfo->nl_group) - 1;
 174
 175        /* calculate the size of the skb needed */
 176        if ((loginfo->copy_range == 0) ||
 177            (loginfo->copy_range > (*pskb)->len)) {
 178                copy_len = (*pskb)->len;
 179        } else {
 180                copy_len = loginfo->copy_range;
 181        }
 182
 183        size = NLMSG_SPACE(sizeof(*pm) + copy_len);
 184
 185        ub = &ulog_buffers[groupnum];
 186        
 187        LOCK_BH(&ulog_lock);
 188
 189        if (!ub->skb) {
 190                if (!(ub->skb = ulog_alloc_skb(size)))
 191                        goto alloc_failure;
 192        } else if (ub->qlen >= loginfo->qthreshold ||
 193                   size > skb_tailroom(ub->skb)) {
 194                /* either the queue len is too high or we don't have 
 195                 * enough room in nlskb left. send it to userspace. */
 196
 197                ulog_send(groupnum);
 198
 199                if (!(ub->skb = ulog_alloc_skb(size)))
 200                        goto alloc_failure;
 201        }
 202
 203        DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, 
 204                loginfo->qthreshold);
 205
 206        /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
 207        nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
 208                        sizeof(*pm)+copy_len);
 209        ub->qlen++;
 210
 211        pm = NLMSG_DATA(nlh);
 212
 213        /* copy hook, prefix, timestamp, payload, etc. */
 214        pm->data_len = copy_len;
 215        pm->timestamp_sec = (*pskb)->stamp.tv_sec;
 216        pm->timestamp_usec = (*pskb)->stamp.tv_usec;
 217        pm->mark = (*pskb)->nfmark;
 218        pm->hook = hooknum;
 219        if (loginfo->prefix[0] != '\0')
 220                strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
 221        else
 222                *(pm->prefix) = '\0';
 223
 224        if (in && in->hard_header_len > 0
 225            && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
 226            && in->hard_header_len <= ULOG_MAC_LEN) {
 227                memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
 228                pm->mac_len = in->hard_header_len;
 229        } else
 230                pm->mac_len = 0;
 231
 232        if (in)
 233                strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
 234        else
 235                pm->indev_name[0] = '\0';
 236
 237        if (out)
 238                strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
 239        else
 240                pm->outdev_name[0] = '\0';
 241
 242        if (copy_len)
 243                memcpy(pm->payload, (*pskb)->data, copy_len);
 244        
 245        /* check if we are building multi-part messages */
 246        if (ub->qlen > 1) {
 247                ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
 248        }
 249
 250        ub->lastnlh = nlh;
 251
 252        /* if timer isn't already running, start it */
 253        if (!timer_pending(&ub->timer)) {
 254                ub->timer.expires = jiffies + flushtimeout;
 255                add_timer(&ub->timer);
 256        }
 257
 258        /* if threshold is reached, send message to userspace */
 259        if (ub->qlen >= loginfo->qthreshold) {
 260                if (loginfo->qthreshold > 1)
 261                        nlh->nlmsg_type = NLMSG_DONE;
 262                ulog_send(groupnum);
 263        }
 264
 265        UNLOCK_BH(&ulog_lock);
 266
 267        return IPT_CONTINUE;
 268
 269
 270nlmsg_failure:
 271        PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
 272
 273alloc_failure:
 274        PRINTR("ipt_ULOG: Error building netlink message\n");
 275
 276        UNLOCK_BH(&ulog_lock);
 277
 278        return IPT_CONTINUE;
 279}
 280
 281static int ipt_ulog_checkentry(const char *tablename,
 282                               const struct ipt_entry *e,
 283                               void *targinfo,
 284                               unsigned int targinfosize,
 285                               unsigned int hookmask)
 286{
 287        struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
 288
 289        if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
 290                DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
 291                return 0;
 292        }
 293
 294        if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
 295                DEBUGP("ipt_ULOG: prefix term %i\n",
 296                       loginfo->prefix[sizeof(loginfo->prefix) - 1]);
 297                return 0;
 298        }
 299
 300        if (loginfo->qthreshold > ULOG_MAX_QLEN) {
 301                DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
 302                        loginfo->qthreshold);
 303                return 0;
 304        }
 305
 306        return 1;
 307}
 308
 309static struct ipt_target ipt_ulog_reg =
 310    { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL,
 311THIS_MODULE
 312};
 313
 314static int __init init(void)
 315{
 316        int i;
 317
 318        DEBUGP("ipt_ULOG: init module\n");
 319
 320        if (nlbufsiz >= 128*1024) {
 321                printk("Netlink buffer has to be <= 128kB\n");
 322                return -EINVAL;
 323        }
 324
 325        /* initialize ulog_buffers */
 326        for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
 327                init_timer(&ulog_buffers[i].timer);
 328                ulog_buffers[i].timer.function = ulog_timer;
 329                ulog_buffers[i].timer.data = i;
 330        }
 331
 332        nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
 333        if (!nflognl)
 334                return -ENOMEM;
 335
 336        if (ipt_register_target(&ipt_ulog_reg) != 0) {
 337                sock_release(nflognl->socket);
 338                return -EINVAL;
 339        }
 340
 341        return 0;
 342}
 343
 344static void __exit fini(void)
 345{
 346        ulog_buff_t *ub;
 347        int i;
 348
 349        DEBUGP("ipt_ULOG: cleanup_module\n");
 350
 351        ipt_unregister_target(&ipt_ulog_reg);
 352        sock_release(nflognl->socket);
 353
 354        /* remove pending timers and free allocated skb's */
 355        for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
 356                ub = &ulog_buffers[i];
 357                if (timer_pending(&ub->timer)) {
 358                        DEBUGP("timer was pending, deleting\n");
 359                        del_timer(&ub->timer);
 360                }
 361
 362                if (ub->skb) {
 363                        kfree_skb(ub->skb);
 364                        ub->skb = NULL;
 365                }
 366        }
 367
 368}
 369
 370module_init(init);
 371module_exit(fini);
 372
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.