blob: aa32aa0750e8034bc44e73784224aa6ec7cefa7f [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);
Stephen Frost7fdbc952002-06-21 17:26:33 +000078 info->side = IPT_RECENT_SOURCE;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000079}
80
81/* Function which parses command options; returns true if it
82 ate an option */
83static int
84parse(int c, char **argv, int invert, unsigned int *flags,
85 const struct ipt_entry *entry,
86 unsigned int *nfcache,
87 struct ipt_entry_match **match)
88{
89 struct ipt_recent_info *info = (struct ipt_recent_info *)(*match)->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +000090 switch (c) {
91 case 201:
92 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +000093 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +000094 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +000095 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +000096 info->check_set |= IPT_RECENT_SET;
97 if (invert) info->invert = 1;
98 *flags = 1;
99 break;
100
101 case 202:
102 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000103 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000104 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000105 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000106 info->check_set |= IPT_RECENT_CHECK;
107 if(invert) info->invert = 1;
108 *flags = 1;
109 break;
110
111 case 203:
112 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000113 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000114 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000115 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000116 info->check_set |= IPT_RECENT_UPDATE;
117 if (invert) info->invert = 1;
118 *flags = 1;
119 break;
120
121 case 206:
122 if (*flags) exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000123 "recent: only one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000124 "`--update' or `--remove' may be set");
Harald Welteb77f1da2002-03-14 11:35:58 +0000125 check_inverse(optarg, &invert, &optind, 0);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000126 info->check_set |= IPT_RECENT_REMOVE;
127 if (invert) info->invert = 1;
128 *flags = 1;
129 break;
130
131 case 204:
132 info->seconds = atoi(optarg);
133 break;
134
135 case 205:
136 info->hit_count = atoi(optarg);
137 break;
138
Stephen Frost4fce44c2002-02-04 11:58:22 +0000139 case 207:
140 info->check_set |= IPT_RECENT_TTL;
141 break;
142
143 case 208:
Stephen Frostd5903952003-03-03 07:24:27 +0000144 strncpy(info->name,optarg,IPT_RECENT_NAME_LEN);
Stephen Frost4fce44c2002-02-04 11:58:22 +0000145 break;
146
Stephen Frost7fdbc952002-06-21 17:26:33 +0000147 case 209:
148 info->side = IPT_RECENT_SOURCE;
149 break;
150
151 case 210:
152 info->side = IPT_RECENT_DEST;
153 break;
154
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000155 default:
156 return 0;
157 }
Stephen Frost4fce44c2002-02-04 11:58:22 +0000158
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000159 return 1;
160}
161
162/* Final check; must have specified a specific option. */
163static void
164final_check(unsigned int flags)
165{
Stephen Frost7fdbc952002-06-21 17:26:33 +0000166
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000167 if (!flags)
168 exit_error(PARAMETER_PROBLEM,
Stephen Frostd5903952003-03-03 07:24:27 +0000169 "recent: you must specify one of `--set', `--rcheck' "
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000170 "`--update' or `--remove'");
171}
172
173/* Prints out the matchinfo. */
174static void
175print(const struct ipt_ip *ip,
176 const struct ipt_entry_match *match,
177 int numeric)
178{
179 struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
180
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000181 if (info->invert)
182 fputc('!', stdout);
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000183
184 printf("recent: ");
185 if(info->check_set & IPT_RECENT_SET) printf("SET ");
186 if(info->check_set & IPT_RECENT_CHECK) printf("CHECK ");
187 if(info->check_set & IPT_RECENT_UPDATE) printf("UPDATE ");
188 if(info->check_set & IPT_RECENT_REMOVE) printf("REMOVE ");
Stephen Frost4fce44c2002-02-04 11:58:22 +0000189 if(info->seconds) printf("seconds: %d ",info->seconds);
190 if(info->hit_count) printf("hit_count: %d ",info->hit_count);
191 if(info->check_set & IPT_RECENT_TTL) printf("TTL-Match ");
Stephen Frost7fdbc952002-06-21 17:26:33 +0000192 if(info->name) printf("name: %s ",info->name);
193 if(info->side == IPT_RECENT_SOURCE) printf("side: source ");
194 if(info->side == IPT_RECENT_DEST) printf("side: dest");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000195}
196
197/* Saves the union ipt_matchinfo in parsable form to stdout. */
198static void
199save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
200{
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000201 struct ipt_recent_info *info = (struct ipt_recent_info *)match->data;
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000202
Sven Strickroth0c1b7762003-06-01 10:11:43 +0000203 if (info->invert)
204 printf("! ");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000205
Stephen Frostd5903952003-03-03 07:24:27 +0000206 if(info->check_set & IPT_RECENT_SET) printf("--set ");
207 if(info->check_set & IPT_RECENT_CHECK) printf("--rcheck ");
208 if(info->check_set & IPT_RECENT_UPDATE) printf("--update ");
209 if(info->check_set & IPT_RECENT_REMOVE) printf("--remove ");
210 if(info->seconds) printf("--seconds %d ",info->seconds);
211 if(info->hit_count) printf("--hitcount %d ",info->hit_count);
Stephen Frost27e1fa82003-04-14 13:33:15 +0000212 if(info->check_set & IPT_RECENT_TTL) printf("--rttl ");
Stephen Frostd5903952003-03-03 07:24:27 +0000213 if(info->name) printf("--name %s ",info->name);
214 if(info->side == IPT_RECENT_SOURCE) printf("--rsource ");
215 if(info->side == IPT_RECENT_DEST) printf("--rdest ");
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000216}
217
Stephen Frost27e1fa82003-04-14 13:33:15 +0000218/* Structure for iptables to use to communicate with module */
219static struct iptables_match recent = {
220 .next = NULL,
221 .name = "recent",
222 .version = IPTABLES_VERSION,
223 .size = IPT_ALIGN(sizeof(struct ipt_recent_info)),
224 .userspacesize = IPT_ALIGN(sizeof(struct ipt_recent_info)),
225 .help = &help,
226 .init = &init,
227 .parse = &parse,
228 .final_check = &final_check,
229 .print = &print,
230 .save = &save,
231 .extra_opts = opts
Stephen Frost93c7e5a2001-11-08 22:35:03 +0000232};
233
234void _init(void)
235{
236 register_match(&recent);
237}