xtoptions.c revision dfe99f1bf291b4b954d3608dbe95a43e16a8bb49
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	Argument parser
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	Copyright © Jan Engelhardt, 2011
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	This program is free software; you can redistribute it and/or
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	modify it under the terms of the GNU General Public License as
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *	published by the Free Software Foundation; either version 2 of
8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *	the License, or (at your option) any later version.
9d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) */
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <errno.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <getopt.h>
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <limits.h>
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <netdb.h>
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <stdbool.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdint.h>
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <stdio.h>
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include <stdlib.h>
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <string.h>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <arpa/inet.h>
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "xtables.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "xshared.h"
22558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define XTOPT_MKPTR(cb) \
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	((void *)((char *)(cb)->data + (cb)->entry->ptroff))
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/**
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Creates getopt options from the x6-style option map, and assigns each a
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * getopt id.
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct option *
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)xtables_options_xfrm(struct option *orig_opts, struct option *oldopts,
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)		     const struct xt_option_entry *entry, unsigned int *offset)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int num_orig, num_old = 0, num_new, i;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct option *merge, *mp;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (entry == NULL)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return oldopts;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (num_orig = 0; orig_opts[num_orig].name != NULL; ++num_orig)
4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		;
4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (oldopts != NULL)
42bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch		for (num_old = 0; oldopts[num_old].name != NULL; ++num_old)
43bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch			;
44bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch	for (num_new = 0; entry[num_new].name != NULL; ++num_new)
45bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch		;
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Since @oldopts also has @orig_opts already (and does so at the
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)	 * start), skip these entries.
50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)	 */
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	oldopts += num_orig;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	num_old -= num_orig;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)	merge = malloc(sizeof(*mp) * (num_orig + num_old + num_new + 1));
55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)	if (merge == NULL)
56a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)		return NULL;
57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
58a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)	/* Let the base options -[ADI...] have precedence over everything */
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	memcpy(merge, orig_opts, sizeof(*mp) * num_orig);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	mp = merge + num_orig;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Second, the new options */
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	*offset = xt_params->option_offset;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)	for (i = 0; i < num_new; ++i, ++mp, ++entry) {
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		mp->name         = entry->name;
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		mp->has_arg      = entry->type != XTTYPE_NONE;
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		mp->flag         = NULL;
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		mp->val          = entry->id + *offset;
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	/* Third, the old options */
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	memcpy(mp, oldopts, sizeof(*mp) * num_old);
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	mp += num_old;
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	xtables_free_opts(0);
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	/* Clear trailing entry */
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	memset(mp, 0, sizeof(*mp));
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return merge;
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/**
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Require a simple integer.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void xtopt_parse_int(struct xt_option_call *cb)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const struct xt_option_entry *entry = cb->entry;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int lmin = 0, lmax = UINT32_MAX;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int value;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (entry->type == XTTYPE_UINT8)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		lmax = UINT8_MAX;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (cb->entry->min != 0)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		lmin = cb->entry->min;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (cb->entry->max != 0)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		lmax = cb->entry->max;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (!xtables_strtoui(cb->arg, NULL, &value, lmin, lmax))
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		xt_params->exit_err(PARAMETER_PROBLEM,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"%s: bad value for option \"--%s\", "
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"or out of range (%u-%u).\n",
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			cb->ext_name, entry->name, lmin, lmax);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (entry->type == XTTYPE_UINT8) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		cb->val.u8 = value;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		if (entry->flags & XTOPT_PUT)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			*(uint8_t *)XTOPT_MKPTR(cb) = cb->val.u8;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	} else if (entry->type == XTTYPE_UINT32) {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		cb->val.u32 = value;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		if (entry->flags & XTOPT_PUT)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			*(uint32_t *)XTOPT_MKPTR(cb) = cb->val.u32;
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	}
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void (*const xtopt_subparse[])(struct xt_option_call *) = {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	[XTTYPE_UINT8]       = xtopt_parse_int,
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	[XTTYPE_UINT32]      = xtopt_parse_int,
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const size_t xtopt_psize[] = {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	[XTTYPE_UINT8]       = sizeof(uint8_t),
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	[XTTYPE_UINT32]      = sizeof(uint32_t),
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * The master option parsing routine. May be used for the ".x6_parse"
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * function pointer in extensions if fully automatic parsing is desired.
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * It may be also called manually from a custom x6_parse function.
130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) */
131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void xtables_option_parse(struct xt_option_call *cb)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	const struct xt_option_entry *entry = cb->entry;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	unsigned int eflag = 1 << cb->entry->id;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	/*
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 * With {.id = P_FOO, .excl = P_FOO} we can have simple double-use
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 * prevention. Though it turned out that this is too much typing (most
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 * of the options are one-time use only), so now we also have
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 * %XTOPT_MULTI.
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 */
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if ((!(entry->flags & XTOPT_MULTI) || (entry->excl & eflag)) &&
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	    cb->xflags & eflag)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		xt_params->exit_err(PARAMETER_PROBLEM,
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			"%s: option \"--%s\" can only be used once.\n",
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			cb->ext_name, cb->entry->name);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (cb->invert && !(entry->flags & XTOPT_INVERT))
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		xt_params->exit_err(PARAMETER_PROBLEM,
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			"%s: option \"--%s\" cannot be inverted.\n",
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			cb->ext_name, entry->name);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (entry->type != XTTYPE_NONE && optarg == NULL)
152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)		xt_params->exit_err(PARAMETER_PROBLEM,
153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			"%s: option \"--%s\" requires an argument.\n",
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			cb->ext_name, entry->name);
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (entry->type <= ARRAY_SIZE(xtopt_subparse) &&
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	    xtopt_subparse[entry->type] != NULL)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		xtopt_subparse[entry->type](cb);
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	/* Exclusion with other flags tested later in finalize. */
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	cb->xflags |= 1 << entry->id;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * Verifies that an extension's option map descriptor is valid, and ought to
164d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * be called right after the extension has been loaded, and before option
165d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * merging/xfrm.
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void xtables_option_metavalidate(const char *name,
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				 const struct xt_option_entry *entry)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	for (; entry->name != NULL; ++entry) {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		if (entry->id >= CHAR_BIT * sizeof(unsigned int) ||
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		    entry->id >= XT_OPTION_OFFSET_SCALE)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			xt_params->exit_err(OTHER_PROBLEM,
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				"Extension %s uses invalid ID %u\n",
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				name, entry->id);
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		if (!(entry->flags & XTOPT_PUT))
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			continue;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (entry->type >= ARRAY_SIZE(xtopt_psize))
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			xt_params->exit_err(OTHER_PROBLEM,
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				"%s: entry type of option \"--%s\" cannot be "
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				"combined with XTOPT_PUT\n",
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				name, entry->name);
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		if (xtopt_psize[entry->type] != entry->size)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			xt_params->exit_err(OTHER_PROBLEM,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				"%s: option \"--%s\" points to a memory block "
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				"of wrong size (expected %zu, got %zu)\n",
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)				name, entry->name,
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				xtopt_psize[entry->type], entry->size);
1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)	}
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
193d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * Find an option entry by its id.
194d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) */
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const struct xt_option_entry *
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)xtables_option_lookup(const struct xt_option_entry *entry, unsigned int id)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	for (; entry->name != NULL; ++entry)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		if (entry->id == id)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			return entry;
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	return NULL;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @c:		getopt id (i.e. with offset)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @fw:		struct ipt_entry or ip6t_entry
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Dispatch arguments to the appropriate parse function, based upon the
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * extension's choice of API.
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void xtables_option_tpcall(unsigned int c, char **argv, bool invert,
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			   struct xtables_target *t, void *fw)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	struct xt_option_call cb;
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (t->x6_parse == NULL) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		if (t->parse != NULL)
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			t->parse(c - t->option_offset, argv, invert,
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				 &t->tflags, fw, &t->t);
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		return;
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	}
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	c -= t->option_offset;
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	cb.entry = xtables_option_lookup(t->x6_options, c);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (cb.entry == NULL)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		xtables_error(OTHER_PROBLEM,
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			"Extension does not know id %u\n", c);
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	cb.arg      = optarg;
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	cb.invert   = invert;
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	cb.ext_name = t->name;
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	cb.data     = t->t->data;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cb.xflags   = t->tflags;
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	t->x6_parse(&cb);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	t->tflags = cb.xflags;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @c:		getopt id (i.e. with offset)
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @fw:		struct ipt_entry or ip6t_entry
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Dispatch arguments to the appropriate parse function, based upon the
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * extension's choice of API.
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void xtables_option_mpcall(unsigned int c, char **argv, bool invert,
245d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			   struct xtables_match *m, void *fw)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct xt_option_call cb;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (m->x6_parse == NULL) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (m->parse != NULL)
251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			m->parse(c - m->option_offset, argv, invert,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				 &m->mflags, fw, &m->m);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)	c -= m->option_offset;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cb.entry = xtables_option_lookup(m->x6_options, c);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (cb.entry == NULL)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		xtables_error(OTHER_PROBLEM,
260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			"Extension does not know id %u\n", c);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cb.arg      = optarg;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cb.invert   = invert;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cb.ext_name = m->name;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cb.data     = m->m->data;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cb.xflags   = m->mflags;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	m->x6_parse(&cb);
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	m->mflags = cb.xflags;
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @name:	name of extension
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @entry:	current option (from all ext's entries) being validated
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @xflags:	flags the extension has collected
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @i:		conflicting option (id) to test for
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)xtables_option_fcheck2(const char *name, const struct xt_option_entry *entry,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		       const struct xt_option_entry *other,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		       unsigned int xflags)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int ef = 1 << entry->id, of = 1 << other->id;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	if (entry->also & of && !(xflags & of))
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		xt_params->exit_err(PARAMETER_PROBLEM,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"%s: option \"--%s\" also requires \"--%s\".\n",
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)			name, entry->name, other->name);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!(entry->excl & of))
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Use of entry does not collide with other option, good. */
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if ((xflags & (ef | of)) != (ef | of))
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Conflicting options were not used. */
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xt_params->exit_err(PARAMETER_PROBLEM,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		"%s: option \"--%s\" cannot be used together with \"--%s\".\n",
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		name, entry->name, other->name);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
299010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
300010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)/**
301010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @name:	name of extension
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @xflags:	accumulated flags
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @entry:	extension's option table
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Check that all option constraints have been met. This effectively replaces
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ->final_check of the older API.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void xtables_options_fcheck(const char *name, unsigned int xflags,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			    const struct xt_option_entry *table)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const struct xt_option_entry *entry, *other;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int i;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)	for (entry = table; entry->name != NULL; ++entry) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (entry->flags & XTOPT_MAND &&
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    !(xflags & (1 << entry->id)))
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			xt_params->exit_err(PARAMETER_PROBLEM,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				"%s: option \"--%s\" must be specified\n",
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				name, entry->name);
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		for (i = 0; i < CHAR_BIT * sizeof(entry->id); ++i) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (entry->id == i)
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)				/*
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				 * Avoid conflict with self. Multi-use check
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				 * was done earlier in xtables_option_parse.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				 */
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				continue;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			other = xtables_option_lookup(table, i);
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)			if (other == NULL)
330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)				continue;
331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)			xtables_option_fcheck2(name, entry, other, xflags);
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		}
333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	}
334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Dispatch arguments to the appropriate final_check function, based upon the
338868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * extension's choice of API.
339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void xtables_option_tfcall(struct xtables_target *t)
341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){
342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	if (t->x6_fcheck != NULL) {
343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		struct xt_fcheck_call cb;
344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		cb.ext_name = t->name;
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		cb.data     = t->t->data;
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		cb.xflags   = t->tflags;
348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		t->x6_fcheck(&cb);
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	} else if (t->final_check != NULL) {
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		t->final_check(t->tflags);
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	}
352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	if (t->x6_options != NULL)
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		xtables_options_fcheck(t->name, t->tflags, t->x6_options);
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Dispatch arguments to the appropriate final_check function, based upon the
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * extension's choice of API.
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void xtables_option_mfcall(struct xtables_match *m)
361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){
362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	if (m->x6_fcheck != NULL) {
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		struct xt_fcheck_call cb;
364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		cb.ext_name = m->name;
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		cb.data     = m->m->data;
367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		cb.xflags   = m->mflags;
368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		m->x6_fcheck(&cb);
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	} else if (m->final_check != NULL) {
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)		m->final_check(m->mflags);
371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	}
372868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	if (m->x6_options != NULL)
373868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		xtables_options_fcheck(m->name, m->mflags, m->x6_options);
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)