📄 xt_hashlimit.c
字号:
if (!(hinfo->cfg.mode & (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) return 0; nexthdr = ip_hdr(skb)->protocol; break;#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) case AF_INET6: if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) memcpy(&dst->addr.ip6.dst, &ipv6_hdr(skb)->daddr, sizeof(dst->addr.ip6.dst)); if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) memcpy(&dst->addr.ip6.src, &ipv6_hdr(skb)->saddr, sizeof(dst->addr.ip6.src)); if (!(hinfo->cfg.mode & (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) return 0; nexthdr = ipv6_find_hdr(skb, &protoff, -1, NULL); if (nexthdr < 0) return -1; break;#endif default: BUG(); return 0; } switch (nexthdr) { case IPPROTO_TCP: case IPPROTO_UDP: case IPPROTO_UDPLITE: case IPPROTO_SCTP: case IPPROTO_DCCP: ports = skb_header_pointer(skb, protoff, sizeof(_ports), &_ports); break; default: _ports[0] = _ports[1] = 0; ports = _ports; break; } if (!ports) return -1; if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SPT) dst->src_port = ports[0]; if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DPT) dst->dst_port = ports[1]; return 0;}static boolhashlimit_match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct xt_match *match, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop){ const struct xt_hashlimit_info *r = ((const struct xt_hashlimit_info *)matchinfo)->u.master; struct xt_hashlimit_htable *hinfo = r->hinfo; unsigned long now = jiffies; struct dsthash_ent *dh; struct dsthash_dst dst; if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0) goto hotdrop; spin_lock_bh(&hinfo->lock); dh = dsthash_find(hinfo, &dst); if (!dh) { dh = dsthash_alloc_init(hinfo, &dst); if (!dh) { spin_unlock_bh(&hinfo->lock); goto hotdrop; } dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); dh->rateinfo.prev = jiffies; dh->rateinfo.credit = user2credits(hinfo->cfg.avg * hinfo->cfg.burst); dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * hinfo->cfg.burst); dh->rateinfo.cost = user2credits(hinfo->cfg.avg); } else { /* update expiration timeout */ dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); rateinfo_recalc(dh, now); } if (dh->rateinfo.credit >= dh->rateinfo.cost) { /* We're underlimit. */ dh->rateinfo.credit -= dh->rateinfo.cost; spin_unlock_bh(&hinfo->lock); return true; } spin_unlock_bh(&hinfo->lock); /* default case: we're overlimit, thus don't match */ return false;hotdrop: *hotdrop = true; return false;}static boolhashlimit_checkentry(const char *tablename, const void *inf, const struct xt_match *match, void *matchinfo, unsigned int hook_mask){ struct xt_hashlimit_info *r = matchinfo; /* Check for overflow. */ if (r->cfg.burst == 0 || user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) { printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n", r->cfg.avg, r->cfg.burst); return false; } if (r->cfg.mode == 0 || r->cfg.mode > (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT)) return false; if (!r->cfg.gc_interval) return false; if (!r->cfg.expire) return false; if (r->name[sizeof(r->name) - 1] != '\0') return false; /* This is the best we've got: We cannot release and re-grab lock, * since checkentry() is called before x_tables.c grabs xt_mutex. * We also cannot grab the hashtable spinlock, since htable_create will * call vmalloc, and that can sleep. And we cannot just re-search * the list of htable's in htable_create(), since then we would * create duplicate proc files. -HW */ mutex_lock(&hlimit_mutex); r->hinfo = htable_find_get(r->name, match->family); if (!r->hinfo && htable_create(r, match->family) != 0) { mutex_unlock(&hlimit_mutex); return false; } mutex_unlock(&hlimit_mutex); /* Ugly hack: For SMP, we only want to use one set */ r->u.master = r; return true;}static voidhashlimit_destroy(const struct xt_match *match, void *matchinfo){ const struct xt_hashlimit_info *r = matchinfo; htable_put(r->hinfo);}#ifdef CONFIG_COMPATstruct compat_xt_hashlimit_info { char name[IFNAMSIZ]; struct hashlimit_cfg cfg; compat_uptr_t hinfo; compat_uptr_t master;};static void compat_from_user(void *dst, void *src){ int off = offsetof(struct compat_xt_hashlimit_info, hinfo); memcpy(dst, src, off); memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off);}static int compat_to_user(void __user *dst, void *src){ int off = offsetof(struct compat_xt_hashlimit_info, hinfo); return copy_to_user(dst, src, off) ? -EFAULT : 0;}#endifstatic struct xt_match xt_hashlimit[] __read_mostly = { { .name = "hashlimit", .family = AF_INET, .match = hashlimit_match, .matchsize = sizeof(struct xt_hashlimit_info),#ifdef CONFIG_COMPAT .compatsize = sizeof(struct compat_xt_hashlimit_info), .compat_from_user = compat_from_user, .compat_to_user = compat_to_user,#endif .checkentry = hashlimit_checkentry, .destroy = hashlimit_destroy, .me = THIS_MODULE }, { .name = "hashlimit", .family = AF_INET6, .match = hashlimit_match, .matchsize = sizeof(struct xt_hashlimit_info),#ifdef CONFIG_COMPAT .compatsize = sizeof(struct compat_xt_hashlimit_info), .compat_from_user = compat_from_user, .compat_to_user = compat_to_user,#endif .checkentry = hashlimit_checkentry, .destroy = hashlimit_destroy, .me = THIS_MODULE },};/* PROC stuff */static void *dl_seq_start(struct seq_file *s, loff_t *pos){ struct proc_dir_entry *pde = s->private; struct xt_hashlimit_htable *htable = pde->data; unsigned int *bucket; spin_lock_bh(&htable->lock); if (*pos >= htable->cfg.size) return NULL; bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC); if (!bucket) return ERR_PTR(-ENOMEM); *bucket = *pos; return bucket;}static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos){ struct proc_dir_entry *pde = s->private; struct xt_hashlimit_htable *htable = pde->data; unsigned int *bucket = (unsigned int *)v; *pos = ++(*bucket); if (*pos >= htable->cfg.size) { kfree(v); return NULL; } return bucket;}static void dl_seq_stop(struct seq_file *s, void *v){ struct proc_dir_entry *pde = s->private; struct xt_hashlimit_htable *htable = pde->data; unsigned int *bucket = (unsigned int *)v; kfree(bucket); spin_unlock_bh(&htable->lock);}static int dl_seq_real_show(struct dsthash_ent *ent, int family, struct seq_file *s){ /* recalculate to show accurate numbers */ rateinfo_recalc(ent, jiffies); switch (family) { case AF_INET: return seq_printf(s, "%ld %u.%u.%u.%u:%u->" "%u.%u.%u.%u:%u %u %u %u\n", (long)(ent->expires - jiffies)/HZ, NIPQUAD(ent->dst.addr.ip.src), ntohs(ent->dst.src_port), NIPQUAD(ent->dst.addr.ip.dst), ntohs(ent->dst.dst_port), ent->rateinfo.credit, ent->rateinfo.credit_cap, ent->rateinfo.cost); case AF_INET6: return seq_printf(s, "%ld " NIP6_FMT ":%u->" NIP6_FMT ":%u %u %u %u\n", (long)(ent->expires - jiffies)/HZ, NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.src), ntohs(ent->dst.src_port), NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.dst), ntohs(ent->dst.dst_port), ent->rateinfo.credit, ent->rateinfo.credit_cap, ent->rateinfo.cost); default: BUG(); return 0; }}static int dl_seq_show(struct seq_file *s, void *v){ struct proc_dir_entry *pde = s->private; struct xt_hashlimit_htable *htable = pde->data; unsigned int *bucket = (unsigned int *)v; struct dsthash_ent *ent; struct hlist_node *pos; if (!hlist_empty(&htable->hash[*bucket])) { hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) if (dl_seq_real_show(ent, htable->family, s)) return 1; } return 0;}static const struct seq_operations dl_seq_ops = { .start = dl_seq_start, .next = dl_seq_next, .stop = dl_seq_stop, .show = dl_seq_show};static int dl_proc_open(struct inode *inode, struct file *file){ int ret = seq_open(file, &dl_seq_ops); if (!ret) { struct seq_file *sf = file->private_data; sf->private = PDE(inode); } return ret;}static const struct file_operations dl_file_ops = { .owner = THIS_MODULE, .open = dl_proc_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release};static int __init xt_hashlimit_init(void){ int err; err = xt_register_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); if (err < 0) goto err1; err = -ENOMEM; hashlimit_cachep = kmem_cache_create("xt_hashlimit", sizeof(struct dsthash_ent), 0, 0, NULL); if (!hashlimit_cachep) { printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); goto err2; } hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", init_net.proc_net); if (!hashlimit_procdir4) { printk(KERN_ERR "xt_hashlimit: unable to create proc dir " "entry\n"); goto err3; } hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", init_net.proc_net); if (!hashlimit_procdir6) { printk(KERN_ERR "xt_hashlimit: unable to create proc dir " "entry\n"); goto err4; } return 0;err4: remove_proc_entry("ipt_hashlimit", init_net.proc_net);err3: kmem_cache_destroy(hashlimit_cachep);err2: xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit));err1: return err;}static void __exit xt_hashlimit_fini(void){ remove_proc_entry("ipt_hashlimit", init_net.proc_net); remove_proc_entry("ip6t_hashlimit", init_net.proc_net); kmem_cache_destroy(hashlimit_cachep); xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit));}module_init(xt_hashlimit_init);module_exit(xt_hashlimit_fini);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -