blob: e1801f1c18952fc3894fda0deb05378f89f4b2bd [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,
Pablo Neira Ayuso88b73a22013-07-15 12:14:55 +020065 .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds), .min = 1},
Russell Senior8cf6fb82013-07-13 10:08:07 +000066 {.name = "reap", .id = O_REAP, .type = XTTYPE_NONE,
67 .also = F_SECONDS },
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +000068 {.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32,
69 .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)},
70 {.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE,
71 .excl = F_SET | F_REMOVE},
72 {.name = "name", .id = O_NAME, .type = XTTYPE_STRING,
73 .flags = XTOPT_PUT, XTOPT_POINTER(s, name)},
74 {.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE},
75 {.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE},
76 {.name = "mask", .id = O_MASK, .type = XTTYPE_HOST,
77 .flags = XTOPT_PUT, XTOPT_POINTER(s, mask)},
78 XTOPT_TABLEEND,
79};
80#undef s
81
Jan Engelhardt59d16402007-10-04 16:28:39 +000082static void recent_help(void)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000083{
84 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020085"recent match options:\n"
Stephen Frost93c7e5a2001-11-08 22:35:03 +000086"[!] --set Add source address to list, always matches.\n"
87"[!] --rcheck Match if source address in list.\n"
88"[!] --update Match if source address in list, also update last-seen time.\n"
89"[!] --remove Match if source address in list, also removes that address from list.\n"
90" --seconds seconds For check and update commands above.\n"
91" Specifies that the match will only occur if source address last seen within\n"
92" the last 'seconds' seconds.\n"
Tim Gardner79ddbf22011-11-30 08:16:53 -070093" --reap Purge entries older then 'seconds'.\n"
94" Can only be used in conjunction with the seconds option.\n"
Stephen Frost93c7e5a2001-11-08 22:35:03 +000095" --hitcount hits For check and update commands above.\n"
96" Specifies that the match will only occur if source address seen hits times.\n"
Fabrice MARIEae31bb62002-06-14 07:38:16 +000097" May be used in conjunction with the seconds option.\n"
Stephen Frost4fce44c2002-02-04 11:58:22 +000098" --rttl For check and update commands above.\n"
99" Specifies that the match will only occur if the source address and the TTL\n"
100" match between this packet and the one which was set.\n"
101" Useful if you have problems with people spoofing their source address in order\n"
102" to DoS you via this module.\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +0000103" --name name Name of the recent list to be used. DEFAULT used if none given.\n"
Stephen Frost27e1fa82003-04-14 13:33:15 +0000104" --rsource Match/Save the source address of each packet in the recent list table (default).\n"
105" --rdest Match/Save the destination address of each packet in the recent list table.\n"
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000106" --mask netmask Netmask that will be applied to this recent list.\n"
Laurence J. Lane8fa26de2013-08-23 16:55:55 -0400107"xt_recent by: Stephen Frost <sfrost@snowman.net>.\n");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000108}
Jan Engelhardtddac6c52008-09-01 14:22:19 +0200109
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000110enum {
111 XT_RECENT_REV_0 = 0,
112 XT_RECENT_REV_1,
113};
114
115static void recent_init(struct xt_entry_match *match, unsigned int rev)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000116{
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000117 struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)match->data;
118 struct xt_recent_mtinfo_v1 *info_v1 =
119 (struct xt_recent_mtinfo_v1 *)match->data;
Stephen Frost7fdbc952002-06-21 17:26:33 +0000120
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200121 strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
122 /* even though XT_RECENT_NAME_LEN is currently defined as 200,
Karsten Desler073df8f2004-01-31 15:33:55 +0000123 * better be safe, than sorry */
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200124 info->name[XT_RECENT_NAME_LEN-1] = '\0';
125 info->side = XT_RECENT_SOURCE;
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000126 if (rev == XT_RECENT_REV_1)
127 memset(&info_v1->mask, 0xFF, sizeof(info_v1->mask));
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000128}
129
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200130static void recent_parse(struct xt_option_call *cb)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000131{
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200132 struct xt_recent_mtinfo *info = cb->data;
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200133
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200134 xtables_option_parse(cb);
135 switch (cb->entry->id) {
136 case O_SET:
137 info->check_set |= XT_RECENT_SET;
138 if (cb->invert)
139 info->invert = true;
140 break;
141 case O_RCHECK:
142 info->check_set |= XT_RECENT_CHECK;
143 if (cb->invert)
144 info->invert = true;
145 break;
146 case O_UPDATE:
147 info->check_set |= XT_RECENT_UPDATE;
148 if (cb->invert)
149 info->invert = true;
150 break;
151 case O_REMOVE:
152 info->check_set |= XT_RECENT_REMOVE;
153 if (cb->invert)
154 info->invert = true;
155 break;
156 case O_RTTL:
157 info->check_set |= XT_RECENT_TTL;
158 break;
159 case O_RSOURCE:
160 info->side = XT_RECENT_SOURCE;
161 break;
162 case O_RDEST:
163 info->side = XT_RECENT_DEST;
164 break;
Tim Gardner79ddbf22011-11-30 08:16:53 -0700165 case O_REAP:
166 info->check_set |= XT_RECENT_REAP;
167 break;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000168 }
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000169}
170
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200171static void recent_check(struct xt_fcheck_call *cb)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000172{
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200173 if (!(cb->xflags & F_ANY_OP))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100174 xtables_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000175 "recent: you must specify one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000176 "`--update' or `--remove'");
177}
178
Jan Engelhardt59d16402007-10-04 16:28:39 +0000179static void recent_print(const void *ip, const struct xt_entry_match *match,
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000180 unsigned int family)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000181{
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000182 const struct xt_recent_mtinfo_v1 *info = (const void *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000183
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000184 if (info->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100185 printf(" !");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000186
Jan Engelhardt73866352010-12-18 02:04:59 +0100187 printf(" recent:");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200188 if (info->check_set & XT_RECENT_SET)
Jan Engelhardt73866352010-12-18 02:04:59 +0100189 printf(" SET");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200190 if (info->check_set & XT_RECENT_CHECK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100191 printf(" CHECK");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200192 if (info->check_set & XT_RECENT_UPDATE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100193 printf(" UPDATE");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200194 if (info->check_set & XT_RECENT_REMOVE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100195 printf(" REMOVE");
196 if(info->seconds) printf(" seconds: %d", info->seconds);
Tim Gardner79ddbf22011-11-30 08:16:53 -0700197 if (info->check_set & XT_RECENT_REAP)
198 printf(" reap");
Jan Engelhardt73866352010-12-18 02:04:59 +0100199 if(info->hit_count) printf(" hit_count: %d", info->hit_count);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200200 if (info->check_set & XT_RECENT_TTL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100201 printf(" TTL-Match");
202 if(info->name) printf(" name: %s", info->name);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200203 if (info->side == XT_RECENT_SOURCE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100204 printf(" side: source");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200205 if (info->side == XT_RECENT_DEST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100206 printf(" side: dest");
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000207
208 switch(family) {
209 case NFPROTO_IPV4:
210 printf(" mask: %s",
211 xtables_ipaddr_to_numeric(&info->mask.in));
212 break;
213 case NFPROTO_IPV6:
214 printf(" mask: %s",
215 xtables_ip6addr_to_numeric(&info->mask.in6));
216 break;
217 }
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000218}
219
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000220static void recent_save(const void *ip, const struct xt_entry_match *match,
221 unsigned int family)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000222{
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000223 const struct xt_recent_mtinfo_v1 *info = (const void *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000224
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000225 if (info->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100226 printf(" !");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000227
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200228 if (info->check_set & XT_RECENT_SET)
Jan Engelhardt73866352010-12-18 02:04:59 +0100229 printf(" --set");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200230 if (info->check_set & XT_RECENT_CHECK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100231 printf(" --rcheck");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200232 if (info->check_set & XT_RECENT_UPDATE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100233 printf(" --update");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200234 if (info->check_set & XT_RECENT_REMOVE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100235 printf(" --remove");
236 if(info->seconds) printf(" --seconds %d", info->seconds);
Tim Gardner79ddbf22011-11-30 08:16:53 -0700237 if (info->check_set & XT_RECENT_REAP)
238 printf(" --reap");
Jan Engelhardt73866352010-12-18 02:04:59 +0100239 if(info->hit_count) printf(" --hitcount %d", info->hit_count);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200240 if (info->check_set & XT_RECENT_TTL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100241 printf(" --rttl");
242 if(info->name) printf(" --name %s",info->name);
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000243
244 switch(family) {
245 case NFPROTO_IPV4:
246 printf(" --mask %s",
247 xtables_ipaddr_to_numeric(&info->mask.in));
248 break;
249 case NFPROTO_IPV6:
250 printf(" --mask %s",
251 xtables_ip6addr_to_numeric(&info->mask.in6));
252 break;
253 }
254
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200255 if (info->side == XT_RECENT_SOURCE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100256 printf(" --rsource");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200257 if (info->side == XT_RECENT_DEST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100258 printf(" --rdest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000259}
260
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000261static void recent_init_v0(struct xt_entry_match *match)
262{
263 recent_init(match, XT_RECENT_REV_0);
264}
265
266static void recent_init_v1(struct xt_entry_match *match)
267{
268 recent_init(match, XT_RECENT_REV_1);
269}
270
271static void recent_save_v0(const void *ip, const struct xt_entry_match *match)
272{
273 recent_save(ip, match, NFPROTO_UNSPEC);
274}
275
276static void recent_save_v4(const void *ip, const struct xt_entry_match *match)
277{
278 recent_save(ip, match, NFPROTO_IPV4);
279}
280
281static void recent_save_v6(const void *ip, const struct xt_entry_match *match)
282{
283 recent_save(ip, match, NFPROTO_IPV6);
284}
285
286static void recent_print_v0(const void *ip, const struct xt_entry_match *match,
287 int numeric)
288{
289 recent_print(ip, match, NFPROTO_UNSPEC);
290}
291
292static void recent_print_v4(const void *ip, const struct xt_entry_match *match,
293 int numeric)
294{
295 recent_print(ip, match, NFPROTO_IPV4);
296}
297
298static void recent_print_v6(const void *ip, const struct xt_entry_match *match,
299 int numeric)
300{
301 recent_print(ip, match, NFPROTO_IPV6);
302}
303
304static struct xtables_match recent_mt_reg[] = {
305 {
306 .name = "recent",
307 .version = XTABLES_VERSION,
308 .revision = 0,
309 .family = NFPROTO_UNSPEC,
310 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
311 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
312 .help = recent_help,
313 .init = recent_init_v0,
314 .x6_parse = recent_parse,
315 .x6_fcheck = recent_check,
316 .print = recent_print_v0,
317 .save = recent_save_v0,
318 .x6_options = recent_opts_v0,
319 },
320 {
321 .name = "recent",
322 .version = XTABLES_VERSION,
323 .revision = 1,
324 .family = NFPROTO_IPV4,
325 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
326 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
327 .help = recent_help,
328 .init = recent_init_v1,
329 .x6_parse = recent_parse,
330 .x6_fcheck = recent_check,
331 .print = recent_print_v4,
332 .save = recent_save_v4,
333 .x6_options = recent_opts_v1,
334 },
335 {
336 .name = "recent",
337 .version = XTABLES_VERSION,
338 .revision = 1,
339 .family = NFPROTO_IPV6,
340 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
341 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)),
342 .help = recent_help,
343 .init = recent_init_v1,
344 .x6_parse = recent_parse,
345 .x6_fcheck = recent_check,
346 .print = recent_print_v6,
347 .save = recent_save_v6,
348 .x6_options = recent_opts_v1,
349 },
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000350};
351
352void _init(void)
353{
Denys Fedoryshchenko74ded722012-05-17 10:08:57 +0000354 xtables_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000355}