blob: 09ea92202a2348ed50e2a52c992f06a989da3d1c [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
Harald Welte122e7c02003-03-30 20:26:42 +000011/* need thos two to not fail compilation with old kernel, new userspace */
12#ifndef RECENT_NAME
13#define RECENT_NAME "ipt_recent"
14#endif /* RECENT_NAME */
15#ifndef RECENT_VER
16#define RECENT_VER "unknown"
17#endif /* RECENT_VER */
18#ifndef IPT_RECENT_NAME_LEN
19#define IPT_RECENT_NAME_LEN 200
20#endif /* IPT_RECENT_NAME_LEN */
21
Stephen Frost93c7e5a2001-11-08 22:35:03 +000022/* Function which prints out usage message. */
23static void
24help(void)
25{
26 printf(
27"recent v%s options:\n"
28"[!] --set Add source address to list, always matches.\n"
29"[!] --rcheck Match if source address in list.\n"
30"[!] --update Match if source address in list, also update last-seen time.\n"
31"[!] --remove Match if source address in list, also removes that address from list.\n"
32" --seconds seconds For check and update commands above.\n"
33" Specifies that the match will only occur if source address last seen within\n"
34" the last 'seconds' seconds.\n"
35" --hitcount hits For check and update commands above.\n"
36" Specifies that the match will only occur if source address seen hits times.\n"
Fabrice MARIEae31bb62002-06-14 07:38:16 +000037" May be used in conjunction with the seconds option.\n"
Stephen Frost4fce44c2002-02-04 11:58:22 +000038" --rttl For check and update commands above.\n"
39" Specifies that the match will only occur if the source address and the TTL\n"
40" match between this packet and the one which was set.\n"
41" Useful if you have problems with people spoofing their source address in order\n"
42" to DoS you via this module.\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +000043" --name name Name of the recent list to be used. DEFAULT used if none given.\n"
44" --rsource Save the source address of each packet in the recent list table (default).\n"
45" --rdest Save the destination address of each packet in the recent list table.\n"
Stephen Frostd5903952003-03-03 07:24:27 +000046RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n"
Stephen Frost7fdbc952002-06-21 17:26:33 +000047,
Harald Welte80fe35d2002-05-29 13:08:15 +000048IPTABLES_VERSION);
Stephen Frost93c7e5a2001-11-08 22:35:03 +000049
50}
51
52static struct option opts[] = {
53 { "set", 0, 0, 201 },
54 { "rcheck", 0, 0, 202 },
55 { "update", 0, 0, 203 },
56 { "seconds", 1, 0, 204 },
57 { "hitcount", 1, 0, 205 },
58 { "remove",0, 0, 206 },
Stephen Frost4fce44c2002-02-04 11:58:22 +000059 { "rttl",0, 0, 207},
60 { "name", 1, 0, 208},
Stephen Frost7fdbc952002-06-21 17:26:33 +000061 { "rsource", 0, 0, 209},
62 { "rdest", 0, 0, 210},
Stephen Frost93c7e5a2001-11-08 22:35:03 +000063 {0}
64};
65
66/* Initialize the match. */
67static void
Stephen Frost7fdbc952002-06-21 17:26:33 +000068init(struct ipt_entry_match *match, unsigned int *nfcache)
Stephen Frost93c7e5a2001-11-08 22:35:03 +000069{
Stephen Frost7fdbc952002-06-21 17:26:33 +000070 struct ipt_recent_info *info = (struct ipt_recent_info *)(match)->data;
71
Stephen Frost93c7e5a2001-11-08 22:35:03 +000072 *nfcache |= NFC_UNKNOWN;
Stephen Frost7fdbc952002-06-21 17:26:33 +000073
Stephen Frostd5903952003-03-03 07:24:27 +000074 strncpy(info->name,"DEFAULT",IPT_RECENT_NAME_LEN);
Stephen Frost7fdbc952002-06-21 17:26:33 +000075 info->side = IPT_RECENT_SOURCE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000076}
77
78/* Function which parses command options; returns true if it
79 ate an option */
80static int
81parse(int c, char **argv, int invert, unsigned int *flags,
82 const struct ipt_entry *entry,
83 unsigned int *nfcache,
84 struct ipt_entry_match **match)
85{
86 struct ipt_recent_info *info = (struct ipt_recent_info *)(*match)->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000087 switch (c) {
88 case 201:
89 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +000090 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +000091 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +000092 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +000093 info->check_set |= IPT_RECENT_SET;
94 if (invert) info->invert = 1;
95 *flags = 1;
96 break;
97
98 case 202:
99 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000100 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000101 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000102 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000103 info->check_set |= IPT_RECENT_CHECK;
104 if(invert) info->invert = 1;
105 *flags = 1;
106 break;
107
108 case 203:
109 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000110 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000111 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000112 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000113 info->check_set |= IPT_RECENT_UPDATE;
114 if (invert) info->invert = 1;
115 *flags = 1;
116 break;
117
118 case 206:
119 if (*flags) 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;
125 *flags = 1;
126 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;
138 break;
139
140 case 208:
Stephen Frostd5903952003-03-03 07:24:27 +0000141 strncpy(info->name,optarg,IPT_RECENT_NAME_LEN);
Stephen Frost4fce44c2002-02-04 11:58:22 +0000142 break;
143
Stephen Frost7fdbc952002-06-21 17:26:33 +0000144 case 209:
145 info->side = IPT_RECENT_SOURCE;
146 break;
147
148 case 210:
149 info->side = IPT_RECENT_DEST;
150 break;
151
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000152 default:
153 return 0;
154 }
Stephen Frost4fce44c2002-02-04 11:58:22 +0000155
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000156 return 1;
157}
158
159/* Final check; must have specified a specific option. */
160static void
161final_check(unsigned int flags)
162{
Stephen Frost7fdbc952002-06-21 17:26:33 +0000163
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000164 if (!flags)
165 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000166 "recent: you must specify one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000167 "`--update' or `--remove'");
168}
169
170/* Prints out the matchinfo. */
171static void
172print(const struct ipt_ip *ip,
173 const struct ipt_entry_match *match,
174 int numeric)
175{
176 struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
177
178 if (info->invert) fputc('!', stdout);
179
180 printf("recent: ");
181 if(info->check_set & IPT_RECENT_SET) printf("SET ");
182 if(info->check_set & IPT_RECENT_CHECK) printf("CHECK ");
183 if(info->check_set & IPT_RECENT_UPDATE) printf("UPDATE ");
184 if(info->check_set & IPT_RECENT_REMOVE) printf("REMOVE ");
Stephen Frost4fce44c2002-02-04 11:58:22 +0000185 if(info->seconds) printf("seconds: %d ",info->seconds);
186 if(info->hit_count) printf("hit_count: %d ",info->hit_count);
187 if(info->check_set & IPT_RECENT_TTL) printf("TTL-Match ");
Stephen Frost7fdbc952002-06-21 17:26:33 +0000188 if(info->name) printf("name: %s ",info->name);
189 if(info->side == IPT_RECENT_SOURCE) printf("side: source ");
190 if(info->side == IPT_RECENT_DEST) printf("side: dest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000191}
192
193/* Saves the union ipt_matchinfo in parsable form to stdout. */
194static void
195save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
196{
197 struct ipt_recent_info *info = (struct ipt_recent_info *)match;
198
199 if (info->invert) fputc('!', stdout);
200
201 printf("recent: ");
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);
208 if(info->check_set & IPT_RECENT_TTL) printf("-rttl ");
209 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
214static
215struct iptables_match recent
216= { NULL,
217 "recent",
Harald Welte80fe35d2002-05-29 13:08:15 +0000218 IPTABLES_VERSION,
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000219 IPT_ALIGN(sizeof(struct ipt_recent_info)),
220 IPT_ALIGN(sizeof(struct ipt_recent_info)),
221 &help,
222 &init,
223 &parse,
224 &final_check,
225 &print,
226 &save,
227 opts
228};
229
230void _init(void)
231{
232 register_match(&recent);
233}