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
16 #include <linux/module.h>
17 #include <linux/skbuff.h>
18 #include <linux/netfilter/x_tables.h>
19 #include <linux/netfilter/xt_connlimit.h>
21 #include <net/netfilter/nf_conntrack.h>
22 #include <net/netfilter/nf_conntrack_core.h>
23 #include <net/netfilter/nf_conntrack_tuple.h>
24 #include <net/netfilter/nf_conntrack_zones.h>
25 #include <net/netfilter/nf_conntrack_count.h>
28 connlimit_mt(const struct sk_buff
*skb
, struct xt_action_param
*par
)
30 struct net
*net
= xt_net(par
);
31 const struct xt_connlimit_info
*info
= par
->matchinfo
;
32 struct nf_conntrack_tuple tuple
;
33 const struct nf_conntrack_tuple
*tuple_ptr
= &tuple
;
34 const struct nf_conntrack_zone
*zone
= &nf_ct_zone_dflt
;
35 enum ip_conntrack_info ctinfo
;
36 const struct nf_conn
*ct
;
37 unsigned int connections
;
40 ct
= nf_ct_get(skb
, &ctinfo
);
42 tuple_ptr
= &ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
;
43 zone
= nf_ct_zone(ct
);
44 } else if (!nf_ct_get_tuplepr(skb
, skb_network_offset(skb
),
45 xt_family(par
), net
, &tuple
)) {
49 if (xt_family(par
) == NFPROTO_IPV6
) {
50 const struct ipv6hdr
*iph
= ipv6_hdr(skb
);
51 union nf_inet_addr addr
;
54 memcpy(&addr
.ip6
, (info
->flags
& XT_CONNLIMIT_DADDR
) ?
55 &iph
->daddr
: &iph
->saddr
, sizeof(addr
.ip6
));
57 for (i
= 0; i
< ARRAY_SIZE(addr
.ip6
); ++i
)
58 addr
.ip6
[i
] &= info
->mask
.ip6
[i
];
59 memcpy(key
, &addr
, sizeof(addr
.ip6
));
62 const struct iphdr
*iph
= ip_hdr(skb
);
63 key
[0] = (info
->flags
& XT_CONNLIMIT_DADDR
) ?
64 iph
->daddr
: iph
->saddr
;
66 key
[0] &= info
->mask
.ip
;
70 connections
= nf_conncount_count(net
, info
->data
, key
,
71 xt_family(par
), tuple_ptr
, zone
);
73 /* kmalloc failed, drop it entirely */
76 return (connections
> info
->limit
) ^ !!(info
->flags
& XT_CONNLIMIT_INVERT
);
83 static int connlimit_mt_check(const struct xt_mtchk_param
*par
)
85 struct xt_connlimit_info
*info
= par
->matchinfo
;
89 if (par
->family
== NFPROTO_IPV6
)
90 keylen
+= sizeof(struct in6_addr
);
92 keylen
+= sizeof(struct in_addr
);
94 /* init private data */
95 info
->data
= nf_conncount_init(par
->net
, par
->family
, keylen
);
96 if (IS_ERR(info
->data
))
97 return PTR_ERR(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");