blob: 94f246a69c25cc989032ecb74068887f7f2e0f1a [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
8#include <iptables.h>
9#include <linux/netfilter_ipv4/ipt_recent.h>
10
Stephen Frost27e1fa82003-04-14 13:33:15 +000011/* Need these in order to not fail when compiling against an older kernel. */
Harald Welte122e7c02003-03-30 20:26:42 +000012#ifndef RECENT_NAME
13#define RECENT_NAME "ipt_recent"
14#endif /* RECENT_NAME */
Stephen Frost27e1fa82003-04-14 13:33:15 +000015
Harald Welte122e7c02003-03-30 20:26:42 +000016#ifndef RECENT_VER
17#define RECENT_VER "unknown"
18#endif /* RECENT_VER */
Stephen Frost27e1fa82003-04-14 13:33:15 +000019
Harald Welte122e7c02003-03-30 20:26:42 +000020#ifndef IPT_RECENT_NAME_LEN
Stephen Frost27e1fa82003-04-14 13:33:15 +000021#define IPT_RECENT_NAME_LEN 200
Harald Welte122e7c02003-03-30 20:26:42 +000022#endif /* IPT_RECENT_NAME_LEN */
23
Jan Engelhardt59d16402007-10-04 16:28:39 +000024static const struct option recent_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000025 { .name = "set", .has_arg = 0, .val = 201 },
26 { .name = "rcheck", .has_arg = 0, .val = 202 },
27 { .name = "update", .has_arg = 0, .val = 203 },
28 { .name = "seconds", .has_arg = 1, .val = 204 },
29 { .name = "hitcount", .has_arg = 1, .val = 205 },
30 { .name = "remove", .has_arg = 0, .val = 206 },
31 { .name = "rttl", .has_arg = 0, .val = 207 },
32 { .name = "name", .has_arg = 1, .val = 208 },
33 { .name = "rsource", .has_arg = 0, .val = 209 },
34 { .name = "rdest", .has_arg = 0, .val = 210 },
Max Kellermann9ee386a2008-01-29 13:48:05 +000035 { .name = NULL }
Stephen Frost27e1fa82003-04-14 13:33:15 +000036};
37
Jan Engelhardt59d16402007-10-04 16:28:39 +000038static void recent_help(void)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000039{
40 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020041"recent match options:\n"
Stephen Frost93c7e5a2001-11-08 22:35:03 +000042"[!] --set Add source address to list, always matches.\n"
43"[!] --rcheck Match if source address in list.\n"
44"[!] --update Match if source address in list, also update last-seen time.\n"
45"[!] --remove Match if source address in list, also removes that address from list.\n"
46" --seconds seconds For check and update commands above.\n"
47" Specifies that the match will only occur if source address last seen within\n"
48" the last 'seconds' seconds.\n"
49" --hitcount hits For check and update commands above.\n"
50" Specifies that the match will only occur if source address seen hits times.\n"
Fabrice MARIEae31bb62002-06-14 07:38:16 +000051" May be used in conjunction with the seconds option.\n"
Stephen Frost4fce44c2002-02-04 11:58:22 +000052" --rttl For check and update commands above.\n"
53" Specifies that the match will only occur if the source address and the TTL\n"
54" match between this packet and the one which was set.\n"
55" Useful if you have problems with people spoofing their source address in order\n"
56" to DoS you via this module.\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +000057" --name name Name of the recent list to be used. DEFAULT used if none given.\n"
Stephen Frost27e1fa82003-04-14 13:33:15 +000058" --rsource Match/Save the source address of each packet in the recent list table (default).\n"
59" --rdest Match/Save the destination address of each packet in the recent list table.\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020060RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n");
Stephen Frost93c7e5a2001-11-08 22:35:03 +000061}
Jan Engelhardtddac6c52008-09-01 14:22:19 +020062
Jan Engelhardt59d16402007-10-04 16:28:39 +000063static void recent_init(struct xt_entry_match *match)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000064{
Stephen Frost7fdbc952002-06-21 17:26:33 +000065 struct ipt_recent_info *info = (struct ipt_recent_info *)(match)->data;
66
Stephen Frost7fdbc952002-06-21 17:26:33 +000067
Stephen Frostd5903952003-03-03 07:24:27 +000068 strncpy(info->name,"DEFAULT",IPT_RECENT_NAME_LEN);
Karsten Desler073df8f2004-01-31 15:33:55 +000069 /* eventhough IPT_RECENT_NAME_LEN is currently defined as 200,
70 * better be safe, than sorry */
71 info->name[IPT_RECENT_NAME_LEN-1] = '\0';
Stephen Frost7fdbc952002-06-21 17:26:33 +000072 info->side = IPT_RECENT_SOURCE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000073}
74
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020075#define RECENT_CMDS \
76 (IPT_RECENT_SET | IPT_RECENT_CHECK | \
77 IPT_RECENT_UPDATE | IPT_RECENT_REMOVE)
78
Jan Engelhardt59d16402007-10-04 16:28:39 +000079static int recent_parse(int c, char **argv, int invert, unsigned int *flags,
80 const void *entry, struct xt_entry_match **match)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000081{
82 struct ipt_recent_info *info = (struct ipt_recent_info *)(*match)->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000083 switch (c) {
84 case 201:
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020085 if (*flags & RECENT_CMDS)
86 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +000087 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +000088 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +000089 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +000090 info->check_set |= IPT_RECENT_SET;
91 if (invert) info->invert = 1;
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020092 *flags |= IPT_RECENT_SET;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000093 break;
94
95 case 202:
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +020096 if (*flags & RECENT_CMDS)
97 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +000098 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +000099 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000100 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000101 info->check_set |= IPT_RECENT_CHECK;
102 if(invert) info->invert = 1;
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200103 *flags |= IPT_RECENT_CHECK;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000104 break;
105
106 case 203:
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200107 if (*flags & RECENT_CMDS)
108 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000109 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000110 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000111 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000112 info->check_set |= IPT_RECENT_UPDATE;
113 if (invert) info->invert = 1;
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200114 *flags |= IPT_RECENT_UPDATE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000115 break;
116
117 case 206:
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200118 if (*flags & RECENT_CMDS)
119 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000120 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000121 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000122 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000123 info->check_set |= IPT_RECENT_REMOVE;
124 if (invert) info->invert = 1;
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200125 *flags |= IPT_RECENT_REMOVE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000126 break;
127
128 case 204:
129 info->seconds = atoi(optarg);
130 break;
131
132 case 205:
133 info->hit_count = atoi(optarg);
134 break;
135
Stephen Frost4fce44c2002-02-04 11:58:22 +0000136 case 207:
137 info->check_set |= IPT_RECENT_TTL;
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200138 *flags |= IPT_RECENT_TTL;
Stephen Frost4fce44c2002-02-04 11:58:22 +0000139 break;
140
141 case 208:
Stephen Frostd5903952003-03-03 07:24:27 +0000142 strncpy(info->name,optarg,IPT_RECENT_NAME_LEN);
Karsten Desler073df8f2004-01-31 15:33:55 +0000143 info->name[IPT_RECENT_NAME_LEN-1] = '\0';
Stephen Frost4fce44c2002-02-04 11:58:22 +0000144 break;
145
Stephen Frost7fdbc952002-06-21 17:26:33 +0000146 case 209:
147 info->side = IPT_RECENT_SOURCE;
148 break;
149
150 case 210:
151 info->side = IPT_RECENT_DEST;
152 break;
153
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000154 default:
155 return 0;
156 }
Stephen Frost4fce44c2002-02-04 11:58:22 +0000157
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000158 return 1;
159}
160
Jan Engelhardt59d16402007-10-04 16:28:39 +0000161static void recent_check(unsigned int flags)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000162{
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200163 if (!(flags & RECENT_CMDS))
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000164 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000165 "recent: you must specify one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000166 "`--update' or `--remove'");
Jan Engelhardt3c5d15c2008-08-04 12:52:27 +0200167 if ((flags & IPT_RECENT_TTL) &&
168 (flags & (IPT_RECENT_SET | IPT_RECENT_REMOVE | IPT_RECENT_UPDATE)))
169 exit_error(PARAMETER_PROBLEM,
170 "recent: --rttl may only be used with --rcheck or "
171 "--update");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000172}
173
Jan Engelhardt59d16402007-10-04 16:28:39 +0000174static void recent_print(const void *ip, const struct xt_entry_match *match,
175 int numeric)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000176{
177 struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
178
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000179 if (info->invert)
180 fputc('!', stdout);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000181
182 printf("recent: ");
183 if(info->check_set & IPT_RECENT_SET) printf("SET ");
184 if(info->check_set & IPT_RECENT_CHECK) printf("CHECK ");
185 if(info->check_set & IPT_RECENT_UPDATE) printf("UPDATE ");
186 if(info->check_set & IPT_RECENT_REMOVE) printf("REMOVE ");
Stephen Frost4fce44c2002-02-04 11:58:22 +0000187 if(info->seconds) printf("seconds: %d ",info->seconds);
188 if(info->hit_count) printf("hit_count: %d ",info->hit_count);
189 if(info->check_set & IPT_RECENT_TTL) printf("TTL-Match ");
Stephen Frost7fdbc952002-06-21 17:26:33 +0000190 if(info->name) printf("name: %s ",info->name);
191 if(info->side == IPT_RECENT_SOURCE) printf("side: source ");
192 if(info->side == IPT_RECENT_DEST) printf("side: dest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000193}
194
Jan Engelhardt59d16402007-10-04 16:28:39 +0000195static void recent_save(const void *ip, const struct xt_entry_match *match)
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000196{
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000197 struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000198
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000199 if (info->invert)
200 printf("! ");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000201
Stephen Frostd5903952003-03-03 07:24:27 +0000202 if(info->check_set & IPT_RECENT_SET) printf("--set ");
203 if(info->check_set & IPT_RECENT_CHECK) printf("--rcheck ");
204 if(info->check_set & IPT_RECENT_UPDATE) printf("--update ");
205 if(info->check_set & IPT_RECENT_REMOVE) printf("--remove ");
206 if(info->seconds) printf("--seconds %d ",info->seconds);
207 if(info->hit_count) printf("--hitcount %d ",info->hit_count);
Stephen Frost27e1fa82003-04-14 13:33:15 +0000208 if(info->check_set & IPT_RECENT_TTL) printf("--rttl ");
Stephen Frostd5903952003-03-03 07:24:27 +0000209 if(info->name) printf("--name %s ",info->name);
210 if(info->side == IPT_RECENT_SOURCE) printf("--rsource ");
211 if(info->side == IPT_RECENT_DEST) printf("--rdest ");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000212}
213
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200214static struct xtables_match recent_mt_reg = {
Stephen Frost27e1fa82003-04-14 13:33:15 +0000215 .name = "recent",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200216 .version = XTABLES_VERSION,
217 .family = PF_INET,
218 .size = XT_ALIGN(sizeof(struct ipt_recent_info)),
219 .userspacesize = XT_ALIGN(sizeof(struct ipt_recent_info)),
Jan Engelhardt59d16402007-10-04 16:28:39 +0000220 .help = recent_help,
221 .init = recent_init,
222 .parse = recent_parse,
223 .final_check = recent_check,
224 .print = recent_print,
225 .save = recent_save,
226 .extra_opts = recent_opts,
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000227};
228
229void _init(void)
230{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200231 xtables_register_match(&recent_mt_reg);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000232}