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