linux/net/netfilter/xt_hashlimit.c
<<
>>
Prefs
   1/* iptables match extension to limit the number of packets per second
   2 * seperately for each hashbucket (sourceip/sourceport/dstip/dstport)
   3 *
   4 * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
   5 *
   6 * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $
   7 *
   8 * Development of this code was funded by Astaro AG, http://www.astaro.com/
   9 */
  10#include <linux/module.h>
  11#include <linux/spinlock.h>
  12#include <linux/random.h>
  13#include <linux/jhash.h>
  14#include <linux/slab.h>
  15#include <linux/vmalloc.h>
  16#include <linux/proc_fs.h>
  17#include <linux/seq_file.h>
  18#include <linux/list.h>
  19#include <linux/skbuff.h>
  20#include <linux/mm.h>
  21#include <linux/in.h>
  22#include <linux/ip.h>
  23#include <linux/ipv6.h>
  24#include <net/net_namespace.h>
  25
  26#include <linux/netfilter/x_tables.h>
  27#include <linux/netfilter_ipv4/ip_tables.h>
  28#include <linux/netfilter_ipv6/ip6_tables.h>
  29#include <linux/netfilter/xt_hashlimit.h>
  30#include <linux/mutex.h>
  31
  32MODULE_LICENSE("GPL");
  33MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  34MODULE_DESCRIPTION("iptables match for limiting per hash-bucket");
  35MODULE_ALIAS("ipt_hashlimit");
  36MODULE_ALIAS("ip6t_hashlimit");
  37
  38/* need to declare this at the top */
  39static struct proc_dir_entry *hashlimit_procdir4;
  40static struct proc_dir_entry *hashlimit_procdir6;
  41static const struct file_operations dl_file_ops;
  42
  43/* hash table crap */
  44struct dsthash_dst {
  45        union {
  46                struct {
  47                        __be32 src;
  48                        __be32 dst;
  49                } ip;
  50                struct {
  51                        __be32 src[4];
  52                        __be32 dst[4];
  53                } ip6;
  54        } addr;
  55        __be16 src_port;
  56        __be16 dst_port;
  57};
  58
  59struct dsthash_ent {
  60        /* static / read-only parts in the beginning */
  61        struct hlist_node node;
  62        struct dsthash_dst dst;
  63
  64        /* modified structure members in the end */
  65        unsigned long expires;          /* precalculated expiry time */
  66        struct {
  67                unsigned long prev;     /* last modification */
  68                u_int32_t credit;
  69                u_int32_t credit_cap, cost;
  70        } rateinfo;
  71};
  72
  73struct xt_hashlimit_htable {
  74        struct hlist_node node;         /* global list of all htables */
  75        atomic_t use;
  76        int family;
  77
  78        struct hashlimit_cfg cfg;       /* config */
  79
  80        /* used internally */
  81        spinlock_t lock;                /* lock for list_head */
  82        u_int32_t rnd;                  /* random seed for hash */
  83        int rnd_initialized;
  84        unsigned int count;             /* number entries in table */
  85        struct timer_list timer;        /* timer for gc */
  86
  87        /* seq_file stuff */
  88        struct proc_dir_entry *pde;
  89
  90        struct hlist_head hash[0];      /* hashtable itself */
  91};
  92
  93static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */
  94static DEFINE_MUTEX(hlimit_mutex);      /* additional checkentry protection */
  95static HLIST_HEAD(hashlimit_htables);
  96static struct kmem_cache *hashlimit_cachep __read_mostly;
  97
  98static inline bool dst_cmp(const struct dsthash_ent *ent,
  99                           const struct dsthash_dst *b)
 100{
 101        return !memcmp(&ent->dst, b, sizeof(ent->dst));
 102}
 103
 104static u_int32_t
 105hash_dst(const struct xt_hashlimit_htable *ht, const struct dsthash_dst *dst)
 106{
 107        return jhash(dst, sizeof(*dst), ht->rnd) % ht->cfg.size;
 108}
 109
 110static struct dsthash_ent *
 111dsthash_find(const struct xt_hashlimit_htable *ht,
 112             const struct dsthash_dst *dst)
 113{
 114        struct dsthash_ent *ent;
 115        struct hlist_node *pos;
 116        u_int32_t hash = hash_dst(ht, dst);
 117
 118        if (!hlist_empty(&ht->hash[hash])) {
 119                hlist_for_each_entry(ent, pos, &ht->hash[hash], node)
 120                        if (dst_cmp(ent, dst))
 121                                return ent;
 122        }
 123        return NULL;
 124}
 125
 126/* allocate dsthash_ent, initialize dst, put in htable and lock it */
 127static struct dsthash_ent *
 128dsthash_alloc_init(struct xt_hashlimit_htable *ht,
 129                   const struct dsthash_dst *dst)
 130{
 131        struct dsthash_ent *ent;
 132
 133        /* initialize hash with random val at the time we allocate
 134         * the first hashtable entry */
 135        if (!ht->rnd_initialized) {
 136                get_random_bytes(&ht->rnd, 4);
 137                ht->rnd_initialized = 1;
 138        }
 139
 140        if (ht->cfg.max && ht->count >= ht->cfg.max) {
 141                /* FIXME: do something. question is what.. */
 142                if (net_ratelimit())
 143                        printk(KERN_WARNING
 144                                "xt_hashlimit: max count of %u reached\n",
 145                                ht->cfg.max);
 146                return NULL;
 147        }
 148
 149        ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC);
 150        if (!ent) {
 151                if (net_ratelimit())
 152                        printk(KERN_ERR
 153                                "xt_hashlimit: can't allocate dsthash_ent\n");
 154                return NULL;
 155        }
 156        memcpy(&ent->dst, dst, sizeof(ent->dst));
 157
 158        hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]);
 159        ht->count++;
 160        return ent;
 161}
 162
 163static inline void
 164dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent)
 165{
 166        hlist_del(&ent->node);
 167        kmem_cache_free(hashlimit_cachep, ent);
 168        ht->count--;
 169}
 170static void htable_gc(unsigned long htlong);
 171
 172static int htable_create(struct xt_hashlimit_info *minfo, int family)
 173{
 174        struct xt_hashlimit_htable *hinfo;
 175        unsigned int size;
 176        unsigned int i;
 177
 178        if (minfo->cfg.size)
 179                size = minfo->cfg.size;
 180        else {
 181                size = ((num_physpages << PAGE_SHIFT) / 16384) /
 182                       sizeof(struct list_head);
 183                if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
 184                        size = 8192;
 185                if (size < 16)
 186                        size = 16;
 187        }
 188        /* FIXME: don't use vmalloc() here or anywhere else -HW */
 189        hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
 190                        sizeof(struct list_head) * size);
 191        if (!hinfo) {
 192                printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n");
 193                return -1;
 194        }
 195        minfo->hinfo = hinfo;
 196
 197        /* copy match config into hashtable config */
 198        memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
 199        hinfo->cfg.size = size;
 200        if (!hinfo->cfg.max)
 201                hinfo->cfg.max = 8 * hinfo->cfg.size;
 202        else if (hinfo->cfg.max < hinfo->cfg.size)
 203                hinfo->cfg.max = hinfo->cfg.size;
 204
 205        for (i = 0; i < hinfo->cfg.size; i++)
 206                INIT_HLIST_HEAD(&hinfo->hash[i]);
 207
 208        atomic_set(&hinfo->use, 1);
 209        hinfo->count = 0;
 210        hinfo->family = family;
 211        hinfo->rnd_initialized = 0;
 212        spin_lock_init(&hinfo->lock);
 213        hinfo->pde = create_proc_entry(minfo->name, 0,
 214                                       family == AF_INET ? hashlimit_procdir4 :
 215                                                           hashlimit_procdir6);
 216        if (!hinfo->pde) {
 217                vfree(hinfo);
 218                return -1;
 219        }
 220        hinfo->pde->proc_fops = &dl_file_ops;
 221        hinfo->pde->data = hinfo;
 222
 223        setup_timer(&hinfo->timer, htable_gc, (unsigned long )hinfo);
 224        hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
 225        add_timer(&hinfo->timer);
 226
 227        spin_lock_bh(&hashlimit_lock);
 228        hlist_add_head(&hinfo->node, &hashlimit_htables);
 229        spin_unlock_bh(&hashlimit_lock);
 230
 231        return 0;
 232}
 233
 234static bool select_all(const struct xt_hashlimit_htable *ht,
 235                       const struct dsthash_ent *he)
 236{
 237        return 1;
 238}
 239
 240static bool select_gc(const struct xt_hashlimit_htable *ht,
 241                      const struct dsthash_ent *he)
 242{
 243        return time_after_eq(jiffies, he->expires);
 244}
 245
 246static void htable_selective_cleanup(struct xt_hashlimit_htable *ht,
 247                        bool (*select)(const struct xt_hashlimit_htable *ht,
 248                                      const struct dsthash_ent *he))
 249{
 250        unsigned int i;
 251
 252        /* lock hash table and iterate over it */
 253        spin_lock_bh(&ht->lock);
 254        for (i = 0; i < ht->cfg.size; i++) {
 255                struct dsthash_ent *dh;
 256                struct hlist_node *pos, *n;
 257                hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) {
 258                        if ((*select)(ht, dh))
 259                                dsthash_free(ht, dh);
 260                }
 261        }
 262        spin_unlock_bh(&ht->lock);
 263}
 264
 265/* hash table garbage collector, run by timer */
 266static void htable_gc(unsigned long htlong)
 267{
 268        struct xt_hashlimit_htable *ht = (struct xt_hashlimit_htable *)htlong;
 269
 270        htable_selective_cleanup(ht, select_gc);
 271
 272        /* re-add the timer accordingly */
 273        ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval);
 274        add_timer(&ht->timer);
 275}
 276
 277static void htable_destroy(struct xt_hashlimit_htable *hinfo)
 278{
 279        /* remove timer, if it is pending */
 280        if (timer_pending(&hinfo->timer))
 281                del_timer(&hinfo->timer);
 282
 283        /* remove proc entry */
 284        remove_proc_entry(hinfo->pde->name,
 285                          hinfo->family == AF_INET ? hashlimit_procdir4 :
 286                                                     hashlimit_procdir6);
 287        htable_selective_cleanup(hinfo, select_all);
 288        vfree(hinfo);
 289}
 290
 291static struct xt_hashlimit_htable *htable_find_get(const char *name,
 292                                                   int family)
 293{
 294        struct xt_hashlimit_htable *hinfo;
 295        struct hlist_node *pos;
 296
 297        spin_lock_bh(&hashlimit_lock);
 298        hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) {
 299                if (!strcmp(name, hinfo->pde->name) &&
 300                    hinfo->family == family) {
 301                        atomic_inc(&hinfo->use);
 302                        spin_unlock_bh(&hashlimit_lock);
 303                        return hinfo;
 304                }
 305        }
 306        spin_unlock_bh(&hashlimit_lock);
 307        return NULL;
 308}
 309
 310static void htable_put(struct xt_hashlimit_htable *hinfo)
 311{
 312        if (atomic_dec_and_test(&hinfo->use)) {
 313                spin_lock_bh(&hashlimit_lock);
 314                hlist_del(&hinfo->node);
 315                spin_unlock_bh(&hashlimit_lock);
 316                htable_destroy(hinfo);
 317        }
 318}
 319
 320/* The algorithm used is the Simple Token Bucket Filter (TBF)
 321 * see net/sched/sch_tbf.c in the linux source tree
 322 */
 323
 324/* Rusty: This is my (non-mathematically-inclined) understanding of
 325   this algorithm.  The `average rate' in jiffies becomes your initial
 326   amount of credit `credit' and the most credit you can ever have
 327   `credit_cap'.  The `peak rate' becomes the cost of passing the
 328   test, `cost'.
 329
 330   `prev' tracks the last packet hit: you gain one credit per jiffy.
 331   If you get credit balance more than this, the extra credit is
 332   discarded.  Every time the match passes, you lose `cost' credits;
 333   if you don't have that many, the test fails.
 334
 335   See Alexey's formal explanation in net/sched/sch_tbf.c.
 336
 337   To get the maximum range, we multiply by this factor (ie. you get N
 338   credits per jiffy).  We want to allow a rate as low as 1 per day
 339   (slowest userspace tool allows), which means
 340   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
 341*/
 342#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
 343
 344/* Repeated shift and or gives us all 1s, final shift and add 1 gives
 345 * us the power of 2 below the theoretical max, so GCC simply does a
 346 * shift. */
 347#define _POW2_BELOW2(x) ((x)|((x)>>1))
 348#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
 349#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
 350#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
 351#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
 352#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
 353
 354#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
 355
 356/* Precision saver. */
 357static inline u_int32_t
 358user2credits(u_int32_t user)
 359{
 360        /* If multiplying would overflow... */
 361        if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
 362                /* Divide first. */
 363                return (user / XT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
 364
 365        return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE;
 366}
 367
 368static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
 369{
 370        dh->rateinfo.credit += (now - dh->rateinfo.prev) * CREDITS_PER_JIFFY;
 371        if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
 372                dh->rateinfo.credit = dh->rateinfo.credit_cap;
 373        dh->rateinfo.prev = now;
 374}
 375
 376static int
 377hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
 378                   struct dsthash_dst *dst,
 379                   const struct sk_buff *skb, unsigned int protoff)
 380{
 381        __be16 _ports[2], *ports;
 382        int nexthdr;
 383
 384        memset(dst, 0, sizeof(*dst));
 385
 386        switch (hinfo->family) {
 387        case AF_INET:
 388                if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
 389                        dst->addr.ip.dst = ip_hdr(skb)->daddr;
 390                if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
 391                        dst->addr.ip.src = ip_hdr(skb)->saddr;
 392
 393                if (!(hinfo->cfg.mode &
 394                      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))
 395                        return 0;
 396                nexthdr = ip_hdr(skb)->protocol;
 397                break;
 398#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 399        case AF_INET6:
 400                if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
 401                        memcpy(&dst->addr.ip6.dst, &ipv6_hdr(skb)->daddr,
 402                               sizeof(dst->addr.ip6.dst));
 403                if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
 404                        memcpy(&dst->addr.ip6.src, &ipv6_hdr(skb)->saddr,
 405                               sizeof(dst->addr.ip6.src));
 406
 407                if (!(hinfo->cfg.mode &
 408                      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))
 409                        return 0;
 410                nexthdr = ipv6_find_hdr(skb, &protoff, -1, NULL);
 411                if (nexthdr < 0)
 412                        return -1;
 413                break;
 414#endif
 415        default:
 416                BUG();
 417                return 0;
 418        }
 419
 420        switch (nexthdr) {
 421        case IPPROTO_TCP:
 422        case IPPROTO_UDP:
 423        case IPPROTO_UDPLITE:
 424        case IPPROTO_SCTP:
 425        case IPPROTO_DCCP:
 426                ports = skb_header_pointer(skb, protoff, sizeof(_ports),
 427                                           &_ports);
 428                break;
 429        default:
 430                _ports[0] = _ports[1] = 0;
 431                ports = _ports;
 432                break;
 433        }
 434        if (!ports)
 435                return -1;
 436        if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SPT)
 437                dst->src_port = ports[0];
 438        if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DPT)
 439                dst->dst_port = ports[1];
 440        return 0;
 441}
 442
 443static bool
 444hashlimit_match(const struct sk_buff *skb,
 445                const struct net_device *in,
 446                const struct net_device *out,
 447                const struct xt_match *match,
 448                const void *matchinfo,
 449                int offset,
 450                unsigned int protoff,
 451                bool *hotdrop)
 452{
 453        const struct xt_hashlimit_info *r =
 454                ((const struct xt_hashlimit_info *)matchinfo)->u.master;
 455        struct xt_hashlimit_htable *hinfo = r->hinfo;
 456        unsigned long now = jiffies;
 457        struct dsthash_ent *dh;
 458        struct dsthash_dst dst;
 459
 460        if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0)
 461                goto hotdrop;
 462
 463        spin_lock_bh(&hinfo->lock);
 464        dh = dsthash_find(hinfo, &dst);
 465        if (!dh) {
 466                dh = dsthash_alloc_init(hinfo, &dst);
 467                if (!dh) {
 468                        spin_unlock_bh(&hinfo->lock);
 469                        goto hotdrop;
 470                }
 471
 472                dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
 473                dh->rateinfo.prev = jiffies;
 474                dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
 475                                                   hinfo->cfg.burst);
 476                dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
 477                                                       hinfo->cfg.burst);
 478                dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
 479        } else {
 480                /* update expiration timeout */
 481                dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
 482                rateinfo_recalc(dh, now);
 483        }
 484
 485        if (dh->rateinfo.credit >= dh->rateinfo.cost) {
 486                /* We're underlimit. */
 487                dh->rateinfo.credit -= dh->rateinfo.cost;
 488                spin_unlock_bh(&hinfo->lock);
 489                return true;
 490        }
 491
 492        spin_unlock_bh(&hinfo->lock);
 493
 494        /* default case: we're overlimit, thus don't match */
 495        return false;
 496
 497hotdrop:
 498        *hotdrop = true;
 499        return false;
 500}
 501
 502static bool
 503hashlimit_checkentry(const char *tablename,
 504                     const void *inf,
 505                     const struct xt_match *match,
 506                     void *matchinfo,
 507                     unsigned int hook_mask)
 508{
 509        struct xt_hashlimit_info *r = matchinfo;
 510
 511        /* Check for overflow. */
 512        if (r->cfg.burst == 0 ||
 513            user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) {
 514                printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n",
 515                       r->cfg.avg, r->cfg.burst);
 516                return false;
 517        }
 518        if (r->cfg.mode == 0 ||
 519            r->cfg.mode > (XT_HASHLIMIT_HASH_DPT |
 520                           XT_HASHLIMIT_HASH_DIP |
 521                           XT_HASHLIMIT_HASH_SIP |
 522                           XT_HASHLIMIT_HASH_SPT))
 523                return false;
 524        if (!r->cfg.gc_interval)
 525                return false;
 526        if (!r->cfg.expire)
 527                return false;
 528        if (r->name[sizeof(r->name) - 1] != '\0')
 529                return false;
 530
 531        /* This is the best we've got: We cannot release and re-grab lock,
 532         * since checkentry() is called before x_tables.c grabs xt_mutex.
 533         * We also cannot grab the hashtable spinlock, since htable_create will
 534         * call vmalloc, and that can sleep.  And we cannot just re-search
 535         * the list of htable's in htable_create(), since then we would
 536         * create duplicate proc files. -HW */
 537        mutex_lock(&hlimit_mutex);
 538        r->hinfo = htable_find_get(r->name, match->family);
 539        if (!r->hinfo && htable_create(r, match->family) != 0) {
 540                mutex_unlock(&hlimit_mutex);
 541                return false;
 542        }
 543        mutex_unlock(&hlimit_mutex);
 544
 545        /* Ugly hack: For SMP, we only want to use one set */
 546        r->u.master = r;
 547        return true;
 548}
 549
 550static void
 551hashlimit_destroy(const struct xt_match *match, void *matchinfo)
 552{
 553        const struct xt_hashlimit_info *r = matchinfo;
 554
 555        htable_put(r->hinfo);
 556}
 557
 558#ifdef CONFIG_COMPAT
 559struct compat_xt_hashlimit_info {
 560        char name[IFNAMSIZ];
 561        struct hashlimit_cfg cfg;
 562        compat_uptr_t hinfo;
 563        compat_uptr_t master;
 564};
 565
 566static void compat_from_user(void *dst, void *src)
 567{
 568        int off = offsetof(struct compat_xt_hashlimit_info, hinfo);
 569
 570        memcpy(dst, src, off);
 571        memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off);
 572}
 573
 574static int compat_to_user(void __user *dst, void *src)
 575{
 576        int off = offsetof(struct compat_xt_hashlimit_info, hinfo);
 577
 578        return copy_to_user(dst, src, off) ? -EFAULT : 0;
 579}
 580#endif
 581
 582static struct xt_match xt_hashlimit[] __read_mostly = {
 583        {
 584                .name           = "hashlimit",
 585                .family         = AF_INET,
 586                .match          = hashlimit_match,
 587                .matchsize      = sizeof(struct xt_hashlimit_info),
 588#ifdef CONFIG_COMPAT
 589                .compatsize     = sizeof(struct compat_xt_hashlimit_info),
 590                .compat_from_user = compat_from_user,
 591                .compat_to_user = compat_to_user,
 592#endif
 593                .checkentry     = hashlimit_checkentry,
 594                .destroy        = hashlimit_destroy,
 595                .me             = THIS_MODULE
 596        },
 597        {
 598                .name           = "hashlimit",
 599                .family         = AF_INET6,
 600                .match          = hashlimit_match,
 601                .matchsize      = sizeof(struct xt_hashlimit_info),
 602#ifdef CONFIG_COMPAT
 603                .compatsize     = sizeof(struct compat_xt_hashlimit_info),
 604                .compat_from_user = compat_from_user,
 605                .compat_to_user = compat_to_user,
 606#endif
 607                .checkentry     = hashlimit_checkentry,
 608                .destroy        = hashlimit_destroy,
 609                .me             = THIS_MODULE
 610        },
 611};
 612
 613/* PROC stuff */
 614static void *dl_seq_start(struct seq_file *s, loff_t *pos)
 615{
 616        struct proc_dir_entry *pde = s->private;
 617        struct xt_hashlimit_htable *htable = pde->data;
 618        unsigned int *bucket;
 619
 620        spin_lock_bh(&htable->lock);
 621        if (*pos >= htable->cfg.size)
 622                return NULL;
 623
 624        bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC);
 625        if (!bucket)
 626                return ERR_PTR(-ENOMEM);
 627
 628        *bucket = *pos;
 629        return bucket;
 630}
 631
 632static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
 633{
 634        struct proc_dir_entry *pde = s->private;
 635        struct xt_hashlimit_htable *htable = pde->data;
 636        unsigned int *bucket = (unsigned int *)v;
 637
 638        *pos = ++(*bucket);
 639        if (*pos >= htable->cfg.size) {
 640                kfree(v);
 641                return NULL;
 642        }
 643        return bucket;
 644}
 645
 646static void dl_seq_stop(struct seq_file *s, void *v)
 647{
 648        struct proc_dir_entry *pde = s->private;
 649        struct xt_hashlimit_htable *htable = pde->data;
 650        unsigned int *bucket = (unsigned int *)v;
 651
 652        kfree(bucket);
 653        spin_unlock_bh(&htable->lock);
 654}
 655
 656static int dl_seq_real_show(struct dsthash_ent *ent, int family,
 657                                   struct seq_file *s)
 658{
 659        /* recalculate to show accurate numbers */
 660        rateinfo_recalc(ent, jiffies);
 661
 662        switch (family) {
 663        case AF_INET:
 664                return seq_printf(s, "%ld %u.%u.%u.%u:%u->"
 665                                     "%u.%u.%u.%u:%u %u %u %u\n",
 666                                 (long)(ent->expires - jiffies)/HZ,
 667                                 NIPQUAD(ent->dst.addr.ip.src),
 668                                 ntohs(ent->dst.src_port),
 669                                 NIPQUAD(ent->dst.addr.ip.dst),
 670                                 ntohs(ent->dst.dst_port),
 671                                 ent->rateinfo.credit, ent->rateinfo.credit_cap,
 672                                 ent->rateinfo.cost);
 673        case AF_INET6:
 674                return seq_printf(s, "%ld " NIP6_FMT ":%u->"
 675                                     NIP6_FMT ":%u %u %u %u\n",
 676                                 (long)(ent->expires - jiffies)/HZ,
 677                                 NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.src),
 678                                 ntohs(ent->dst.src_port),
 679                                 NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.dst),
 680                                 ntohs(ent->dst.dst_port),
 681                                 ent->rateinfo.credit, ent->rateinfo.credit_cap,
 682                                 ent->rateinfo.cost);
 683        default:
 684                BUG();
 685                return 0;
 686        }
 687}
 688
 689static int dl_seq_show(struct seq_file *s, void *v)
 690{
 691        struct proc_dir_entry *pde = s->private;
 692        struct xt_hashlimit_htable *htable = pde->data;
 693        unsigned int *bucket = (unsigned int *)v;
 694        struct dsthash_ent *ent;
 695        struct hlist_node *pos;
 696
 697        if (!hlist_empty(&htable->hash[*bucket])) {
 698                hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node)
 699                        if (dl_seq_real_show(ent, htable->family, s))
 700                                return 1;
 701        }
 702        return 0;
 703}
 704
 705static const struct seq_operations dl_seq_ops = {
 706        .start = dl_seq_start,
 707        .next  = dl_seq_next,
 708        .stop  = dl_seq_stop,
 709        .show  = dl_seq_show
 710};
 711
 712static int dl_proc_open(struct inode *inode, struct file *file)
 713{
 714        int ret = seq_open(file, &dl_seq_ops);
 715
 716        if (!ret) {
 717                struct seq_file *sf = file->private_data;
 718                sf->private = PDE(inode);
 719        }
 720        return ret;
 721}
 722
 723static const struct file_operations dl_file_ops = {
 724        .owner   = THIS_MODULE,
 725        .open    = dl_proc_open,
 726        .read    = seq_read,
 727        .llseek  = seq_lseek,
 728        .release = seq_release
 729};
 730
 731static int __init xt_hashlimit_init(void)
 732{
 733        int err;
 734
 735        err = xt_register_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit));
 736        if (err < 0)
 737                goto err1;
 738
 739        err = -ENOMEM;
 740        hashlimit_cachep = kmem_cache_create("xt_hashlimit",
 741                                            sizeof(struct dsthash_ent), 0, 0,
 742                                            NULL);
 743        if (!hashlimit_cachep) {
 744                printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n");
 745                goto err2;
 746        }
 747        hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", init_net.proc_net);
 748        if (!hashlimit_procdir4) {
 749                printk(KERN_ERR "xt_hashlimit: unable to create proc dir "
 750                                "entry\n");
 751                goto err3;
 752        }
 753        hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", init_net.proc_net);
 754        if (!hashlimit_procdir6) {
 755                printk(KERN_ERR "xt_hashlimit: unable to create proc dir "
 756                                "entry\n");
 757                goto err4;
 758        }
 759        return 0;
 760err4:
 761        remove_proc_entry("ipt_hashlimit", init_net.proc_net);
 762err3:
 763        kmem_cache_destroy(hashlimit_cachep);
 764err2:
 765        xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit));
 766err1:
 767        return err;
 768
 769}
 770
 771static void __exit xt_hashlimit_fini(void)
 772{
 773        remove_proc_entry("ipt_hashlimit", init_net.proc_net);
 774        remove_proc_entry("ip6t_hashlimit", init_net.proc_net);
 775        kmem_cache_destroy(hashlimit_cachep);
 776        xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit));
 777}
 778
 779module_init(xt_hashlimit_init);
 780module_exit(xt_hashlimit_fini);
 781