1/* Shared library add-on to iptables to add ipv4 options 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 <iptables.h>
9#include <linux/netfilter_ipv4/ipt_ipv4options.h>
10
11#ifndef XTABLES_VERSION
12#define XTABLES_VERSION IPTABLES_VERSION
13#endif
14
15#ifdef IPT_LIB_DIR
16#define xtables_target iptables_target
17#define xtables_register_target register_target
18#endif
19
20/* Function which prints out usage message. */
21static void
22help(void)
23{
24	printf(
25"ipv4options v%s options:\n"
26"      --ssrr    (match strict source routing flag)\n"
27"      --lsrr    (match loose  source routing flag)\n"
28"      --no-srr  (match packets with no source routing)\n\n"
29"  [!] --rr      (match record route flag)\n\n"
30"  [!] --ts      (match timestamp flag)\n\n"
31"  [!] --ra      (match router-alert option)\n\n"
32"  [!] --any-opt (match any option or no option at all if used with '!')\n",
33XTABLES_VERSION);
34}
35
36static struct option opts[] = {
37	{ "ssrr", 0, 0, '1' },
38	{ "lsrr", 0, 0, '2' },
39	{ "no-srr", 0, 0, '3'},
40	{ "rr", 0, 0, '4'},
41	{ "ts", 0, 0, '5'},
42	{ "ra", 0, 0, '6'},
43	{ "any-opt", 0, 0, '7'},
44	{0}
45};
46
47/* Function which parses command options; returns true if it
48   ate an option */
49static int
50parse(int c, char **argv, int invert, unsigned int *flags,
51#ifdef _XTABLES_H
52      const void *entry, struct xt_entry_match **match)
53#else
54      const struct ipt_entry *entry, unsigned int *nfcache, struct ipt_entry_match **match)
55#endif
56{
57	struct ipt_ipv4options_info *info = (struct ipt_ipv4options_info *)(*match)->data;
58
59	switch (c)
60	{
61		/* strict-source-routing */
62	case '1':
63		if (invert)
64			exit_error(PARAMETER_PROBLEM,
65				   "ipv4options: unexpected `!' with --ssrr");
66		if (*flags & IPT_IPV4OPTION_MATCH_SSRR)
67                        exit_error(PARAMETER_PROBLEM,
68                                   "Can't specify --ssrr twice");
69		if (*flags & IPT_IPV4OPTION_MATCH_LSRR)
70			exit_error(PARAMETER_PROBLEM,
71				   "Can't specify --ssrr with --lsrr");
72		if (*flags & IPT_IPV4OPTION_DONT_MATCH_SRR)
73			exit_error(PARAMETER_PROBLEM,
74				   "Can't specify --ssrr with --no-srr");
75
76		info->options |= IPT_IPV4OPTION_MATCH_SSRR;
77		*flags |= IPT_IPV4OPTION_MATCH_SSRR;
78		break;
79
80		/* loose-source-routing */
81	case '2':
82		if (invert)
83			exit_error(PARAMETER_PROBLEM,
84				   "ipv4options: unexpected `!' with --lsrr");
85		if (*flags & IPT_IPV4OPTION_MATCH_SSRR)
86                        exit_error(PARAMETER_PROBLEM,
87                                   "Can't specify --lsrr twice");
88		if (*flags & IPT_IPV4OPTION_MATCH_LSRR)
89			exit_error(PARAMETER_PROBLEM,
90				   "Can't specify --lsrr with --ssrr");
91		if (*flags & IPT_IPV4OPTION_DONT_MATCH_SRR)
92			exit_error(PARAMETER_PROBLEM,
93				   "Can't specify --lsrr with --no-srr");
94		info->options |= IPT_IPV4OPTION_MATCH_LSRR;
95		*flags |= IPT_IPV4OPTION_MATCH_LSRR;
96		break;
97
98		/* no-source-routing */
99	case '3':
100		if (invert)
101			exit_error(PARAMETER_PROBLEM,
102					   "ipv4options: unexpected `!' with --no-srr");
103		if (*flags & IPT_IPV4OPTION_DONT_MATCH_SRR)
104                        exit_error(PARAMETER_PROBLEM,
105                                   "Can't specify --no-srr twice");
106		if (*flags & IPT_IPV4OPTION_MATCH_SSRR)
107			exit_error(PARAMETER_PROBLEM,
108				   "Can't specify --no-srr with --ssrr");
109		if (*flags & IPT_IPV4OPTION_MATCH_LSRR)
110			exit_error(PARAMETER_PROBLEM,
111				   "Can't specify --no-srr with --lsrr");
112		info->options |= IPT_IPV4OPTION_DONT_MATCH_SRR;
113		*flags |= IPT_IPV4OPTION_DONT_MATCH_SRR;
114		break;
115
116		/* record-route */
117	case '4':
118		if ((!invert) && (*flags & IPT_IPV4OPTION_MATCH_RR))
119			exit_error(PARAMETER_PROBLEM,
120				   "Can't specify --rr twice");
121		if (invert && (*flags & IPT_IPV4OPTION_DONT_MATCH_RR))
122			exit_error(PARAMETER_PROBLEM,
123				   "Can't specify ! --rr twice");
124		if ((!invert) && (*flags & IPT_IPV4OPTION_DONT_MATCH_RR))
125			exit_error(PARAMETER_PROBLEM,
126				   "Can't specify --rr with ! --rr");
127		if (invert && (*flags & IPT_IPV4OPTION_MATCH_RR))
128			exit_error(PARAMETER_PROBLEM,
129				   "Can't specify ! --rr with --rr");
130		if (invert) {
131			info->options |= IPT_IPV4OPTION_DONT_MATCH_RR;
132			*flags |= IPT_IPV4OPTION_DONT_MATCH_RR;
133		}
134		else {
135			info->options |= IPT_IPV4OPTION_MATCH_RR;
136			*flags |= IPT_IPV4OPTION_MATCH_RR;
137		}
138		break;
139
140		/* timestamp */
141	case '5':
142		if ((!invert) && (*flags & IPT_IPV4OPTION_MATCH_TIMESTAMP))
143			exit_error(PARAMETER_PROBLEM,
144				   "Can't specify --ts twice");
145		if (invert && (*flags & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
146			exit_error(PARAMETER_PROBLEM,
147				   "Can't specify ! --ts twice");
148		if ((!invert) && (*flags & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
149			exit_error(PARAMETER_PROBLEM,
150				   "Can't specify --ts with ! --ts");
151		if (invert && (*flags & IPT_IPV4OPTION_MATCH_TIMESTAMP))
152			exit_error(PARAMETER_PROBLEM,
153				   "Can't specify ! --ts with --ts");
154		if (invert) {
155			info->options |= IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP;
156			*flags |= IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP;
157		}
158		else {
159			info->options |= IPT_IPV4OPTION_MATCH_TIMESTAMP;
160			*flags |= IPT_IPV4OPTION_MATCH_TIMESTAMP;
161		}
162		break;
163
164		/* router-alert  */
165	case '6':
166		if ((!invert) && (*flags & IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
167			exit_error(PARAMETER_PROBLEM,
168				   "Can't specify --ra twice");
169		if (invert && (*flags & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
170			exit_error(PARAMETER_PROBLEM,
171				   "Can't specify ! --rr twice");
172		if ((!invert) && (*flags & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
173			exit_error(PARAMETER_PROBLEM,
174				   "Can't specify --ra with ! --ra");
175		if (invert && (*flags & IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
176			exit_error(PARAMETER_PROBLEM,
177				   "Can't specify ! --ra with --ra");
178		if (invert) {
179			info->options |= IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT;
180			*flags |= IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT;
181		}
182		else {
183			info->options |= IPT_IPV4OPTION_MATCH_ROUTER_ALERT;
184			*flags |= IPT_IPV4OPTION_MATCH_ROUTER_ALERT;
185		}
186		break;
187
188		/* any option */
189	case '7' :
190		if ((!invert) && (*flags & IPT_IPV4OPTION_MATCH_ANY_OPT))
191			exit_error(PARAMETER_PROBLEM,
192				   "Can't specify --any-opt twice");
193		if (invert && (*flags & IPT_IPV4OPTION_MATCH_ANY_OPT))
194			exit_error(PARAMETER_PROBLEM,
195				   "Can't specify ! --any-opt with --any-opt");
196		if (invert && (*flags & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
197			exit_error(PARAMETER_PROBLEM,
198				   "Can't specify ! --any-opt twice");
199		if ((!invert) &&
200		    ((*flags & IPT_IPV4OPTION_DONT_MATCH_SRR)       ||
201		     (*flags & IPT_IPV4OPTION_DONT_MATCH_RR)        ||
202		     (*flags & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
203		     (*flags & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)))
204			exit_error(PARAMETER_PROBLEM,
205				   "Can't specify --any-opt with any other negative ipv4options match");
206		if (invert &&
207		    ((*flags & IPT_IPV4OPTION_MATCH_LSRR)      ||
208		     (*flags & IPT_IPV4OPTION_MATCH_SSRR)      ||
209		     (*flags & IPT_IPV4OPTION_MATCH_RR)        ||
210		     (*flags & IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
211		     (*flags & IPT_IPV4OPTION_MATCH_ROUTER_ALERT)))
212			exit_error(PARAMETER_PROBLEM,
213				   "Can't specify ! --any-opt with any other positive ipv4options match");
214		if (invert) {
215			info->options |= IPT_IPV4OPTION_DONT_MATCH_ANY_OPT;
216			*flags |= IPT_IPV4OPTION_DONT_MATCH_ANY_OPT;
217		}
218		else {
219			info->options |= IPT_IPV4OPTION_MATCH_ANY_OPT;
220			*flags |= IPT_IPV4OPTION_MATCH_ANY_OPT;
221		}
222		break;
223
224	default:
225		return 0;
226	}
227	return 1;
228}
229
230static void
231final_check(unsigned int flags)
232{
233	if (flags == 0)
234		exit_error(PARAMETER_PROBLEM,
235			   "ipv4options match: you must specify some parameters. See iptables -m ipv4options --help for help.'");
236}
237
238/* Prints out the matchinfo. */
239static void
240#ifdef _XTABLES_H
241print(const void *ip,
242      const struct xt_entry_match *match,
243#else
244print(const struct ipt_ip *ip,
245      const struct ipt_entry_match *match,
246#endif
247      int numeric)
248{
249	struct ipt_ipv4options_info *info = ((struct ipt_ipv4options_info *)match->data);
250
251	printf(" IPV4OPTS");
252	if (info->options & IPT_IPV4OPTION_MATCH_SSRR)
253		printf(" SSRR");
254	else if (info->options & IPT_IPV4OPTION_MATCH_LSRR)
255		printf(" LSRR");
256	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_SRR)
257		printf(" !SRR");
258	if (info->options & IPT_IPV4OPTION_MATCH_RR)
259		printf(" RR");
260	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_RR)
261		printf(" !RR");
262	if (info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP)
263		printf(" TS");
264	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP)
265		printf(" !TS");
266	if (info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT)
267		printf(" RA");
268	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)
269		printf(" !RA");
270	if (info->options & IPT_IPV4OPTION_MATCH_ANY_OPT)
271		printf(" ANYOPT ");
272	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
273		printf(" NOOPT");
274
275	printf(" ");
276}
277
278/* Saves the data in parsable form to stdout. */
279static void
280#ifdef _XTABLES_H
281save(const void *ip,
282     const struct xt_entry_match *match)
283#else
284save(const struct ipt_ip *ip,
285     const struct ipt_entry_match *match)
286#endif
287{
288	struct ipt_ipv4options_info *info = ((struct ipt_ipv4options_info *)match->data);
289
290	if (info->options & IPT_IPV4OPTION_MATCH_SSRR)
291		printf(" --ssrr");
292	else if (info->options & IPT_IPV4OPTION_MATCH_LSRR)
293		printf(" --lsrr");
294	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_SRR)
295		printf(" --no-srr");
296	if (info->options & IPT_IPV4OPTION_MATCH_RR)
297		printf(" --rr");
298	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_RR)
299		printf(" ! --rr");
300	if (info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP)
301		printf(" --ts");
302	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP)
303		printf(" ! --ts");
304	if (info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT)
305		printf(" --ra");
306	else if (info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)
307		printf(" ! --ra");
308	if (info->options & IPT_IPV4OPTION_MATCH_ANY_OPT)
309		printf(" --any-opt");
310	if (info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
311		printf(" ! --any-opt");
312
313	printf(" ");
314}
315
316static struct xtables_match ipv4options_struct = {
317	.next		= NULL,
318	.name		= "ipv4options",
319	.version	= XTABLES_VERSION,
320	.size		= IPT_ALIGN(sizeof(struct ipt_ipv4options_info)),
321	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_ipv4options_info)),
322	.help		= &help,
323	.parse		= &parse,
324	.final_check	= &final_check,
325	.print		= &print,
326	.save		= &save,
327	.extra_opts	= opts
328};
329
330void _init(void)
331{
332	xtables_register_match(&ipv4options_struct);
333}
334