]>
Commit | Line | Data |
---|---|---|
2fbfbe6c | 1 | /* |
74880dd6 JE |
2 | * "CHAOS" target extension for Xtables |
3 | * Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2006 - 2008 | |
2fbfbe6c | 4 | * |
74880dd6 JE |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License; either | |
7 | * version 2 of the License, or any later version, as published by the | |
8 | * Free Software Foundation. | |
2fbfbe6c JE |
9 | */ |
10 | #include <linux/icmp.h> | |
11 | #include <linux/in.h> | |
12 | #include <linux/ip.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/skbuff.h> | |
15 | #include <linux/stat.h> | |
16 | #include <linux/netfilter/x_tables.h> | |
17 | #include <linux/netfilter/xt_tcpudp.h> | |
18 | #include <linux/netfilter_ipv4/ipt_REJECT.h> | |
19 | #include <net/ip.h> | |
20 | #include "xt_CHAOS.h" | |
21 | static struct xt_match *xm_tcp; | |
22 | static struct xt_target *xt_delude, *xt_reject, *xt_tarpit; | |
23 | #include "compat_xtables.h" | |
24 | #define PFX KBUILD_MODNAME ": " | |
25 | ||
26 | /* Module parameters */ | |
27 | static unsigned int reject_percentage = ~0U * .01; | |
28 | static unsigned int delude_percentage = ~0U * .0101; | |
29 | module_param(reject_percentage, uint, S_IRUGO | S_IWUSR); | |
30 | module_param(delude_percentage, uint, S_IRUGO | S_IWUSR); | |
31 | ||
32 | /* References to other matches/targets */ | |
33 | ||
34 | static int have_delude, have_tarpit; | |
35 | ||
36 | /* Static data for other matches/targets */ | |
37 | static const struct ipt_reject_info reject_params = { | |
38 | .with = ICMP_HOST_UNREACH, | |
39 | }; | |
40 | ||
41 | static const struct xt_tcp tcp_params = { | |
42 | .spts = {0, ~0}, | |
43 | .dpts = {0, ~0}, | |
44 | }; | |
45 | ||
46 | /* CHAOS functions */ | |
ee7e4f5a | 47 | static void |
5b472be9 | 48 | xt_chaos_total(struct sk_buff *skb, const struct xt_action_param *par) |
2fbfbe6c | 49 | { |
ee7e4f5a | 50 | const struct xt_chaos_tginfo *info = par->targinfo; |
2fbfbe6c | 51 | const struct iphdr *iph = ip_hdr(skb); |
ee7e4f5a JE |
52 | const int thoff = 4 * iph->ihl; |
53 | const int fragoff = ntohs(iph->frag_off) & IP_OFFSET; | |
2fbfbe6c JE |
54 | typeof(xt_tarpit) destiny; |
55 | bool ret; | |
5fd97e99 | 56 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) |
2fbfbe6c JE |
57 | int hotdrop = false; |
58 | #else | |
59 | bool hotdrop = false; | |
60 | #endif | |
61 | ||
ee7e4f5a JE |
62 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27) |
63 | ret = xm_tcp->match(skb, par->in, par->out, xm_tcp, &tcp_params, | |
64 | fragoff, thoff, &hotdrop); | |
65 | #else | |
66 | { | |
67 | struct xt_match_param local_par = { | |
68 | .in = par->in, | |
69 | .out = par->out, | |
70 | .match = xm_tcp, | |
71 | .matchinfo = &tcp_params, | |
72 | .fragoff = fragoff, | |
73 | .thoff = thoff, | |
74 | .hotdrop = &hotdrop, | |
75 | }; | |
76 | ret = xm_tcp->match(skb, &local_par); | |
77 | } | |
78 | #endif | |
2fbfbe6c JE |
79 | if (!ret || hotdrop || (unsigned int)net_random() > delude_percentage) |
80 | return; | |
81 | ||
82 | destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude; | |
5fd97e99 | 83 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) |
ee7e4f5a | 84 | destiny->target(&skb, par->in, par->out, par->hooknum, destiny, NULL, NULL); |
5fd97e99 | 85 | #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23) |
ee7e4f5a JE |
86 | destiny->target(&skb, par->in, par->out, par->hooknum, destiny, NULL); |
87 | #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27) | |
88 | destiny->target(skb, par->in, par->out, par->hooknum, destiny, NULL); | |
2fbfbe6c | 89 | #else |
ee7e4f5a | 90 | { |
5b472be9 JE |
91 | struct xt_target_param local_par = { |
92 | .in = par->in, | |
93 | .out = par->out, | |
94 | .hooknum = par->hooknum, | |
95 | .target = destiny, | |
96 | .targinfo = par->targinfo, | |
97 | .family = par->family, | |
98 | }; | |
ee7e4f5a JE |
99 | destiny->target(skb, &local_par); |
100 | } | |
2fbfbe6c | 101 | #endif |
2fbfbe6c JE |
102 | } |
103 | ||
ee7e4f5a | 104 | static unsigned int |
5b472be9 | 105 | chaos_tg(struct sk_buff **pskb, const struct xt_action_param *par) |
2fbfbe6c JE |
106 | { |
107 | /* | |
108 | * Equivalent to: | |
109 | * -A chaos -m statistic --mode random --probability \ | |
110 | * $reject_percentage -j REJECT --reject-with host-unreach; | |
111 | * -A chaos -p tcp -m statistic --mode random --probability \ | |
112 | * $delude_percentage -j DELUDE; | |
113 | * -A chaos -j DROP; | |
114 | */ | |
ee7e4f5a | 115 | const struct xt_chaos_tginfo *info = par->targinfo; |
ab27472e | 116 | struct sk_buff *skb = *pskb; |
2fbfbe6c JE |
117 | const struct iphdr *iph = ip_hdr(skb); |
118 | ||
ee7e4f5a | 119 | if ((unsigned int)net_random() <= reject_percentage) { |
5fd97e99 | 120 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) |
ee7e4f5a JE |
121 | return xt_reject->target(pskb, par->in, par->out, par->hooknum, |
122 | xt_reject, &reject_params, NULL); | |
5fd97e99 | 123 | #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23) |
ee7e4f5a JE |
124 | return xt_reject->target(pskb, par->in, par->out, par->hooknum, |
125 | xt_reject, &reject_params); | |
126 | #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27) | |
127 | return xt_reject->target(skb, par->in, par->out, par->hooknum, | |
128 | xt_reject, &reject_params); | |
2fbfbe6c | 129 | #else |
ee7e4f5a JE |
130 | struct xt_target_param local_par = { |
131 | .in = par->in, | |
132 | .out = par->out, | |
133 | .hooknum = par->hooknum, | |
134 | .target = xt_reject, | |
135 | .targinfo = &reject_params, | |
136 | }; | |
137 | return xt_reject->target(skb, &local_par); | |
2fbfbe6c | 138 | #endif |
ee7e4f5a | 139 | } |
2fbfbe6c JE |
140 | |
141 | /* TARPIT/DELUDE may not be called from the OUTPUT chain */ | |
142 | if (iph->protocol == IPPROTO_TCP && | |
ee7e4f5a JE |
143 | info->variant != XTCHAOS_NORMAL && |
144 | par->hooknum != NF_INET_LOCAL_OUT) | |
145 | xt_chaos_total(skb, par); | |
2fbfbe6c JE |
146 | |
147 | return NF_DROP; | |
148 | } | |
149 | ||
ad146dbe | 150 | static int chaos_tg_check(const struct xt_tgchk_param *par) |
2fbfbe6c | 151 | { |
ee7e4f5a | 152 | const struct xt_chaos_tginfo *info = par->targinfo; |
2fbfbe6c JE |
153 | |
154 | if (info->variant == XTCHAOS_DELUDE && !have_delude) { | |
155 | printk(KERN_WARNING PFX "Error: Cannot use --delude when " | |
156 | "DELUDE module not available\n"); | |
ad146dbe | 157 | return -EINVAL; |
2fbfbe6c JE |
158 | } |
159 | if (info->variant == XTCHAOS_TARPIT && !have_tarpit) { | |
160 | printk(KERN_WARNING PFX "Error: Cannot use --tarpit when " | |
161 | "TARPIT module not available\n"); | |
ad146dbe | 162 | return -EINVAL; |
2fbfbe6c JE |
163 | } |
164 | ||
ad146dbe | 165 | return 0; |
2fbfbe6c JE |
166 | } |
167 | ||
168 | static struct xt_target chaos_tg_reg = { | |
169 | .name = "CHAOS", | |
be6fbee5 JE |
170 | .revision = 0, |
171 | .family = NFPROTO_IPV4, | |
2fbfbe6c JE |
172 | .table = "filter", |
173 | .hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD) | | |
174 | (1 << NF_INET_LOCAL_OUT), | |
175 | .target = chaos_tg, | |
176 | .checkentry = chaos_tg_check, | |
177 | .targetsize = sizeof(struct xt_chaos_tginfo), | |
178 | .me = THIS_MODULE, | |
179 | }; | |
180 | ||
181 | static int __init chaos_tg_init(void) | |
182 | { | |
183 | int ret = -EINVAL; | |
184 | ||
be6fbee5 | 185 | xm_tcp = xt_request_find_match(NFPROTO_IPV4, "tcp", 0); |
2fbfbe6c JE |
186 | if (xm_tcp == NULL) { |
187 | printk(KERN_WARNING PFX "Error: Could not find or load " | |
188 | "\"tcp\" match\n"); | |
189 | return -EINVAL; | |
190 | } | |
191 | ||
be6fbee5 | 192 | xt_reject = xt_request_find_target(NFPROTO_IPV4, "REJECT", 0); |
2fbfbe6c JE |
193 | if (xt_reject == NULL) { |
194 | printk(KERN_WARNING PFX "Error: Could not find or load " | |
195 | "\"REJECT\" target\n"); | |
196 | goto out2; | |
197 | } | |
198 | ||
be6fbee5 | 199 | xt_tarpit = xt_request_find_target(NFPROTO_IPV4, "TARPIT", 0); |
2fbfbe6c JE |
200 | have_tarpit = xt_tarpit != NULL; |
201 | if (!have_tarpit) | |
202 | printk(KERN_WARNING PFX "Warning: Could not find or load " | |
203 | "\"TARPIT\" target\n"); | |
204 | ||
be6fbee5 | 205 | xt_delude = xt_request_find_target(NFPROTO_IPV4, "DELUDE", 0); |
2fbfbe6c JE |
206 | have_delude = xt_delude != NULL; |
207 | if (!have_delude) | |
208 | printk(KERN_WARNING PFX "Warning: Could not find or load " | |
209 | "\"DELUDE\" target\n"); | |
210 | ||
211 | if ((ret = xt_register_target(&chaos_tg_reg)) != 0) { | |
212 | printk(KERN_WARNING PFX "xt_register_target returned " | |
213 | "error %d\n", ret); | |
214 | goto out3; | |
215 | } | |
216 | ||
217 | return 0; | |
218 | ||
219 | out3: | |
220 | if (have_delude) | |
221 | module_put(xt_delude->me); | |
222 | if (have_tarpit) | |
223 | module_put(xt_tarpit->me); | |
224 | module_put(xt_reject->me); | |
225 | out2: | |
226 | module_put(xm_tcp->me); | |
227 | return ret; | |
228 | } | |
229 | ||
230 | static void __exit chaos_tg_exit(void) | |
231 | { | |
232 | xt_unregister_target(&chaos_tg_reg); | |
233 | module_put(xm_tcp->me); | |
234 | module_put(xt_reject->me); | |
235 | if (have_delude) | |
236 | module_put(xt_delude->me); | |
237 | if (have_tarpit) | |
238 | module_put(xt_tarpit->me); | |
2fbfbe6c JE |
239 | } |
240 | ||
241 | module_init(chaos_tg_init); | |
242 | module_exit(chaos_tg_exit); | |
2fbfbe6c | 243 | MODULE_DESCRIPTION("Xtables: Network scan slowdown with non-deterministic results"); |
538d74b5 | 244 | MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); |
2fbfbe6c JE |
245 | MODULE_LICENSE("GPL"); |
246 | MODULE_ALIAS("ipt_CHAOS"); |