libxt_recent.c revision 79ddbf202a06e6f018e087a328c2ca91e65a8463
1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <stdbool.h>
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <stdio.h>
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string.h>
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <xtables.h>
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <linux/netfilter/xt_recent.h>
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum {
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	O_SET = 0,
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	O_RCHECK,
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	O_UPDATE,
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	O_REMOVE,
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	O_SECONDS,
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	O_REAP,
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	O_HITCOUNT,
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	O_RTTL,
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	O_NAME,
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	O_RSOURCE,
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	O_RDEST,
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	F_SET    = 1 << O_SET,
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	F_RCHECK = 1 << O_RCHECK,
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	F_UPDATE = 1 << O_UPDATE,
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	F_REMOVE = 1 << O_REMOVE,
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	F_SECONDS = 1 << O_SECONDS,
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	F_ANY_OP = F_SET | F_RCHECK | F_UPDATE | F_REMOVE,
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#define s struct xt_recent_mtinfo
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static const struct xt_option_entry recent_opts[] = {
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	{.name = "set", .id = O_SET, .type = XTTYPE_NONE,
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	{.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE,
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	{.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE,
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	{.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE,
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 .excl = F_ANY_OP, .flags = XTOPT_INVERT},
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	{.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32,
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds), .min = 1},
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	{.name = "reap", .id = O_REAP, .type = XTTYPE_NONE,
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 .also = F_SECONDS },
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	{.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32,
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)},
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	{.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE,
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 .excl = F_SET | F_REMOVE},
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	{.name = "name", .id = O_NAME, .type = XTTYPE_STRING,
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 .flags = XTOPT_PUT, XTOPT_POINTER(s, name)},
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	{.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE},
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	{.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE},
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	XTOPT_TABLEEND,
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#undef s
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static void recent_help(void)
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles){
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	printf(
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"recent match options:\n"
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)"[!] --set                       Add source address to list, always matches.\n"
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)"[!] --rcheck                    Match if source address in list.\n"
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"[!] --update                    Match if source address in list, also update last-seen time.\n"
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)"[!] --remove                    Match if source address in list, also removes that address from list.\n"
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)"    --seconds seconds           For check and update commands above.\n"
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch"                                Specifies that the match will only occur if source address last seen within\n"
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch"                                the last 'seconds' seconds.\n"
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch"    --reap                      Purge entries older then 'seconds'.\n"
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu"                                Can only be used in conjunction with the seconds option.\n"
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch"    --hitcount hits             For check and update commands above.\n"
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch"                                Specifies that the match will only occur if source address seen hits times.\n"
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"                                May be used in conjunction with the seconds option.\n"
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch"    --rttl                      For check and update commands above.\n"
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch"                                Specifies that the match will only occur if the source address and the TTL\n"
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"                                match between this packet and the one which was set.\n"
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"                                Useful if you have problems with people spoofing their source address in order\n"
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"                                to DoS you via this module.\n"
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"    --name name                 Name of the recent list to be used.  DEFAULT used if none given.\n"
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"    --rsource                   Match/Save the source address of each packet in the recent list table (default).\n"
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"    --rdest                     Match/Save the destination address of each packet in the recent list table.\n"
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"xt_recent by: Stephen Frost <sfrost@snowman.net>.  http://snowman.net/projects/ipt_recent/\n");
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static void recent_init(struct xt_entry_match *match)
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct xt_recent_mtinfo *info = (void *)(match)->data;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	/* even though XT_RECENT_NAME_LEN is currently defined as 200,
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 * better be safe, than sorry */
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	info->name[XT_RECENT_NAME_LEN-1] = '\0';
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	info->side = XT_RECENT_SOURCE;
89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
90c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstatic void recent_parse(struct xt_option_call *cb)
92c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch{
93c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch	struct xt_recent_mtinfo *info = cb->data;
94c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
95c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch	xtables_option_parse(cb);
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	switch (cb->entry->id) {
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	case O_SET:
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		info->check_set |= XT_RECENT_SET;
99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch		if (cb->invert)
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			info->invert = true;
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		break;
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	case O_RCHECK:
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		info->check_set |= XT_RECENT_CHECK;
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		if (cb->invert)
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			info->invert = true;
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		break;
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	case O_UPDATE:
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu		info->check_set |= XT_RECENT_UPDATE;
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu		if (cb->invert)
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu			info->invert = true;
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu		break;
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu	case O_REMOVE:
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu		info->check_set |= XT_RECENT_REMOVE;
114		if (cb->invert)
115			info->invert = true;
116		break;
117	case O_RTTL:
118		info->check_set |= XT_RECENT_TTL;
119		break;
120	case O_RSOURCE:
121		info->side = XT_RECENT_SOURCE;
122		break;
123	case O_RDEST:
124		info->side = XT_RECENT_DEST;
125		break;
126	case O_REAP:
127		info->check_set |= XT_RECENT_REAP;
128		break;
129	}
130}
131
132static void recent_check(struct xt_fcheck_call *cb)
133{
134	struct xt_recent_mtinfo *info = cb->data;
135
136	if (!(cb->xflags & F_ANY_OP))
137		xtables_error(PARAMETER_PROBLEM,
138			"recent: you must specify one of `--set', `--rcheck' "
139			"`--update' or `--remove'");
140}
141
142static void recent_print(const void *ip, const struct xt_entry_match *match,
143                         int numeric)
144{
145	const struct xt_recent_mtinfo *info = (const void *)match->data;
146
147	if (info->invert)
148		printf(" !");
149
150	printf(" recent:");
151	if (info->check_set & XT_RECENT_SET)
152		printf(" SET");
153	if (info->check_set & XT_RECENT_CHECK)
154		printf(" CHECK");
155	if (info->check_set & XT_RECENT_UPDATE)
156		printf(" UPDATE");
157	if (info->check_set & XT_RECENT_REMOVE)
158		printf(" REMOVE");
159	if(info->seconds) printf(" seconds: %d", info->seconds);
160	if (info->check_set & XT_RECENT_REAP)
161		printf(" reap");
162	if(info->hit_count) printf(" hit_count: %d", info->hit_count);
163	if (info->check_set & XT_RECENT_TTL)
164		printf(" TTL-Match");
165	if(info->name) printf(" name: %s", info->name);
166	if (info->side == XT_RECENT_SOURCE)
167		printf(" side: source");
168	if (info->side == XT_RECENT_DEST)
169		printf(" side: dest");
170}
171
172static void recent_save(const void *ip, const struct xt_entry_match *match)
173{
174	const struct xt_recent_mtinfo *info = (const void *)match->data;
175
176	if (info->invert)
177		printf(" !");
178
179	if (info->check_set & XT_RECENT_SET)
180		printf(" --set");
181	if (info->check_set & XT_RECENT_CHECK)
182		printf(" --rcheck");
183	if (info->check_set & XT_RECENT_UPDATE)
184		printf(" --update");
185	if (info->check_set & XT_RECENT_REMOVE)
186		printf(" --remove");
187	if(info->seconds) printf(" --seconds %d", info->seconds);
188	if (info->check_set & XT_RECENT_REAP)
189		printf(" --reap");
190	if(info->hit_count) printf(" --hitcount %d", info->hit_count);
191	if (info->check_set & XT_RECENT_TTL)
192		printf(" --rttl");
193	if(info->name) printf(" --name %s",info->name);
194	if (info->side == XT_RECENT_SOURCE)
195		printf(" --rsource");
196	if (info->side == XT_RECENT_DEST)
197		printf(" --rdest");
198}
199
200static struct xtables_match recent_mt_reg = {
201	.name          = "recent",
202	.version       = XTABLES_VERSION,
203	.family        = NFPROTO_UNSPEC,
204	.size          = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
205	.userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
206	.help          = recent_help,
207	.init          = recent_init,
208	.x6_parse      = recent_parse,
209	.x6_fcheck     = recent_check,
210	.print         = recent_print,
211	.save          = recent_save,
212	.x6_options    = recent_opts,
213};
214
215void _init(void)
216{
217	xtables_register_match(&recent_mt_reg);
218}
219