blob: a3942720fd08c9395fcb7eebe7d2d097ef170b24 [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
Stephen Frost27e1fa82003-04-14 13:33:15 +000024/* Options for this module */
25static struct option opts[] = {
26 { .name = "set", .has_arg = 0, .flag = 0, .val = 201 },
27 { .name = "rcheck", .has_arg = 0, .flag = 0, .val = 202 },
28 { .name = "update", .has_arg = 0, .flag = 0, .val = 203 },
29 { .name = "seconds", .has_arg = 1, .flag = 0, .val = 204 },
30 { .name = "hitcount", .has_arg = 1, .flag = 0, .val = 205 },
31 { .name = "remove", .has_arg = 0, .flag = 0, .val = 206 },
32 { .name = "rttl", .has_arg = 0, .flag = 0, .val = 207 },
33 { .name = "name", .has_arg = 1, .flag = 0, .val = 208 },
34 { .name = "rsource", .has_arg = 0, .flag = 0, .val = 209 },
35 { .name = "rdest", .has_arg = 0, .flag = 0, .val = 210 },
36 { .name = 0, .has_arg = 0, .flag = 0, .val = 0 }
37};
38
Stephen Frost93c7e5a2001-11-08 22:35:03 +000039/* Function which prints out usage message. */
40static void
41help(void)
42{
43 printf(
44"recent v%s options:\n"
45"[!] --set Add source address to list, always matches.\n"
46"[!] --rcheck Match if source address in list.\n"
47"[!] --update Match if source address in list, also update last-seen time.\n"
48"[!] --remove Match if source address in list, also removes that address from list.\n"
49" --seconds seconds For check and update commands above.\n"
50" Specifies that the match will only occur if source address last seen within\n"
51" the last 'seconds' seconds.\n"
52" --hitcount hits For check and update commands above.\n"
53" Specifies that the match will only occur if source address seen hits times.\n"
Fabrice MARIEae31bb62002-06-14 07:38:16 +000054" May be used in conjunction with the seconds option.\n"
Stephen Frost4fce44c2002-02-04 11:58:22 +000055" --rttl For check and update commands above.\n"
56" Specifies that the match will only occur if the source address and the TTL\n"
57" match between this packet and the one which was set.\n"
58" Useful if you have problems with people spoofing their source address in order\n"
59" to DoS you via this module.\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +000060" --name name Name of the recent list to be used. DEFAULT used if none given.\n"
Stephen Frost27e1fa82003-04-14 13:33:15 +000061" --rsource Match/Save the source address of each packet in the recent list table (default).\n"
62" --rdest Match/Save the destination address of each packet in the recent list table.\n"
Stephen Frostd5903952003-03-03 07:24:27 +000063RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +000064,
Harald Welte80fe35d2002-05-29 13:08:15 +000065IPTABLES_VERSION);
Stephen Frost93c7e5a2001-11-08 22:35:03 +000066
67}
68
Stephen Frost93c7e5a2001-11-08 22:35:03 +000069/* Initialize the match. */
70static void
Stephen Frost7fdbc952002-06-21 17:26:33 +000071init(struct ipt_entry_match *match, unsigned int *nfcache)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000072{
Stephen Frost7fdbc952002-06-21 17:26:33 +000073 struct ipt_recent_info *info = (struct ipt_recent_info *)(match)->data;
74
Stephen Frost93c7e5a2001-11-08 22:35:03 +000075 *nfcache |= NFC_UNKNOWN;
Stephen Frost7fdbc952002-06-21 17:26:33 +000076
Stephen Frostd5903952003-03-03 07:24:27 +000077 strncpy(info->name,"DEFAULT",IPT_RECENT_NAME_LEN);
Karsten Desler073df8f2004-01-31 15:33:55 +000078 /* eventhough IPT_RECENT_NAME_LEN is currently defined as 200,
79 * better be safe, than sorry */
80 info->name[IPT_RECENT_NAME_LEN-1] = '\0';
Stephen Frost7fdbc952002-06-21 17:26:33 +000081 info->side = IPT_RECENT_SOURCE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000082}
83
84/* Function which parses command options; returns true if it
85 ate an option */
86static int
87parse(int c, char **argv, int invert, unsigned int *flags,
88 const struct ipt_entry *entry,
89 unsigned int *nfcache,
90 struct ipt_entry_match **match)
91{
92 struct ipt_recent_info *info = (struct ipt_recent_info *)(*match)->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000093 switch (c) {
94 case 201:
95 if (*flags) 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);
Stephen Frost93c7e5a2001-11-08 22:35:03 +000099 info->check_set |= IPT_RECENT_SET;
100 if (invert) info->invert = 1;
101 *flags = 1;
102 break;
103
104 case 202:
105 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000106 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000107 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000108 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000109 info->check_set |= IPT_RECENT_CHECK;
110 if(invert) info->invert = 1;
111 *flags = 1;
112 break;
113
114 case 203:
115 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000116 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000117 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000118 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000119 info->check_set |= IPT_RECENT_UPDATE;
120 if (invert) info->invert = 1;
121 *flags = 1;
122 break;
123
124 case 206:
125 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000126 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000127 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000128 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000129 info->check_set |= IPT_RECENT_REMOVE;
130 if (invert) info->invert = 1;
131 *flags = 1;
132 break;
133
134 case 204:
135 info->seconds = atoi(optarg);
136 break;
137
138 case 205:
139 info->hit_count = atoi(optarg);
140 break;
141
Stephen Frost4fce44c2002-02-04 11:58:22 +0000142 case 207:
143 info->check_set |= IPT_RECENT_TTL;
144 break;
145
146 case 208:
Stephen Frostd5903952003-03-03 07:24:27 +0000147 strncpy(info->name,optarg,IPT_RECENT_NAME_LEN);
Karsten Desler073df8f2004-01-31 15:33:55 +0000148 info->name[IPT_RECENT_NAME_LEN-1] = '\0';
Stephen Frost4fce44c2002-02-04 11:58:22 +0000149 break;
150
Stephen Frost7fdbc952002-06-21 17:26:33 +0000151 case 209:
152 info->side = IPT_RECENT_SOURCE;
153 break;
154
155 case 210:
156 info->side = IPT_RECENT_DEST;
157 break;
158
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000159 default:
160 return 0;
161 }
Stephen Frost4fce44c2002-02-04 11:58:22 +0000162
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000163 return 1;
164}
165
166/* Final check; must have specified a specific option. */
167static void
168final_check(unsigned int flags)
169{
Stephen Frost7fdbc952002-06-21 17:26:33 +0000170
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000171 if (!flags)
172 exit_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
177/* Prints out the matchinfo. */
178static void
179print(const struct ipt_ip *ip,
180 const struct ipt_entry_match *match,
181 int numeric)
182{
183 struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
184
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000185 if (info->invert)
186 fputc('!', stdout);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000187
188 printf("recent: ");
189 if(info->check_set & IPT_RECENT_SET) printf("SET ");
190 if(info->check_set & IPT_RECENT_CHECK) printf("CHECK ");
191 if(info->check_set & IPT_RECENT_UPDATE) printf("UPDATE ");
192 if(info->check_set & IPT_RECENT_REMOVE) printf("REMOVE ");
Stephen Frost4fce44c2002-02-04 11:58:22 +0000193 if(info->seconds) printf("seconds: %d ",info->seconds);
194 if(info->hit_count) printf("hit_count: %d ",info->hit_count);
195 if(info->check_set & IPT_RECENT_TTL) printf("TTL-Match ");
Stephen Frost7fdbc952002-06-21 17:26:33 +0000196 if(info->name) printf("name: %s ",info->name);
197 if(info->side == IPT_RECENT_SOURCE) printf("side: source ");
198 if(info->side == IPT_RECENT_DEST) printf("side: dest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000199}
200
201/* Saves the union ipt_matchinfo in parsable form to stdout. */
202static void
203save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
204{
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000205 struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000206
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000207 if (info->invert)
208 printf("! ");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000209
Stephen Frostd5903952003-03-03 07:24:27 +0000210 if(info->check_set & IPT_RECENT_SET) printf("--set ");
211 if(info->check_set & IPT_RECENT_CHECK) printf("--rcheck ");
212 if(info->check_set & IPT_RECENT_UPDATE) printf("--update ");
213 if(info->check_set & IPT_RECENT_REMOVE) printf("--remove ");
214 if(info->seconds) printf("--seconds %d ",info->seconds);
215 if(info->hit_count) printf("--hitcount %d ",info->hit_count);
Stephen Frost27e1fa82003-04-14 13:33:15 +0000216 if(info->check_set & IPT_RECENT_TTL) printf("--rttl ");
Stephen Frostd5903952003-03-03 07:24:27 +0000217 if(info->name) printf("--name %s ",info->name);
218 if(info->side == IPT_RECENT_SOURCE) printf("--rsource ");
219 if(info->side == IPT_RECENT_DEST) printf("--rdest ");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000220}
221
Stephen Frost27e1fa82003-04-14 13:33:15 +0000222/* Structure for iptables to use to communicate with module */
223static struct iptables_match recent = {
224 .next = NULL,
225 .name = "recent",
226 .version = IPTABLES_VERSION,
227 .size = IPT_ALIGN(sizeof(struct ipt_recent_info)),
228 .userspacesize = IPT_ALIGN(sizeof(struct ipt_recent_info)),
229 .help = &help,
230 .init = &init,
231 .parse = &parse,
232 .final_check = &final_check,
233 .print = &print,
234 .save = &save,
235 .extra_opts = opts
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000236};
237
238void _init(void)
239{
240 register_match(&recent);
241}