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