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