libxt_recent.c revision 6ce22ff936611347f1154c8546c93f4781be199d
1/* 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 <xtables.h>
9#include <linux/netfilter/xt_recent.h>
10
11static const struct option recent_opts[] = {
12	{ .name = "set",      .has_arg = 0, .val = 201 },
13	{ .name = "rcheck",   .has_arg = 0, .val = 202 },
14	{ .name = "update",   .has_arg = 0, .val = 203 },
15	{ .name = "seconds",  .has_arg = 1, .val = 204 },
16	{ .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 },
22	{ .name = NULL }
23};
24
25static void recent_help(void)
26{
27	printf(
28"recent match options:\n"
29"[!] --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"
38"                                May be used in conjunction with the seconds option.\n"
39"    --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"
44"    --name name                 Name of the recent list to be used.  DEFAULT used if none given.\n"
45"    --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"
47"xt_recent by: Stephen Frost <sfrost@snowman.net>.  http://snowman.net/projects/ipt_recent/\n");
48}
49
50static void recent_init(struct xt_entry_match *match)
51{
52	struct xt_recent_mtinfo *info = (void *)(match)->data;
53
54	strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
55	/* even though XT_RECENT_NAME_LEN is currently defined as 200,
56	 * better be safe, than sorry */
57	info->name[XT_RECENT_NAME_LEN-1] = '\0';
58	info->side = XT_RECENT_SOURCE;
59}
60
61#define RECENT_CMDS \
62	(XT_RECENT_SET | XT_RECENT_CHECK | \
63	XT_RECENT_UPDATE | XT_RECENT_REMOVE)
64
65static int recent_parse(int c, char **argv, int invert, unsigned int *flags,
66                        const void *entry, struct xt_entry_match **match)
67{
68	struct xt_recent_mtinfo *info = (void *)(*match)->data;
69
70	switch (c) {
71		case 201:
72			if (*flags & RECENT_CMDS)
73				xtables_error(PARAMETER_PROBLEM,
74					"recent: only one of `--set', `--rcheck' "
75					"`--update' or `--remove' may be set");
76			xtables_check_inverse(optarg, &invert, &optind, 0, argv);
77			info->check_set |= XT_RECENT_SET;
78			if (invert) info->invert = 1;
79			*flags |= XT_RECENT_SET;
80			break;
81
82		case 202:
83			if (*flags & RECENT_CMDS)
84				xtables_error(PARAMETER_PROBLEM,
85					"recent: only one of `--set', `--rcheck' "
86					"`--update' or `--remove' may be set");
87			xtables_check_inverse(optarg, &invert, &optind, 0, argv);
88			info->check_set |= XT_RECENT_CHECK;
89			if(invert) info->invert = 1;
90			*flags |= XT_RECENT_CHECK;
91			break;
92
93		case 203:
94			if (*flags & RECENT_CMDS)
95				xtables_error(PARAMETER_PROBLEM,
96					"recent: only one of `--set', `--rcheck' "
97					"`--update' or `--remove' may be set");
98			xtables_check_inverse(optarg, &invert, &optind, 0, argv);
99			info->check_set |= XT_RECENT_UPDATE;
100			if (invert) info->invert = 1;
101			*flags |= XT_RECENT_UPDATE;
102			break;
103
104		case 204:
105			info->seconds = atoi(optarg);
106			break;
107
108		case 205:
109			info->hit_count = atoi(optarg);
110			break;
111
112		case 206:
113			if (*flags & RECENT_CMDS)
114				xtables_error(PARAMETER_PROBLEM,
115					"recent: only one of `--set', `--rcheck' "
116					"`--update' or `--remove' may be set");
117			xtables_check_inverse(optarg, &invert, &optind, 0, argv);
118			info->check_set |= XT_RECENT_REMOVE;
119			if (invert) info->invert = 1;
120			*flags |= XT_RECENT_REMOVE;
121			break;
122
123		case 207:
124			info->check_set |= XT_RECENT_TTL;
125			*flags |= XT_RECENT_TTL;
126			break;
127
128		case 208:
129			strncpy(info->name,optarg, XT_RECENT_NAME_LEN);
130			info->name[XT_RECENT_NAME_LEN-1] = '\0';
131			break;
132
133		case 209:
134			info->side = XT_RECENT_SOURCE;
135			break;
136
137		case 210:
138			info->side = XT_RECENT_DEST;
139			break;
140
141		default:
142			return 0;
143	}
144
145	return 1;
146}
147
148static void recent_check(unsigned int flags)
149{
150	if (!(flags & RECENT_CMDS))
151		xtables_error(PARAMETER_PROBLEM,
152			"recent: you must specify one of `--set', `--rcheck' "
153			"`--update' or `--remove'");
154	if ((flags & XT_RECENT_TTL) &&
155	    (flags & (XT_RECENT_SET | XT_RECENT_REMOVE)))
156		xtables_error(PARAMETER_PROBLEM,
157		           "recent: --rttl may only be used with --rcheck or "
158		           "--update");
159}
160
161static void recent_print(const void *ip, const struct xt_entry_match *match,
162                         int numeric)
163{
164	const struct xt_recent_mtinfo *info = (const void *)match->data;
165
166	if (info->invert)
167		fputc('!', stdout);
168
169	printf("recent: ");
170	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 ");
178	if(info->seconds) printf("seconds: %d ",info->seconds);
179	if(info->hit_count) printf("hit_count: %d ",info->hit_count);
180	if (info->check_set & XT_RECENT_TTL)
181		printf("TTL-Match ");
182	if(info->name) printf("name: %s ",info->name);
183	if (info->side == XT_RECENT_SOURCE)
184		printf("side: source ");
185	if (info->side == XT_RECENT_DEST)
186		printf("side: dest");
187}
188
189static void recent_save(const void *ip, const struct xt_entry_match *match)
190{
191	const struct xt_recent_mtinfo *info = (const void *)match->data;
192
193	if (info->invert)
194		printf("! ");
195
196	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 ");
204	if(info->seconds) printf("--seconds %d ",info->seconds);
205	if(info->hit_count) printf("--hitcount %d ",info->hit_count);
206	if (info->check_set & XT_RECENT_TTL)
207		printf("--rttl ");
208	if(info->name) printf("--name %s ",info->name);
209	if (info->side == XT_RECENT_SOURCE)
210		printf("--rsource ");
211	if (info->side == XT_RECENT_DEST)
212		printf("--rdest ");
213}
214
215static struct xtables_match recent_mt_reg = {
216    .name          = "recent",
217    .version       = XTABLES_VERSION,
218    .family        = NFPROTO_UNSPEC,
219    .size          = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
220    .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
221    .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,
228};
229
230void _init(void)
231{
232	xtables_register_match(&recent_mt_reg);
233}
234