blob: c7dce4e7226dae738688f6dc2934254279d2a158 [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,
19 F_SET = 1 << O_SET,
20 F_RCHECK = 1 << O_RCHECK,
21 F_UPDATE = 1 << O_UPDATE,
22 F_REMOVE = 1 << O_REMOVE,
Tim Gardner79ddbf22011-11-30 08:16:53 -070023 F_SECONDS = 1 << O_SECONDS,
Jan Engelhardt51a746e2011-05-04 12:30:15 +020024 F_ANY_OP = F_SET | F_RCHECK | F_UPDATE | F_REMOVE,
Stephen Frost27e1fa82003-04-14 13:33:15 +000025};
26
Jan Engelhardt51a746e2011-05-04 12:30:15 +020027#define s struct xt_recent_mtinfo
28static const struct xt_option_entry recent_opts[] = {
29 {.name = "set", .id = O_SET, .type = XTTYPE_NONE,
30 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
31 {.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE,
32 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
33 {.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE,
34 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
35 {.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE,
36 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
37 {.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32,
Tim Gardner79ddbf22011-11-30 08:16:53 -070038 .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds), .min = 1},
39 {.name = "reap", .id = O_REAP, .type = XTTYPE_NONE,
40 .also = F_SECONDS },
Jan Engelhardt51a746e2011-05-04 12:30:15 +020041 {.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32,
42 .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)},
43 {.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE,
44 .excl = F_SET | F_REMOVE},
45 {.name = "name", .id = O_NAME, .type = XTTYPE_STRING,
46 .flags = XTOPT_PUT, XTOPT_POINTER(s, name)},
47 {.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE},
48 {.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE},
49 XTOPT_TABLEEND,
50};
51#undef s
52
Jan Engelhardt59d16402007-10-04 16:28:39 +000053static void recent_help(void)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000054{
55 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020056"recent match options:\n"
Stephen Frost93c7e5a2001-11-08 22:35:03 +000057"[!] --set Add source address to list, always matches.\n"
58"[!] --rcheck Match if source address in list.\n"
59"[!] --update Match if source address in list, also update last-seen time.\n"
60"[!] --remove Match if source address in list, also removes that address from list.\n"
61" --seconds seconds For check and update commands above.\n"
62" Specifies that the match will only occur if source address last seen within\n"
63" the last 'seconds' seconds.\n"
Tim Gardner79ddbf22011-11-30 08:16:53 -070064" --reap Purge entries older then 'seconds'.\n"
65" Can only be used in conjunction with the seconds option.\n"
Stephen Frost93c7e5a2001-11-08 22:35:03 +000066" --hitcount hits For check and update commands above.\n"
67" Specifies that the match will only occur if source address seen hits times.\n"
Fabrice MARIEae31bb62002-06-14 07:38:16 +000068" May be used in conjunction with the seconds option.\n"
Stephen Frost4fce44c2002-02-04 11:58:22 +000069" --rttl For check and update commands above.\n"
70" Specifies that the match will only occur if the source address and the TTL\n"
71" match between this packet and the one which was set.\n"
72" Useful if you have problems with people spoofing their source address in order\n"
73" to DoS you via this module.\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +000074" --name name Name of the recent list to be used. DEFAULT used if none given.\n"
Stephen Frost27e1fa82003-04-14 13:33:15 +000075" --rsource Match/Save the source address of each packet in the recent list table (default).\n"
76" --rdest Match/Save the destination address of each packet in the recent list table.\n"
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020077"xt_recent by: Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n");
Stephen Frost93c7e5a2001-11-08 22:35:03 +000078}
Jan Engelhardtddac6c52008-09-01 14:22:19 +020079
Jan Engelhardt59d16402007-10-04 16:28:39 +000080static void recent_init(struct xt_entry_match *match)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000081{
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020082 struct xt_recent_mtinfo *info = (void *)(match)->data;
Stephen Frost7fdbc952002-06-21 17:26:33 +000083
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020084 strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
85 /* even though XT_RECENT_NAME_LEN is currently defined as 200,
Karsten Desler073df8f2004-01-31 15:33:55 +000086 * better be safe, than sorry */
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020087 info->name[XT_RECENT_NAME_LEN-1] = '\0';
88 info->side = XT_RECENT_SOURCE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000089}
90
Jan Engelhardt51a746e2011-05-04 12:30:15 +020091static void recent_parse(struct xt_option_call *cb)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000092{
Jan Engelhardt51a746e2011-05-04 12:30:15 +020093 struct xt_recent_mtinfo *info = cb->data;
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020094
Jan Engelhardt51a746e2011-05-04 12:30:15 +020095 xtables_option_parse(cb);
96 switch (cb->entry->id) {
97 case O_SET:
98 info->check_set |= XT_RECENT_SET;
99 if (cb->invert)
100 info->invert = true;
101 break;
102 case O_RCHECK:
103 info->check_set |= XT_RECENT_CHECK;
104 if (cb->invert)
105 info->invert = true;
106 break;
107 case O_UPDATE:
108 info->check_set |= XT_RECENT_UPDATE;
109 if (cb->invert)
110 info->invert = true;
111 break;
112 case O_REMOVE:
113 info->check_set |= XT_RECENT_REMOVE;
114 if (cb->invert)
115 info->invert = true;
116 break;
117 case O_RTTL:
118 info->check_set |= XT_RECENT_TTL;
119 break;
120 case O_RSOURCE:
121 info->side = XT_RECENT_SOURCE;
122 break;
123 case O_RDEST:
124 info->side = XT_RECENT_DEST;
125 break;
Tim Gardner79ddbf22011-11-30 08:16:53 -0700126 case O_REAP:
127 info->check_set |= XT_RECENT_REAP;
128 break;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000129 }
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000130}
131
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200132static void recent_check(struct xt_fcheck_call *cb)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000133{
Tim Gardner79ddbf22011-11-30 08:16:53 -0700134 struct xt_recent_mtinfo *info = cb->data;
135
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200136 if (!(cb->xflags & F_ANY_OP))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100137 xtables_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000138 "recent: you must specify one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000139 "`--update' or `--remove'");
140}
141
Jan Engelhardt59d16402007-10-04 16:28:39 +0000142static void recent_print(const void *ip, const struct xt_entry_match *match,
143 int numeric)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000144{
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200145 const struct xt_recent_mtinfo *info = (const void *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000146
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000147 if (info->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100148 printf(" !");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000149
Jan Engelhardt73866352010-12-18 02:04:59 +0100150 printf(" recent:");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200151 if (info->check_set & XT_RECENT_SET)
Jan Engelhardt73866352010-12-18 02:04:59 +0100152 printf(" SET");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200153 if (info->check_set & XT_RECENT_CHECK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100154 printf(" CHECK");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200155 if (info->check_set & XT_RECENT_UPDATE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100156 printf(" UPDATE");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200157 if (info->check_set & XT_RECENT_REMOVE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100158 printf(" REMOVE");
159 if(info->seconds) printf(" seconds: %d", info->seconds);
Tim Gardner79ddbf22011-11-30 08:16:53 -0700160 if (info->check_set & XT_RECENT_REAP)
161 printf(" reap");
Jan Engelhardt73866352010-12-18 02:04:59 +0100162 if(info->hit_count) printf(" hit_count: %d", info->hit_count);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200163 if (info->check_set & XT_RECENT_TTL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100164 printf(" TTL-Match");
165 if(info->name) printf(" name: %s", info->name);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200166 if (info->side == XT_RECENT_SOURCE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100167 printf(" side: source");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200168 if (info->side == XT_RECENT_DEST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100169 printf(" side: dest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000170}
171
Jan Engelhardt59d16402007-10-04 16:28:39 +0000172static void recent_save(const void *ip, const struct xt_entry_match *match)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000173{
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200174 const struct xt_recent_mtinfo *info = (const void *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000175
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000176 if (info->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100177 printf(" !");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000178
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200179 if (info->check_set & XT_RECENT_SET)
Jan Engelhardt73866352010-12-18 02:04:59 +0100180 printf(" --set");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200181 if (info->check_set & XT_RECENT_CHECK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100182 printf(" --rcheck");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200183 if (info->check_set & XT_RECENT_UPDATE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100184 printf(" --update");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200185 if (info->check_set & XT_RECENT_REMOVE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100186 printf(" --remove");
187 if(info->seconds) printf(" --seconds %d", info->seconds);
Tim Gardner79ddbf22011-11-30 08:16:53 -0700188 if (info->check_set & XT_RECENT_REAP)
189 printf(" --reap");
Jan Engelhardt73866352010-12-18 02:04:59 +0100190 if(info->hit_count) printf(" --hitcount %d", info->hit_count);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200191 if (info->check_set & XT_RECENT_TTL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100192 printf(" --rttl");
193 if(info->name) printf(" --name %s",info->name);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200194 if (info->side == XT_RECENT_SOURCE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100195 printf(" --rsource");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200196 if (info->side == XT_RECENT_DEST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100197 printf(" --rdest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000198}
199
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200200static struct xtables_match recent_mt_reg = {
Jan Engelhardte1df2212011-02-15 12:02:51 +0100201 .name = "recent",
202 .version = XTABLES_VERSION,
203 .family = NFPROTO_UNSPEC,
204 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
205 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
206 .help = recent_help,
207 .init = recent_init,
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200208 .x6_parse = recent_parse,
209 .x6_fcheck = recent_check,
Jan Engelhardte1df2212011-02-15 12:02:51 +0100210 .print = recent_print,
211 .save = recent_save,
Jan Engelhardt51a746e2011-05-04 12:30:15 +0200212 .x6_options = recent_opts,
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000213};
214
215void _init(void)
216{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200217 xtables_register_match(&recent_mt_reg);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000218}