Home | History | Annotate | Download | only in libxtables
      1 /*
      2  * (C) 2000-2006 by the netfilter coreteam <coreteam (at) netfilter.org>:
      3  *
      4  *	This program is free software; you can redistribute it and/or modify
      5  *	it under the terms of the GNU General Public License as published by
      6  *	the Free Software Foundation; either version 2 of the License, or
      7  *	(at your option) any later version.
      8  *
      9  *	This program is distributed in the hope that it will be useful,
     10  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  *	GNU General Public License for more details.
     13  *
     14  *	You should have received a copy of the GNU General Public License
     15  *	along with this program; if not, write to the Free Software
     16  *	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
     17  */
     18 #include "config.h"
     19 #include <ctype.h>
     20 #include <errno.h>
     21 #include <fcntl.h>
     22 #include <inttypes.h>
     23 #include <netdb.h>
     24 #include <stdarg.h>
     25 #include <stdbool.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 #include <unistd.h>
     30 #include <sys/socket.h>
     31 #include <sys/stat.h>
     32 #include <sys/statfs.h>
     33 #include <sys/types.h>
     34 #include <sys/utsname.h>
     35 #include <sys/wait.h>
     36 #include <arpa/inet.h>
     37 #if defined(HAVE_LINUX_MAGIC_H)
     38 #	include <linux/magic.h> /* for PROC_SUPER_MAGIC */
     39 #elif defined(HAVE_LINUX_PROC_FS_H)
     40 #	include <linux/proc_fs.h>	/* Linux 2.4 */
     41 #else
     42 #	define PROC_SUPER_MAGIC	0x9fa0
     43 #endif
     44 
     45 #include <xtables.h>
     46 #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
     47 #include <linux/netfilter_ipv4/ip_tables.h>
     48 #include <linux/netfilter_ipv6/ip6_tables.h>
     49 #include <libiptc/libxtc.h>
     50 
     51 #ifndef NO_SHARED_LIBS
     52 #include <dlfcn.h>
     53 #endif
     54 #ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
     55 #	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
     56 #	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
     57 #endif
     58 #ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
     59 #	define IP6T_SO_GET_REVISION_MATCH	68
     60 #	define IP6T_SO_GET_REVISION_TARGET	69
     61 #endif
     62 #include <getopt.h>
     63 #include "iptables/internal.h"
     64 #include "xshared.h"
     65 
     66 #define NPROTO	255
     67 
     68 #ifndef PROC_SYS_MODPROBE
     69 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
     70 #endif
     71 
     72 /* we need this for ip6?tables-restore.  ip6?tables-restore.c sets line to the
     73  * current line of the input file, in order  to give a more precise error
     74  * message.  ip6?tables itself doesn't need this, so it is initialized to the
     75  * magic number of -1 */
     76 int line = -1;
     77 
     78 void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
     79 
     80 struct xtables_globals *xt_params = NULL;
     81 
     82 void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
     83 {
     84 	va_list args;
     85 
     86 	va_start(args, msg);
     87 	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
     88 	vfprintf(stderr, msg, args);
     89 	va_end(args);
     90 	fprintf(stderr, "\n");
     91 	exit(status);
     92 }
     93 
     94 void xtables_free_opts(int unused)
     95 {
     96 	if (xt_params->opts != xt_params->orig_opts) {
     97 		free(xt_params->opts);
     98 		xt_params->opts = NULL;
     99 	}
    100 }
    101 
    102 struct option *xtables_merge_options(struct option *orig_opts,
    103 				     struct option *oldopts,
    104 				     const struct option *newopts,
    105 				     unsigned int *option_offset)
    106 {
    107 	unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
    108 	struct option *merge, *mp;
    109 
    110 	if (newopts == NULL)
    111 		return oldopts;
    112 
    113 	for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
    114 	if (oldopts != NULL)
    115 		for (num_old = 0; oldopts[num_old].name; num_old++) ;
    116 	for (num_new = 0; newopts[num_new].name; num_new++) ;
    117 
    118 	/*
    119 	 * Since @oldopts also has @orig_opts already (and does so at the
    120 	 * start), skip these entries.
    121 	 */
    122 	oldopts += num_oold;
    123 	num_old -= num_oold;
    124 
    125 	merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
    126 	if (merge == NULL)
    127 		return NULL;
    128 
    129 	/* Let the base options -[ADI...] have precedence over everything */
    130 	memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
    131 	mp = merge + num_oold;
    132 
    133 	/* Second, the new options */
    134 	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
    135 	*option_offset = xt_params->option_offset;
    136 	memcpy(mp, newopts, sizeof(*mp) * num_new);
    137 
    138 	for (i = 0; i < num_new; ++i, ++mp)
    139 		mp->val += *option_offset;
    140 
    141 	/* Third, the old options */
    142 	memcpy(mp, oldopts, sizeof(*mp) * num_old);
    143 	mp += num_old;
    144 	xtables_free_opts(0);
    145 
    146 	/* Clear trailing entry */
    147 	memset(mp, 0, sizeof(*mp));
    148 	return merge;
    149 }
    150 
    151 static const struct xtables_afinfo afinfo_ipv4 = {
    152 	.kmod          = "ip_tables",
    153 	.proc_exists   = "/proc/net/ip_tables_names",
    154 	.libprefix     = "libipt_",
    155 	.family	       = NFPROTO_IPV4,
    156 	.ipproto       = IPPROTO_IP,
    157 	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
    158 	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
    159 };
    160 
    161 static const struct xtables_afinfo afinfo_ipv6 = {
    162 	.kmod          = "ip6_tables",
    163 	.proc_exists   = "/proc/net/ip6_tables_names",
    164 	.libprefix     = "libip6t_",
    165 	.family        = NFPROTO_IPV6,
    166 	.ipproto       = IPPROTO_IPV6,
    167 	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
    168 	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
    169 };
    170 
    171 /* Dummy families for arptables-compat and ebtables-compat. Leave structure
    172  * fields that we don't use unset.
    173  */
    174 static const struct xtables_afinfo afinfo_bridge = {
    175 	.libprefix     = "libebt_",
    176 	.family        = NFPROTO_BRIDGE,
    177 };
    178 
    179 static const struct xtables_afinfo afinfo_arp = {
    180 	.libprefix     = "libarpt_",
    181 	.family        = NFPROTO_ARP,
    182 };
    183 
    184 const struct xtables_afinfo *afinfo;
    185 
    186 /* Search path for Xtables .so files */
    187 static const char *xtables_libdir;
    188 
    189 /* the path to command to load kernel module */
    190 const char *xtables_modprobe_program;
    191 
    192 /* Keep track of matches/targets pending full registration: linked lists. */
    193 struct xtables_match *xtables_pending_matches;
    194 struct xtables_target *xtables_pending_targets;
    195 
    196 /* Keep track of fully registered external matches/targets: linked lists. */
    197 struct xtables_match *xtables_matches;
    198 struct xtables_target *xtables_targets;
    199 
    200 /* Fully register a match/target which was previously partially registered. */
    201 static void xtables_fully_register_pending_match(struct xtables_match *me);
    202 static void xtables_fully_register_pending_target(struct xtables_target *me);
    203 
    204 void xtables_init(void)
    205 {
    206 	xtables_libdir = getenv("XTABLES_LIBDIR");
    207 	if (xtables_libdir != NULL)
    208 		return;
    209 	xtables_libdir = getenv("IPTABLES_LIB_DIR");
    210 	if (xtables_libdir != NULL) {
    211 		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
    212 		        "use XTABLES_LIBDIR.\n");
    213 		return;
    214 	}
    215 	/*
    216 	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
    217 	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
    218 	 * for these env vars are deprecated anyhow, and in light of the
    219 	 * (shared) libxt_*.so files, makes less sense to have
    220 	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
    221 	 */
    222 	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
    223 	if (xtables_libdir != NULL) {
    224 		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
    225 		        "use XTABLES_LIBDIR.\n");
    226 		return;
    227 	}
    228 	xtables_libdir = XTABLES_LIBDIR;
    229 }
    230 
    231 void xtables_set_nfproto(uint8_t nfproto)
    232 {
    233 	switch (nfproto) {
    234 	case NFPROTO_IPV4:
    235 		afinfo = &afinfo_ipv4;
    236 		break;
    237 	case NFPROTO_IPV6:
    238 		afinfo = &afinfo_ipv6;
    239 		break;
    240 	case NFPROTO_BRIDGE:
    241 		afinfo = &afinfo_bridge;
    242 		break;
    243 	case NFPROTO_ARP:
    244 		afinfo = &afinfo_arp;
    245 		break;
    246 	default:
    247 		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
    248 		        __func__);
    249 	}
    250 }
    251 
    252 /**
    253  * xtables_set_params - set the global parameters used by xtables
    254  * @xtp:	input xtables_globals structure
    255  *
    256  * The app is expected to pass a valid xtables_globals data-filled
    257  * with proper values
    258  * @xtp cannot be NULL
    259  *
    260  * Returns -1 on failure to set and 0 on success
    261  */
    262 int xtables_set_params(struct xtables_globals *xtp)
    263 {
    264 	if (!xtp) {
    265 		fprintf(stderr, "%s: Illegal global params\n",__func__);
    266 		return -1;
    267 	}
    268 
    269 	xt_params = xtp;
    270 
    271 	if (!xt_params->exit_err)
    272 		xt_params->exit_err = basic_exit_err;
    273 
    274 	return 0;
    275 }
    276 
    277 int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
    278 {
    279 	xtables_init();
    280 	xtables_set_nfproto(nfproto);
    281 	return xtables_set_params(xtp);
    282 }
    283 
    284 /**
    285  * xtables_*alloc - wrappers that exit on failure
    286  */
    287 void *xtables_calloc(size_t count, size_t size)
    288 {
    289 	void *p;
    290 
    291 	if ((p = calloc(count, size)) == NULL) {
    292 		perror("ip[6]tables: calloc failed");
    293 		exit(1);
    294 	}
    295 
    296 	return p;
    297 }
    298 
    299 void *xtables_malloc(size_t size)
    300 {
    301 	void *p;
    302 
    303 	if ((p = malloc(size)) == NULL) {
    304 		perror("ip[6]tables: malloc failed");
    305 		exit(1);
    306 	}
    307 
    308 	return p;
    309 }
    310 
    311 void *xtables_realloc(void *ptr, size_t size)
    312 {
    313 	void *p;
    314 
    315 	if ((p = realloc(ptr, size)) == NULL) {
    316 		perror("ip[6]tables: realloc failed");
    317 		exit(1);
    318 	}
    319 
    320 	return p;
    321 }
    322 
    323 static char *get_modprobe(void)
    324 {
    325 	int procfile;
    326 	char *ret;
    327 	int count;
    328 
    329 	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
    330 	if (procfile < 0)
    331 		return NULL;
    332 	if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
    333 		fprintf(stderr, "Could not set close on exec: %s\n",
    334 			strerror(errno));
    335 		exit(1);
    336 	}
    337 
    338 	ret = malloc(PATH_MAX);
    339 	if (ret) {
    340 		count = read(procfile, ret, PATH_MAX);
    341 		if (count > 0 && count < PATH_MAX)
    342 		{
    343 			if (ret[count - 1] == '\n')
    344 				ret[count - 1] = '\0';
    345 			else
    346 				ret[count] = '\0';
    347 			close(procfile);
    348 			return ret;
    349 		}
    350 	}
    351 	free(ret);
    352 	close(procfile);
    353 	return NULL;
    354 }
    355 
    356 int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
    357 {
    358 	char *buf = NULL;
    359 	char *argv[4];
    360 	int status;
    361 
    362 	/* If they don't explicitly set it, read out of kernel */
    363 	if (!modprobe) {
    364 		buf = get_modprobe();
    365 		if (!buf)
    366 			return -1;
    367 		modprobe = buf;
    368 	}
    369 
    370 	argv[0] = (char *)modprobe;
    371 	argv[1] = (char *)modname;
    372 	argv[2] = quiet ? "-q" : NULL;
    373 	argv[3] = NULL;
    374 
    375 	/*
    376 	 * Need to flush the buffer, or the child may output it again
    377 	 * when switching the program thru execv.
    378 	 */
    379 	fflush(stdout);
    380 
    381 	switch (vfork()) {
    382 	case 0:
    383 		execv(argv[0], argv);
    384 
    385 		/* not usually reached */
    386 		_exit(1);
    387 	case -1:
    388 		free(buf);
    389 		return -1;
    390 
    391 	default: /* parent */
    392 		wait(&status);
    393 	}
    394 
    395 	free(buf);
    396 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
    397 		return 0;
    398 	return -1;
    399 }
    400 
    401 /* return true if a given file exists within procfs */
    402 static bool proc_file_exists(const char *filename)
    403 {
    404 	struct stat s;
    405 	struct statfs f;
    406 
    407 	if (lstat(filename, &s))
    408 		return false;
    409 	if (!S_ISREG(s.st_mode))
    410 		return false;
    411 	if (statfs(filename, &f))
    412 		return false;
    413 	if (f.f_type != PROC_SUPER_MAGIC)
    414 		return false;
    415 	return true;
    416 }
    417 
    418 int xtables_load_ko(const char *modprobe, bool quiet)
    419 {
    420 	static bool loaded = false;
    421 	int ret;
    422 
    423 	if (loaded)
    424 		return 0;
    425 
    426 	if (proc_file_exists(afinfo->proc_exists)) {
    427 		loaded = true;
    428 		return 0;
    429 	};
    430 
    431 	ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
    432 	if (ret == 0)
    433 		loaded = true;
    434 
    435 	return ret;
    436 }
    437 
    438 /**
    439  * xtables_strtou{i,l} - string to number conversion
    440  * @s:	input string
    441  * @end:	like strtoul's "end" pointer
    442  * @value:	pointer for result
    443  * @min:	minimum accepted value
    444  * @max:	maximum accepted value
    445  *
    446  * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
    447  * "15a" is rejected.
    448  * In either case, the value obtained is compared for min-max compliance.
    449  * Base is always 0, i.e. autodetect depending on @s.
    450  *
    451  * Returns true/false whether number was accepted. On failure, *value has
    452  * undefined contents.
    453  */
    454 bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
    455                      uintmax_t min, uintmax_t max)
    456 {
    457 	uintmax_t v;
    458 	const char *p;
    459 	char *my_end;
    460 
    461 	errno = 0;
    462 	/* Since strtoul allows leading minus, we have to check for ourself. */
    463 	for (p = s; isspace(*p); ++p)
    464 		;
    465 	if (*p == '-')
    466 		return false;
    467 	v = strtoumax(s, &my_end, 0);
    468 	if (my_end == s)
    469 		return false;
    470 	if (end != NULL)
    471 		*end = my_end;
    472 
    473 	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
    474 		if (value != NULL)
    475 			*value = v;
    476 		if (end == NULL)
    477 			return *my_end == '\0';
    478 		return true;
    479 	}
    480 
    481 	return false;
    482 }
    483 
    484 bool xtables_strtoui(const char *s, char **end, unsigned int *value,
    485                      unsigned int min, unsigned int max)
    486 {
    487 	uintmax_t v;
    488 	bool ret;
    489 
    490 	ret = xtables_strtoul(s, end, &v, min, max);
    491 	if (value != NULL)
    492 		*value = v;
    493 	return ret;
    494 }
    495 
    496 int xtables_service_to_port(const char *name, const char *proto)
    497 {
    498 	struct servent *service;
    499 
    500 	if ((service = getservbyname(name, proto)) != NULL)
    501 		return ntohs((unsigned short) service->s_port);
    502 
    503 	return -1;
    504 }
    505 
    506 uint16_t xtables_parse_port(const char *port, const char *proto)
    507 {
    508 	unsigned int portnum;
    509 
    510 	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
    511 	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
    512 		return portnum;
    513 
    514 	xt_params->exit_err(PARAMETER_PROBLEM,
    515 		   "invalid port/service `%s' specified", port);
    516 }
    517 
    518 void xtables_parse_interface(const char *arg, char *vianame,
    519 			     unsigned char *mask)
    520 {
    521 	unsigned int vialen = strlen(arg);
    522 	unsigned int i;
    523 
    524 	memset(mask, 0, IFNAMSIZ);
    525 	memset(vianame, 0, IFNAMSIZ);
    526 
    527 	if (vialen + 1 > IFNAMSIZ)
    528 		xt_params->exit_err(PARAMETER_PROBLEM,
    529 			   "interface name `%s' must be shorter than IFNAMSIZ"
    530 			   " (%i)", arg, IFNAMSIZ-1);
    531 
    532 	strcpy(vianame, arg);
    533 	if (vialen == 0)
    534 		return;
    535 	else if (vianame[vialen - 1] == '+') {
    536 		memset(mask, 0xFF, vialen - 1);
    537 		/* Don't remove `+' here! -HW */
    538 	} else {
    539 		/* Include nul-terminator in match */
    540 		memset(mask, 0xFF, vialen + 1);
    541 		for (i = 0; vianame[i]; i++) {
    542 			if (vianame[i] == '/' ||
    543 			    vianame[i] == ' ') {
    544 				fprintf(stderr,
    545 					"Warning: weird character in interface"
    546 					" `%s' ('/' and ' ' are not allowed by the kernel).\n",
    547 					vianame);
    548 				break;
    549 			}
    550 		}
    551 	}
    552 }
    553 
    554 #ifndef NO_SHARED_LIBS
    555 static void *load_extension(const char *search_path, const char *af_prefix,
    556     const char *name, bool is_target)
    557 {
    558 	const char *all_prefixes[] = {af_prefix, "libxt_", NULL};
    559 	const char **prefix;
    560 	const char *dir = search_path, *next;
    561 	void *ptr = NULL;
    562 	struct stat sb;
    563 	char path[256];
    564 
    565 	do {
    566 		next = strchr(dir, ':');
    567 		if (next == NULL)
    568 			next = dir + strlen(dir);
    569 
    570 		for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
    571 			snprintf(path, sizeof(path), "%.*s/%s%s.so",
    572 			         (unsigned int)(next - dir), dir,
    573 			         *prefix, name);
    574 
    575 			if (stat(path, &sb) != 0) {
    576 				if (errno == ENOENT)
    577 					continue;
    578 				fprintf(stderr, "%s: %s\n", path,
    579 					strerror(errno));
    580 				return NULL;
    581 			}
    582 			if (dlopen(path, RTLD_NOW) == NULL) {
    583 				fprintf(stderr, "%s: %s\n", path, dlerror());
    584 				break;
    585 			}
    586 
    587 			if (is_target)
    588 				ptr = xtables_find_target(name, XTF_DONT_LOAD);
    589 			else
    590 				ptr = xtables_find_match(name,
    591 				      XTF_DONT_LOAD, NULL);
    592 
    593 			if (ptr != NULL)
    594 				return ptr;
    595 
    596 			errno = ENOENT;
    597 			return NULL;
    598 		}
    599 		dir = next + 1;
    600 	} while (*next != '\0');
    601 
    602 	return NULL;
    603 }
    604 #endif
    605 
    606 static bool extension_cmp(const char *name1, const char *name2, uint32_t family)
    607 {
    608 	if (strcmp(name1, name2) == 0 &&
    609 	    (family == afinfo->family ||
    610 	     family == NFPROTO_UNSPEC))
    611 		return true;
    612 
    613 	return false;
    614 }
    615 
    616 struct xtables_match *
    617 xtables_find_match(const char *name, enum xtables_tryload tryload,
    618 		   struct xtables_rule_match **matches)
    619 {
    620 	struct xtables_match **dptr;
    621 	struct xtables_match *ptr;
    622 	const char *icmp6 = "icmp6";
    623 
    624 	if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
    625 		xtables_error(PARAMETER_PROBLEM,
    626 			   "Invalid match name \"%s\" (%u chars max)",
    627 			   name, XT_EXTENSION_MAXNAMELEN - 1);
    628 
    629 	/* This is ugly as hell. Nonetheless, there is no way of changing
    630 	 * this without hurting backwards compatibility */
    631 	if ( (strcmp(name,"icmpv6") == 0) ||
    632 	     (strcmp(name,"ipv6-icmp") == 0) ||
    633 	     (strcmp(name,"icmp6") == 0) )
    634 		name = icmp6;
    635 
    636 	/* Trigger delayed initialization */
    637 	for (dptr = &xtables_pending_matches; *dptr; ) {
    638 		if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
    639 			ptr = *dptr;
    640 			*dptr = (*dptr)->next;
    641 			ptr->next = NULL;
    642 			xtables_fully_register_pending_match(ptr);
    643 		} else {
    644 			dptr = &((*dptr)->next);
    645 		}
    646 	}
    647 
    648 	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
    649 		if (extension_cmp(name, ptr->name, ptr->family)) {
    650 			struct xtables_match *clone;
    651 
    652 			/* First match of this type: */
    653 			if (ptr->m == NULL)
    654 				break;
    655 
    656 			/* Second and subsequent clones */
    657 			clone = xtables_malloc(sizeof(struct xtables_match));
    658 			memcpy(clone, ptr, sizeof(struct xtables_match));
    659 			clone->udata = NULL;
    660 			clone->mflags = 0;
    661 			/* This is a clone: */
    662 			clone->next = clone;
    663 
    664 			ptr = clone;
    665 			break;
    666 		}
    667 	}
    668 
    669 #ifndef NO_SHARED_LIBS
    670 	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
    671 		ptr = load_extension(xtables_libdir, afinfo->libprefix,
    672 		      name, false);
    673 
    674 		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
    675 			xt_params->exit_err(PARAMETER_PROBLEM,
    676 				   "Couldn't load match `%s':%s\n",
    677 				   name, strerror(errno));
    678 	}
    679 #else
    680 	if (ptr && !ptr->loaded) {
    681 		if (tryload != XTF_DONT_LOAD)
    682 			ptr->loaded = 1;
    683 		else
    684 			ptr = NULL;
    685 	}
    686 	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
    687 		xt_params->exit_err(PARAMETER_PROBLEM,
    688 			   "Couldn't find match `%s'\n", name);
    689 	}
    690 #endif
    691 
    692 	if (ptr && matches) {
    693 		struct xtables_rule_match **i;
    694 		struct xtables_rule_match *newentry;
    695 
    696 		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
    697 
    698 		for (i = matches; *i; i = &(*i)->next) {
    699 			if (extension_cmp(name, (*i)->match->name,
    700 					  (*i)->match->family))
    701 				(*i)->completed = true;
    702 		}
    703 		newentry->match = ptr;
    704 		newentry->completed = false;
    705 		newentry->next = NULL;
    706 		*i = newentry;
    707 	}
    708 
    709 	return ptr;
    710 }
    711 
    712 struct xtables_target *
    713 xtables_find_target(const char *name, enum xtables_tryload tryload)
    714 {
    715 	struct xtables_target **dptr;
    716 	struct xtables_target *ptr;
    717 
    718 	/* Standard target? */
    719 	if (strcmp(name, "") == 0
    720 	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
    721 	    || strcmp(name, XTC_LABEL_DROP) == 0
    722 	    || strcmp(name, XTC_LABEL_QUEUE) == 0
    723 	    || strcmp(name, XTC_LABEL_RETURN) == 0)
    724 		name = "standard";
    725 
    726 	/* Trigger delayed initialization */
    727 	for (dptr = &xtables_pending_targets; *dptr; ) {
    728 		if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
    729 			ptr = *dptr;
    730 			*dptr = (*dptr)->next;
    731 			ptr->next = NULL;
    732 			xtables_fully_register_pending_target(ptr);
    733 		} else {
    734 			dptr = &((*dptr)->next);
    735 		}
    736 	}
    737 
    738 	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
    739 		if (extension_cmp(name, ptr->name, ptr->family))
    740 			break;
    741 	}
    742 
    743 #ifndef NO_SHARED_LIBS
    744 	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
    745 		ptr = load_extension(xtables_libdir, afinfo->libprefix,
    746 		      name, true);
    747 
    748 		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
    749 			xt_params->exit_err(PARAMETER_PROBLEM,
    750 				   "Couldn't load target `%s':%s\n",
    751 				   name, strerror(errno));
    752 	}
    753 #else
    754 	if (ptr && !ptr->loaded) {
    755 		if (tryload != XTF_DONT_LOAD)
    756 			ptr->loaded = 1;
    757 		else
    758 			ptr = NULL;
    759 	}
    760 	if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
    761 		xt_params->exit_err(PARAMETER_PROBLEM,
    762 			   "Couldn't find target `%s'\n", name);
    763 	}
    764 #endif
    765 
    766 	if (ptr)
    767 		ptr->used = 1;
    768 
    769 	return ptr;
    770 }
    771 
    772 int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
    773 {
    774 	struct xt_get_revision rev;
    775 	socklen_t s = sizeof(rev);
    776 	int max_rev, sockfd;
    777 
    778 	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
    779 	if (sockfd < 0) {
    780 		if (errno == EPERM) {
    781 			/* revision 0 is always supported. */
    782 			if (revision != 0)
    783 				fprintf(stderr, "%s: Could not determine whether "
    784 						"revision %u is supported, "
    785 						"assuming it is.\n",
    786 					name, revision);
    787 			return 1;
    788 		}
    789 		fprintf(stderr, "Could not open socket to kernel: %s\n",
    790 			strerror(errno));
    791 		exit(1);
    792 	}
    793 
    794 	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
    795 		fprintf(stderr, "Could not set close on exec: %s\n",
    796 			strerror(errno));
    797 		exit(1);
    798 	}
    799 
    800 	xtables_load_ko(xtables_modprobe_program, true);
    801 
    802 	strcpy(rev.name, name);
    803 	rev.revision = revision;
    804 
    805 	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
    806 	if (max_rev < 0) {
    807 		/* Definitely don't support this? */
    808 		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
    809 			close(sockfd);
    810 			return 0;
    811 		} else if (errno == ENOPROTOOPT) {
    812 			close(sockfd);
    813 			/* Assume only revision 0 support (old kernel) */
    814 			return (revision == 0);
    815 		} else {
    816 			fprintf(stderr, "getsockopt failed strangely: %s\n",
    817 				strerror(errno));
    818 			exit(1);
    819 		}
    820 	}
    821 	close(sockfd);
    822 	return 1;
    823 }
    824 
    825 
    826 static int compatible_match_revision(const char *name, uint8_t revision)
    827 {
    828 	return xt_params->compat_rev(name, revision, afinfo->so_rev_match);
    829 }
    830 
    831 static int compatible_target_revision(const char *name, uint8_t revision)
    832 {
    833 	return xt_params->compat_rev(name, revision, afinfo->so_rev_target);
    834 }
    835 
    836 static void xtables_check_options(const char *name, const struct option *opt)
    837 {
    838 	for (; opt->name != NULL; ++opt)
    839 		if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
    840 			fprintf(stderr, "%s: Extension %s uses invalid "
    841 			        "option value %d\n",xt_params->program_name,
    842 			        name, opt->val);
    843 			exit(1);
    844 		}
    845 }
    846 
    847 void xtables_register_match(struct xtables_match *me)
    848 {
    849 	if (me->version == NULL) {
    850 		fprintf(stderr, "%s: match %s<%u> is missing a version\n",
    851 		        xt_params->program_name, me->name, me->revision);
    852 		exit(1);
    853 	}
    854 	if (strcmp(me->version, XTABLES_VERSION) != 0) {
    855 		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
    856 		        "but \"%s\" is required.\n",
    857 			xt_params->program_name, me->name,
    858 			me->version, XTABLES_VERSION);
    859 		exit(1);
    860 	}
    861 
    862 	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
    863 		fprintf(stderr, "%s: match `%s' has invalid name\n",
    864 			xt_params->program_name, me->name);
    865 		exit(1);
    866 	}
    867 
    868 	if (me->family >= NPROTO) {
    869 		fprintf(stderr,
    870 			"%s: BUG: match %s has invalid protocol family\n",
    871 			xt_params->program_name, me->name);
    872 		exit(1);
    873 	}
    874 
    875 	if (me->x6_options != NULL)
    876 		xtables_option_metavalidate(me->name, me->x6_options);
    877 	if (me->extra_opts != NULL)
    878 		xtables_check_options(me->name, me->extra_opts);
    879 
    880 	/* ignore not interested match */
    881 	if (me->family != afinfo->family && me->family != AF_UNSPEC)
    882 		return;
    883 
    884 	/* place on linked list of matches pending full registration */
    885 	me->next = xtables_pending_matches;
    886 	xtables_pending_matches = me;
    887 }
    888 
    889 /**
    890  * Compare two actions for their preference
    891  * @a:	one action
    892  * @b: 	another
    893  *
    894  * Like strcmp, returns a negative number if @a is less preferred than @b,
    895  * positive number if @a is more preferred than @b, or zero if equally
    896  * preferred.
    897  */
    898 static int
    899 xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam,
    900 		  bool b_alias, unsigned int b_rev, unsigned int b_fam)
    901 {
    902 	/*
    903 	 * Alias ranks higher than no alias.
    904 	 * (We want the new action to be used whenever possible.)
    905 	 */
    906 	if (!a_alias && b_alias)
    907 		return -1;
    908 	if (a_alias && !b_alias)
    909 		return 1;
    910 
    911 	/* Higher revision ranks higher. */
    912 	if (a_rev < b_rev)
    913 		return -1;
    914 	if (a_rev > b_rev)
    915 		return 1;
    916 
    917 	/* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */
    918 	if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC)
    919 		return -1;
    920 	if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC)
    921 		return 1;
    922 
    923 	/* Must be the same thing. */
    924 	return 0;
    925 }
    926 
    927 static int xtables_match_prefer(const struct xtables_match *a,
    928 				const struct xtables_match *b)
    929 {
    930 	return xtables_mt_prefer(a->real_name != NULL,
    931 				 a->revision, a->family,
    932 				 b->real_name != NULL,
    933 				 b->revision, b->family);
    934 }
    935 
    936 static int xtables_target_prefer(const struct xtables_target *a,
    937 				 const struct xtables_target *b)
    938 {
    939 	/*
    940 	 * Note that if x->real_name==NULL, it will be set to x->name in
    941 	 * xtables_register_*; the direct pointer comparison here is therefore
    942 	 * legitimate to detect an alias.
    943 	 */
    944 	return xtables_mt_prefer(a->real_name != NULL,
    945 				 a->revision, a->family,
    946 				 b->real_name != NULL,
    947 				 b->revision, b->family);
    948 }
    949 
    950 static void xtables_fully_register_pending_match(struct xtables_match *me)
    951 {
    952 	struct xtables_match **i, *old;
    953 	const char *rn;
    954 	int compare;
    955 
    956 	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
    957 	if (old) {
    958 		compare = xtables_match_prefer(old, me);
    959 		if (compare == 0) {
    960 			fprintf(stderr,
    961 				"%s: match `%s' already registered.\n",
    962 				xt_params->program_name, me->name);
    963 			exit(1);
    964 		}
    965 
    966 		/* Now we have two (or more) options, check compatibility. */
    967 		rn = (old->real_name != NULL) ? old->real_name : old->name;
    968 		if (compare > 0 &&
    969 		    compatible_match_revision(rn, old->revision))
    970 			return;
    971 
    972 		/* See if new match can be used. */
    973 		rn = (me->real_name != NULL) ? me->real_name : me->name;
    974 		if (!compatible_match_revision(rn, me->revision))
    975 			return;
    976 
    977 		/* Delete old one. */
    978 		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
    979 		*i = old->next;
    980 	}
    981 
    982 	if (me->size != XT_ALIGN(me->size)) {
    983 		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
    984 		        xt_params->program_name, me->name,
    985 		        (unsigned int)me->size);
    986 		exit(1);
    987 	}
    988 
    989 	/* Append to list. */
    990 	for (i = &xtables_matches; *i; i = &(*i)->next);
    991 	me->next = NULL;
    992 	*i = me;
    993 
    994 	me->m = NULL;
    995 	me->mflags = 0;
    996 }
    997 
    998 void xtables_register_matches(struct xtables_match *match, unsigned int n)
    999 {
   1000 	do {
   1001 		xtables_register_match(&match[--n]);
   1002 	} while (n > 0);
   1003 }
   1004 
   1005 void xtables_register_target(struct xtables_target *me)
   1006 {
   1007 	if (me->version == NULL) {
   1008 		fprintf(stderr, "%s: target %s<%u> is missing a version\n",
   1009 		        xt_params->program_name, me->name, me->revision);
   1010 		exit(1);
   1011 	}
   1012 	if (strcmp(me->version, XTABLES_VERSION) != 0) {
   1013 		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
   1014 		        "but \"%s\" is required.\n",
   1015 			xt_params->program_name, me->name,
   1016 			me->version, XTABLES_VERSION);
   1017 		exit(1);
   1018 	}
   1019 
   1020 	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
   1021 		fprintf(stderr, "%s: target `%s' has invalid name\n",
   1022 			xt_params->program_name, me->name);
   1023 		exit(1);
   1024 	}
   1025 
   1026 	if (me->family >= NPROTO) {
   1027 		fprintf(stderr,
   1028 			"%s: BUG: target %s has invalid protocol family\n",
   1029 			xt_params->program_name, me->name);
   1030 		exit(1);
   1031 	}
   1032 
   1033 	if (me->x6_options != NULL)
   1034 		xtables_option_metavalidate(me->name, me->x6_options);
   1035 	if (me->extra_opts != NULL)
   1036 		xtables_check_options(me->name, me->extra_opts);
   1037 
   1038 	/* ignore not interested target */
   1039 	if (me->family != afinfo->family && me->family != AF_UNSPEC)
   1040 		return;
   1041 
   1042 	/* place on linked list of targets pending full registration */
   1043 	me->next = xtables_pending_targets;
   1044 	xtables_pending_targets = me;
   1045 }
   1046 
   1047 static void xtables_fully_register_pending_target(struct xtables_target *me)
   1048 {
   1049 	struct xtables_target *old;
   1050 	const char *rn;
   1051 	int compare;
   1052 
   1053 	old = xtables_find_target(me->name, XTF_DURING_LOAD);
   1054 	if (old) {
   1055 		struct xtables_target **i;
   1056 
   1057 		compare = xtables_target_prefer(old, me);
   1058 		if (compare == 0) {
   1059 			fprintf(stderr,
   1060 				"%s: target `%s' already registered.\n",
   1061 				xt_params->program_name, me->name);
   1062 			exit(1);
   1063 		}
   1064 
   1065 		/* Now we have two (or more) options, check compatibility. */
   1066 		rn = (old->real_name != NULL) ? old->real_name : old->name;
   1067 		if (compare > 0 &&
   1068 		    compatible_target_revision(rn, old->revision))
   1069 			return;
   1070 
   1071 		/* See if new target can be used. */
   1072 		rn = (me->real_name != NULL) ? me->real_name : me->name;
   1073 		if (!compatible_target_revision(rn, me->revision))
   1074 			return;
   1075 
   1076 		/* Delete old one. */
   1077 		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
   1078 		*i = old->next;
   1079 	}
   1080 
   1081 	if (me->size != XT_ALIGN(me->size)) {
   1082 		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
   1083 		        xt_params->program_name, me->name,
   1084 		        (unsigned int)me->size);
   1085 		exit(1);
   1086 	}
   1087 
   1088 	/* Prepend to list. */
   1089 	me->next = xtables_targets;
   1090 	xtables_targets = me;
   1091 	me->t = NULL;
   1092 	me->tflags = 0;
   1093 }
   1094 
   1095 void xtables_register_targets(struct xtables_target *target, unsigned int n)
   1096 {
   1097 	do {
   1098 		xtables_register_target(&target[--n]);
   1099 	} while (n > 0);
   1100 }
   1101 
   1102 /* receives a list of xtables_rule_match, release them */
   1103 void xtables_rule_matches_free(struct xtables_rule_match **matches)
   1104 {
   1105 	struct xtables_rule_match *matchp, *tmp;
   1106 
   1107 	for (matchp = *matches; matchp;) {
   1108 		tmp = matchp->next;
   1109 		if (matchp->match->m) {
   1110 			free(matchp->match->m);
   1111 			matchp->match->m = NULL;
   1112 		}
   1113 		if (matchp->match == matchp->match->next) {
   1114 			free(matchp->match);
   1115 			matchp->match = NULL;
   1116 		}
   1117 		free(matchp);
   1118 		matchp = tmp;
   1119 	}
   1120 
   1121 	*matches = NULL;
   1122 }
   1123 
   1124 /**
   1125  * xtables_param_act - act on condition
   1126  * @status:	a constant from enum xtables_exittype
   1127  *
   1128  * %XTF_ONLY_ONCE: print error message that option may only be used once.
   1129  * @p1:		module name (e.g. "mark")
   1130  * @p2(...):	option in conflict (e.g. "--mark")
   1131  * @p3(...):	condition to match on (see extensions/ for examples)
   1132  *
   1133  * %XTF_NO_INVERT: option does not support inversion
   1134  * @p1:		module name
   1135  * @p2:		option in conflict
   1136  * @p3:		condition to match on
   1137  *
   1138  * %XTF_BAD_VALUE: bad value for option
   1139  * @p1:		module name
   1140  * @p2:		option with which the problem occurred (e.g. "--mark")
   1141  * @p3:		string the user passed in (e.g. "99999999999999")
   1142  *
   1143  * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
   1144  * @p1:		module name
   1145  *
   1146  * Displays an error message and exits the program.
   1147  */
   1148 void xtables_param_act(unsigned int status, const char *p1, ...)
   1149 {
   1150 	const char *p2, *p3;
   1151 	va_list args;
   1152 	bool b;
   1153 
   1154 	va_start(args, p1);
   1155 
   1156 	switch (status) {
   1157 	case XTF_ONLY_ONCE:
   1158 		p2 = va_arg(args, const char *);
   1159 		b  = va_arg(args, unsigned int);
   1160 		if (!b) {
   1161 			va_end(args);
   1162 			return;
   1163 		}
   1164 		xt_params->exit_err(PARAMETER_PROBLEM,
   1165 		           "%s: \"%s\" option may only be specified once",
   1166 		           p1, p2);
   1167 		break;
   1168 	case XTF_NO_INVERT:
   1169 		p2 = va_arg(args, const char *);
   1170 		b  = va_arg(args, unsigned int);
   1171 		if (!b) {
   1172 			va_end(args);
   1173 			return;
   1174 		}
   1175 		xt_params->exit_err(PARAMETER_PROBLEM,
   1176 		           "%s: \"%s\" option cannot be inverted", p1, p2);
   1177 		break;
   1178 	case XTF_BAD_VALUE:
   1179 		p2 = va_arg(args, const char *);
   1180 		p3 = va_arg(args, const char *);
   1181 		xt_params->exit_err(PARAMETER_PROBLEM,
   1182 		           "%s: Bad value for \"%s\" option: \"%s\"",
   1183 		           p1, p2, p3);
   1184 		break;
   1185 	case XTF_ONE_ACTION:
   1186 		b = va_arg(args, unsigned int);
   1187 		if (!b) {
   1188 			va_end(args);
   1189 			return;
   1190 		}
   1191 		xt_params->exit_err(PARAMETER_PROBLEM,
   1192 		           "%s: At most one action is possible", p1);
   1193 		break;
   1194 	default:
   1195 		xt_params->exit_err(status, p1, args);
   1196 		break;
   1197 	}
   1198 
   1199 	va_end(args);
   1200 }
   1201 
   1202 const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
   1203 {
   1204 	static char buf[20];
   1205 	const unsigned char *bytep = (const void *)&addrp->s_addr;
   1206 
   1207 	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
   1208 	return buf;
   1209 }
   1210 
   1211 static const char *ipaddr_to_host(const struct in_addr *addr)
   1212 {
   1213 	static char hostname[NI_MAXHOST];
   1214 	struct sockaddr_in saddr = {
   1215 		.sin_family = AF_INET,
   1216 		.sin_addr = *addr,
   1217 	};
   1218 	int err;
   1219 
   1220 
   1221 	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in),
   1222 		       hostname, sizeof(hostname) - 1, NULL, 0, 0);
   1223 	if (err != 0)
   1224 		return NULL;
   1225 
   1226 	return hostname;
   1227 }
   1228 
   1229 static const char *ipaddr_to_network(const struct in_addr *addr)
   1230 {
   1231 	struct netent *net;
   1232 
   1233 	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
   1234 		return net->n_name;
   1235 
   1236 	return NULL;
   1237 }
   1238 
   1239 const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
   1240 {
   1241 	const char *name;
   1242 
   1243 	if ((name = ipaddr_to_host(addr)) != NULL ||
   1244 	    (name = ipaddr_to_network(addr)) != NULL)
   1245 		return name;
   1246 
   1247 	return xtables_ipaddr_to_numeric(addr);
   1248 }
   1249 
   1250 int xtables_ipmask_to_cidr(const struct in_addr *mask)
   1251 {
   1252 	uint32_t maskaddr, bits;
   1253 	int i;
   1254 
   1255 	maskaddr = ntohl(mask->s_addr);
   1256 	/* shortcut for /32 networks */
   1257 	if (maskaddr == 0xFFFFFFFFL)
   1258 		return 32;
   1259 
   1260 	i = 32;
   1261 	bits = 0xFFFFFFFEL;
   1262 	while (--i >= 0 && maskaddr != bits)
   1263 		bits <<= 1;
   1264 	if (i >= 0)
   1265 		return i;
   1266 
   1267 	/* this mask cannot be converted to CIDR notation */
   1268 	return -1;
   1269 }
   1270 
   1271 const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
   1272 {
   1273 	static char buf[20];
   1274 	uint32_t cidr;
   1275 
   1276 	cidr = xtables_ipmask_to_cidr(mask);
   1277 	if (cidr == (unsigned int)-1) {
   1278 		/* mask was not a decent combination of 1's and 0's */
   1279 		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
   1280 		return buf;
   1281 	} else if (cidr == 32) {
   1282 		/* we don't want to see "/32" */
   1283 		return "";
   1284 	}
   1285 
   1286 	sprintf(buf, "/%d", cidr);
   1287 	return buf;
   1288 }
   1289 
   1290 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
   1291 {
   1292 	static struct in_addr addr;
   1293 	unsigned char *addrp;
   1294 	unsigned int onebyte;
   1295 	char buf[20], *p, *q;
   1296 	int i;
   1297 
   1298 	/* copy dotted string, because we need to modify it */
   1299 	strncpy(buf, dotted, sizeof(buf) - 1);
   1300 	buf[sizeof(buf) - 1] = '\0';
   1301 	addrp = (void *)&addr.s_addr;
   1302 
   1303 	p = buf;
   1304 	for (i = 0; i < 3; ++i) {
   1305 		if ((q = strchr(p, '.')) == NULL) {
   1306 			if (is_mask)
   1307 				return NULL;
   1308 
   1309 			/* autocomplete, this is a network address */
   1310 			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
   1311 				return NULL;
   1312 
   1313 			addrp[i] = onebyte;
   1314 			while (i < 3)
   1315 				addrp[++i] = 0;
   1316 
   1317 			return &addr;
   1318 		}
   1319 
   1320 		*q = '\0';
   1321 		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
   1322 			return NULL;
   1323 
   1324 		addrp[i] = onebyte;
   1325 		p = q + 1;
   1326 	}
   1327 
   1328 	/* we have checked 3 bytes, now we check the last one */
   1329 	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
   1330 		return NULL;
   1331 
   1332 	addrp[3] = onebyte;
   1333 	return &addr;
   1334 }
   1335 
   1336 struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
   1337 {
   1338 	return __numeric_to_ipaddr(dotted, false);
   1339 }
   1340 
   1341 struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
   1342 {
   1343 	return __numeric_to_ipaddr(dotted, true);
   1344 }
   1345 
   1346 static struct in_addr *network_to_ipaddr(const char *name)
   1347 {
   1348 	static struct in_addr addr;
   1349 	struct netent *net;
   1350 
   1351 	if ((net = getnetbyname(name)) != NULL) {
   1352 		if (net->n_addrtype != AF_INET)
   1353 			return NULL;
   1354 		addr.s_addr = htonl(net->n_net);
   1355 		return &addr;
   1356 	}
   1357 
   1358 	return NULL;
   1359 }
   1360 
   1361 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
   1362 {
   1363 	struct in_addr *addr;
   1364 	struct addrinfo hints;
   1365 	struct addrinfo *res, *p;
   1366 	int err;
   1367 	unsigned int i;
   1368 
   1369 	memset(&hints, 0, sizeof(hints));
   1370 	hints.ai_flags    = AI_CANONNAME;
   1371 	hints.ai_family   = AF_INET;
   1372 	hints.ai_socktype = SOCK_RAW;
   1373 
   1374 	*naddr = 0;
   1375 	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
   1376 		return NULL;
   1377 	} else {
   1378 		for (p = res; p != NULL; p = p->ai_next)
   1379 			++*naddr;
   1380 		addr = xtables_calloc(*naddr, sizeof(struct in_addr));
   1381 		for (i = 0, p = res; p != NULL; p = p->ai_next)
   1382 			memcpy(&addr[i++],
   1383 			       &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
   1384 			       sizeof(struct in_addr));
   1385 		freeaddrinfo(res);
   1386 		return addr;
   1387 	}
   1388 
   1389 	return NULL;
   1390 }
   1391 
   1392 static struct in_addr *
   1393 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
   1394 {
   1395 	struct in_addr *addrptmp, *addrp;
   1396 
   1397 	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
   1398 	    (addrptmp = network_to_ipaddr(name)) != NULL) {
   1399 		addrp = xtables_malloc(sizeof(struct in_addr));
   1400 		memcpy(addrp, addrptmp, sizeof(*addrp));
   1401 		*naddrs = 1;
   1402 		return addrp;
   1403 	}
   1404 	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
   1405 		return addrptmp;
   1406 
   1407 	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
   1408 }
   1409 
   1410 static struct in_addr *parse_ipmask(const char *mask)
   1411 {
   1412 	static struct in_addr maskaddr;
   1413 	struct in_addr *addrp;
   1414 	unsigned int bits;
   1415 
   1416 	if (mask == NULL) {
   1417 		/* no mask at all defaults to 32 bits */
   1418 		maskaddr.s_addr = 0xFFFFFFFF;
   1419 		return &maskaddr;
   1420 	}
   1421 	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
   1422 		/* dotted_to_addr already returns a network byte order addr */
   1423 		return addrp;
   1424 	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
   1425 		xt_params->exit_err(PARAMETER_PROBLEM,
   1426 			   "invalid mask `%s' specified", mask);
   1427 	if (bits != 0) {
   1428 		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
   1429 		return &maskaddr;
   1430 	}
   1431 
   1432 	maskaddr.s_addr = 0U;
   1433 	return &maskaddr;
   1434 }
   1435 
   1436 void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
   1437                               struct in_addr **maskpp, unsigned int *naddrs)
   1438 {
   1439 	struct in_addr *addrp;
   1440 	char buf[256], *p, *next;
   1441 	unsigned int len, i, j, n, count = 1;
   1442 	const char *loop = name;
   1443 
   1444 	while ((loop = strchr(loop, ',')) != NULL) {
   1445 		++count;
   1446 		++loop; /* skip ',' */
   1447 	}
   1448 
   1449 	*addrpp = xtables_malloc(sizeof(struct in_addr) * count);
   1450 	*maskpp = xtables_malloc(sizeof(struct in_addr) * count);
   1451 
   1452 	loop = name;
   1453 
   1454 	for (i = 0; i < count; ++i) {
   1455 		while (isspace(*loop))
   1456 			++loop;
   1457 		next = strchr(loop, ',');
   1458 		if (next != NULL)
   1459 			len = next - loop;
   1460 		else
   1461 			len = strlen(loop);
   1462 		if (len > sizeof(buf) - 1)
   1463 			xt_params->exit_err(PARAMETER_PROBLEM,
   1464 				"Hostname too long");
   1465 
   1466 		strncpy(buf, loop, len);
   1467 		buf[len] = '\0';
   1468 		if ((p = strrchr(buf, '/')) != NULL) {
   1469 			*p = '\0';
   1470 			addrp = parse_ipmask(p + 1);
   1471 		} else {
   1472 			addrp = parse_ipmask(NULL);
   1473 		}
   1474 		memcpy(*maskpp + i, addrp, sizeof(*addrp));
   1475 
   1476 		/* if a null mask is given, the name is ignored, like in "any/0" */
   1477 		if ((*maskpp + i)->s_addr == 0)
   1478 			/*
   1479 			 * A bit pointless to process multiple addresses
   1480 			 * in this case...
   1481 			 */
   1482 			strcpy(buf, "0.0.0.0");
   1483 
   1484 		addrp = ipparse_hostnetwork(buf, &n);
   1485 		if (n > 1) {
   1486 			count += n - 1;
   1487 			*addrpp = xtables_realloc(*addrpp,
   1488 			          sizeof(struct in_addr) * count);
   1489 			*maskpp = xtables_realloc(*maskpp,
   1490 			          sizeof(struct in_addr) * count);
   1491 			for (j = 0; j < n; ++j)
   1492 				/* for each new addr */
   1493 				memcpy(*addrpp + i + j, addrp + j,
   1494 				       sizeof(*addrp));
   1495 			for (j = 1; j < n; ++j)
   1496 				/* for each new mask */
   1497 				memcpy(*maskpp + i + j, *maskpp + i,
   1498 				       sizeof(*addrp));
   1499 			i += n - 1;
   1500 		} else {
   1501 			memcpy(*addrpp + i, addrp, sizeof(*addrp));
   1502 		}
   1503 		/* free what ipparse_hostnetwork had allocated: */
   1504 		free(addrp);
   1505 		if (next == NULL)
   1506 			break;
   1507 		loop = next + 1;
   1508 	}
   1509 	*naddrs = count;
   1510 	for (i = 0; i < count; ++i)
   1511 		(*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
   1512 }
   1513 
   1514 
   1515 /**
   1516  * xtables_ipparse_any - transform arbitrary name to in_addr
   1517  *
   1518  * Possible inputs (pseudo regex):
   1519  * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
   1520  * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
   1521  */
   1522 void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
   1523                          struct in_addr *maskp, unsigned int *naddrs)
   1524 {
   1525 	unsigned int i, j, k, n;
   1526 	struct in_addr *addrp;
   1527 	char buf[256], *p;
   1528 
   1529 	strncpy(buf, name, sizeof(buf) - 1);
   1530 	buf[sizeof(buf) - 1] = '\0';
   1531 	if ((p = strrchr(buf, '/')) != NULL) {
   1532 		*p = '\0';
   1533 		addrp = parse_ipmask(p + 1);
   1534 	} else {
   1535 		addrp = parse_ipmask(NULL);
   1536 	}
   1537 	memcpy(maskp, addrp, sizeof(*maskp));
   1538 
   1539 	/* if a null mask is given, the name is ignored, like in "any/0" */
   1540 	if (maskp->s_addr == 0U)
   1541 		strcpy(buf, "0.0.0.0");
   1542 
   1543 	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
   1544 	n = *naddrs;
   1545 	for (i = 0, j = 0; i < n; ++i) {
   1546 		addrp[j++].s_addr &= maskp->s_addr;
   1547 		for (k = 0; k < j - 1; ++k)
   1548 			if (addrp[k].s_addr == addrp[j-1].s_addr) {
   1549 				/*
   1550 				 * Nuke the dup by copying an address from the
   1551 				 * tail here, and check the current position
   1552 				 * again (--j).
   1553 				 */
   1554 				memcpy(&addrp[--j], &addrp[--*naddrs],
   1555 				       sizeof(struct in_addr));
   1556 				break;
   1557 			}
   1558 	}
   1559 }
   1560 
   1561 const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
   1562 {
   1563 	/* 0000:0000:0000:0000:0000:0000:000.000.000.000
   1564 	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
   1565 	static char buf[50+1];
   1566 	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
   1567 }
   1568 
   1569 static const char *ip6addr_to_host(const struct in6_addr *addr)
   1570 {
   1571 	static char hostname[NI_MAXHOST];
   1572 	struct sockaddr_in6 saddr;
   1573 	int err;
   1574 
   1575 	memset(&saddr, 0, sizeof(struct sockaddr_in6));
   1576 	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
   1577 	saddr.sin6_family = AF_INET6;
   1578 
   1579 	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
   1580 			hostname, sizeof(hostname) - 1, NULL, 0, 0);
   1581 	if (err != 0)
   1582 		return NULL;
   1583 
   1584 	return hostname;
   1585 }
   1586 
   1587 const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
   1588 {
   1589 	const char *name;
   1590 
   1591 	if ((name = ip6addr_to_host(addr)) != NULL)
   1592 		return name;
   1593 
   1594 	return xtables_ip6addr_to_numeric(addr);
   1595 }
   1596 
   1597 int xtables_ip6mask_to_cidr(const struct in6_addr *k)
   1598 {
   1599 	unsigned int bits = 0;
   1600 	uint32_t a, b, c, d;
   1601 
   1602 	a = ntohl(k->s6_addr32[0]);
   1603 	b = ntohl(k->s6_addr32[1]);
   1604 	c = ntohl(k->s6_addr32[2]);
   1605 	d = ntohl(k->s6_addr32[3]);
   1606 	while (a & 0x80000000U) {
   1607 		++bits;
   1608 		a <<= 1;
   1609 		a  |= (b >> 31) & 1;
   1610 		b <<= 1;
   1611 		b  |= (c >> 31) & 1;
   1612 		c <<= 1;
   1613 		c  |= (d >> 31) & 1;
   1614 		d <<= 1;
   1615 	}
   1616 	if (a != 0 || b != 0 || c != 0 || d != 0)
   1617 		return -1;
   1618 	return bits;
   1619 }
   1620 
   1621 const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
   1622 {
   1623 	static char buf[50+2];
   1624 	int l = xtables_ip6mask_to_cidr(addrp);
   1625 
   1626 	if (l == -1) {
   1627 		strcpy(buf, "/");
   1628 		strcat(buf, xtables_ip6addr_to_numeric(addrp));
   1629 		return buf;
   1630 	}
   1631 	/* we don't want to see "/128" */
   1632 	if (l == 128)
   1633 		return "";
   1634 	else
   1635 		sprintf(buf, "/%d", l);
   1636 	return buf;
   1637 }
   1638 
   1639 struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
   1640 {
   1641 	static struct in6_addr ap;
   1642 	int err;
   1643 
   1644 	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
   1645 		return &ap;
   1646 
   1647 	return NULL;
   1648 }
   1649 
   1650 static struct in6_addr *
   1651 host_to_ip6addr(const char *name, unsigned int *naddr)
   1652 {
   1653 	struct in6_addr *addr;
   1654 	struct addrinfo hints;
   1655 	struct addrinfo *res, *p;
   1656 	int err;
   1657 	unsigned int i;
   1658 
   1659 	memset(&hints, 0, sizeof(hints));
   1660 	hints.ai_flags    = AI_CANONNAME;
   1661 	hints.ai_family   = AF_INET6;
   1662 	hints.ai_socktype = SOCK_RAW;
   1663 
   1664 	*naddr = 0;
   1665 	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
   1666 		return NULL;
   1667 	} else {
   1668 		/* Find length of address chain */
   1669 		for (p = res; p != NULL; p = p->ai_next)
   1670 			++*naddr;
   1671 		/* Copy each element of the address chain */
   1672 		addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
   1673 		for (i = 0, p = res; p != NULL; p = p->ai_next)
   1674 			memcpy(&addr[i++],
   1675 			       &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
   1676 			       sizeof(struct in6_addr));
   1677 		freeaddrinfo(res);
   1678 		return addr;
   1679 	}
   1680 
   1681 	return NULL;
   1682 }
   1683 
   1684 static struct in6_addr *network_to_ip6addr(const char *name)
   1685 {
   1686 	/*	abort();*/
   1687 	/* TODO: not implemented yet, but the exception breaks the
   1688 	 *       name resolvation */
   1689 	return NULL;
   1690 }
   1691 
   1692 static struct in6_addr *
   1693 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
   1694 {
   1695 	struct in6_addr *addrp, *addrptmp;
   1696 
   1697 	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
   1698 	    (addrptmp = network_to_ip6addr(name)) != NULL) {
   1699 		addrp = xtables_malloc(sizeof(struct in6_addr));
   1700 		memcpy(addrp, addrptmp, sizeof(*addrp));
   1701 		*naddrs = 1;
   1702 		return addrp;
   1703 	}
   1704 	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
   1705 		return addrp;
   1706 
   1707 	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
   1708 }
   1709 
   1710 static struct in6_addr *parse_ip6mask(char *mask)
   1711 {
   1712 	static struct in6_addr maskaddr;
   1713 	struct in6_addr *addrp;
   1714 	unsigned int bits;
   1715 
   1716 	if (mask == NULL) {
   1717 		/* no mask at all defaults to 128 bits */
   1718 		memset(&maskaddr, 0xff, sizeof maskaddr);
   1719 		return &maskaddr;
   1720 	}
   1721 	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
   1722 		return addrp;
   1723 	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
   1724 		xt_params->exit_err(PARAMETER_PROBLEM,
   1725 			   "invalid mask `%s' specified", mask);
   1726 	if (bits != 0) {
   1727 		char *p = (void *)&maskaddr;
   1728 		memset(p, 0xff, bits / 8);
   1729 		memset(p + ((bits + 7) / 8), 0, (128 - bits) / 8);
   1730 		if (bits < 128)
   1731 			p[bits/8] = 0xff << (8 - (bits & 7));
   1732 		return &maskaddr;
   1733 	}
   1734 
   1735 	memset(&maskaddr, 0, sizeof(maskaddr));
   1736 	return &maskaddr;
   1737 }
   1738 
   1739 void
   1740 xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
   1741 		      struct in6_addr **maskpp, unsigned int *naddrs)
   1742 {
   1743 	static const struct in6_addr zero_addr;
   1744 	struct in6_addr *addrp;
   1745 	char buf[256], *p, *next;
   1746 	unsigned int len, i, j, n, count = 1;
   1747 	const char *loop = name;
   1748 
   1749 	while ((loop = strchr(loop, ',')) != NULL) {
   1750 		++count;
   1751 		++loop; /* skip ',' */
   1752 	}
   1753 
   1754 	*addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
   1755 	*maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
   1756 
   1757 	loop = name;
   1758 
   1759 	for (i = 0; i < count /*NB: count can grow*/; ++i) {
   1760 		while (isspace(*loop))
   1761 			++loop;
   1762 		next = strchr(loop, ',');
   1763 		if (next != NULL)
   1764 			len = next - loop;
   1765 		else
   1766 			len = strlen(loop);
   1767 		if (len > sizeof(buf) - 1)
   1768 			xt_params->exit_err(PARAMETER_PROBLEM,
   1769 				"Hostname too long");
   1770 
   1771 		strncpy(buf, loop, len);
   1772 		buf[len] = '\0';
   1773 		if ((p = strrchr(buf, '/')) != NULL) {
   1774 			*p = '\0';
   1775 			addrp = parse_ip6mask(p + 1);
   1776 		} else {
   1777 			addrp = parse_ip6mask(NULL);
   1778 		}
   1779 		memcpy(*maskpp + i, addrp, sizeof(*addrp));
   1780 
   1781 		/* if a null mask is given, the name is ignored, like in "any/0" */
   1782 		if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
   1783 			strcpy(buf, "::");
   1784 
   1785 		addrp = ip6parse_hostnetwork(buf, &n);
   1786 		if (n > 1) {
   1787 			count += n - 1;
   1788 			*addrpp = xtables_realloc(*addrpp,
   1789 			          sizeof(struct in6_addr) * count);
   1790 			*maskpp = xtables_realloc(*maskpp,
   1791 			          sizeof(struct in6_addr) * count);
   1792 			for (j = 0; j < n; ++j)
   1793 				/* for each new addr */
   1794 				memcpy(*addrpp + i + j, addrp + j,
   1795 				       sizeof(*addrp));
   1796 			for (j = 1; j < n; ++j)
   1797 				/* for each new mask */
   1798 				memcpy(*maskpp + i + j, *maskpp + i,
   1799 				       sizeof(*addrp));
   1800 			i += n - 1;
   1801 		} else {
   1802 			memcpy(*addrpp + i, addrp, sizeof(*addrp));
   1803 		}
   1804 		/* free what ip6parse_hostnetwork had allocated: */
   1805 		free(addrp);
   1806 		if (next == NULL)
   1807 			break;
   1808 		loop = next + 1;
   1809 	}
   1810 	*naddrs = count;
   1811 	for (i = 0; i < count; ++i)
   1812 		for (j = 0; j < 4; ++j)
   1813 			(*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
   1814 }
   1815 
   1816 void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
   1817                           struct in6_addr *maskp, unsigned int *naddrs)
   1818 {
   1819 	static const struct in6_addr zero_addr;
   1820 	struct in6_addr *addrp;
   1821 	unsigned int i, j, k, n;
   1822 	char buf[256], *p;
   1823 
   1824 	strncpy(buf, name, sizeof(buf) - 1);
   1825 	buf[sizeof(buf)-1] = '\0';
   1826 	if ((p = strrchr(buf, '/')) != NULL) {
   1827 		*p = '\0';
   1828 		addrp = parse_ip6mask(p + 1);
   1829 	} else {
   1830 		addrp = parse_ip6mask(NULL);
   1831 	}
   1832 	memcpy(maskp, addrp, sizeof(*maskp));
   1833 
   1834 	/* if a null mask is given, the name is ignored, like in "any/0" */
   1835 	if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
   1836 		strcpy(buf, "::");
   1837 
   1838 	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
   1839 	n = *naddrs;
   1840 	for (i = 0, j = 0; i < n; ++i) {
   1841 		for (k = 0; k < 4; ++k)
   1842 			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
   1843 		++j;
   1844 		for (k = 0; k < j - 1; ++k)
   1845 			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
   1846 				/*
   1847 				 * Nuke the dup by copying an address from the
   1848 				 * tail here, and check the current position
   1849 				 * again (--j).
   1850 				 */
   1851 				memcpy(&addrp[--j], &addrp[--*naddrs],
   1852 				       sizeof(struct in_addr));
   1853 				break;
   1854 			}
   1855 	}
   1856 }
   1857 
   1858 void xtables_save_string(const char *value)
   1859 {
   1860 	static const char no_quote_chars[] = "_-0123456789"
   1861 		"abcdefghijklmnopqrstuvwxyz"
   1862 		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   1863 	static const char escape_chars[] = "\"\\'";
   1864 	size_t length;
   1865 	const char *p;
   1866 
   1867 	length = strspn(value, no_quote_chars);
   1868 	if (length > 0 && value[length] == 0) {
   1869 		/* no quoting required */
   1870 		putchar(' ');
   1871 		fputs(value, stdout);
   1872 	} else {
   1873 		/* there is at least one dangerous character in the
   1874 		   value, which we have to quote.  Write double quotes
   1875 		   around the value and escape special characters with
   1876 		   a backslash */
   1877 		printf(" \"");
   1878 
   1879 		for (p = strpbrk(value, escape_chars); p != NULL;
   1880 		     p = strpbrk(value, escape_chars)) {
   1881 			if (p > value)
   1882 				fwrite(value, 1, p - value, stdout);
   1883 			putchar('\\');
   1884 			putchar(*p);
   1885 			value = p + 1;
   1886 		}
   1887 
   1888 		/* print the rest and finish the double quoted
   1889 		   string */
   1890 		fputs(value, stdout);
   1891 		putchar('\"');
   1892 	}
   1893 }
   1894 
   1895 const struct xtables_pprot xtables_chain_protos[] = {
   1896 	{"tcp",       IPPROTO_TCP},
   1897 	{"sctp",      IPPROTO_SCTP},
   1898 	{"udp",       IPPROTO_UDP},
   1899 	{"udplite",   IPPROTO_UDPLITE},
   1900 	{"icmp",      IPPROTO_ICMP},
   1901 	{"icmpv6",    IPPROTO_ICMPV6},
   1902 	{"ipv6-icmp", IPPROTO_ICMPV6},
   1903 	{"esp",       IPPROTO_ESP},
   1904 	{"ah",        IPPROTO_AH},
   1905 	{"ipv6-mh",   IPPROTO_MH},
   1906 	{"mh",        IPPROTO_MH},
   1907 	{"all",       0},
   1908 	{NULL},
   1909 };
   1910 
   1911 uint16_t
   1912 xtables_parse_protocol(const char *s)
   1913 {
   1914 	const struct protoent *pent;
   1915 	unsigned int proto, i;
   1916 
   1917 	if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
   1918 		return proto;
   1919 
   1920 	/* first deal with the special case of 'all' to prevent
   1921 	 * people from being able to redefine 'all' in nsswitch
   1922 	 * and/or provoke expensive [not working] ldap/nis/...
   1923 	 * lookups */
   1924 	if (strcmp(s, "all") == 0)
   1925 		return 0;
   1926 
   1927 	pent = getprotobyname(s);
   1928 	if (pent != NULL)
   1929 		return pent->p_proto;
   1930 
   1931 	for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
   1932 		if (xtables_chain_protos[i].name == NULL)
   1933 			continue;
   1934 		if (strcmp(s, xtables_chain_protos[i].name) == 0)
   1935 			return xtables_chain_protos[i].num;
   1936 	}
   1937 	xt_params->exit_err(PARAMETER_PROBLEM,
   1938 		"unknown protocol \"%s\" specified", s);
   1939 	return -1;
   1940 }
   1941 
   1942 void xtables_print_num(uint64_t number, unsigned int format)
   1943 {
   1944 	if (!(format & FMT_KILOMEGAGIGA)) {
   1945 		printf(FMT("%8llu ","%llu "), (unsigned long long)number);
   1946 		return;
   1947 	}
   1948 	if (number <= 99999) {
   1949 		printf(FMT("%5llu ","%llu "), (unsigned long long)number);
   1950 		return;
   1951 	}
   1952 	number = (number + 500) / 1000;
   1953 	if (number <= 9999) {
   1954 		printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
   1955 		return;
   1956 	}
   1957 	number = (number + 500) / 1000;
   1958 	if (number <= 9999) {
   1959 		printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
   1960 		return;
   1961 	}
   1962 	number = (number + 500) / 1000;
   1963 	if (number <= 9999) {
   1964 		printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
   1965 		return;
   1966 	}
   1967 	number = (number + 500) / 1000;
   1968 	printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
   1969 }
   1970 
   1971 int kernel_version;
   1972 
   1973 void get_kernel_version(void)
   1974 {
   1975 	static struct utsname uts;
   1976 	int x = 0, y = 0, z = 0;
   1977 
   1978 	if (uname(&uts) == -1) {
   1979 		fprintf(stderr, "Unable to retrieve kernel version.\n");
   1980 		xtables_free_opts(1);
   1981 		exit(1);
   1982 	}
   1983 
   1984 	sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
   1985 	kernel_version = LINUX_VERSION(x, y, z);
   1986 }
   1987 
   1988 #include <linux/netfilter/nf_tables.h>
   1989 
   1990 struct xt_xlate {
   1991 	struct {
   1992 		char	*data;
   1993 		int	size;
   1994 		int	rem;
   1995 		int	off;
   1996 	} buf;
   1997 	char comment[NFT_USERDATA_MAXLEN];
   1998 };
   1999 
   2000 struct xt_xlate *xt_xlate_alloc(int size)
   2001 {
   2002 	struct xt_xlate *xl;
   2003 
   2004 	xl = malloc(sizeof(struct xt_xlate));
   2005 	if (xl == NULL)
   2006 		xtables_error(RESOURCE_PROBLEM, "OOM");
   2007 
   2008 	xl->buf.data = malloc(size);
   2009 	if (xl->buf.data == NULL)
   2010 		xtables_error(RESOURCE_PROBLEM, "OOM");
   2011 
   2012 	xl->buf.size = size;
   2013 	xl->buf.rem = size;
   2014 	xl->buf.off = 0;
   2015 	xl->comment[0] = '\0';
   2016 
   2017 	return xl;
   2018 }
   2019 
   2020 void xt_xlate_free(struct xt_xlate *xl)
   2021 {
   2022 	free(xl->buf.data);
   2023 	free(xl);
   2024 }
   2025 
   2026 void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...)
   2027 {
   2028 	va_list ap;
   2029 	int len;
   2030 
   2031 	va_start(ap, fmt);
   2032 	len = vsnprintf(xl->buf.data + xl->buf.off, xl->buf.rem, fmt, ap);
   2033 	if (len < 0 || len >= xl->buf.rem)
   2034 		xtables_error(RESOURCE_PROBLEM, "OOM");
   2035 
   2036 	va_end(ap);
   2037 	xl->buf.rem -= len;
   2038 	xl->buf.off += len;
   2039 }
   2040 
   2041 void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
   2042 {
   2043 	strncpy(xl->comment, comment, NFT_USERDATA_MAXLEN - 1);
   2044 	xl->comment[NFT_USERDATA_MAXLEN - 1] = '\0';
   2045 }
   2046 
   2047 const char *xt_xlate_get_comment(struct xt_xlate *xl)
   2048 {
   2049 	return xl->comment[0] ? xl->comment : NULL;
   2050 }
   2051 
   2052 const char *xt_xlate_get(struct xt_xlate *xl)
   2053 {
   2054 	return xl->buf.data;
   2055 }
   2056