Commit | Line | Data |
---|---|---|
9d810fd2 HW |
1 | /* Kernel module to match connection tracking byte counter. |
2 | * GPL (C) 2002 Martin Devera (devik@cdi.cz). | |
9d810fd2 HW |
3 | */ |
4 | #include <linux/module.h> | |
1977f032 | 5 | #include <linux/bitops.h> |
9d810fd2 | 6 | #include <linux/skbuff.h> |
2e4e6a17 HW |
7 | #include <linux/netfilter/x_tables.h> |
8 | #include <linux/netfilter/xt_connbytes.h> | |
587aa641 | 9 | #include <net/netfilter/nf_conntrack.h> |
9d810fd2 HW |
10 | |
11 | #include <asm/div64.h> | |
9d810fd2 HW |
12 | |
13 | MODULE_LICENSE("GPL"); | |
14 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | |
15 | MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection"); | |
2e4e6a17 | 16 | MODULE_ALIAS("ipt_connbytes"); |
73aaf935 | 17 | MODULE_ALIAS("ip6t_connbytes"); |
9d810fd2 | 18 | |
1d93a9cb | 19 | static bool |
9d810fd2 HW |
20 | match(const struct sk_buff *skb, |
21 | const struct net_device *in, | |
22 | const struct net_device *out, | |
c4986734 | 23 | const struct xt_match *match, |
9d810fd2 HW |
24 | const void *matchinfo, |
25 | int offset, | |
2e4e6a17 | 26 | unsigned int protoff, |
cff533ac | 27 | bool *hotdrop) |
9d810fd2 | 28 | { |
2e4e6a17 | 29 | const struct xt_connbytes_info *sinfo = matchinfo; |
a47362a2 | 30 | const struct nf_conn *ct; |
587aa641 | 31 | enum ip_conntrack_info ctinfo; |
9d810fd2 | 32 | u_int64_t what = 0; /* initialize to make gcc happy */ |
fb74a841 PM |
33 | u_int64_t bytes = 0; |
34 | u_int64_t pkts = 0; | |
9fb9cbb1 | 35 | const struct ip_conntrack_counter *counters; |
9d810fd2 | 36 | |
587aa641 PM |
37 | ct = nf_ct_get(skb, &ctinfo); |
38 | if (!ct) | |
1d93a9cb | 39 | return false; |
587aa641 | 40 | counters = ct->counters; |
9d810fd2 HW |
41 | |
42 | switch (sinfo->what) { | |
2e4e6a17 | 43 | case XT_CONNBYTES_PKTS: |
9d810fd2 | 44 | switch (sinfo->direction) { |
2e4e6a17 | 45 | case XT_CONNBYTES_DIR_ORIGINAL: |
9fb9cbb1 | 46 | what = counters[IP_CT_DIR_ORIGINAL].packets; |
9d810fd2 | 47 | break; |
2e4e6a17 | 48 | case XT_CONNBYTES_DIR_REPLY: |
9fb9cbb1 | 49 | what = counters[IP_CT_DIR_REPLY].packets; |
9d810fd2 | 50 | break; |
2e4e6a17 | 51 | case XT_CONNBYTES_DIR_BOTH: |
9fb9cbb1 YK |
52 | what = counters[IP_CT_DIR_ORIGINAL].packets; |
53 | what += counters[IP_CT_DIR_REPLY].packets; | |
9d810fd2 HW |
54 | break; |
55 | } | |
56 | break; | |
2e4e6a17 | 57 | case XT_CONNBYTES_BYTES: |
9d810fd2 | 58 | switch (sinfo->direction) { |
2e4e6a17 | 59 | case XT_CONNBYTES_DIR_ORIGINAL: |
9fb9cbb1 | 60 | what = counters[IP_CT_DIR_ORIGINAL].bytes; |
9d810fd2 | 61 | break; |
2e4e6a17 | 62 | case XT_CONNBYTES_DIR_REPLY: |
9fb9cbb1 | 63 | what = counters[IP_CT_DIR_REPLY].bytes; |
9d810fd2 | 64 | break; |
2e4e6a17 | 65 | case XT_CONNBYTES_DIR_BOTH: |
9fb9cbb1 YK |
66 | what = counters[IP_CT_DIR_ORIGINAL].bytes; |
67 | what += counters[IP_CT_DIR_REPLY].bytes; | |
9d810fd2 HW |
68 | break; |
69 | } | |
70 | break; | |
2e4e6a17 | 71 | case XT_CONNBYTES_AVGPKT: |
9d810fd2 | 72 | switch (sinfo->direction) { |
2e4e6a17 | 73 | case XT_CONNBYTES_DIR_ORIGINAL: |
fb74a841 PM |
74 | bytes = counters[IP_CT_DIR_ORIGINAL].bytes; |
75 | pkts = counters[IP_CT_DIR_ORIGINAL].packets; | |
9d810fd2 | 76 | break; |
2e4e6a17 | 77 | case XT_CONNBYTES_DIR_REPLY: |
fb74a841 PM |
78 | bytes = counters[IP_CT_DIR_REPLY].bytes; |
79 | pkts = counters[IP_CT_DIR_REPLY].packets; | |
9d810fd2 | 80 | break; |
2e4e6a17 | 81 | case XT_CONNBYTES_DIR_BOTH: |
fb74a841 PM |
82 | bytes = counters[IP_CT_DIR_ORIGINAL].bytes + |
83 | counters[IP_CT_DIR_REPLY].bytes; | |
84 | pkts = counters[IP_CT_DIR_ORIGINAL].packets + | |
85 | counters[IP_CT_DIR_REPLY].packets; | |
9d810fd2 HW |
86 | break; |
87 | } | |
fb74a841 PM |
88 | if (pkts != 0) |
89 | what = div64_64(bytes, pkts); | |
9d810fd2 HW |
90 | break; |
91 | } | |
92 | ||
93 | if (sinfo->count.to) | |
7c4e36bc | 94 | return what <= sinfo->count.to && what >= sinfo->count.from; |
9d810fd2 | 95 | else |
7c4e36bc | 96 | return what >= sinfo->count.from; |
9d810fd2 HW |
97 | } |
98 | ||
ccb79bdc JE |
99 | static bool check(const char *tablename, |
100 | const void *ip, | |
101 | const struct xt_match *match, | |
102 | void *matchinfo, | |
103 | unsigned int hook_mask) | |
9d810fd2 | 104 | { |
2e4e6a17 | 105 | const struct xt_connbytes_info *sinfo = matchinfo; |
9d810fd2 | 106 | |
2e4e6a17 HW |
107 | if (sinfo->what != XT_CONNBYTES_PKTS && |
108 | sinfo->what != XT_CONNBYTES_BYTES && | |
109 | sinfo->what != XT_CONNBYTES_AVGPKT) | |
ccb79bdc | 110 | return false; |
9d810fd2 | 111 | |
2e4e6a17 HW |
112 | if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL && |
113 | sinfo->direction != XT_CONNBYTES_DIR_REPLY && | |
114 | sinfo->direction != XT_CONNBYTES_DIR_BOTH) | |
ccb79bdc | 115 | return false; |
9d810fd2 | 116 | |
11078c37 YK |
117 | if (nf_ct_l3proto_try_module_get(match->family) < 0) { |
118 | printk(KERN_WARNING "can't load conntrack support for " | |
119 | "proto=%d\n", match->family); | |
ccb79bdc | 120 | return false; |
11078c37 YK |
121 | } |
122 | ||
ccb79bdc | 123 | return true; |
9d810fd2 HW |
124 | } |
125 | ||
11078c37 YK |
126 | static void |
127 | destroy(const struct xt_match *match, void *matchinfo) | |
128 | { | |
129 | nf_ct_l3proto_module_put(match->family); | |
130 | } | |
131 | ||
9f15c530 | 132 | static struct xt_match xt_connbytes_match[] __read_mostly = { |
4470bbc7 PM |
133 | { |
134 | .name = "connbytes", | |
135 | .family = AF_INET, | |
136 | .checkentry = check, | |
137 | .match = match, | |
11078c37 | 138 | .destroy = destroy, |
4470bbc7 PM |
139 | .matchsize = sizeof(struct xt_connbytes_info), |
140 | .me = THIS_MODULE | |
141 | }, | |
142 | { | |
143 | .name = "connbytes", | |
144 | .family = AF_INET6, | |
145 | .checkentry = check, | |
146 | .match = match, | |
11078c37 | 147 | .destroy = destroy, |
4470bbc7 PM |
148 | .matchsize = sizeof(struct xt_connbytes_info), |
149 | .me = THIS_MODULE | |
150 | }, | |
9d810fd2 HW |
151 | }; |
152 | ||
65b4b4e8 | 153 | static int __init xt_connbytes_init(void) |
9d810fd2 | 154 | { |
4470bbc7 PM |
155 | return xt_register_matches(xt_connbytes_match, |
156 | ARRAY_SIZE(xt_connbytes_match)); | |
9d810fd2 HW |
157 | } |
158 | ||
65b4b4e8 | 159 | static void __exit xt_connbytes_fini(void) |
9d810fd2 | 160 | { |
4470bbc7 PM |
161 | xt_unregister_matches(xt_connbytes_match, |
162 | ARRAY_SIZE(xt_connbytes_match)); | |
9d810fd2 HW |
163 | } |
164 | ||
65b4b4e8 AM |
165 | module_init(xt_connbytes_init); |
166 | module_exit(xt_connbytes_fini); |