linux/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 * (C) 1999-2001 Paul `Rusty' Russell
   6 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 * This module accepts two parameters:
  13 *
  14 * nlbufsiz:
  15 *   The parameter specifies how big the buffer for each netlink multicast
  16 * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
  17 * get accumulated in the kernel until they are sent to userspace. It is
  18 * NOT possible to allocate more than 128kB, and it is strongly discouraged,
  19 * because atomically allocating 128kB inside the network rx softirq is not
  20 * reliable. Please also keep in mind that this buffer size is allocated for
  21 * each nlgroup you are using, so the total kernel memory usage increases
  22 * by that factor.
  23 *
  24 * Actually you should use nlbufsiz a bit smaller than PAGE_SIZE, since
  25 * nlbufsiz is used with alloc_skb, which adds another
  26 * sizeof(struct skb_shared_info).  Use NLMSG_GOODSIZE instead.
  27 *
  28 * flushtimeout:
  29 *   Specify, after how many hundredths of a second the queue should be
  30 *   flushed even if it is not full yet.
  31 */
  32#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  33#include <linux/module.h>
  34#include <linux/spinlock.h>
  35#include <linux/socket.h>
  36#include <linux/slab.h>
  37#include <linux/skbuff.h>
  38#include <linux/kernel.h>
  39#include <linux/timer.h>
  40#include <linux/netlink.h>
  41#include <linux/netdevice.h>
  42#include <linux/mm.h>
  43#include <linux/moduleparam.h>
  44#include <linux/netfilter.h>
  45#include <linux/netfilter/x_tables.h>
  46#include <linux/netfilter_ipv4/ipt_ULOG.h>
  47#include <net/netfilter/nf_log.h>
  48#include <net/sock.h>
  49#include <linux/bitops.h>
  50#include <asm/unaligned.h>
  51
  52MODULE_LICENSE("GPL");
  53MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
  54MODULE_DESCRIPTION("Xtables: packet logging to netlink using ULOG");
  55MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG);
  56
  57#define ULOG_NL_EVENT           111             /* Harald's favorite number */
  58#define ULOG_MAXNLGROUPS        32              /* numer of nlgroups */
  59
  60static unsigned int nlbufsiz = NLMSG_GOODSIZE;
  61module_param(nlbufsiz, uint, 0400);
  62MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
  63
  64static unsigned int flushtimeout = 10;
  65module_param(flushtimeout, uint, 0600);
  66MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second)");
  67
  68static int nflog = 1;
  69module_param(nflog, bool, 0400);
  70MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
  71
  72/* global data structures */
  73
  74typedef struct {
  75        unsigned int qlen;              /* number of nlmsgs' in the skb */
  76        struct nlmsghdr *lastnlh;       /* netlink header of last msg in skb */
  77        struct sk_buff *skb;            /* the pre-allocated skb */
  78        struct timer_list timer;        /* the timer function */
  79} ulog_buff_t;
  80
  81static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS];      /* array of buffers */
  82
  83static struct sock *nflognl;            /* our socket */
  84static DEFINE_SPINLOCK(ulog_lock);      /* spinlock */
  85
  86/* send one ulog_buff_t to userspace */
  87static void ulog_send(unsigned int nlgroupnum)
  88{
  89        ulog_buff_t *ub = &ulog_buffers[nlgroupnum];
  90
  91        if (timer_pending(&ub->timer)) {
  92                pr_debug("ulog_send: timer was pending, deleting\n");
  93                del_timer(&ub->timer);
  94        }
  95
  96        if (!ub->skb) {
  97                pr_debug("ulog_send: nothing to send\n");
  98                return;
  99        }
 100
 101        /* last nlmsg needs NLMSG_DONE */
 102        if (ub->qlen > 1)
 103                ub->lastnlh->nlmsg_type = NLMSG_DONE;
 104
 105        NETLINK_CB(ub->skb).dst_group = nlgroupnum + 1;
 106        pr_debug("throwing %d packets to netlink group %u\n",
 107                 ub->qlen, nlgroupnum + 1);
 108        netlink_broadcast(nflognl, ub->skb, 0, nlgroupnum + 1, GFP_ATOMIC);
 109
 110        ub->qlen = 0;
 111        ub->skb = NULL;
 112        ub->lastnlh = NULL;
 113}
 114
 115
 116/* timer function to flush queue in flushtimeout time */
 117static void ulog_timer(unsigned long data)
 118{
 119        pr_debug("timer function called, calling ulog_send\n");
 120
 121        /* lock to protect against somebody modifying our structure
 122         * from ipt_ulog_target at the same time */
 123        spin_lock_bh(&ulog_lock);
 124        ulog_send(data);
 125        spin_unlock_bh(&ulog_lock);
 126}
 127
 128static struct sk_buff *ulog_alloc_skb(unsigned int size)
 129{
 130        struct sk_buff *skb;
 131        unsigned int n;
 132
 133        /* alloc skb which should be big enough for a whole
 134         * multipart message. WARNING: has to be <= 131000
 135         * due to slab allocator restrictions */
 136
 137        n = max(size, nlbufsiz);
 138        skb = alloc_skb(n, GFP_ATOMIC);
 139        if (!skb) {
 140                pr_debug("cannot alloc whole buffer %ub!\n", n);
 141
 142                if (n > size) {
 143                        /* try to allocate only as much as we need for
 144                         * current packet */
 145
 146                        skb = alloc_skb(size, GFP_ATOMIC);
 147                        if (!skb)
 148                                pr_debug("cannot even allocate %ub\n", size);
 149                }
 150        }
 151
 152        return skb;
 153}
 154
 155static void ipt_ulog_packet(unsigned int hooknum,
 156                            const struct sk_buff *skb,
 157                            const struct net_device *in,
 158                            const struct net_device *out,
 159                            const struct ipt_ulog_info *loginfo,
 160                            const char *prefix)
 161{
 162        ulog_buff_t *ub;
 163        ulog_packet_msg_t *pm;
 164        size_t size, copy_len;
 165        struct nlmsghdr *nlh;
 166        struct timeval tv;
 167
 168        /* ffs == find first bit set, necessary because userspace
 169         * is already shifting groupnumber, but we need unshifted.
 170         * ffs() returns [1..32], we need [0..31] */
 171        unsigned int groupnum = ffs(loginfo->nl_group) - 1;
 172
 173        /* calculate the size of the skb needed */
 174        if (loginfo->copy_range == 0 || loginfo->copy_range > skb->len)
 175                copy_len = skb->len;
 176        else
 177                copy_len = loginfo->copy_range;
 178
 179        size = NLMSG_SPACE(sizeof(*pm) + copy_len);
 180
 181        ub = &ulog_buffers[groupnum];
 182
 183        spin_lock_bh(&ulog_lock);
 184
 185        if (!ub->skb) {
 186                if (!(ub->skb = ulog_alloc_skb(size)))
 187                        goto alloc_failure;
 188        } else if (ub->qlen >= loginfo->qthreshold ||
 189                   size > skb_tailroom(ub->skb)) {
 190                /* either the queue len is too high or we don't have
 191                 * enough room in nlskb left. send it to userspace. */
 192
 193                ulog_send(groupnum);
 194
 195                if (!(ub->skb = ulog_alloc_skb(size)))
 196                        goto alloc_failure;
 197        }
 198
 199        pr_debug("qlen %d, qthreshold %Zu\n", ub->qlen, loginfo->qthreshold);
 200
 201        /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
 202        nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT,
 203                        sizeof(*pm)+copy_len);
 204        ub->qlen++;
 205
 206        pm = NLMSG_DATA(nlh);
 207
 208        /* We might not have a timestamp, get one */
 209        if (skb->tstamp.tv64 == 0)
 210                __net_timestamp((struct sk_buff *)skb);
 211
 212        /* copy hook, prefix, timestamp, payload, etc. */
 213        pm->data_len = copy_len;
 214        tv = ktime_to_timeval(skb->tstamp);
 215        put_unaligned(tv.tv_sec, &pm->timestamp_sec);
 216        put_unaligned(tv.tv_usec, &pm->timestamp_usec);
 217        put_unaligned(skb->mark, &pm->mark);
 218        pm->hook = hooknum;
 219        if (prefix != NULL)
 220                strncpy(pm->prefix, prefix, sizeof(pm->prefix));
 221        else if (loginfo->prefix[0] != '\0')
 222                strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
 223        else
 224                *(pm->prefix) = '\0';
 225
 226        if (in && in->hard_header_len > 0 &&
 227            skb->mac_header != skb->network_header &&
 228            in->hard_header_len <= ULOG_MAC_LEN) {
 229                memcpy(pm->mac, skb_mac_header(skb), in->hard_header_len);
 230                pm->mac_len = in->hard_header_len;
 231        } else
 232                pm->mac_len = 0;
 233
 234        if (in)
 235                strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
 236        else
 237                pm->indev_name[0] = '\0';
 238
 239        if (out)
 240                strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
 241        else
 242                pm->outdev_name[0] = '\0';
 243
 244        /* copy_len <= skb->len, so can't fail. */
 245        if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
 246                BUG();
 247
 248        /* check if we are building multi-part messages */
 249        if (ub->qlen > 1)
 250                ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
 251
 252        ub->lastnlh = nlh;
 253
 254        /* if timer isn't already running, start it */
 255        if (!timer_pending(&ub->timer)) {
 256                ub->timer.expires = jiffies + flushtimeout * HZ / 100;
 257                add_timer(&ub->timer);
 258        }
 259
 260        /* if threshold is reached, send message to userspace */
 261        if (ub->qlen >= loginfo->qthreshold) {
 262                if (loginfo->qthreshold > 1)
 263                        nlh->nlmsg_type = NLMSG_DONE;
 264                ulog_send(groupnum);
 265        }
 266
 267        spin_unlock_bh(&ulog_lock);
 268
 269        return;
 270
 271nlmsg_failure:
 272        pr_debug("error during NLMSG_PUT\n");
 273alloc_failure:
 274        pr_debug("Error building netlink message\n");
 275        spin_unlock_bh(&ulog_lock);
 276}
 277
 278static unsigned int
 279ulog_tg(struct sk_buff *skb, const struct xt_action_param *par)
 280{
 281        ipt_ulog_packet(par->hooknum, skb, par->in, par->out,
 282                        par->targinfo, NULL);
 283        return XT_CONTINUE;
 284}
 285
 286static void ipt_logfn(u_int8_t pf,
 287                      unsigned int hooknum,
 288                      const struct sk_buff *skb,
 289                      const struct net_device *in,
 290                      const struct net_device *out,
 291                      const struct nf_loginfo *li,
 292                      const char *prefix)
 293{
 294        struct ipt_ulog_info loginfo;
 295
 296        if (!li || li->type != NF_LOG_TYPE_ULOG) {
 297                loginfo.nl_group = ULOG_DEFAULT_NLGROUP;
 298                loginfo.copy_range = 0;
 299                loginfo.qthreshold = ULOG_DEFAULT_QTHRESHOLD;
 300                loginfo.prefix[0] = '\0';
 301        } else {
 302                loginfo.nl_group = li->u.ulog.group;
 303                loginfo.copy_range = li->u.ulog.copy_len;
 304                loginfo.qthreshold = li->u.ulog.qthreshold;
 305                strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix));
 306        }
 307
 308        ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
 309}
 310
 311static int ulog_tg_check(const struct xt_tgchk_param *par)
 312{
 313        const struct ipt_ulog_info *loginfo = par->targinfo;
 314
 315        if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
 316                pr_debug("prefix not null-terminated\n");
 317                return -EINVAL;
 318        }
 319        if (loginfo->qthreshold > ULOG_MAX_QLEN) {
 320                pr_debug("queue threshold %Zu > MAX_QLEN\n",
 321                         loginfo->qthreshold);
 322                return -EINVAL;
 323        }
 324        return 0;
 325}
 326
 327#ifdef CONFIG_COMPAT
 328struct compat_ipt_ulog_info {
 329        compat_uint_t   nl_group;
 330        compat_size_t   copy_range;
 331        compat_size_t   qthreshold;
 332        char            prefix[ULOG_PREFIX_LEN];
 333};
 334
 335static void ulog_tg_compat_from_user(void *dst, const void *src)
 336{
 337        const struct compat_ipt_ulog_info *cl = src;
 338        struct ipt_ulog_info l = {
 339                .nl_group       = cl->nl_group,
 340                .copy_range     = cl->copy_range,
 341                .qthreshold     = cl->qthreshold,
 342        };
 343
 344        memcpy(l.prefix, cl->prefix, sizeof(l.prefix));
 345        memcpy(dst, &l, sizeof(l));
 346}
 347
 348static int ulog_tg_compat_to_user(void __user *dst, const void *src)
 349{
 350        const struct ipt_ulog_info *l = src;
 351        struct compat_ipt_ulog_info cl = {
 352                .nl_group       = l->nl_group,
 353                .copy_range     = l->copy_range,
 354                .qthreshold     = l->qthreshold,
 355        };
 356
 357        memcpy(cl.prefix, l->prefix, sizeof(cl.prefix));
 358        return copy_to_user(dst, &cl, sizeof(cl)) ? -EFAULT : 0;
 359}
 360#endif /* CONFIG_COMPAT */
 361
 362static struct xt_target ulog_tg_reg __read_mostly = {
 363        .name           = "ULOG",
 364        .family         = NFPROTO_IPV4,
 365        .target         = ulog_tg,
 366        .targetsize     = sizeof(struct ipt_ulog_info),
 367        .checkentry     = ulog_tg_check,
 368#ifdef CONFIG_COMPAT
 369        .compatsize     = sizeof(struct compat_ipt_ulog_info),
 370        .compat_from_user = ulog_tg_compat_from_user,
 371        .compat_to_user = ulog_tg_compat_to_user,
 372#endif
 373        .me             = THIS_MODULE,
 374};
 375
 376static struct nf_logger ipt_ulog_logger __read_mostly = {
 377        .name           = "ipt_ULOG",
 378        .logfn          = ipt_logfn,
 379        .me             = THIS_MODULE,
 380};
 381
 382static int __init ulog_tg_init(void)
 383{
 384        int ret, i;
 385
 386        pr_debug("init module\n");
 387
 388        if (nlbufsiz > 128*1024) {
 389                pr_warning("Netlink buffer has to be <= 128kB\n");
 390                return -EINVAL;
 391        }
 392
 393        /* initialize ulog_buffers */
 394        for (i = 0; i < ULOG_MAXNLGROUPS; i++)
 395                setup_timer(&ulog_buffers[i].timer, ulog_timer, i);
 396
 397        nflognl = netlink_kernel_create(&init_net,
 398                                        NETLINK_NFLOG, ULOG_MAXNLGROUPS, NULL,
 399                                        NULL, THIS_MODULE);
 400        if (!nflognl)
 401                return -ENOMEM;
 402
 403        ret = xt_register_target(&ulog_tg_reg);
 404        if (ret < 0) {
 405                netlink_kernel_release(nflognl);
 406                return ret;
 407        }
 408        if (nflog)
 409                nf_log_register(NFPROTO_IPV4, &ipt_ulog_logger);
 410
 411        return 0;
 412}
 413
 414static void __exit ulog_tg_exit(void)
 415{
 416        ulog_buff_t *ub;
 417        int i;
 418
 419        pr_debug("cleanup_module\n");
 420
 421        if (nflog)
 422                nf_log_unregister(&ipt_ulog_logger);
 423        xt_unregister_target(&ulog_tg_reg);
 424        netlink_kernel_release(nflognl);
 425
 426        /* remove pending timers and free allocated skb's */
 427        for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
 428                ub = &ulog_buffers[i];
 429                if (timer_pending(&ub->timer)) {
 430                        pr_debug("timer was pending, deleting\n");
 431                        del_timer(&ub->timer);
 432                }
 433
 434                if (ub->skb) {
 435                        kfree_skb(ub->skb);
 436                        ub->skb = NULL;
 437                }
 438        }
 439}
 440
 441module_init(ulog_tg_init);
 442module_exit(ulog_tg_exit);
 443