2 * netfilter module to limit the number of parallel tcp
3 * connections per IP address.
4 * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
5 * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
6 * only ignore TIME_WAIT or gone connections
7 * (C) CC Computer Consultants GmbH, 2007
11 * Kernel module to match connection tracking information.
12 * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17 #include <linux/ipv6.h>
18 #include <linux/module.h>
19 #include <linux/skbuff.h>
20 #include <linux/netfilter/x_tables.h>
21 #include <linux/netfilter/xt_connlimit.h>
23 #include <net/netfilter/nf_conntrack.h>
24 #include <net/netfilter/nf_conntrack_core.h>
25 #include <net/netfilter/nf_conntrack_tuple.h>
26 #include <net/netfilter/nf_conntrack_zones.h>
27 #include <net/netfilter/nf_conntrack_count.h>
30 connlimit_mt(const struct sk_buff
*skb
, struct xt_action_param
*par
)
32 struct net
*net
= xt_net(par
);
33 const struct xt_connlimit_info
*info
= par
->matchinfo
;
34 struct nf_conntrack_tuple tuple
;
35 const struct nf_conntrack_tuple
*tuple_ptr
= &tuple
;
36 const struct nf_conntrack_zone
*zone
= &nf_ct_zone_dflt
;
37 enum ip_conntrack_info ctinfo
;
38 const struct nf_conn
*ct
;
39 unsigned int connections
;
42 ct
= nf_ct_get(skb
, &ctinfo
);
44 tuple_ptr
= &ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
;
45 zone
= nf_ct_zone(ct
);
46 } else if (!nf_ct_get_tuplepr(skb
, skb_network_offset(skb
),
47 xt_family(par
), net
, &tuple
)) {
51 if (xt_family(par
) == NFPROTO_IPV6
) {
52 const struct ipv6hdr
*iph
= ipv6_hdr(skb
);
53 union nf_inet_addr addr
;
56 memcpy(&addr
.ip6
, (info
->flags
& XT_CONNLIMIT_DADDR
) ?
57 &iph
->daddr
: &iph
->saddr
, sizeof(addr
.ip6
));
59 for (i
= 0; i
< ARRAY_SIZE(addr
.ip6
); ++i
)
60 addr
.ip6
[i
] &= info
->mask
.ip6
[i
];
61 memcpy(key
, &addr
, sizeof(addr
.ip6
));
64 const struct iphdr
*iph
= ip_hdr(skb
);
65 key
[0] = (info
->flags
& XT_CONNLIMIT_DADDR
) ?
66 iph
->daddr
: iph
->saddr
;
68 key
[0] &= info
->mask
.ip
;
72 connections
= nf_conncount_count(net
, info
->data
, key
, tuple_ptr
,
75 /* kmalloc failed, drop it entirely */
78 return (connections
> info
->limit
) ^ !!(info
->flags
& XT_CONNLIMIT_INVERT
);
85 static int connlimit_mt_check(const struct xt_mtchk_param
*par
)
87 struct xt_connlimit_info
*info
= par
->matchinfo
;
91 if (par
->family
== NFPROTO_IPV6
)
92 keylen
+= sizeof(struct in6_addr
);
94 keylen
+= sizeof(struct in_addr
);
96 /* init private data */
97 info
->data
= nf_conncount_init(par
->net
, par
->family
, keylen
);
99 return PTR_ERR_OR_ZERO(info
->data
);
102 static void connlimit_mt_destroy(const struct xt_mtdtor_param
*par
)
104 const struct xt_connlimit_info
*info
= par
->matchinfo
;
106 nf_conncount_destroy(par
->net
, par
->family
, info
->data
);
109 static struct xt_match connlimit_mt_reg __read_mostly
= {
112 .family
= NFPROTO_UNSPEC
,
113 .checkentry
= connlimit_mt_check
,
114 .match
= connlimit_mt
,
115 .matchsize
= sizeof(struct xt_connlimit_info
),
116 .usersize
= offsetof(struct xt_connlimit_info
, data
),
117 .destroy
= connlimit_mt_destroy
,
121 static int __init
connlimit_mt_init(void)
123 return xt_register_match(&connlimit_mt_reg
);
126 static void __exit
connlimit_mt_exit(void)
128 xt_unregister_match(&connlimit_mt_reg
);
131 module_init(connlimit_mt_init
);
132 module_exit(connlimit_mt_exit
);
133 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
134 MODULE_DESCRIPTION("Xtables: Number of connections matching");
135 MODULE_LICENSE("GPL");
136 MODULE_ALIAS("ipt_connlimit");
137 MODULE_ALIAS("ip6t_connlimit");