libxt_recent.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
1/* Shared library add-on to iptables to add recent matching support. */
2#include <stdbool.h>
3#include <stdio.h>
4#include <netdb.h>
5#include <string.h>
6#include <stdlib.h>
7#include <getopt.h>
8
9#include <xtables.h>
10#include <linux/netfilter/xt_recent.h>
11
12static const struct option recent_opts[] = {
13	{.name = "set",      .has_arg = false, .val = 201},
14	{.name = "rcheck",   .has_arg = false, .val = 202},
15	{.name = "update",   .has_arg = false, .val = 203},
16	{.name = "seconds",  .has_arg = true,  .val = 204},
17	{.name = "hitcount", .has_arg = true,  .val = 205},
18	{.name = "remove",   .has_arg = false, .val = 206},
19	{.name = "rttl",     .has_arg = false, .val = 207},
20	{.name = "name",     .has_arg = true,  .val = 208},
21	{.name = "rsource",  .has_arg = false, .val = 209},
22	{.name = "rdest",    .has_arg = false, .val = 210},
23	XT_GETOPT_TABLEEND,
24};
25
26static void recent_help(void)
27{
28	printf(
29"recent match options:\n"
30"[!] --set                       Add source address to list, always matches.\n"
31"[!] --rcheck                    Match if source address in list.\n"
32"[!] --update                    Match if source address in list, also update last-seen time.\n"
33"[!] --remove                    Match if source address in list, also removes that address from list.\n"
34"    --seconds seconds           For check and update commands above.\n"
35"                                Specifies that the match will only occur if source address last seen within\n"
36"                                the last 'seconds' seconds.\n"
37"    --hitcount hits             For check and update commands above.\n"
38"                                Specifies that the match will only occur if source address seen hits times.\n"
39"                                May be used in conjunction with the seconds option.\n"
40"    --rttl                      For check and update commands above.\n"
41"                                Specifies that the match will only occur if the source address and the TTL\n"
42"                                match between this packet and the one which was set.\n"
43"                                Useful if you have problems with people spoofing their source address in order\n"
44"                                to DoS you via this module.\n"
45"    --name name                 Name of the recent list to be used.  DEFAULT used if none given.\n"
46"    --rsource                   Match/Save the source address of each packet in the recent list table (default).\n"
47"    --rdest                     Match/Save the destination address of each packet in the recent list table.\n"
48"xt_recent by: Stephen Frost <sfrost@snowman.net>.  http://snowman.net/projects/ipt_recent/\n");
49}
50
51static void recent_init(struct xt_entry_match *match)
52{
53	struct xt_recent_mtinfo *info = (void *)(match)->data;
54
55	strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
56	/* even though XT_RECENT_NAME_LEN is currently defined as 200,
57	 * better be safe, than sorry */
58	info->name[XT_RECENT_NAME_LEN-1] = '\0';
59	info->side = XT_RECENT_SOURCE;
60}
61
62#define RECENT_CMDS \
63	(XT_RECENT_SET | XT_RECENT_CHECK | \
64	XT_RECENT_UPDATE | XT_RECENT_REMOVE)
65
66static int recent_parse(int c, char **argv, int invert, unsigned int *flags,
67                        const void *entry, struct xt_entry_match **match)
68{
69	struct xt_recent_mtinfo *info = (void *)(*match)->data;
70
71	switch (c) {
72		case 201:
73			if (*flags & RECENT_CMDS)
74				xtables_error(PARAMETER_PROBLEM,
75					"recent: only one of `--set', `--rcheck' "
76					"`--update' or `--remove' may be set");
77			xtables_check_inverse(optarg, &invert, &optind, 0, argv);
78			info->check_set |= XT_RECENT_SET;
79			if (invert) info->invert = 1;
80			*flags |= XT_RECENT_SET;
81			break;
82
83		case 202:
84			if (*flags & RECENT_CMDS)
85				xtables_error(PARAMETER_PROBLEM,
86					"recent: only one of `--set', `--rcheck' "
87					"`--update' or `--remove' may be set");
88			xtables_check_inverse(optarg, &invert, &optind, 0, argv);
89			info->check_set |= XT_RECENT_CHECK;
90			if(invert) info->invert = 1;
91			*flags |= XT_RECENT_CHECK;
92			break;
93
94		case 203:
95			if (*flags & RECENT_CMDS)
96				xtables_error(PARAMETER_PROBLEM,
97					"recent: only one of `--set', `--rcheck' "
98					"`--update' or `--remove' may be set");
99			xtables_check_inverse(optarg, &invert, &optind, 0, argv);
100			info->check_set |= XT_RECENT_UPDATE;
101			if (invert) info->invert = 1;
102			*flags |= XT_RECENT_UPDATE;
103			break;
104
105		case 204:
106			info->seconds = atoi(optarg);
107			break;
108
109		case 205:
110			info->hit_count = atoi(optarg);
111			break;
112
113		case 206:
114			if (*flags & RECENT_CMDS)
115				xtables_error(PARAMETER_PROBLEM,
116					"recent: only one of `--set', `--rcheck' "
117					"`--update' or `--remove' may be set");
118			xtables_check_inverse(optarg, &invert, &optind, 0, argv);
119			info->check_set |= XT_RECENT_REMOVE;
120			if (invert) info->invert = 1;
121			*flags |= XT_RECENT_REMOVE;
122			break;
123
124		case 207:
125			info->check_set |= XT_RECENT_TTL;
126			*flags |= XT_RECENT_TTL;
127			break;
128
129		case 208:
130			strncpy(info->name,optarg, XT_RECENT_NAME_LEN);
131			info->name[XT_RECENT_NAME_LEN-1] = '\0';
132			break;
133
134		case 209:
135			info->side = XT_RECENT_SOURCE;
136			break;
137
138		case 210:
139			info->side = XT_RECENT_DEST;
140			break;
141	}
142
143	return 1;
144}
145
146static void recent_check(unsigned int flags)
147{
148	if (!(flags & RECENT_CMDS))
149		xtables_error(PARAMETER_PROBLEM,
150			"recent: you must specify one of `--set', `--rcheck' "
151			"`--update' or `--remove'");
152	if ((flags & XT_RECENT_TTL) &&
153	    (flags & (XT_RECENT_SET | XT_RECENT_REMOVE)))
154		xtables_error(PARAMETER_PROBLEM,
155		           "recent: --rttl may only be used with --rcheck or "
156		           "--update");
157}
158
159static void recent_print(const void *ip, const struct xt_entry_match *match,
160                         int numeric)
161{
162	const struct xt_recent_mtinfo *info = (const void *)match->data;
163
164	if (info->invert)
165		printf(" !");
166
167	printf(" recent:");
168	if (info->check_set & XT_RECENT_SET)
169		printf(" SET");
170	if (info->check_set & XT_RECENT_CHECK)
171		printf(" CHECK");
172	if (info->check_set & XT_RECENT_UPDATE)
173		printf(" UPDATE");
174	if (info->check_set & XT_RECENT_REMOVE)
175		printf(" REMOVE");
176	if(info->seconds) printf(" seconds: %d", info->seconds);
177	if(info->hit_count) printf(" hit_count: %d", info->hit_count);
178	if (info->check_set & XT_RECENT_TTL)
179		printf(" TTL-Match");
180	if(info->name) printf(" name: %s", info->name);
181	if (info->side == XT_RECENT_SOURCE)
182		printf(" side: source");
183	if (info->side == XT_RECENT_DEST)
184		printf(" side: dest");
185}
186
187static void recent_save(const void *ip, const struct xt_entry_match *match)
188{
189	const struct xt_recent_mtinfo *info = (const void *)match->data;
190
191	if (info->invert)
192		printf(" !");
193
194	if (info->check_set & XT_RECENT_SET)
195		printf(" --set");
196	if (info->check_set & XT_RECENT_CHECK)
197		printf(" --rcheck");
198	if (info->check_set & XT_RECENT_UPDATE)
199		printf(" --update");
200	if (info->check_set & XT_RECENT_REMOVE)
201		printf(" --remove");
202	if(info->seconds) printf(" --seconds %d", info->seconds);
203	if(info->hit_count) printf(" --hitcount %d", info->hit_count);
204	if (info->check_set & XT_RECENT_TTL)
205		printf(" --rttl");
206	if(info->name) printf(" --name %s",info->name);
207	if (info->side == XT_RECENT_SOURCE)
208		printf(" --rsource");
209	if (info->side == XT_RECENT_DEST)
210		printf(" --rdest");
211}
212
213static struct xtables_match recent_mt_reg = {
214    .name          = "recent",
215    .version       = XTABLES_VERSION,
216    .family        = NFPROTO_UNSPEC,
217    .size          = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
218    .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
219    .help          = recent_help,
220    .init          = recent_init,
221    .parse         = recent_parse,
222    .final_check   = recent_check,
223    .print         = recent_print,
224    .save          = recent_save,
225    .extra_opts    = recent_opts,
226};
227
228void _init(void)
229{
230	xtables_register_match(&recent_mt_reg);
231}
232