1 /* Kernel module to match connection tracking byte counter.
2 * GPL (C) 2002 Martin Devera (devik@cdi.cz).
4 * 2004-07-20 Harald Welte <laforge@netfilter.org>
5 * - reimplemented to use per-connection accounting counters
6 * - add functionality to match number of packets
7 * - add functionality to match average packet size
8 * - add support to match directions seperately
11 #include <linux/module.h>
12 #include <linux/skbuff.h>
13 #include <net/netfilter/nf_conntrack_compat.h>
14 #include <linux/netfilter_ipv4/ip_tables.h>
15 #include <linux/netfilter_ipv4/ipt_connbytes.h>
17 #include <asm/div64.h>
18 #include <asm/bitops.h>
20 MODULE_LICENSE("GPL");
21 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
22 MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
24 /* 64bit divisor, dividend and result. dynamic precision */
25 static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
27 u_int32_t d = divisor;
29 if (divisor > 0xffffffffULL) {
30 unsigned int shift = fls(divisor >> 32);
41 match(const struct sk_buff *skb,
42 const struct net_device *in,
43 const struct net_device *out,
44 const void *matchinfo,
48 const struct ipt_connbytes_info *sinfo = matchinfo;
49 u_int64_t what = 0; /* initialize to make gcc happy */
50 const struct ip_conntrack_counter *counters;
52 if (!(counters = nf_ct_get_counters(skb)))
53 return 0; /* no match */
55 switch (sinfo->what) {
56 case IPT_CONNBYTES_PKTS:
57 switch (sinfo->direction) {
58 case IPT_CONNBYTES_DIR_ORIGINAL:
59 what = counters[IP_CT_DIR_ORIGINAL].packets;
61 case IPT_CONNBYTES_DIR_REPLY:
62 what = counters[IP_CT_DIR_REPLY].packets;
64 case IPT_CONNBYTES_DIR_BOTH:
65 what = counters[IP_CT_DIR_ORIGINAL].packets;
66 what += counters[IP_CT_DIR_REPLY].packets;
70 case IPT_CONNBYTES_BYTES:
71 switch (sinfo->direction) {
72 case IPT_CONNBYTES_DIR_ORIGINAL:
73 what = counters[IP_CT_DIR_ORIGINAL].bytes;
75 case IPT_CONNBYTES_DIR_REPLY:
76 what = counters[IP_CT_DIR_REPLY].bytes;
78 case IPT_CONNBYTES_DIR_BOTH:
79 what = counters[IP_CT_DIR_ORIGINAL].bytes;
80 what += counters[IP_CT_DIR_REPLY].bytes;
84 case IPT_CONNBYTES_AVGPKT:
85 switch (sinfo->direction) {
86 case IPT_CONNBYTES_DIR_ORIGINAL:
87 what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
88 counters[IP_CT_DIR_ORIGINAL].packets);
90 case IPT_CONNBYTES_DIR_REPLY:
91 what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
92 counters[IP_CT_DIR_REPLY].packets);
94 case IPT_CONNBYTES_DIR_BOTH:
98 bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
99 counters[IP_CT_DIR_REPLY].bytes;
100 pkts = counters[IP_CT_DIR_ORIGINAL].packets+
101 counters[IP_CT_DIR_REPLY].packets;
103 /* FIXME_THEORETICAL: what to do if sum
106 what = div64_64(bytes, pkts);
114 return (what <= sinfo->count.to && what >= sinfo->count.from);
116 return (what >= sinfo->count.from);
119 static int check(const char *tablename,
120 const struct ipt_ip *ip,
122 unsigned int matchsize,
123 unsigned int hook_mask)
125 const struct ipt_connbytes_info *sinfo = matchinfo;
127 if (matchsize != IPT_ALIGN(sizeof(struct ipt_connbytes_info)))
130 if (sinfo->what != IPT_CONNBYTES_PKTS &&
131 sinfo->what != IPT_CONNBYTES_BYTES &&
132 sinfo->what != IPT_CONNBYTES_AVGPKT)
135 if (sinfo->direction != IPT_CONNBYTES_DIR_ORIGINAL &&
136 sinfo->direction != IPT_CONNBYTES_DIR_REPLY &&
137 sinfo->direction != IPT_CONNBYTES_DIR_BOTH)
143 static struct ipt_match state_match = {
146 .checkentry = &check,
150 static int __init init(void)
152 return ipt_register_match(&state_match);
155 static void __exit fini(void)
157 ipt_unregister_match(&state_match);