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 <ip6tables.h>
9#include <linux/netfilter_ipv6/ip6_tables.h>
10#include <linux/netfilter/xt_recent.h>
11
12#ifndef XTABLES_VERSION
13#define XTABLES_VERSION IPTABLES_VERSION
14#endif
15
16#ifdef IPT_LIB_DIR
17#define xtables_target ip6tables_target
18#define xtables_register_target register_target6
19#endif
20
21/* Need these in order to not fail when compiling against an older kernel. */
22#ifndef RECENT_NAME
23#define RECENT_NAME	"ip6t_recent"
24#endif /* RECENT_NAME */
25
26#ifndef RECENT_VER
27#define RECENT_VER	"unknown"
28#endif /* RECENT_VER */
29
30/* Options for this module */
31static struct option opts[] = {
32	{ .name = "set",      .has_arg = 0, .flag = 0, .val = 201 },
33	{ .name = "rcheck",   .has_arg = 0, .flag = 0, .val = 202 },
34	{ .name = "update",   .has_arg = 0, .flag = 0, .val = 203 },
35	{ .name = "seconds",  .has_arg = 1, .flag = 0, .val = 204 },
36	{ .name = "hitcount", .has_arg = 1, .flag = 0, .val = 205 },
37	{ .name = "remove",   .has_arg = 0, .flag = 0, .val = 206 },
38	{ .name = "rttl",     .has_arg = 0, .flag = 0, .val = 207 },
39	{ .name = "name",     .has_arg = 1, .flag = 0, .val = 208 },
40	{ .name = "rsource",  .has_arg = 0, .flag = 0, .val = 209 },
41	{ .name = "rdest",    .has_arg = 0, .flag = 0, .val = 210 },
42	{ .name = 0,          .has_arg = 0, .flag = 0, .val = 0   }
43};
44
45/* Function which prints out usage message. */
46static void
47help(void)
48{
49	printf(
50"recent v%s options:\n"
51"[!] --set                       Add source address to list, always matches.\n"
52"[!] --rcheck                    Match if source address in list.\n"
53"[!] --update                    Match if source address in list, also update last-seen time.\n"
54"[!] --remove                    Match if source address in list, also removes that address from list.\n"
55"    --seconds seconds           For check and update commands above.\n"
56"                                Specifies that the match will only occur if source address last seen within\n"
57"                                the last 'seconds' seconds.\n"
58"    --hitcount hits             For check and update commands above.\n"
59"                                Specifies that the match will only occur if source address seen hits times.\n"
60"                                May be used in conjunction with the seconds option.\n"
61"    --rttl                      For check and update commands above.\n"
62"                                Specifies that the match will only occur if the source address and the TTL\n"
63"                                match between this packet and the one which was set.\n"
64"                                Useful if you have problems with people spoofing their source address in order\n"
65"                                to DoS you via this module.\n"
66"    --name name                 Name of the recent list to be used.  DEFAULT used if none given.\n"
67"    --rsource                   Match/Save the source address of each packet in the recent list table (default).\n"
68"    --rdest                     Match/Save the destination address of each packet in the recent list table.\n"
69RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>.  http://snowman.net/projects/ipt_recent/\n"
70,
71IPTABLES_VERSION);
72
73}
74
75/* Initialize the match. */
76static void
77init(struct ip6t_entry_match *match, unsigned int *nfcache)
78{
79	struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)(match)->data;
80
81
82	strncpy(info->name,"DEFAULT",XT_RECENT_NAME_LEN);
83	/* eventhough XT_RECENT_NAME_LEN is currently defined as 200,
84	 * better be safe, than sorry */
85	info->name[XT_RECENT_NAME_LEN-1] = '\0';
86	info->side = XT_RECENT_SOURCE;
87}
88
89/* Function which parses command options; returns true if it
90   ate an option */
91static int
92parse(int c, char **argv, int invert, unsigned int *flags,
93      const struct ip6t_entry *entry,
94      unsigned int *nfcache,
95      struct ip6t_entry_match **match)
96{
97	struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)(*match)->data;
98	switch (c) {
99		case 201:
100			if (*flags) exit_error(PARAMETER_PROBLEM,
101					"recent: only one of `--set', `--rcheck' "
102					"`--update' or `--remove' may be set");
103			check_inverse(optarg, &invert, &optind, 0);
104			info->check_set |= XT_RECENT_SET;
105			if (invert) info->invert = 1;
106			*flags = 1;
107			break;
108
109		case 202:
110			if (*flags) exit_error(PARAMETER_PROBLEM,
111					"recent: only one of `--set', `--rcheck' "
112					"`--update' or `--remove' may be set");
113			check_inverse(optarg, &invert, &optind, 0);
114			info->check_set |= XT_RECENT_CHECK;
115			if(invert) info->invert = 1;
116			*flags = 1;
117			break;
118
119		case 203:
120			if (*flags) exit_error(PARAMETER_PROBLEM,
121					"recent: only one of `--set', `--rcheck' "
122					"`--update' or `--remove' may be set");
123			check_inverse(optarg, &invert, &optind, 0);
124			info->check_set |= XT_RECENT_UPDATE;
125			if (invert) info->invert = 1;
126			*flags = 1;
127			break;
128
129		case 206:
130			if (*flags) exit_error(PARAMETER_PROBLEM,
131					"recent: only one of `--set', `--rcheck' "
132					"`--update' or `--remove' may be set");
133			check_inverse(optarg, &invert, &optind, 0);
134			info->check_set |= XT_RECENT_REMOVE;
135			if (invert) info->invert = 1;
136			*flags = 1;
137			break;
138
139		case 204:
140			info->seconds = atoi(optarg);
141			break;
142
143		case 205:
144			info->hit_count = atoi(optarg);
145			break;
146
147		case 207:
148			info->check_set |= XT_RECENT_TTL;
149			break;
150
151		case 208:
152			strncpy(info->name,optarg,XT_RECENT_NAME_LEN);
153			info->name[XT_RECENT_NAME_LEN-1] = '\0';
154			break;
155
156		case 209:
157			info->side = XT_RECENT_SOURCE;
158			break;
159
160		case 210:
161			info->side = XT_RECENT_DEST;
162			break;
163
164		default:
165			return 0;
166	}
167
168	return 1;
169}
170
171/* Final check; must have specified a specific option. */
172static void
173final_check(unsigned int flags)
174{
175	if (!flags)
176		exit_error(PARAMETER_PROBLEM,
177			"recent: you must specify one of `--set', `--rcheck' "
178			"`--update' or `--remove'");
179}
180
181/* Prints out the matchinfo. */
182static void
183print(const struct ip6t_ip6 *ip,
184      const struct ip6t_entry_match *match,
185      int numeric)
186{
187	struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)match->data;
188
189	if (info->invert)
190		fputc('!', stdout);
191
192	printf("recent: ");
193	if(info->check_set & XT_RECENT_SET) printf("SET ");
194	if(info->check_set & XT_RECENT_CHECK) printf("CHECK ");
195	if(info->check_set & XT_RECENT_UPDATE) printf("UPDATE ");
196	if(info->check_set & XT_RECENT_REMOVE) printf("REMOVE ");
197	if(info->seconds) printf("seconds: %d ",info->seconds);
198	if(info->hit_count) printf("hit_count: %d ",info->hit_count);
199	if(info->check_set & XT_RECENT_TTL) printf("TTL-Match ");
200	if(info->name) printf("name: %s ",info->name);
201	if(info->side == XT_RECENT_SOURCE) printf("side: source ");
202	if(info->side == XT_RECENT_DEST) printf("side: dest");
203}
204
205/* Saves the union ip6t_matchinfo in parsable form to stdout. */
206static void
207save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
208{
209	struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)match->data;
210
211	if (info->invert)
212		printf("! ");
213
214	if(info->check_set & XT_RECENT_SET) printf("--set ");
215	if(info->check_set & XT_RECENT_CHECK) printf("--rcheck ");
216	if(info->check_set & XT_RECENT_UPDATE) printf("--update ");
217	if(info->check_set & XT_RECENT_REMOVE) printf("--remove ");
218	if(info->seconds) printf("--seconds %d ",info->seconds);
219	if(info->hit_count) printf("--hitcount %d ",info->hit_count);
220	if(info->check_set & XT_RECENT_TTL) printf("--rttl ");
221	if(info->name) printf("--name %s ",info->name);
222	if(info->side == XT_RECENT_SOURCE) printf("--rsource ");
223	if(info->side == XT_RECENT_DEST) printf("--rdest ");
224}
225
226/* Structure for iptables to use to communicate with module */
227static struct ip6tables_match recent = {
228    .next          = NULL,
229    .name          = "recent",
230    .version       = XTABLES_VERSION,
231    .size          = IP6T_ALIGN(sizeof(struct xt_recent_mtinfo)),
232    .userspacesize = IP6T_ALIGN(sizeof(struct xt_recent_mtinfo)),
233    .help          = &help,
234    .init          = &init,
235    .parse         = &parse,
236    .final_check   = &final_check,
237    .print         = &print,
238    .save          = &save,
239    .extra_opts    = opts,
240};
241
242void _init(void)
243{
244	register_match6(&recent);
245}
246