Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * netfilter module to limit the number of parallel tcp
0003  * connections per IP address.
0004  *   (c) 2000 Gerd Knorr <kraxel@bytesex.org>
0005  *   Nov 2002: Martin Bene <martin.bene@icomedias.com>:
0006  *      only ignore TIME_WAIT or gone connections
0007  *   (C) CC Computer Consultants GmbH, 2007
0008  *
0009  * based on ...
0010  *
0011  * Kernel module to match connection tracking information.
0012  * GPL (C) 1999  Rusty Russell (rusty@rustcorp.com.au).
0013  */
0014 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0015 
0016 #include <linux/ip.h>
0017 #include <linux/ipv6.h>
0018 #include <linux/module.h>
0019 #include <linux/skbuff.h>
0020 #include <linux/netfilter/x_tables.h>
0021 #include <linux/netfilter/xt_connlimit.h>
0022 
0023 #include <net/netfilter/nf_conntrack.h>
0024 #include <net/netfilter/nf_conntrack_core.h>
0025 #include <net/netfilter/nf_conntrack_tuple.h>
0026 #include <net/netfilter/nf_conntrack_zones.h>
0027 #include <net/netfilter/nf_conntrack_count.h>
0028 
0029 static bool
0030 connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
0031 {
0032     struct net *net = xt_net(par);
0033     const struct xt_connlimit_info *info = par->matchinfo;
0034     struct nf_conntrack_tuple tuple;
0035     const struct nf_conntrack_tuple *tuple_ptr = &tuple;
0036     const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
0037     enum ip_conntrack_info ctinfo;
0038     const struct nf_conn *ct;
0039     unsigned int connections;
0040     u32 key[5];
0041 
0042     ct = nf_ct_get(skb, &ctinfo);
0043     if (ct != NULL) {
0044         tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
0045         zone = nf_ct_zone(ct);
0046     } else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
0047                       xt_family(par), net, &tuple)) {
0048         goto hotdrop;
0049     }
0050 
0051     if (xt_family(par) == NFPROTO_IPV6) {
0052         const struct ipv6hdr *iph = ipv6_hdr(skb);
0053         union nf_inet_addr addr;
0054         unsigned int i;
0055 
0056         memcpy(&addr.ip6, (info->flags & XT_CONNLIMIT_DADDR) ?
0057                &iph->daddr : &iph->saddr, sizeof(addr.ip6));
0058 
0059         for (i = 0; i < ARRAY_SIZE(addr.ip6); ++i)
0060             addr.ip6[i] &= info->mask.ip6[i];
0061         memcpy(key, &addr, sizeof(addr.ip6));
0062         key[4] = zone->id;
0063     } else {
0064         const struct iphdr *iph = ip_hdr(skb);
0065 
0066         key[0] = (info->flags & XT_CONNLIMIT_DADDR) ?
0067              (__force __u32)iph->daddr : (__force __u32)iph->saddr;
0068         key[0] &= (__force __u32)info->mask.ip;
0069         key[1] = zone->id;
0070     }
0071 
0072     connections = nf_conncount_count(net, info->data, key, tuple_ptr,
0073                      zone);
0074     if (connections == 0)
0075         /* kmalloc failed, drop it entirely */
0076         goto hotdrop;
0077 
0078     return (connections > info->limit) ^ !!(info->flags & XT_CONNLIMIT_INVERT);
0079 
0080  hotdrop:
0081     par->hotdrop = true;
0082     return false;
0083 }
0084 
0085 static int connlimit_mt_check(const struct xt_mtchk_param *par)
0086 {
0087     struct xt_connlimit_info *info = par->matchinfo;
0088     unsigned int keylen;
0089 
0090     keylen = sizeof(u32);
0091     if (par->family == NFPROTO_IPV6)
0092         keylen += sizeof(struct in6_addr);
0093     else
0094         keylen += sizeof(struct in_addr);
0095 
0096     /* init private data */
0097     info->data = nf_conncount_init(par->net, par->family, keylen);
0098 
0099     return PTR_ERR_OR_ZERO(info->data);
0100 }
0101 
0102 static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
0103 {
0104     const struct xt_connlimit_info *info = par->matchinfo;
0105 
0106     nf_conncount_destroy(par->net, par->family, info->data);
0107 }
0108 
0109 static struct xt_match connlimit_mt_reg __read_mostly = {
0110     .name       = "connlimit",
0111     .revision   = 1,
0112     .family     = NFPROTO_UNSPEC,
0113     .checkentry = connlimit_mt_check,
0114     .match      = connlimit_mt,
0115     .matchsize  = sizeof(struct xt_connlimit_info),
0116     .usersize   = offsetof(struct xt_connlimit_info, data),
0117     .destroy    = connlimit_mt_destroy,
0118     .me         = THIS_MODULE,
0119 };
0120 
0121 static int __init connlimit_mt_init(void)
0122 {
0123     return xt_register_match(&connlimit_mt_reg);
0124 }
0125 
0126 static void __exit connlimit_mt_exit(void)
0127 {
0128     xt_unregister_match(&connlimit_mt_reg);
0129 }
0130 
0131 module_init(connlimit_mt_init);
0132 module_exit(connlimit_mt_exit);
0133 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
0134 MODULE_DESCRIPTION("Xtables: Number of connections matching");
0135 MODULE_LICENSE("GPL");
0136 MODULE_ALIAS("ipt_connlimit");
0137 MODULE_ALIAS("ip6t_connlimit");