blob: f4ebe6a3cf12b2b31a53e17095b20ef7e97b7606 [file] [log] [blame]
Jan Engelhardt32b8e612010-07-23 21:16:14 +02001#include <stdbool.h>
Stephen Frost93c7e5a2001-11-08 22:35:03 +00002#include <stdio.h>
Stephen Frost93c7e5a2001-11-08 22:35:03 +00003#include <string.h>
Jan Engelhardtaf1660f2008-10-22 18:53:39 +02004#include <xtables.h>
5#include <linux/netfilter/xt_recent.h>
Harald Welte122e7c02003-03-30 20:26:42 +00006
Jan Engelhardt51a746e2011-05-04 12:30:15 +02007enum {
8 O_SET = 0,
9 O_RCHECK,
10 O_UPDATE,
11 O_REMOVE,
12 O_SECONDS,
Tim Gardner79ddbf22011-11-30 08:16:53 -070013 O_REAP,
Jan Engelhardt51a746e2011-05-04 12:30:15 +020014 O_HITCOUNT,
15 O_RTTL,
16 O_NAME,
17 O_RSOURCE,
18 O_RDEST,
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +000019 O_MASK,
Jan Engelhardt51a746e2011-05-04 12:30:15 +020020 F_SET = 1 << O_SET,
21 F_RCHECK = 1 << O_RCHECK,
22 F_UPDATE = 1 << O_UPDATE,
23 F_REMOVE = 1 << O_REMOVE,
Tim Gardner79ddbf22011-11-30 08:16:53 -070024 F_SECONDS = 1 << O_SECONDS,
Jan Engelhardt51a746e2011-05-04 12:30:15 +020025 F_ANY_OP = F_SET | F_RCHECK | F_UPDATE | F_REMOVE,
Stephen Frost27e1fa82003-04-14 13:33:15 +000026};
27
Jan Engelhardt51a746e2011-05-04 12:30:15 +020028#define s struct xt_recent_mtinfo
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +000029static const struct xt_option_entry recent_opts_v0[] = {
Jan Engelhardt51a746e2011-05-04 12:30:15 +020030 {.name = "set", .id = O_SET, .type = XTTYPE_NONE,
31 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
32 {.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE,
33 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
34 {.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE,
35 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
36 {.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE,
37 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
38 {.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32,
Tim Gardner79ddbf22011-11-30 08:16:53 -070039 .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds), .min = 1},
40 {.name = "reap", .id = O_REAP, .type = XTTYPE_NONE,
41 .also = F_SECONDS },
Jan Engelhardt51a746e2011-05-04 12:30:15 +020042 {.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32,
43 .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)},
44 {.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE,
45 .excl = F_SET | F_REMOVE},
46 {.name = "name", .id = O_NAME, .type = XTTYPE_STRING,
47 .flags = XTOPT_PUT, XTOPT_POINTER(s, name)},
48 {.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE},
49 {.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE},
50 XTOPT_TABLEEND,
51};
52#undef s
53
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +000054#define s struct xt_recent_mtinfo_v1
55static const struct xt_option_entry recent_opts_v1[] = {
56 {.name = "set", .id = O_SET, .type = XTTYPE_NONE,
57 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
58 {.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE,
59 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
60 {.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE,
61 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
62 {.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE,
63 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
64 {.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32,
65 .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds)},
66 {.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32,
67 .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)},
68 {.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE,
69 .excl = F_SET | F_REMOVE},
70 {.name = "name", .id = O_NAME, .type = XTTYPE_STRING,
71 .flags = XTOPT_PUT, XTOPT_POINTER(s, name)},
72 {.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE},
73 {.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE},
74 {.name = "mask", .id = O_MASK, .type = XTTYPE_HOST,
75 .flags = XTOPT_PUT, XTOPT_POINTER(s, mask)},
76 XTOPT_TABLEEND,
77};
78#undef s
79
Jan Engelhardt59d16402007-10-04 16:28:39 +000080static void recent_help(void)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000081{
82 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020083"recent match options:\n"
Stephen Frost93c7e5a2001-11-08 22:35:03 +000084"[!] --set Add source address to list, always matches.\n"
85"[!] --rcheck Match if source address in list.\n"
86"[!] --update Match if source address in list, also update last-seen time.\n"
87"[!] --remove Match if source address in list, also removes that address from list.\n"
88" --seconds seconds For check and update commands above.\n"
89" Specifies that the match will only occur if source address last seen within\n"
90" the last 'seconds' seconds.\n"
Tim Gardner79ddbf22011-11-30 08:16:53 -070091" --reap Purge entries older then 'seconds'.\n"
92" Can only be used in conjunction with the seconds option.\n"
Stephen Frost93c7e5a2001-11-08 22:35:03 +000093" --hitcount hits For check and update commands above.\n"
94" Specifies that the match will only occur if source address seen hits times.\n"
Fabrice MARIEae31bb62002-06-14 07:38:16 +000095" May be used in conjunction with the seconds option.\n"
Stephen Frost4fce44c2002-02-04 11:58:22 +000096" --rttl For check and update commands above.\n"
97" Specifies that the match will only occur if the source address and the TTL\n"
98" match between this packet and the one which was set.\n"
99" Useful if you have problems with people spoofing their source address in order\n"
100" to DoS you via this module.\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +0000101" --name name Name of the recent list to be used. DEFAULT used if none given.\n"
Stephen Frost27e1fa82003-04-14 13:33:15 +0000102" --rsource Match/Save the source address of each packet in the recent list table (default).\n"
103" --rdest Match/Save the destination address of each packet in the recent list table.\n"
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000104" --mask netmask Netmask that will be applied to this recent list.\n"
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200105"xt_recent by: Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000106}
Jan Engelhardtddac6c52008-09-01 14:22:19 +0200107
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000108enum {
109 XT_RECENT_REV_0 = 0,
110 XT_RECENT_REV_1,
111};
112
113static void recent_init(struct xt_entry_match *match, unsigned int rev)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000114{
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000115 struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)match->data;
116 struct xt_recent_mtinfo_v1 *info_v1 =
117 (struct xt_recent_mtinfo_v1 *)match->data;
Stephen Frost7fdbc952002-06-21 17:26:33 +0000118
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200119 strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
120 /* even though XT_RECENT_NAME_LEN is currently defined as 200,
Karsten Desler073df8f2004-01-31 15:33:55 +0000121 * better be safe, than sorry */
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200122 info->name[XT_RECENT_NAME_LEN-1] = '\0';
123 info->side = XT_RECENT_SOURCE;
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000124 if (rev == XT_RECENT_REV_1)
125 memset(&info_v1->mask, 0xFF, sizeof(info_v1->mask));
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000126}
127
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200128static void recent_parse(struct xt_option_call *cb)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000129{
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200130 struct xt_recent_mtinfo *info = cb->data;
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200131
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200132 xtables_option_parse(cb);
133 switch (cb->entry->id) {
134 case O_SET:
135 info->check_set |= XT_RECENT_SET;
136 if (cb->invert)
137 info->invert = true;
138 break;
139 case O_RCHECK:
140 info->check_set |= XT_RECENT_CHECK;
141 if (cb->invert)
142 info->invert = true;
143 break;
144 case O_UPDATE:
145 info->check_set |= XT_RECENT_UPDATE;
146 if (cb->invert)
147 info->invert = true;
148 break;
149 case O_REMOVE:
150 info->check_set |= XT_RECENT_REMOVE;
151 if (cb->invert)
152 info->invert = true;
153 break;
154 case O_RTTL:
155 info->check_set |= XT_RECENT_TTL;
156 break;
157 case O_RSOURCE:
158 info->side = XT_RECENT_SOURCE;
159 break;
160 case O_RDEST:
161 info->side = XT_RECENT_DEST;
162 break;
Tim Gardner79ddbf22011-11-30 08:16:53 -0700163 case O_REAP:
164 info->check_set |= XT_RECENT_REAP;
165 break;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000166 }
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000167}
168
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200169static void recent_check(struct xt_fcheck_call *cb)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000170{
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200171 if (!(cb->xflags & F_ANY_OP))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100172 xtables_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000173 "recent: you must specify one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000174 "`--update' or `--remove'");
175}
176
Jan Engelhardt59d16402007-10-04 16:28:39 +0000177static void recent_print(const void *ip, const struct xt_entry_match *match,
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000178 unsigned int family)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000179{
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000180 const struct xt_recent_mtinfo_v1 *info = (const void *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000181
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000182 if (info->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100183 printf(" !");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000184
Jan Engelhardt73866352010-12-18 02:04:59 +0100185 printf(" recent:");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200186 if (info->check_set & XT_RECENT_SET)
Jan Engelhardt73866352010-12-18 02:04:59 +0100187 printf(" SET");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200188 if (info->check_set & XT_RECENT_CHECK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100189 printf(" CHECK");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200190 if (info->check_set & XT_RECENT_UPDATE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100191 printf(" UPDATE");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200192 if (info->check_set & XT_RECENT_REMOVE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100193 printf(" REMOVE");
194 if(info->seconds) printf(" seconds: %d", info->seconds);
Tim Gardner79ddbf22011-11-30 08:16:53 -0700195 if (info->check_set & XT_RECENT_REAP)
196 printf(" reap");
Jan Engelhardt73866352010-12-18 02:04:59 +0100197 if(info->hit_count) printf(" hit_count: %d", info->hit_count);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200198 if (info->check_set & XT_RECENT_TTL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100199 printf(" TTL-Match");
200 if(info->name) printf(" name: %s", info->name);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200201 if (info->side == XT_RECENT_SOURCE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100202 printf(" side: source");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200203 if (info->side == XT_RECENT_DEST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100204 printf(" side: dest");
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000205
206 switch(family) {
207 case NFPROTO_IPV4:
208 printf(" mask: %s",
209 xtables_ipaddr_to_numeric(&info->mask.in));
210 break;
211 case NFPROTO_IPV6:
212 printf(" mask: %s",
213 xtables_ip6addr_to_numeric(&info->mask.in6));
214 break;
215 }
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000216}
217
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000218static void recent_save(const void *ip, const struct xt_entry_match *match,
219 unsigned int family)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000220{
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000221 const struct xt_recent_mtinfo_v1 *info = (const void *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000222
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000223 if (info->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100224 printf(" !");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000225
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200226 if (info->check_set & XT_RECENT_SET)
Jan Engelhardt73866352010-12-18 02:04:59 +0100227 printf(" --set");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200228 if (info->check_set & XT_RECENT_CHECK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100229 printf(" --rcheck");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200230 if (info->check_set & XT_RECENT_UPDATE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100231 printf(" --update");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200232 if (info->check_set & XT_RECENT_REMOVE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100233 printf(" --remove");
234 if(info->seconds) printf(" --seconds %d", info->seconds);
Tim Gardner79ddbf22011-11-30 08:16:53 -0700235 if (info->check_set & XT_RECENT_REAP)
236 printf(" --reap");
Jan Engelhardt73866352010-12-18 02:04:59 +0100237 if(info->hit_count) printf(" --hitcount %d", info->hit_count);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200238 if (info->check_set & XT_RECENT_TTL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100239 printf(" --rttl");
240 if(info->name) printf(" --name %s",info->name);
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000241
242 switch(family) {
243 case NFPROTO_IPV4:
244 printf(" --mask %s",
245 xtables_ipaddr_to_numeric(&info->mask.in));
246 break;
247 case NFPROTO_IPV6:
248 printf(" --mask %s",
249 xtables_ip6addr_to_numeric(&info->mask.in6));
250 break;
251 }
252
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200253 if (info->side == XT_RECENT_SOURCE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100254 printf(" --rsource");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200255 if (info->side == XT_RECENT_DEST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100256 printf(" --rdest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000257}
258
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000259static void recent_init_v0(struct xt_entry_match *match)
260{
261 recent_init(match, XT_RECENT_REV_0);
262}
263
264static void recent_init_v1(struct xt_entry_match *match)
265{
266 recent_init(match, XT_RECENT_REV_1);
267}
268
269static void recent_save_v0(const void *ip, const struct xt_entry_match *match)
270{
271 recent_save(ip, match, NFPROTO_UNSPEC);
272}
273
274static void recent_save_v4(const void *ip, const struct xt_entry_match *match)
275{
276 recent_save(ip, match, NFPROTO_IPV4);
277}
278
279static void recent_save_v6(const void *ip, const struct xt_entry_match *match)
280{
281 recent_save(ip, match, NFPROTO_IPV6);
282}
283
284static void recent_print_v0(const void *ip, const struct xt_entry_match *match,
285 int numeric)
286{
287 recent_print(ip, match, NFPROTO_UNSPEC);
288}
289
290static void recent_print_v4(const void *ip, const struct xt_entry_match *match,
291 int numeric)
292{
293 recent_print(ip, match, NFPROTO_IPV4);
294}
295
296static void recent_print_v6(const void *ip, const struct xt_entry_match *match,
297 int numeric)
298{
299 recent_print(ip, match, NFPROTO_IPV6);
300}
301
302static struct xtables_match recent_mt_reg[] = {
303 {
304 .name = "recent",
305 .version = XTABLES_VERSION,
306 .revision = 0,
307 .family = NFPROTO_UNSPEC,
308 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
309 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
310 .help = recent_help,
311 .init = recent_init_v0,
312 .x6_parse = recent_parse,
313 .x6_fcheck = recent_check,
314 .print = recent_print_v0,
315 .save = recent_save_v0,
316 .x6_options = recent_opts_v0,
317 },
318 {
319 .name = "recent",
320 .version = XTABLES_VERSION,
321 .revision = 1,
322 .family = NFPROTO_IPV4,
323 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
324 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
325 .help = recent_help,
326 .init = recent_init_v1,
327 .x6_parse = recent_parse,
328 .x6_fcheck = recent_check,
329 .print = recent_print_v4,
330 .save = recent_save_v4,
331 .x6_options = recent_opts_v1,
332 },
333 {
334 .name = "recent",
335 .version = XTABLES_VERSION,
336 .revision = 1,
337 .family = NFPROTO_IPV6,
338 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
339 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
340 .help = recent_help,
341 .init = recent_init_v1,
342 .x6_parse = recent_parse,
343 .x6_fcheck = recent_check,
344 .print = recent_print_v6,
345 .save = recent_save_v6,
346 .x6_options = recent_opts_v1,
347 },
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000348};
349
350void _init(void)
351{
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000352 xtables_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000353}