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