blob: 1ae90133703bdddc5d43275e31bcd05eaf841d13 [file] [log] [blame]
Stephen Frost93c7e5a2001-11-08 22:35:03 +00001/* Shared library add-on to iptables to add recent matching support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7
Jan Engelhardtaf1660f2008-10-22 18:53:39 +02008#include <xtables.h>
9#include <linux/netfilter/xt_recent.h>
Harald Welte122e7c02003-03-30 20:26:42 +000010
Jan Engelhardt59d16402007-10-04 16:28:39 +000011static const struct option recent_opts[] = {
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020012 { .name = "set", .has_arg = 0, .val = 201 },
13 { .name = "rcheck", .has_arg = 0, .val = 202 },
Patrick McHardy500f4832007-09-08 15:59:04 +000014 { .name = "update", .has_arg = 0, .val = 203 },
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020015 { .name = "seconds", .has_arg = 1, .val = 204 },
Patrick McHardy500f4832007-09-08 15:59:04 +000016 { .name = "hitcount", .has_arg = 1, .val = 205 },
17 { .name = "remove", .has_arg = 0, .val = 206 },
18 { .name = "rttl", .has_arg = 0, .val = 207 },
19 { .name = "name", .has_arg = 1, .val = 208 },
20 { .name = "rsource", .has_arg = 0, .val = 209 },
21 { .name = "rdest", .has_arg = 0, .val = 210 },
Max Kellermann9ee386a2008-01-29 13:48:05 +000022 { .name = NULL }
Stephen Frost27e1fa82003-04-14 13:33:15 +000023};
24
Jan Engelhardt59d16402007-10-04 16:28:39 +000025static void recent_help(void)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000026{
27 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020028"recent match options:\n"
Stephen Frost93c7e5a2001-11-08 22:35:03 +000029"[!] --set Add source address to list, always matches.\n"
30"[!] --rcheck Match if source address in list.\n"
31"[!] --update Match if source address in list, also update last-seen time.\n"
32"[!] --remove Match if source address in list, also removes that address from list.\n"
33" --seconds seconds For check and update commands above.\n"
34" Specifies that the match will only occur if source address last seen within\n"
35" the last 'seconds' seconds.\n"
36" --hitcount hits For check and update commands above.\n"
37" Specifies that the match will only occur if source address seen hits times.\n"
Fabrice MARIEae31bb62002-06-14 07:38:16 +000038" May be used in conjunction with the seconds option.\n"
Stephen Frost4fce44c2002-02-04 11:58:22 +000039" --rttl For check and update commands above.\n"
40" Specifies that the match will only occur if the source address and the TTL\n"
41" match between this packet and the one which was set.\n"
42" Useful if you have problems with people spoofing their source address in order\n"
43" to DoS you via this module.\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +000044" --name name Name of the recent list to be used. DEFAULT used if none given.\n"
Stephen Frost27e1fa82003-04-14 13:33:15 +000045" --rsource Match/Save the source address of each packet in the recent list table (default).\n"
46" --rdest Match/Save the destination address of each packet in the recent list table.\n"
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020047"xt_recent by: Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n");
Stephen Frost93c7e5a2001-11-08 22:35:03 +000048}
Jan Engelhardtddac6c52008-09-01 14:22:19 +020049
Jan Engelhardt59d16402007-10-04 16:28:39 +000050static void recent_init(struct xt_entry_match *match)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000051{
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020052 struct xt_recent_mtinfo *info = (void *)(match)->data;
Stephen Frost7fdbc952002-06-21 17:26:33 +000053
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020054 strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
55 /* even though XT_RECENT_NAME_LEN is currently defined as 200,
Karsten Desler073df8f2004-01-31 15:33:55 +000056 * better be safe, than sorry */
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020057 info->name[XT_RECENT_NAME_LEN-1] = '\0';
58 info->side = XT_RECENT_SOURCE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000059}
60
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020061#define RECENT_CMDS \
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020062 (XT_RECENT_SET | XT_RECENT_CHECK | \
63 XT_RECENT_UPDATE | XT_RECENT_REMOVE)
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020064
Jan Engelhardt59d16402007-10-04 16:28:39 +000065static int recent_parse(int c, char **argv, int invert, unsigned int *flags,
66 const void *entry, struct xt_entry_match **match)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000067{
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020068 struct xt_recent_mtinfo *info = (void *)(*match)->data;
69
Stephen Frost93c7e5a2001-11-08 22:35:03 +000070 switch (c) {
71 case 201:
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020072 if (*flags & RECENT_CMDS)
73 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +000074 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +000075 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +000076 check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020077 info->check_set |= XT_RECENT_SET;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000078 if (invert) info->invert = 1;
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020079 *flags |= XT_RECENT_SET;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000080 break;
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020081
Stephen Frost93c7e5a2001-11-08 22:35:03 +000082 case 202:
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020083 if (*flags & RECENT_CMDS)
84 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +000085 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +000086 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +000087 check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020088 info->check_set |= XT_RECENT_CHECK;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000089 if(invert) info->invert = 1;
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020090 *flags |= XT_RECENT_CHECK;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000091 break;
92
93 case 203:
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020094 if (*flags & RECENT_CMDS)
95 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +000096 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +000097 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +000098 check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +020099 info->check_set |= XT_RECENT_UPDATE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000100 if (invert) info->invert = 1;
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200101 *flags |= XT_RECENT_UPDATE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000102 break;
103
104 case 206:
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200105 if (*flags & RECENT_CMDS)
106 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000107 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000108 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000109 check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200110 info->check_set |= XT_RECENT_REMOVE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000111 if (invert) info->invert = 1;
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200112 *flags |= XT_RECENT_REMOVE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000113 break;
114
115 case 204:
116 info->seconds = atoi(optarg);
117 break;
118
119 case 205:
120 info->hit_count = atoi(optarg);
121 break;
122
Stephen Frost4fce44c2002-02-04 11:58:22 +0000123 case 207:
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200124 info->check_set |= XT_RECENT_TTL;
125 *flags |= XT_RECENT_TTL;
Stephen Frost4fce44c2002-02-04 11:58:22 +0000126 break;
127
128 case 208:
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200129 strncpy(info->name,optarg, XT_RECENT_NAME_LEN);
130 info->name[XT_RECENT_NAME_LEN-1] = '\0';
Stephen Frost4fce44c2002-02-04 11:58:22 +0000131 break;
132
Stephen Frost7fdbc952002-06-21 17:26:33 +0000133 case 209:
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200134 info->side = XT_RECENT_SOURCE;
Stephen Frost7fdbc952002-06-21 17:26:33 +0000135 break;
136
137 case 210:
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200138 info->side = XT_RECENT_DEST;
Stephen Frost7fdbc952002-06-21 17:26:33 +0000139 break;
140
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000141 default:
142 return 0;
143 }
Stephen Frost4fce44c2002-02-04 11:58:22 +0000144
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000145 return 1;
146}
147
Jan Engelhardt59d16402007-10-04 16:28:39 +0000148static void recent_check(unsigned int flags)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000149{
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200150 if (!(flags & RECENT_CMDS))
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000151 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000152 "recent: you must specify one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000153 "`--update' or `--remove'");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200154 if ((flags & XT_RECENT_TTL) &&
155 (flags & (XT_RECENT_SET | XT_RECENT_REMOVE)))
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200156 exit_error(PARAMETER_PROBLEM,
157 "recent: --rttl may only be used with --rcheck or "
158 "--update");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000159}
160
Jan Engelhardt59d16402007-10-04 16:28:39 +0000161static void recent_print(const void *ip, const struct xt_entry_match *match,
162 int numeric)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000163{
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200164 const struct xt_recent_mtinfo *info = (const void *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000165
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000166 if (info->invert)
167 fputc('!', stdout);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000168
169 printf("recent: ");
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200170 if (info->check_set & XT_RECENT_SET)
171 printf("SET ");
172 if (info->check_set & XT_RECENT_CHECK)
173 printf("CHECK ");
174 if (info->check_set & XT_RECENT_UPDATE)
175 printf("UPDATE ");
176 if (info->check_set & XT_RECENT_REMOVE)
177 printf("REMOVE ");
Stephen Frost4fce44c2002-02-04 11:58:22 +0000178 if(info->seconds) printf("seconds: %d ",info->seconds);
179 if(info->hit_count) printf("hit_count: %d ",info->hit_count);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200180 if (info->check_set & XT_RECENT_TTL)
181 printf("TTL-Match ");
Stephen Frost7fdbc952002-06-21 17:26:33 +0000182 if(info->name) printf("name: %s ",info->name);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200183 if (info->side == XT_RECENT_SOURCE)
184 printf("side: source ");
185 if (info->side == XT_RECENT_DEST)
186 printf("side: dest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000187}
188
Jan Engelhardt59d16402007-10-04 16:28:39 +0000189static void recent_save(const void *ip, const struct xt_entry_match *match)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000190{
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200191 const struct xt_recent_mtinfo *info = (const void *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000192
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000193 if (info->invert)
194 printf("! ");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000195
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200196 if (info->check_set & XT_RECENT_SET)
197 printf("--set ");
198 if (info->check_set & XT_RECENT_CHECK)
199 printf("--rcheck ");
200 if (info->check_set & XT_RECENT_UPDATE)
201 printf("--update ");
202 if (info->check_set & XT_RECENT_REMOVE)
203 printf("--remove ");
Stephen Frostd5903952003-03-03 07:24:27 +0000204 if(info->seconds) printf("--seconds %d ",info->seconds);
205 if(info->hit_count) printf("--hitcount %d ",info->hit_count);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200206 if (info->check_set & XT_RECENT_TTL)
207 printf("--rttl ");
Stephen Frostd5903952003-03-03 07:24:27 +0000208 if(info->name) printf("--name %s ",info->name);
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200209 if (info->side == XT_RECENT_SOURCE)
210 printf("--rsource ");
211 if (info->side == XT_RECENT_DEST)
212 printf("--rdest ");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000213}
214
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200215static struct xtables_match recent_mt_reg = {
Stephen Frost27e1fa82003-04-14 13:33:15 +0000216 .name = "recent",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200217 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100218 .family = NFPROTO_IPV4,
Jan Engelhardtaf1660f2008-10-22 18:53:39 +0200219 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
220 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
Jan Engelhardt59d16402007-10-04 16:28:39 +0000221 .help = recent_help,
222 .init = recent_init,
223 .parse = recent_parse,
224 .final_check = recent_check,
225 .print = recent_print,
226 .save = recent_save,
227 .extra_opts = recent_opts,
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000228};
229
Jan Engelhardtc7f0e942008-10-22 18:53:57 +0200230static struct xtables_match recent_mt6_reg = {
231 .version = XTABLES_VERSION,
232 .name = "recent",
233 .revision = 0,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100234 .family = NFPROTO_IPV6,
Jan Engelhardtc7f0e942008-10-22 18:53:57 +0200235 .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
236 .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
237 .help = recent_help,
238 .init = recent_init,
239 .parse = recent_parse,
240 .final_check = recent_check,
241 .print = recent_print,
242 .save = recent_save,
243 .extra_opts = recent_opts,
244};
245
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000246void _init(void)
247{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200248 xtables_register_match(&recent_mt_reg);
Jan Engelhardtc7f0e942008-10-22 18:53:57 +0200249 xtables_register_match(&recent_mt6_reg);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000250}