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