xtoptions.c revision fa9b759bacc0ad6a093892ef508811e7feb981b0
1/*
2 *	Argument parser
3 *	Copyright © Jan Engelhardt, 2011
4 *
5 *	This program is free software; you can redistribute it and/or
6 *	modify it under the terms of the GNU General Public License as
7 *	published by the Free Software Foundation; either version 2 of
8 *	the License, or (at your option) any later version.
9 */
10#include <ctype.h>
11#include <errno.h>
12#include <getopt.h>
13#include <limits.h>
14#include <netdb.h>
15#include <stdbool.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <syslog.h>
21#include <arpa/inet.h>
22#include <netinet/ip.h>
23#include "xtables.h"
24#include "xshared.h"
25#ifndef IPTOS_NORMALSVC
26#	define IPTOS_NORMALSVC 0
27#endif
28
29#define XTOPT_MKPTR(cb) \
30	((void *)((char *)(cb)->data + (cb)->entry->ptroff))
31
32/**
33 * Simple key-value pairs for syslog levels
34 */
35struct syslog_level {
36	char name[8];
37	uint8_t level;
38};
39
40struct tos_value_mask {
41	uint8_t value, mask;
42};
43
44/**
45 * Creates getopt options from the x6-style option map, and assigns each a
46 * getopt id.
47 */
48struct option *
49xtables_options_xfrm(struct option *orig_opts, struct option *oldopts,
50		     const struct xt_option_entry *entry, unsigned int *offset)
51{
52	unsigned int num_orig, num_old = 0, num_new, i;
53	struct option *merge, *mp;
54
55	if (entry == NULL)
56		return oldopts;
57	for (num_orig = 0; orig_opts[num_orig].name != NULL; ++num_orig)
58		;
59	if (oldopts != NULL)
60		for (num_old = 0; oldopts[num_old].name != NULL; ++num_old)
61			;
62	for (num_new = 0; entry[num_new].name != NULL; ++num_new)
63		;
64
65	/*
66	 * Since @oldopts also has @orig_opts already (and does so at the
67	 * start), skip these entries.
68	 */
69	oldopts += num_orig;
70	num_old -= num_orig;
71
72	merge = malloc(sizeof(*mp) * (num_orig + num_old + num_new + 1));
73	if (merge == NULL)
74		return NULL;
75
76	/* Let the base options -[ADI...] have precedence over everything */
77	memcpy(merge, orig_opts, sizeof(*mp) * num_orig);
78	mp = merge + num_orig;
79
80	/* Second, the new options */
81	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
82	*offset = xt_params->option_offset;
83
84	for (i = 0; i < num_new; ++i, ++mp, ++entry) {
85		mp->name         = entry->name;
86		mp->has_arg      = entry->type != XTTYPE_NONE;
87		mp->flag         = NULL;
88		mp->val          = entry->id + *offset;
89	}
90
91	/* Third, the old options */
92	memcpy(mp, oldopts, sizeof(*mp) * num_old);
93	mp += num_old;
94	xtables_free_opts(0);
95
96	/* Clear trailing entry */
97	memset(mp, 0, sizeof(*mp));
98	return merge;
99}
100
101/**
102 * Require a simple integer.
103 */
104static void xtopt_parse_int(struct xt_option_call *cb)
105{
106	const struct xt_option_entry *entry = cb->entry;
107	unsigned long long lmin = 0, lmax = UINT32_MAX;
108	unsigned int value;
109
110	if (entry->type == XTTYPE_UINT8)
111		lmax = UINT8_MAX;
112	else if (entry->type == XTTYPE_UINT16)
113		lmax = UINT16_MAX;
114	else if (entry->type == XTTYPE_UINT64)
115		lmax = UINT64_MAX;
116	if (cb->entry->min != 0)
117		lmin = cb->entry->min;
118	if (cb->entry->max != 0)
119		lmax = cb->entry->max;
120
121	if (!xtables_strtoui(cb->arg, NULL, &value, lmin, lmax))
122		xt_params->exit_err(PARAMETER_PROBLEM,
123			"%s: bad value for option \"--%s\", "
124			"or out of range (%llu-%llu).\n",
125			cb->ext_name, entry->name, lmin, lmax);
126
127	if (entry->type == XTTYPE_UINT8) {
128		cb->val.u8 = value;
129		if (entry->flags & XTOPT_PUT)
130			*(uint8_t *)XTOPT_MKPTR(cb) = cb->val.u8;
131	} else if (entry->type == XTTYPE_UINT16) {
132		cb->val.u16 = value;
133		if (entry->flags & XTOPT_PUT)
134			*(uint16_t *)XTOPT_MKPTR(cb) = cb->val.u16;
135	} else if (entry->type == XTTYPE_UINT32) {
136		cb->val.u32 = value;
137		if (entry->flags & XTOPT_PUT)
138			*(uint32_t *)XTOPT_MKPTR(cb) = cb->val.u32;
139	} else if (entry->type == XTTYPE_UINT64) {
140		cb->val.u64 = value;
141		if (entry->flags & XTOPT_PUT)
142			*(uint64_t *)XTOPT_MKPTR(cb) = cb->val.u64;
143	}
144}
145
146/**
147 * Require a simple floating point number.
148 */
149static void xtopt_parse_float(struct xt_option_call *cb)
150{
151	const struct xt_option_entry *entry = cb->entry;
152	double value;
153	char *end;
154
155	value = strtod(cb->arg, &end);
156	if (end == cb->arg || *end != '\0' ||
157	    (entry->min != entry->max &&
158	    (value < entry->min || value > entry->max)))
159		xt_params->exit_err(PARAMETER_PROBLEM,
160			"%s: bad value for option \"--%s\", "
161			"or out of range (%u-%u).\n",
162			cb->ext_name, entry->name, entry->min, entry->max);
163
164	cb->val.dbl = value;
165	if (entry->flags & XTOPT_PUT)
166		*(double *)XTOPT_MKPTR(cb) = cb->val.dbl;
167}
168
169/**
170 * Multiple integer parse routine.
171 *
172 * This function is capable of parsing any number of fields. Only the first
173 * two values from the string will be put into @cb however (and as such,
174 * @cb->val.uXX_range is just that large) to cater for the few extensions that
175 * do not have a range[2] field, but {min, max}, and which cannot use
176 * XTOPT_POINTER.
177 */
178static void xtopt_parse_mint(struct xt_option_call *cb)
179{
180	const struct xt_option_entry *entry = cb->entry;
181	const char *arg = cb->arg;
182	size_t esize = sizeof(uint32_t);
183	char *put = XTOPT_MKPTR(cb);
184	unsigned int maxiter, value;
185	char *end = "";
186	char sep = ':';
187
188	if (entry->type == XTTYPE_UINT8RC)
189		esize = sizeof(uint8_t);
190	else if (entry->type == XTTYPE_UINT16RC)
191		esize = sizeof(uint16_t);
192	else if (entry->type == XTTYPE_UINT64RC)
193		esize = sizeof(uint64_t);
194	maxiter = entry->size / esize;
195	if (maxiter == 0)
196		maxiter = 2; /* ARRAY_SIZE(cb->val.uXX_range) */
197	if (entry->size % esize != 0)
198		xt_params->exit_err(OTHER_PROBLEM, "%s: memory block does "
199			"not have proper size\n", __func__);
200
201	cb->nvals = 0;
202	for (arg = cb->arg; ; arg = end + 1) {
203		if (cb->nvals == maxiter)
204			xt_params->exit_err(PARAMETER_PROBLEM, "%s: Too many "
205				"components for option \"--%s\" (max: %u)\n",
206				cb->ext_name, entry->name, maxiter);
207		if (!xtables_strtoui(arg, &end, &value, 0, UINT32_MAX))
208			xt_params->exit_err(PARAMETER_PROBLEM,
209				"%s: bad value for option \"--%s\", "
210				"or out of range (0-%u).\n",
211				cb->ext_name, entry->name, UINT32_MAX);
212		if (*end != '\0' && *end != sep)
213			xt_params->exit_err(PARAMETER_PROBLEM,
214				"%s: Argument to \"--%s\" has unexpected "
215				"characters.\n", cb->ext_name, entry->name);
216		if (cb->nvals < ARRAY_SIZE(cb->val.u32_range)) {
217			if (entry->type == XTTYPE_UINT8RC)
218				cb->val.u8_range[cb->nvals] = value;
219			else if (entry->type == XTTYPE_UINT16RC)
220				cb->val.u16_range[cb->nvals] = value;
221			else if (entry->type == XTTYPE_UINT32RC)
222				cb->val.u32_range[cb->nvals] = value;
223			else if (entry->type == XTTYPE_UINT64RC)
224				cb->val.u64_range[cb->nvals] = value;
225		}
226		++cb->nvals;
227		if (entry->flags & XTOPT_PUT) {
228			if (entry->type == XTTYPE_UINT8RC)
229				*(uint8_t *)put = value;
230			else if (entry->type == XTTYPE_UINT16RC)
231				*(uint16_t *)put = value;
232			else if (entry->type == XTTYPE_UINT32RC)
233				*(uint32_t *)put = value;
234			else if (entry->type == XTTYPE_UINT64RC)
235				*(uint64_t *)put = value;
236			put += esize;
237		}
238		if (*end == '\0')
239			break;
240	}
241}
242
243static void xtopt_parse_string(struct xt_option_call *cb)
244{
245	const struct xt_option_entry *entry = cb->entry;
246	size_t z = strlen(cb->arg);
247	char *p;
248
249	if (entry->min != 0 && z < entry->min)
250		xt_params->exit_err(PARAMETER_PROBLEM,
251			"Argument must have a minimum length of "
252			"%u characters\n", entry->min);
253	if (entry->max != 0 && z > entry->max)
254		xt_params->exit_err(PARAMETER_PROBLEM,
255			"Argument must have a maximum length of "
256			"%u characters\n", entry->max);
257	if (!(entry->flags & XTOPT_PUT))
258		return;
259	if (z >= entry->size)
260		z = entry->size - 1;
261	p = XTOPT_MKPTR(cb);
262	strncpy(p, cb->arg, z);
263	p[z] = '\0';
264}
265
266static const struct tos_symbol_info {
267	unsigned char value;
268	const char *name;
269} tos_symbol_names[] = {
270	{IPTOS_LOWDELAY,    "Minimize-Delay"},
271	{IPTOS_THROUGHPUT,  "Maximize-Throughput"},
272	{IPTOS_RELIABILITY, "Maximize-Reliability"},
273	{IPTOS_MINCOST,     "Minimize-Cost"},
274	{IPTOS_NORMALSVC,   "Normal-Service"},
275	{},
276};
277
278/*
279 * tos_parse_numeric - parse a string like "15/255"
280 *
281 * @str:	input string
282 * @tvm:	(value/mask) tuple
283 * @max:	maximum allowed value (must be pow(2,some_int)-1)
284 */
285static bool tos_parse_numeric(const char *str, struct xt_option_call *cb,
286                              unsigned int max)
287{
288	unsigned int value;
289	char *end;
290
291	xtables_strtoui(str, &end, &value, 0, max);
292	cb->val.tos_value = value;
293	cb->val.tos_mask  = max;
294
295	if (*end == '/') {
296		const char *p = end + 1;
297
298		if (!xtables_strtoui(p, &end, &value, 0, max))
299			xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"",
300			           str);
301		cb->val.tos_mask = value;
302	}
303
304	if (*end != '\0')
305		xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"", str);
306	return true;
307}
308
309/**
310 * @str:	input string
311 * @tvm:	(value/mask) tuple
312 * @def_mask:	mask to force when a symbolic name is used
313 */
314static void xtopt_parse_tosmask(struct xt_option_call *cb)
315{
316	const struct tos_symbol_info *symbol;
317	char *tmp;
318
319	if (xtables_strtoui(cb->arg, &tmp, NULL, 0, UINT8_MAX)) {
320		tos_parse_numeric(cb->arg, cb, UINT8_MAX);
321		return;
322	}
323	/*
324	 * This is our way we deal with different defaults
325	 * for different revisions.
326	 */
327	cb->val.tos_mask = cb->entry->max;
328	for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
329		if (strcasecmp(cb->arg, symbol->name) == 0) {
330			cb->val.tos_value = symbol->value;
331			return;
332		}
333
334	xtables_error(PARAMETER_PROBLEM, "Symbolic name \"%s\" is unknown",
335		      cb->arg);
336}
337
338/**
339 * Validate the input for being conformant to "mark[/mask]".
340 */
341static void xtopt_parse_markmask(struct xt_option_call *cb)
342{
343	unsigned int mark = 0, mask = ~0U;
344	char *end;
345
346	if (!xtables_strtoui(cb->arg, &end, &mark, 0, UINT32_MAX))
347		xt_params->exit_err(PARAMETER_PROBLEM,
348			"%s: bad mark value for option \"--%s\", "
349			"or out of range.\n",
350			cb->ext_name, cb->entry->name);
351	if (*end == '/' &&
352	    !xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
353		xt_params->exit_err(PARAMETER_PROBLEM,
354			"%s: bad mask value for option \"--%s\", "
355			"or out of range.\n",
356			cb->ext_name, cb->entry->name);
357	if (*end != '\0')
358		xt_params->exit_err(PARAMETER_PROBLEM,
359			"%s: trailing garbage after value "
360			"for option \"--%s\".\n",
361			cb->ext_name, cb->entry->name);
362	cb->val.mark = mark;
363	cb->val.mask = mask;
364}
365
366static int xtopt_sysloglvl_compare(const void *a, const void *b)
367{
368	const char *name = a;
369	const struct syslog_level *entry = b;
370
371	return strcmp(name, entry->name);
372}
373
374static void xtopt_parse_sysloglevel(struct xt_option_call *cb)
375{
376	static const struct syslog_level log_names[] = { /* must be sorted */
377		{"alert",   LOG_ALERT},
378		{"crit",    LOG_CRIT},
379		{"debug",   LOG_DEBUG},
380		{"emerg",   LOG_EMERG},
381		{"error",   LOG_ERR}, /* deprecated */
382		{"info",    LOG_INFO},
383		{"notice",  LOG_NOTICE},
384		{"panic",   LOG_EMERG}, /* deprecated */
385		{"warning", LOG_WARNING},
386	};
387	const struct syslog_level *e;
388	unsigned int num = 0;
389
390	if (!xtables_strtoui(cb->arg, NULL, &num, 0, 7)) {
391		e = bsearch(cb->arg, log_names, ARRAY_SIZE(log_names),
392			    sizeof(*log_names), xtopt_sysloglvl_compare);
393		if (e == NULL)
394			xt_params->exit_err(PARAMETER_PROBLEM,
395				"log level \"%s\" unknown\n", cb->arg);
396		num = e->level;
397	}
398	cb->val.syslog_level = num;
399	if (cb->entry->flags & XTOPT_PUT)
400		*(uint8_t *)XTOPT_MKPTR(cb) = num;
401}
402
403static void *xtables_sa_host(const void *sa, unsigned int afproto)
404{
405	if (afproto == AF_INET6)
406		return &((struct sockaddr_in6 *)sa)->sin6_addr;
407	else if (afproto == AF_INET)
408		return &((struct sockaddr_in *)sa)->sin_addr;
409	return (void *)sa;
410}
411
412static socklen_t xtables_sa_hostlen(unsigned int afproto)
413{
414	if (afproto == AF_INET6)
415		return sizeof(struct in6_addr);
416	else if (afproto == AF_INET)
417		return sizeof(struct in_addr);
418	return 0;
419}
420
421/**
422 * Accepts: a hostname (DNS), or a single inetaddr - without any mask. The
423 * result is stored in @cb->val.haddr. Additionally, @cb->val.hmask and
424 * @cb->val.hlen are set for completeness to the appropriate values.
425 */
426static void xtopt_parse_host(struct xt_option_call *cb)
427{
428	struct addrinfo hints = {.ai_family = afinfo->family};
429	unsigned int adcount = 0;
430	struct addrinfo *res, *p;
431	int ret;
432
433	ret = getaddrinfo(cb->arg, NULL, &hints, &res);
434	if (ret < 0)
435		xt_params->exit_err(PARAMETER_PROBLEM,
436			"getaddrinfo: %s\n", gai_strerror(ret));
437
438	memset(&cb->val.hmask, 0xFF, sizeof(cb->val.hmask));
439	cb->val.hlen = (afinfo->family == NFPROTO_IPV4) ? 32 : 128;
440
441	for (p = res; p != NULL; p = p->ai_next) {
442		if (adcount == 0) {
443			memset(&cb->val.haddr, 0, sizeof(cb->val.haddr));
444			memcpy(&cb->val.haddr,
445			       xtables_sa_host(p->ai_addr, p->ai_family),
446			       xtables_sa_hostlen(p->ai_family));
447			++adcount;
448			continue;
449		}
450		if (memcmp(&cb->val.haddr,
451		    xtables_sa_host(p->ai_addr, p->ai_family),
452		    xtables_sa_hostlen(p->ai_family)) != 0)
453			xt_params->exit_err(PARAMETER_PROBLEM,
454				"%s resolves to more than one address\n",
455				cb->arg);
456	}
457
458	freeaddrinfo(res);
459	if (cb->entry->flags & XTOPT_PUT)
460		/* Validation in xtables_option_metavalidate */
461		memcpy(XTOPT_MKPTR(cb), &cb->val.haddr,
462		       sizeof(cb->val.haddr));
463}
464
465/**
466 * @name:	port name, or number as a string (e.g. "http" or "80")
467 *
468 * Resolve a port name to a number. Returns the port number in integral
469 * form on success, or <0 on error. (errno will not be set.)
470 */
471static int xtables_getportbyname(const char *name)
472{
473	struct addrinfo *res = NULL, *p;
474	int ret;
475
476	ret = getaddrinfo(NULL, name, NULL, &res);
477	if (ret < 0)
478		return -1;
479	ret = -1;
480	for (p = res; p != NULL; p = p->ai_next) {
481		if (p->ai_family == AF_INET6) {
482			ret = ((struct sockaddr_in6 *)p->ai_addr)->sin6_port;
483			break;
484		} else if (p->ai_family == AF_INET) {
485			ret = ((struct sockaddr_in *)p->ai_addr)->sin_port;
486			break;
487		}
488	}
489	freeaddrinfo(res);
490	if (ret < 0)
491		return ret;
492	return ntohs(ret);
493}
494
495/**
496 * Validate and parse a port specification and put the result into
497 * @cb->val.port.
498 */
499static void xtopt_parse_port(struct xt_option_call *cb)
500{
501	int ret;
502
503	ret = xtables_getportbyname(cb->arg);
504	if (ret < 0)
505		xt_params->exit_err(PARAMETER_PROBLEM,
506			"Port \"%s\" does not resolve to anything.\n",
507			cb->arg);
508	cb->val.port = ret;
509	if (cb->entry->type == XTTYPE_PORT_NE)
510		cb->val.port = htons(cb->val.port);
511	if (cb->entry->flags & XTOPT_PUT)
512		*(uint16_t *)XTOPT_MKPTR(cb) = cb->val.port;
513}
514
515static void xtopt_parse_mport(struct xt_option_call *cb)
516{
517	static const size_t esize = sizeof(uint16_t);
518	const struct xt_option_entry *entry = cb->entry;
519	char *lo_arg, *wp_arg, *arg;
520	unsigned int maxiter;
521	int value;
522
523	wp_arg = lo_arg = strdup(cb->arg);
524	if (lo_arg == NULL)
525		xt_params->exit_err(RESOURCE_PROBLEM, "strdup");
526
527	maxiter = entry->size / esize;
528	if (maxiter == 0)
529		maxiter = 2; /* ARRAY_SIZE(cb->val.port_range) */
530	if (entry->size % esize != 0)
531		xt_params->exit_err(OTHER_PROBLEM, "%s: memory block does "
532			"not have proper size\n", __func__);
533
534	cb->val.port_range[0] = 0;
535	cb->val.port_range[1] = UINT16_MAX;
536	cb->nvals = 0;
537
538	while ((arg = strsep(&wp_arg, ":")) != NULL) {
539		if (cb->nvals == maxiter)
540			xt_params->exit_err(PARAMETER_PROBLEM, "%s: Too many "
541				"components for option \"--%s\" (max: %u)\n",
542				cb->ext_name, entry->name, maxiter);
543		if (*arg == '\0') {
544			++cb->nvals;
545			continue;
546		}
547
548		value = xtables_getportbyname(arg);
549		if (value < 0)
550			xt_params->exit_err(PARAMETER_PROBLEM,
551				"Port \"%s\" does not resolve to "
552				"anything.\n", arg);
553		if (entry->type == XTTYPE_PORTRC_NE)
554			value = htons(value);
555		if (cb->nvals < ARRAY_SIZE(cb->val.port_range))
556			cb->val.port_range[cb->nvals] = value;
557		++cb->nvals;
558	}
559
560	if (cb->nvals == 1) {
561		cb->val.port_range[1] = cb->val.port_range[0];
562		++cb->nvals;
563	}
564	if (entry->flags & XTOPT_PUT)
565		memcpy(XTOPT_MKPTR(cb), cb->val.port_range, sizeof(uint16_t) *
566		       (cb->nvals <= maxiter ? cb->nvals : maxiter));
567	free(lo_arg);
568}
569
570/**
571 * Parse an integer and ensure it is within the address family's prefix length
572 * limits. The result is stored in @cb->val.hlen.
573 */
574static void xtopt_parse_plen(struct xt_option_call *cb)
575{
576	const struct xt_option_entry *entry = cb->entry;
577	unsigned int prefix_len = 128; /* happiness is a warm gcc */
578
579	cb->val.hlen = (afinfo->family == NFPROTO_IPV4) ? 32 : 128;
580	if (!xtables_strtoui(cb->arg, NULL, &prefix_len, 0, cb->val.hlen))
581		xt_params->exit_err(PARAMETER_PROBLEM,
582			"%s: bad value for option \"--%s\", "
583			"or out of range (%u-%u).\n",
584			cb->ext_name, entry->name, 0, cb->val.hlen);
585
586	cb->val.hlen = prefix_len;
587}
588
589/**
590 * Reuse xtopt_parse_plen for testing the integer. Afterwards convert this to
591 * a bitmask, and make it available through @cb->val.hmask (hlen remains
592 * valid). If %XTOPT_PUT is used, hmask will be copied to the target area.
593 */
594static void xtopt_parse_plenmask(struct xt_option_call *cb)
595{
596	const struct xt_option_entry *entry = cb->entry;
597	uint32_t *mask = cb->val.hmask.all;
598
599	xtopt_parse_plen(cb);
600
601	memset(mask, 0xFF, sizeof(union nf_inet_addr));
602	/* This shifting is AF-independent. */
603	if (cb->val.hlen == 0) {
604		mask[0] = mask[1] = mask[2] = mask[3] = 0;
605	} else if (cb->val.hlen <= 32) {
606		mask[0] <<= 32 - cb->val.hlen;
607		mask[1] = mask[2] = mask[3] = 0;
608	} else if (cb->val.hlen <= 64) {
609		mask[1] <<= 32 - (cb->val.hlen - 32);
610		mask[2] = mask[3] = 0;
611	} else if (cb->val.hlen <= 96) {
612		mask[2] <<= 32 - (cb->val.hlen - 64);
613		mask[3] = 0;
614	} else if (cb->val.hlen <= 128) {
615		mask[3] <<= 32 - (cb->val.hlen - 96);
616	}
617	mask[0] = htonl(mask[0]);
618	mask[1] = htonl(mask[1]);
619	mask[2] = htonl(mask[2]);
620	mask[3] = htonl(mask[3]);
621	if (entry->flags & XTOPT_PUT)
622		memcpy(XTOPT_MKPTR(cb), mask, sizeof(union nf_inet_addr));
623}
624
625static void (*const xtopt_subparse[])(struct xt_option_call *) = {
626	[XTTYPE_UINT8]       = xtopt_parse_int,
627	[XTTYPE_UINT16]      = xtopt_parse_int,
628	[XTTYPE_UINT32]      = xtopt_parse_int,
629	[XTTYPE_UINT64]      = xtopt_parse_int,
630	[XTTYPE_UINT8RC]     = xtopt_parse_mint,
631	[XTTYPE_UINT16RC]    = xtopt_parse_mint,
632	[XTTYPE_UINT32RC]    = xtopt_parse_mint,
633	[XTTYPE_UINT64RC]    = xtopt_parse_mint,
634	[XTTYPE_DOUBLE]      = xtopt_parse_float,
635	[XTTYPE_STRING]      = xtopt_parse_string,
636	[XTTYPE_TOSMASK]     = xtopt_parse_tosmask,
637	[XTTYPE_MARKMASK32]  = xtopt_parse_markmask,
638	[XTTYPE_SYSLOGLEVEL] = xtopt_parse_sysloglevel,
639	[XTTYPE_HOST]        = xtopt_parse_host,
640	[XTTYPE_PORT]        = xtopt_parse_port,
641	[XTTYPE_PORT_NE]     = xtopt_parse_port,
642	[XTTYPE_PORTRC]      = xtopt_parse_mport,
643	[XTTYPE_PORTRC_NE]   = xtopt_parse_mport,
644	[XTTYPE_PLEN]        = xtopt_parse_plen,
645	[XTTYPE_PLENMASK]    = xtopt_parse_plenmask,
646};
647
648static const size_t xtopt_psize[] = {
649	/*
650	 * All types not listed here, and thus essentially being initialized to
651	 * zero have zero on purpose.
652	 */
653	[XTTYPE_UINT8]       = sizeof(uint8_t),
654	[XTTYPE_UINT16]      = sizeof(uint16_t),
655	[XTTYPE_UINT32]      = sizeof(uint32_t),
656	[XTTYPE_UINT64]      = sizeof(uint64_t),
657	[XTTYPE_UINT8RC]     = sizeof(uint8_t[2]),
658	[XTTYPE_UINT16RC]    = sizeof(uint16_t[2]),
659	[XTTYPE_UINT32RC]    = sizeof(uint32_t[2]),
660	[XTTYPE_UINT64RC]    = sizeof(uint64_t[2]),
661	[XTTYPE_DOUBLE]      = sizeof(double),
662	[XTTYPE_STRING]      = -1,
663	[XTTYPE_SYSLOGLEVEL] = sizeof(uint8_t),
664	[XTTYPE_HOST]        = sizeof(union nf_inet_addr),
665	[XTTYPE_PORT]        = sizeof(uint16_t),
666	[XTTYPE_PORT_NE]     = sizeof(uint16_t),
667	[XTTYPE_PORTRC]      = sizeof(uint16_t[2]),
668	[XTTYPE_PORTRC_NE]   = sizeof(uint16_t[2]),
669	[XTTYPE_PLENMASK]    = sizeof(union nf_inet_addr),
670};
671
672/**
673 * The master option parsing routine. May be used for the ".x6_parse"
674 * function pointer in extensions if fully automatic parsing is desired.
675 * It may be also called manually from a custom x6_parse function.
676 */
677void xtables_option_parse(struct xt_option_call *cb)
678{
679	const struct xt_option_entry *entry = cb->entry;
680	unsigned int eflag = 1 << cb->entry->id;
681
682	/*
683	 * With {.id = P_FOO, .excl = P_FOO} we can have simple double-use
684	 * prevention. Though it turned out that this is too much typing (most
685	 * of the options are one-time use only), so now we also have
686	 * %XTOPT_MULTI.
687	 */
688	if ((!(entry->flags & XTOPT_MULTI) || (entry->excl & eflag)) &&
689	    cb->xflags & eflag)
690		xt_params->exit_err(PARAMETER_PROBLEM,
691			"%s: option \"--%s\" can only be used once.\n",
692			cb->ext_name, cb->entry->name);
693	if (cb->invert && !(entry->flags & XTOPT_INVERT))
694		xt_params->exit_err(PARAMETER_PROBLEM,
695			"%s: option \"--%s\" cannot be inverted.\n",
696			cb->ext_name, entry->name);
697	if (entry->type != XTTYPE_NONE && optarg == NULL)
698		xt_params->exit_err(PARAMETER_PROBLEM,
699			"%s: option \"--%s\" requires an argument.\n",
700			cb->ext_name, entry->name);
701	if (entry->type <= ARRAY_SIZE(xtopt_subparse) &&
702	    xtopt_subparse[entry->type] != NULL)
703		xtopt_subparse[entry->type](cb);
704	/* Exclusion with other flags tested later in finalize. */
705	cb->xflags |= 1 << entry->id;
706}
707
708/**
709 * Verifies that an extension's option map descriptor is valid, and ought to
710 * be called right after the extension has been loaded, and before option
711 * merging/xfrm.
712 */
713void xtables_option_metavalidate(const char *name,
714				 const struct xt_option_entry *entry)
715{
716	for (; entry->name != NULL; ++entry) {
717		if (entry->id >= CHAR_BIT * sizeof(unsigned int) ||
718		    entry->id >= XT_OPTION_OFFSET_SCALE)
719			xt_params->exit_err(OTHER_PROBLEM,
720				"Extension %s uses invalid ID %u\n",
721				name, entry->id);
722		if (!(entry->flags & XTOPT_PUT))
723			continue;
724		if (entry->type >= ARRAY_SIZE(xtopt_psize) ||
725		    xtopt_psize[entry->type] == 0)
726			xt_params->exit_err(OTHER_PROBLEM,
727				"%s: entry type of option \"--%s\" cannot be "
728				"combined with XTOPT_PUT\n",
729				name, entry->name);
730		if (xtopt_psize[entry->type] != -1 &&
731		    xtopt_psize[entry->type] != entry->size)
732			xt_params->exit_err(OTHER_PROBLEM,
733				"%s: option \"--%s\" points to a memory block "
734				"of wrong size (expected %zu, got %zu)\n",
735				name, entry->name,
736				xtopt_psize[entry->type], entry->size);
737	}
738}
739
740/**
741 * Find an option entry by its id.
742 */
743static const struct xt_option_entry *
744xtables_option_lookup(const struct xt_option_entry *entry, unsigned int id)
745{
746	for (; entry->name != NULL; ++entry)
747		if (entry->id == id)
748			return entry;
749	return NULL;
750}
751
752/**
753 * @c:		getopt id (i.e. with offset)
754 * @fw:		struct ipt_entry or ip6t_entry
755 *
756 * Dispatch arguments to the appropriate parse function, based upon the
757 * extension's choice of API.
758 */
759void xtables_option_tpcall(unsigned int c, char **argv, bool invert,
760			   struct xtables_target *t, void *fw)
761{
762	struct xt_option_call cb;
763
764	if (t->x6_parse == NULL) {
765		if (t->parse != NULL)
766			t->parse(c - t->option_offset, argv, invert,
767				 &t->tflags, fw, &t->t);
768		return;
769	}
770
771	c -= t->option_offset;
772	cb.entry = xtables_option_lookup(t->x6_options, c);
773	if (cb.entry == NULL)
774		xtables_error(OTHER_PROBLEM,
775			"Extension does not know id %u\n", c);
776	cb.arg      = optarg;
777	cb.invert   = invert;
778	cb.ext_name = t->name;
779	cb.data     = t->t->data;
780	cb.xflags   = t->tflags;
781	cb.target   = &t->t;
782	t->x6_parse(&cb);
783	t->tflags = cb.xflags;
784}
785
786/**
787 * @c:		getopt id (i.e. with offset)
788 * @fw:		struct ipt_entry or ip6t_entry
789 *
790 * Dispatch arguments to the appropriate parse function, based upon the
791 * extension's choice of API.
792 */
793void xtables_option_mpcall(unsigned int c, char **argv, bool invert,
794			   struct xtables_match *m, void *fw)
795{
796	struct xt_option_call cb;
797
798	if (m->x6_parse == NULL) {
799		if (m->parse != NULL)
800			m->parse(c - m->option_offset, argv, invert,
801				 &m->mflags, fw, &m->m);
802		return;
803	}
804
805	c -= m->option_offset;
806	cb.entry = xtables_option_lookup(m->x6_options, c);
807	if (cb.entry == NULL)
808		xtables_error(OTHER_PROBLEM,
809			"Extension does not know id %u\n", c);
810	cb.arg      = optarg;
811	cb.invert   = invert;
812	cb.ext_name = m->name;
813	cb.data     = m->m->data;
814	cb.xflags   = m->mflags;
815	cb.match    = &m->m;
816	m->x6_parse(&cb);
817	m->mflags = cb.xflags;
818}
819
820/**
821 * @name:	name of extension
822 * @entry:	current option (from all ext's entries) being validated
823 * @xflags:	flags the extension has collected
824 * @i:		conflicting option (id) to test for
825 */
826static void
827xtables_option_fcheck2(const char *name, const struct xt_option_entry *entry,
828		       const struct xt_option_entry *other,
829		       unsigned int xflags)
830{
831	unsigned int ef = 1 << entry->id, of = 1 << other->id;
832
833	if (entry->also & of && !(xflags & of))
834		xt_params->exit_err(PARAMETER_PROBLEM,
835			"%s: option \"--%s\" also requires \"--%s\".\n",
836			name, entry->name, other->name);
837
838	if (!(entry->excl & of))
839		/* Use of entry does not collide with other option, good. */
840		return;
841	if ((xflags & (ef | of)) != (ef | of))
842		/* Conflicting options were not used. */
843		return;
844
845	xt_params->exit_err(PARAMETER_PROBLEM,
846		"%s: option \"--%s\" cannot be used together with \"--%s\".\n",
847		name, entry->name, other->name);
848}
849
850/**
851 * @name:	name of extension
852 * @xflags:	accumulated flags
853 * @entry:	extension's option table
854 *
855 * Check that all option constraints have been met. This effectively replaces
856 * ->final_check of the older API.
857 */
858void xtables_options_fcheck(const char *name, unsigned int xflags,
859			    const struct xt_option_entry *table)
860{
861	const struct xt_option_entry *entry, *other;
862	unsigned int i;
863
864	for (entry = table; entry->name != NULL; ++entry) {
865		if (entry->flags & XTOPT_MAND &&
866		    !(xflags & (1 << entry->id)))
867			xt_params->exit_err(PARAMETER_PROBLEM,
868				"%s: option \"--%s\" must be specified\n",
869				name, entry->name);
870
871		for (i = 0; i < CHAR_BIT * sizeof(entry->id); ++i) {
872			if (entry->id == i)
873				/*
874				 * Avoid conflict with self. Multi-use check
875				 * was done earlier in xtables_option_parse.
876				 */
877				continue;
878			other = xtables_option_lookup(table, i);
879			if (other == NULL)
880				continue;
881			xtables_option_fcheck2(name, entry, other, xflags);
882		}
883	}
884}
885
886/**
887 * Dispatch arguments to the appropriate final_check function, based upon the
888 * extension's choice of API.
889 */
890void xtables_option_tfcall(struct xtables_target *t)
891{
892	if (t->x6_fcheck != NULL) {
893		struct xt_fcheck_call cb;
894
895		cb.ext_name = t->name;
896		cb.data     = t->t->data;
897		cb.xflags   = t->tflags;
898		t->x6_fcheck(&cb);
899	} else if (t->final_check != NULL) {
900		t->final_check(t->tflags);
901	}
902	if (t->x6_options != NULL)
903		xtables_options_fcheck(t->name, t->tflags, t->x6_options);
904}
905
906/**
907 * Dispatch arguments to the appropriate final_check function, based upon the
908 * extension's choice of API.
909 */
910void xtables_option_mfcall(struct xtables_match *m)
911{
912	if (m->x6_fcheck != NULL) {
913		struct xt_fcheck_call cb;
914
915		cb.ext_name = m->name;
916		cb.data     = m->m->data;
917		cb.xflags   = m->mflags;
918		m->x6_fcheck(&cb);
919	} else if (m->final_check != NULL) {
920		m->final_check(m->mflags);
921	}
922	if (m->x6_options != NULL)
923		xtables_options_fcheck(m->name, m->mflags, m->x6_options);
924}
925
926struct xtables_lmap *xtables_lmap_init(const char *file)
927{
928	struct xtables_lmap *lmap_head = NULL, *lmap_prev = NULL, *lmap_this;
929	char buf[512];
930	FILE *fp;
931	char *cur, *nxt;
932	int id;
933
934	fp = fopen(file, "re");
935	if (fp == NULL)
936		return NULL;
937
938	while (fgets(buf, sizeof(buf), fp) != NULL) {
939		cur = buf;
940		while (isspace(*cur))
941			++cur;
942		if (*cur == '#' || *cur == '\n' || *cur == '\0')
943			continue;
944
945		/* iproute2 allows hex and dec format */
946		errno = 0;
947		id = strtoul(cur, &nxt, strncmp(cur, "0x", 2) == 0 ? 16 : 10);
948		if (nxt == cur || errno != 0)
949			continue;
950
951		/* same boundaries as in iproute2 */
952		if (id < 0 || id > 255)
953			continue;
954		cur = nxt;
955
956		if (!isspace(*cur))
957			continue;
958		while (isspace(*cur))
959			++cur;
960		if (*cur == '#' || *cur == '\n' || *cur == '\0')
961			continue;
962		nxt = cur;
963		while (*nxt != '\0' && !isspace(*nxt))
964			++nxt;
965		if (nxt == cur)
966			continue;
967		*nxt = '\0';
968
969		/* found valid data */
970		lmap_this = malloc(sizeof(*lmap_this));
971		if (lmap_this == NULL) {
972			perror("malloc");
973			goto out;
974		}
975		lmap_this->id   = id;
976		lmap_this->name = strdup(cur);
977		if (lmap_this->name == NULL) {
978			free(lmap_this);
979			goto out;
980		}
981		lmap_this->next = NULL;
982
983		if (lmap_prev != NULL)
984			lmap_prev->next = lmap_this;
985		else
986			lmap_head = lmap_this;
987		lmap_prev = lmap_this;
988	}
989
990	fclose(fp);
991	return lmap_head;
992 out:
993	xtables_lmap_free(lmap_head);
994	return NULL;
995}
996
997void xtables_lmap_free(struct xtables_lmap *head)
998{
999	struct xtables_lmap *next;
1000
1001	for (; head != NULL; head = next) {
1002		next = head->next;
1003		free(head->name);
1004		free(head);
1005	}
1006}
1007
1008int xtables_lmap_name2id(const struct xtables_lmap *head, const char *name)
1009{
1010	for (; head != NULL; head = head->next)
1011		if (strcmp(head->name, name) == 0)
1012			return head->id;
1013	return -1;
1014}
1015
1016const char *xtables_lmap_id2name(const struct xtables_lmap *head, int id)
1017{
1018	for (; head != NULL; head = head->next)
1019		if (head->id == id)
1020			return head->name;
1021	return NULL;
1022}
1023