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