xtoptions.c revision 44517bda3d8130638882f69478a8091316f30cbb
1/* 2 * Argument parser 3 * Copyright © Jan Engelhardt, 2011 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of 8 * the License, or (at your option) any later version. 9 */ 10#include <ctype.h> 11#include <errno.h> 12#include <getopt.h> 13#include <limits.h> 14#include <netdb.h> 15#include <stdbool.h> 16#include <stdint.h> 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20#include <syslog.h> 21#include <arpa/inet.h> 22#include "xtables.h" 23#include "xshared.h" 24 25#define XTOPT_MKPTR(cb) \ 26 ((void *)((char *)(cb)->data + (cb)->entry->ptroff)) 27 28/** 29 * Simple key-value pairs for syslog levels 30 */ 31struct syslog_level { 32 char name[8]; 33 uint8_t level; 34}; 35 36/** 37 * Creates getopt options from the x6-style option map, and assigns each a 38 * getopt id. 39 */ 40struct option * 41xtables_options_xfrm(struct option *orig_opts, struct option *oldopts, 42 const struct xt_option_entry *entry, unsigned int *offset) 43{ 44 unsigned int num_orig, num_old = 0, num_new, i; 45 struct option *merge, *mp; 46 47 if (entry == NULL) 48 return oldopts; 49 for (num_orig = 0; orig_opts[num_orig].name != NULL; ++num_orig) 50 ; 51 if (oldopts != NULL) 52 for (num_old = 0; oldopts[num_old].name != NULL; ++num_old) 53 ; 54 for (num_new = 0; entry[num_new].name != NULL; ++num_new) 55 ; 56 57 /* 58 * Since @oldopts also has @orig_opts already (and does so at the 59 * start), skip these entries. 60 */ 61 oldopts += num_orig; 62 num_old -= num_orig; 63 64 merge = malloc(sizeof(*mp) * (num_orig + num_old + num_new + 1)); 65 if (merge == NULL) 66 return NULL; 67 68 /* Let the base options -[ADI...] have precedence over everything */ 69 memcpy(merge, orig_opts, sizeof(*mp) * num_orig); 70 mp = merge + num_orig; 71 72 /* Second, the new options */ 73 xt_params->option_offset += XT_OPTION_OFFSET_SCALE; 74 *offset = xt_params->option_offset; 75 76 for (i = 0; i < num_new; ++i, ++mp, ++entry) { 77 mp->name = entry->name; 78 mp->has_arg = entry->type != XTTYPE_NONE; 79 mp->flag = NULL; 80 mp->val = entry->id + *offset; 81 } 82 83 /* Third, the old options */ 84 memcpy(mp, oldopts, sizeof(*mp) * num_old); 85 mp += num_old; 86 xtables_free_opts(0); 87 88 /* Clear trailing entry */ 89 memset(mp, 0, sizeof(*mp)); 90 return merge; 91} 92 93/** 94 * Require a simple integer. 95 */ 96static void xtopt_parse_int(struct xt_option_call *cb) 97{ 98 const struct xt_option_entry *entry = cb->entry; 99 unsigned long long lmin = 0, lmax = UINT32_MAX; 100 unsigned int value; 101 102 if (entry->type == XTTYPE_UINT8) 103 lmax = UINT8_MAX; 104 else if (entry->type == XTTYPE_UINT16) 105 lmax = UINT16_MAX; 106 else if (entry->type == XTTYPE_UINT64) 107 lmax = UINT64_MAX; 108 if (cb->entry->min != 0) 109 lmin = cb->entry->min; 110 if (cb->entry->max != 0) 111 lmax = cb->entry->max; 112 113 if (!xtables_strtoui(cb->arg, NULL, &value, lmin, lmax)) 114 xt_params->exit_err(PARAMETER_PROBLEM, 115 "%s: bad value for option \"--%s\", " 116 "or out of range (%llu-%llu).\n", 117 cb->ext_name, entry->name, lmin, lmax); 118 119 if (entry->type == XTTYPE_UINT8) { 120 cb->val.u8 = value; 121 if (entry->flags & XTOPT_PUT) 122 *(uint8_t *)XTOPT_MKPTR(cb) = cb->val.u8; 123 } else if (entry->type == XTTYPE_UINT16) { 124 cb->val.u16 = value; 125 if (entry->flags & XTOPT_PUT) 126 *(uint16_t *)XTOPT_MKPTR(cb) = cb->val.u16; 127 } else if (entry->type == XTTYPE_UINT32) { 128 cb->val.u32 = value; 129 if (entry->flags & XTOPT_PUT) 130 *(uint32_t *)XTOPT_MKPTR(cb) = cb->val.u32; 131 } else if (entry->type == XTTYPE_UINT64) { 132 cb->val.u64 = value; 133 if (entry->flags & XTOPT_PUT) 134 *(uint64_t *)XTOPT_MKPTR(cb) = cb->val.u64; 135 } 136} 137 138/** 139 * Multiple integer parse routine. 140 * 141 * This function is capable of parsing any number of fields. Only the first 142 * two values from the string will be put into @cb however (and as such, 143 * @cb->val.uXX_range is just that large) to cater for the few extensions that 144 * do not have a range[2] field, but {min, max}, and which cannot use 145 * XTOPT_POINTER. 146 */ 147static void xtopt_parse_mint(struct xt_option_call *cb) 148{ 149 const struct xt_option_entry *entry = cb->entry; 150 const char *arg = cb->arg; 151 size_t esize = sizeof(uint32_t); 152 char *put = XTOPT_MKPTR(cb); 153 unsigned int maxiter, value; 154 char *end = ""; 155 char sep = ':'; 156 157 if (entry->type == XTTYPE_UINT8RC) 158 esize = sizeof(uint8_t); 159 else if (entry->type == XTTYPE_UINT16RC) 160 esize = sizeof(uint16_t); 161 else if (entry->type == XTTYPE_UINT64RC) 162 esize = sizeof(uint64_t); 163 maxiter = entry->size / esize; 164 if (maxiter == 0) 165 maxiter = 2; /* ARRAY_SIZE(cb->val.uXX_range) */ 166 if (entry->size % esize != 0) 167 xt_params->exit_err(OTHER_PROBLEM, "%s: memory block does " 168 "not have proper size\n", __func__); 169 170 cb->nvals = 0; 171 for (arg = cb->arg; ; arg = end + 1) { 172 if (cb->nvals == maxiter) 173 xt_params->exit_err(PARAMETER_PROBLEM, "%s: Too many " 174 "components for option \"--%s\" (max: %u)\n", 175 cb->ext_name, entry->name, maxiter); 176 if (!xtables_strtoui(arg, &end, &value, 0, UINT32_MAX)) 177 xt_params->exit_err(PARAMETER_PROBLEM, 178 "%s: bad value for option \"--%s\", " 179 "or out of range (0-%u).\n", 180 cb->ext_name, entry->name, UINT32_MAX); 181 if (*end != '\0' && *end != sep) 182 xt_params->exit_err(PARAMETER_PROBLEM, 183 "%s: Argument to \"--%s\" has unexpected " 184 "characters.\n", cb->ext_name, entry->name); 185 ++cb->nvals; 186 if (cb->nvals < ARRAY_SIZE(cb->val.u32_range)) { 187 if (entry->type == XTTYPE_UINT8RC) 188 cb->val.u8_range[cb->nvals] = value; 189 else if (entry->type == XTTYPE_UINT16RC) 190 cb->val.u16_range[cb->nvals] = value; 191 else if (entry->type == XTTYPE_UINT32RC) 192 cb->val.u32_range[cb->nvals] = value; 193 else if (entry->type == XTTYPE_UINT64RC) 194 cb->val.u64_range[cb->nvals] = value; 195 } 196 if (entry->flags & XTOPT_PUT) { 197 if (entry->type == XTTYPE_UINT8RC) 198 *(uint8_t *)put = value; 199 else if (entry->type == XTTYPE_UINT16RC) 200 *(uint16_t *)put = value; 201 else if (entry->type == XTTYPE_UINT32RC) 202 *(uint32_t *)put = value; 203 else if (entry->type == XTTYPE_UINT64RC) 204 *(uint64_t *)put = value; 205 put += esize; 206 } 207 if (*end == '\0') 208 break; 209 } 210} 211 212static void xtopt_parse_string(struct xt_option_call *cb) 213{ 214 const struct xt_option_entry *entry = cb->entry; 215 size_t z = strlen(cb->arg); 216 char *p; 217 218 if (entry->min != 0 && z < entry->min) 219 xt_params->exit_err(PARAMETER_PROBLEM, 220 "Argument must have a minimum length of " 221 "%u characters\n", entry->min); 222 if (entry->max != 0 && z > entry->max) 223 xt_params->exit_err(PARAMETER_PROBLEM, 224 "Argument must have a maximum length of " 225 "%u characters\n", entry->max); 226 if (!(entry->flags & XTOPT_PUT)) 227 return; 228 if (z >= entry->size) 229 z = entry->size - 1; 230 p = XTOPT_MKPTR(cb); 231 strncpy(p, cb->arg, z); 232 p[z] = '\0'; 233} 234 235/** 236 * Validate the input for being conformant to "mark[/mask]". 237 */ 238static void xtopt_parse_markmask(struct xt_option_call *cb) 239{ 240 unsigned int mark = 0, mask = ~0U; 241 char *end; 242 243 if (!xtables_strtoui(cb->arg, &end, &mark, 0, UINT32_MAX)) 244 xt_params->exit_err(PARAMETER_PROBLEM, 245 "%s: bad mark value for option \"--%s\", " 246 "or out of range.\n", 247 cb->ext_name, cb->entry->name); 248 if (*end == '/' && 249 !xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) 250 xt_params->exit_err(PARAMETER_PROBLEM, 251 "%s: bad mask value for option \"--%s\", " 252 "or out of range.\n", 253 cb->ext_name, cb->entry->name); 254 if (*end != '\0') 255 xt_params->exit_err(PARAMETER_PROBLEM, 256 "%s: trailing garbage after value " 257 "for option \"--%s\".\n", 258 cb->ext_name, cb->entry->name); 259 cb->val.mark = mark; 260 cb->val.mask = mask; 261} 262 263static int xtopt_sysloglvl_compare(const void *a, const void *b) 264{ 265 const char *name = a; 266 const struct syslog_level *entry = b; 267 268 return strcmp(name, entry->name); 269} 270 271static void xtopt_parse_sysloglevel(struct xt_option_call *cb) 272{ 273 static const struct syslog_level log_names[] = { /* must be sorted */ 274 {"alert", LOG_ALERT}, 275 {"crit", LOG_CRIT}, 276 {"debug", LOG_DEBUG}, 277 {"emerg", LOG_EMERG}, 278 {"error", LOG_ERR}, /* deprecated */ 279 {"info", LOG_INFO}, 280 {"notice", LOG_NOTICE}, 281 {"panic", LOG_EMERG}, /* deprecated */ 282 {"warning", LOG_WARNING}, 283 }; 284 const struct syslog_level *e; 285 unsigned int num = 0; 286 287 if (!xtables_strtoui(cb->arg, NULL, &num, 0, 7)) { 288 e = bsearch(cb->arg, log_names, ARRAY_SIZE(log_names), 289 sizeof(*log_names), xtopt_sysloglvl_compare); 290 if (e == NULL) 291 xt_params->exit_err(PARAMETER_PROBLEM, 292 "log level \"%s\" unknown\n", cb->arg); 293 num = e->level; 294 } 295 cb->val.syslog_level = num; 296 if (cb->entry->flags & XTOPT_PUT) 297 *(uint8_t *)XTOPT_MKPTR(cb) = num; 298} 299 300static void *xtables_sa_host(const void *sa, unsigned int afproto) 301{ 302 if (afproto == AF_INET6) 303 return &((struct sockaddr_in6 *)sa)->sin6_addr; 304 else if (afproto == AF_INET) 305 return &((struct sockaddr_in *)sa)->sin_addr; 306 return (void *)sa; 307} 308 309static socklen_t xtables_sa_hostlen(unsigned int afproto) 310{ 311 if (afproto == AF_INET6) 312 return sizeof(struct in6_addr); 313 else if (afproto == AF_INET) 314 return sizeof(struct in_addr); 315 return 0; 316} 317 318/** 319 * Accepts: a hostname (DNS), or a single inetaddr. 320 */ 321static void xtopt_parse_onehost(struct xt_option_call *cb) 322{ 323 struct addrinfo hints = {.ai_family = afinfo->family}; 324 unsigned int adcount = 0; 325 struct addrinfo *res, *p; 326 int ret; 327 328 ret = getaddrinfo(cb->arg, NULL, &hints, &res); 329 if (ret < 0) 330 xt_params->exit_err(PARAMETER_PROBLEM, 331 "getaddrinfo: %s\n", gai_strerror(ret)); 332 333 for (p = res; p != NULL; p = p->ai_next) { 334 if (adcount == 0) { 335 memset(&cb->val.inetaddr, 0, sizeof(cb->val.inetaddr)); 336 memcpy(&cb->val.inetaddr, 337 xtables_sa_host(p->ai_addr, p->ai_family), 338 xtables_sa_hostlen(p->ai_family)); 339 ++adcount; 340 continue; 341 } 342 if (memcmp(&cb->val.inetaddr, 343 xtables_sa_host(p->ai_addr, p->ai_family), 344 xtables_sa_hostlen(p->ai_family)) != 0) 345 xt_params->exit_err(PARAMETER_PROBLEM, 346 "%s resolves to more than one address\n", 347 cb->arg); 348 } 349 350 freeaddrinfo(res); 351 if (cb->entry->flags & XTOPT_PUT) 352 /* Validation in xtables_option_metavalidate */ 353 memcpy(XTOPT_MKPTR(cb), &cb->val.inetaddr, 354 sizeof(cb->val.inetaddr)); 355} 356 357/** 358 * @name: port name, or number as a string (e.g. "http" or "80") 359 * 360 * Resolve a port name to a number. Returns the port number in integral 361 * form on success, or <0 on error. (errno will not be set.) 362 */ 363static int xtables_getportbyname(const char *name) 364{ 365 struct addrinfo *res = NULL, *p; 366 int ret; 367 368 ret = getaddrinfo(NULL, name, NULL, &res); 369 if (ret < 0) 370 return -1; 371 ret = -1; 372 for (p = res; p != NULL; p = p->ai_next) { 373 if (p->ai_family == AF_INET6) { 374 ret = ((struct sockaddr_in6 *)p->ai_addr)->sin6_port; 375 break; 376 } else if (p->ai_family == AF_INET) { 377 ret = ((struct sockaddr_in *)p->ai_addr)->sin_port; 378 break; 379 } 380 } 381 freeaddrinfo(res); 382 if (ret < 0) 383 return ret; 384 return ntohs(ret); 385} 386 387/** 388 * Validate and parse a port specification and put the result into @cb. 389 */ 390static void xtopt_parse_port(struct xt_option_call *cb) 391{ 392 int ret; 393 394 ret = xtables_getportbyname(cb->arg); 395 if (ret < 0) 396 xt_params->exit_err(PARAMETER_PROBLEM, 397 "Port \"%s\" does not resolve to anything.\n", 398 cb->arg); 399 cb->val.port = ret; 400 if (cb->entry->type == XTTYPE_PORT_NE) 401 cb->val.port = htons(cb->val.port); 402 if (cb->entry->flags & XTOPT_PUT) 403 *(uint16_t *)XTOPT_MKPTR(cb) = cb->val.port; 404} 405 406static void (*const xtopt_subparse[])(struct xt_option_call *) = { 407 [XTTYPE_UINT8] = xtopt_parse_int, 408 [XTTYPE_UINT16] = xtopt_parse_int, 409 [XTTYPE_UINT32] = xtopt_parse_int, 410 [XTTYPE_UINT64] = xtopt_parse_int, 411 [XTTYPE_UINT8RC] = xtopt_parse_mint, 412 [XTTYPE_UINT16RC] = xtopt_parse_mint, 413 [XTTYPE_UINT32RC] = xtopt_parse_mint, 414 [XTTYPE_UINT64RC] = xtopt_parse_mint, 415 [XTTYPE_STRING] = xtopt_parse_string, 416 [XTTYPE_MARKMASK32] = xtopt_parse_markmask, 417 [XTTYPE_SYSLOGLEVEL] = xtopt_parse_sysloglevel, 418 [XTTYPE_ONEHOST] = xtopt_parse_onehost, 419 [XTTYPE_PORT] = xtopt_parse_port, 420 [XTTYPE_PORT_NE] = xtopt_parse_port, 421}; 422 423static const size_t xtopt_psize[] = { 424 [XTTYPE_UINT8] = sizeof(uint8_t), 425 [XTTYPE_UINT16] = sizeof(uint16_t), 426 [XTTYPE_UINT32] = sizeof(uint32_t), 427 [XTTYPE_UINT64] = sizeof(uint64_t), 428 [XTTYPE_UINT8RC] = sizeof(uint8_t[2]), 429 [XTTYPE_UINT16RC] = sizeof(uint16_t[2]), 430 [XTTYPE_UINT32RC] = sizeof(uint32_t[2]), 431 [XTTYPE_UINT64RC] = sizeof(uint64_t[2]), 432 [XTTYPE_STRING] = -1, 433 [XTTYPE_SYSLOGLEVEL] = sizeof(uint8_t), 434 [XTTYPE_ONEHOST] = sizeof(union nf_inet_addr), 435 [XTTYPE_PORT] = sizeof(uint16_t), 436 [XTTYPE_PORT_NE] = sizeof(uint16_t), 437}; 438 439/** 440 * The master option parsing routine. May be used for the ".x6_parse" 441 * function pointer in extensions if fully automatic parsing is desired. 442 * It may be also called manually from a custom x6_parse function. 443 */ 444void xtables_option_parse(struct xt_option_call *cb) 445{ 446 const struct xt_option_entry *entry = cb->entry; 447 unsigned int eflag = 1 << cb->entry->id; 448 449 /* 450 * With {.id = P_FOO, .excl = P_FOO} we can have simple double-use 451 * prevention. Though it turned out that this is too much typing (most 452 * of the options are one-time use only), so now we also have 453 * %XTOPT_MULTI. 454 */ 455 if ((!(entry->flags & XTOPT_MULTI) || (entry->excl & eflag)) && 456 cb->xflags & eflag) 457 xt_params->exit_err(PARAMETER_PROBLEM, 458 "%s: option \"--%s\" can only be used once.\n", 459 cb->ext_name, cb->entry->name); 460 if (cb->invert && !(entry->flags & XTOPT_INVERT)) 461 xt_params->exit_err(PARAMETER_PROBLEM, 462 "%s: option \"--%s\" cannot be inverted.\n", 463 cb->ext_name, entry->name); 464 if (entry->type != XTTYPE_NONE && optarg == NULL) 465 xt_params->exit_err(PARAMETER_PROBLEM, 466 "%s: option \"--%s\" requires an argument.\n", 467 cb->ext_name, entry->name); 468 if (entry->type <= ARRAY_SIZE(xtopt_subparse) && 469 xtopt_subparse[entry->type] != NULL) 470 xtopt_subparse[entry->type](cb); 471 /* Exclusion with other flags tested later in finalize. */ 472 cb->xflags |= 1 << entry->id; 473} 474 475/** 476 * Verifies that an extension's option map descriptor is valid, and ought to 477 * be called right after the extension has been loaded, and before option 478 * merging/xfrm. 479 */ 480void xtables_option_metavalidate(const char *name, 481 const struct xt_option_entry *entry) 482{ 483 for (; entry->name != NULL; ++entry) { 484 if (entry->id >= CHAR_BIT * sizeof(unsigned int) || 485 entry->id >= XT_OPTION_OFFSET_SCALE) 486 xt_params->exit_err(OTHER_PROBLEM, 487 "Extension %s uses invalid ID %u\n", 488 name, entry->id); 489 if (!(entry->flags & XTOPT_PUT)) 490 continue; 491 if (entry->type >= ARRAY_SIZE(xtopt_psize)) 492 xt_params->exit_err(OTHER_PROBLEM, 493 "%s: entry type of option \"--%s\" cannot be " 494 "combined with XTOPT_PUT\n", 495 name, entry->name); 496 if (xtopt_psize[entry->type] != -1 && 497 xtopt_psize[entry->type] != entry->size) 498 xt_params->exit_err(OTHER_PROBLEM, 499 "%s: option \"--%s\" points to a memory block " 500 "of wrong size (expected %zu, got %zu)\n", 501 name, entry->name, 502 xtopt_psize[entry->type], entry->size); 503 } 504} 505 506/** 507 * Find an option entry by its id. 508 */ 509static const struct xt_option_entry * 510xtables_option_lookup(const struct xt_option_entry *entry, unsigned int id) 511{ 512 for (; entry->name != NULL; ++entry) 513 if (entry->id == id) 514 return entry; 515 return NULL; 516} 517 518/** 519 * @c: getopt id (i.e. with offset) 520 * @fw: struct ipt_entry or ip6t_entry 521 * 522 * Dispatch arguments to the appropriate parse function, based upon the 523 * extension's choice of API. 524 */ 525void xtables_option_tpcall(unsigned int c, char **argv, bool invert, 526 struct xtables_target *t, void *fw) 527{ 528 struct xt_option_call cb; 529 530 if (t->x6_parse == NULL) { 531 if (t->parse != NULL) 532 t->parse(c - t->option_offset, argv, invert, 533 &t->tflags, fw, &t->t); 534 return; 535 } 536 537 c -= t->option_offset; 538 cb.entry = xtables_option_lookup(t->x6_options, c); 539 if (cb.entry == NULL) 540 xtables_error(OTHER_PROBLEM, 541 "Extension does not know id %u\n", c); 542 cb.arg = optarg; 543 cb.invert = invert; 544 cb.ext_name = t->name; 545 cb.data = t->t->data; 546 cb.xflags = t->tflags; 547 cb.target = &t->t; 548 t->x6_parse(&cb); 549 t->tflags = cb.xflags; 550} 551 552/** 553 * @c: getopt id (i.e. with offset) 554 * @fw: struct ipt_entry or ip6t_entry 555 * 556 * Dispatch arguments to the appropriate parse function, based upon the 557 * extension's choice of API. 558 */ 559void xtables_option_mpcall(unsigned int c, char **argv, bool invert, 560 struct xtables_match *m, void *fw) 561{ 562 struct xt_option_call cb; 563 564 if (m->x6_parse == NULL) { 565 if (m->parse != NULL) 566 m->parse(c - m->option_offset, argv, invert, 567 &m->mflags, fw, &m->m); 568 return; 569 } 570 571 c -= m->option_offset; 572 cb.entry = xtables_option_lookup(m->x6_options, c); 573 if (cb.entry == NULL) 574 xtables_error(OTHER_PROBLEM, 575 "Extension does not know id %u\n", c); 576 cb.arg = optarg; 577 cb.invert = invert; 578 cb.ext_name = m->name; 579 cb.data = m->m->data; 580 cb.xflags = m->mflags; 581 cb.match = &m->m; 582 m->x6_parse(&cb); 583 m->mflags = cb.xflags; 584} 585 586/** 587 * @name: name of extension 588 * @entry: current option (from all ext's entries) being validated 589 * @xflags: flags the extension has collected 590 * @i: conflicting option (id) to test for 591 */ 592static void 593xtables_option_fcheck2(const char *name, const struct xt_option_entry *entry, 594 const struct xt_option_entry *other, 595 unsigned int xflags) 596{ 597 unsigned int ef = 1 << entry->id, of = 1 << other->id; 598 599 if (entry->also & of && !(xflags & of)) 600 xt_params->exit_err(PARAMETER_PROBLEM, 601 "%s: option \"--%s\" also requires \"--%s\".\n", 602 name, entry->name, other->name); 603 604 if (!(entry->excl & of)) 605 /* Use of entry does not collide with other option, good. */ 606 return; 607 if ((xflags & (ef | of)) != (ef | of)) 608 /* Conflicting options were not used. */ 609 return; 610 611 xt_params->exit_err(PARAMETER_PROBLEM, 612 "%s: option \"--%s\" cannot be used together with \"--%s\".\n", 613 name, entry->name, other->name); 614} 615 616/** 617 * @name: name of extension 618 * @xflags: accumulated flags 619 * @entry: extension's option table 620 * 621 * Check that all option constraints have been met. This effectively replaces 622 * ->final_check of the older API. 623 */ 624void xtables_options_fcheck(const char *name, unsigned int xflags, 625 const struct xt_option_entry *table) 626{ 627 const struct xt_option_entry *entry, *other; 628 unsigned int i; 629 630 for (entry = table; entry->name != NULL; ++entry) { 631 if (entry->flags & XTOPT_MAND && 632 !(xflags & (1 << entry->id))) 633 xt_params->exit_err(PARAMETER_PROBLEM, 634 "%s: option \"--%s\" must be specified\n", 635 name, entry->name); 636 637 for (i = 0; i < CHAR_BIT * sizeof(entry->id); ++i) { 638 if (entry->id == i) 639 /* 640 * Avoid conflict with self. Multi-use check 641 * was done earlier in xtables_option_parse. 642 */ 643 continue; 644 other = xtables_option_lookup(table, i); 645 if (other == NULL) 646 continue; 647 xtables_option_fcheck2(name, entry, other, xflags); 648 } 649 } 650} 651 652/** 653 * Dispatch arguments to the appropriate final_check function, based upon the 654 * extension's choice of API. 655 */ 656void xtables_option_tfcall(struct xtables_target *t) 657{ 658 if (t->x6_fcheck != NULL) { 659 struct xt_fcheck_call cb; 660 661 cb.ext_name = t->name; 662 cb.data = t->t->data; 663 cb.xflags = t->tflags; 664 t->x6_fcheck(&cb); 665 } else if (t->final_check != NULL) { 666 t->final_check(t->tflags); 667 } 668 if (t->x6_options != NULL) 669 xtables_options_fcheck(t->name, t->tflags, t->x6_options); 670} 671 672/** 673 * Dispatch arguments to the appropriate final_check function, based upon the 674 * extension's choice of API. 675 */ 676void xtables_option_mfcall(struct xtables_match *m) 677{ 678 if (m->x6_fcheck != NULL) { 679 struct xt_fcheck_call cb; 680 681 cb.ext_name = m->name; 682 cb.data = m->m->data; 683 cb.xflags = m->mflags; 684 m->x6_fcheck(&cb); 685 } else if (m->final_check != NULL) { 686 m->final_check(m->mflags); 687 } 688 if (m->x6_options != NULL) 689 xtables_options_fcheck(m->name, m->mflags, m->x6_options); 690} 691 692struct xtables_lmap *xtables_lmap_init(const char *file) 693{ 694 struct xtables_lmap *lmap_head = NULL, *lmap_prev = NULL, *lmap_this; 695 char buf[512]; 696 FILE *fp; 697 char *cur, *nxt; 698 int id; 699 700 fp = fopen(file, "re"); 701 if (fp == NULL) 702 return NULL; 703 704 while (fgets(buf, sizeof(buf), fp) != NULL) { 705 cur = buf; 706 while (isspace(*cur)) 707 ++cur; 708 if (*cur == '#' || *cur == '\n' || *cur == '\0') 709 continue; 710 711 /* iproute2 allows hex and dec format */ 712 errno = 0; 713 id = strtoul(cur, &nxt, strncmp(cur, "0x", 2) == 0 ? 16 : 10); 714 if (nxt == cur || errno != 0) 715 continue; 716 717 /* same boundaries as in iproute2 */ 718 if (id < 0 || id > 255) 719 continue; 720 cur = nxt; 721 722 if (!isspace(*cur)) 723 continue; 724 while (isspace(*cur)) 725 ++cur; 726 if (*cur == '#' || *cur == '\n' || *cur == '\0') 727 continue; 728 nxt = cur; 729 while (*nxt != '\0' && !isspace(*nxt)) 730 ++nxt; 731 if (nxt == cur) 732 continue; 733 *nxt = '\0'; 734 735 /* found valid data */ 736 lmap_this = malloc(sizeof(*lmap_this)); 737 if (lmap_this == NULL) { 738 perror("malloc"); 739 goto out; 740 } 741 lmap_this->id = id; 742 lmap_this->name = strdup(cur); 743 if (lmap_this->name == NULL) { 744 free(lmap_this); 745 goto out; 746 } 747 lmap_this->next = NULL; 748 749 if (lmap_prev != NULL) 750 lmap_prev->next = lmap_this; 751 else 752 lmap_head = lmap_this; 753 lmap_prev = lmap_this; 754 } 755 756 fclose(fp); 757 return lmap_head; 758 out: 759 xtables_lmap_free(lmap_head); 760 return NULL; 761} 762 763void xtables_lmap_free(struct xtables_lmap *head) 764{ 765 struct xtables_lmap *next; 766 767 for (; head != NULL; head = next) { 768 next = head->next; 769 free(head->name); 770 free(head); 771 } 772} 773 774int xtables_lmap_name2id(const struct xtables_lmap *head, const char *name) 775{ 776 for (; head != NULL; head = head->next) 777 if (strcmp(head->name, name) == 0) 778 return head->id; 779 return -1; 780} 781 782const char *xtables_lmap_id2name(const struct xtables_lmap *head, int id) 783{ 784 for (; head != NULL; head = head->next) 785 if (head->id == id) 786 return head->name; 787 return NULL; 788} 789