xref: /aosp_15_r20/external/iptables/libxtables/xtables.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 /*
2  * (C) 2000-2006 by the netfilter coreteam <[email protected]>:
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 <spawn.h>
25 #include <stdarg.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <netinet/ether.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/statfs.h>
35 #include <sys/types.h>
36 #include <sys/utsname.h>
37 #include <sys/wait.h>
38 #include <arpa/inet.h>
39 #if defined(HAVE_LINUX_MAGIC_H)
40 #	include <linux/magic.h> /* for PROC_SUPER_MAGIC */
41 #elif defined(HAVE_LINUX_PROC_FS_H)
42 #	include <linux/proc_fs.h>	/* Linux 2.4 */
43 #else
44 #	define PROC_SUPER_MAGIC	0x9fa0
45 #endif
46 
47 #include <xtables.h>
48 #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
49 #include <linux/netfilter_ipv4/ip_tables.h>
50 #include <linux/netfilter_ipv6/ip6_tables.h>
51 #include <libiptc/libxtc.h>
52 #include <libiptc/linux_list.h>
53 
54 #ifndef NO_SHARED_LIBS
55 #include <dlfcn.h>
56 #endif
57 #ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
58 #	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
59 #	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
60 #endif
61 #ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
62 #	define IP6T_SO_GET_REVISION_MATCH	68
63 #	define IP6T_SO_GET_REVISION_TARGET	69
64 #endif
65 #include <getopt.h>
66 #include "iptables/internal.h"
67 
68 #define NPROTO	255
69 
70 #ifndef PROC_SYS_MODPROBE
71 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
72 #endif
73 
74 #ifndef ETH_ALEN
75 #define ETH_ALEN 6
76 #endif
77 
78 /* we need this for ip6?tables-restore.  ip6?tables-restore.c sets line to the
79  * current line of the input file, in order  to give a more precise error
80  * message.  ip6?tables itself doesn't need this, so it is initialized to the
81  * magic number of -1 */
82 int line = -1;
83 
84 void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
85 
86 struct xtables_globals *xt_params = NULL;
87 
basic_exit_err(enum xtables_exittype status,const char * msg,...)88 void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
89 {
90 	va_list args;
91 
92 	va_start(args, msg);
93 	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
94 	vfprintf(stderr, msg, args);
95 	va_end(args);
96 	fprintf(stderr, "\n");
97 	if (status == PARAMETER_PROBLEM) {
98 		if (line != -1)
99 			fprintf(stderr, "Error occurred at line: %d\n", line);
100 		fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
101 				xt_params->program_name, xt_params->program_name);
102 	} else if (status == VERSION_PROBLEM) {
103 		fprintf(stderr,
104 			"Perhaps %s or your kernel needs to be upgraded.\n",
105 			xt_params->program_name);
106 	}
107 	/* On error paths, make sure that we don't leak memory */
108 	xtables_free_opts(1);
109 	exit(status);
110 }
111 
xtables_free_opts(int unused)112 void xtables_free_opts(int unused)
113 {
114 	if (xt_params->opts != xt_params->orig_opts) {
115 		free(xt_params->opts);
116 		xt_params->opts = NULL;
117 	}
118 }
119 
xtables_merge_options(struct option * orig_opts,struct option * oldopts,const struct option * newopts,unsigned int * option_offset)120 struct option *xtables_merge_options(struct option *orig_opts,
121 				     struct option *oldopts,
122 				     const struct option *newopts,
123 				     unsigned int *option_offset)
124 {
125 	unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
126 	struct option *merge, *mp;
127 
128 	if (newopts == NULL)
129 		return oldopts;
130 
131 	for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
132 	if (oldopts != NULL)
133 		for (num_old = 0; oldopts[num_old].name; num_old++) ;
134 	for (num_new = 0; newopts[num_new].name; num_new++) ;
135 
136 	/*
137 	 * Since @oldopts also has @orig_opts already (and does so at the
138 	 * start), skip these entries.
139 	 */
140 	if (oldopts != NULL) {
141 		oldopts += num_oold;
142 		num_old -= num_oold;
143 	}
144 
145 	merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
146 	if (merge == NULL)
147 		return NULL;
148 
149 	/* Let the base options -[ADI...] have precedence over everything */
150 	memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
151 	mp = merge + num_oold;
152 
153 	/* Second, the new options */
154 	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
155 	*option_offset = xt_params->option_offset;
156 	memcpy(mp, newopts, sizeof(*mp) * num_new);
157 
158 	for (i = 0; i < num_new; ++i, ++mp)
159 		mp->val += *option_offset;
160 
161 	/* Third, the old options */
162 	if (oldopts != NULL) {
163 		memcpy(mp, oldopts, sizeof(*mp) * num_old);
164 		mp += num_old;
165 	}
166 	xtables_free_opts(0);
167 
168 	/* Clear trailing entry */
169 	memset(mp, 0, sizeof(*mp));
170 	return merge;
171 }
172 
173 static const struct xtables_afinfo afinfo_ipv4 = {
174 	.kmod          = "ip_tables",
175 	.proc_exists   = "/proc/net/ip_tables_names",
176 	.libprefix     = "libipt_",
177 	.family	       = NFPROTO_IPV4,
178 	.ipproto       = IPPROTO_IP,
179 	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
180 	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
181 };
182 
183 static const struct xtables_afinfo afinfo_ipv6 = {
184 	.kmod          = "ip6_tables",
185 	.proc_exists   = "/proc/net/ip6_tables_names",
186 	.libprefix     = "libip6t_",
187 	.family        = NFPROTO_IPV6,
188 	.ipproto       = IPPROTO_IPV6,
189 	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
190 	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
191 };
192 
193 /* Dummy families for arptables-compat and ebtables-compat. Leave structure
194  * fields that we don't use unset.
195  */
196 static const struct xtables_afinfo afinfo_bridge = {
197 	.libprefix     = "libebt_",
198 	.family        = NFPROTO_BRIDGE,
199 };
200 
201 static const struct xtables_afinfo afinfo_arp = {
202 	.libprefix     = "libarpt_",
203 	.family        = NFPROTO_ARP,
204 };
205 
206 const struct xtables_afinfo *afinfo;
207 
208 /* Search path for Xtables .so files */
209 static const char *xtables_libdir;
210 
211 /* the path to command to load kernel module */
212 const char *xtables_modprobe_program;
213 
214 /* Keep track of matches/targets pending full registration: linked lists. */
215 struct xtables_match *xtables_pending_matches;
216 struct xtables_target *xtables_pending_targets;
217 
218 /* Keep track of fully registered external matches/targets: linked lists. */
219 struct xtables_match *xtables_matches;
220 struct xtables_target *xtables_targets;
221 
222 /* Fully register a match/target which was previously partially registered. */
223 static bool xtables_fully_register_pending_match(struct xtables_match *me,
224 						 struct xtables_match *prev);
225 static bool xtables_fully_register_pending_target(struct xtables_target *me,
226 						  struct xtables_target *prev);
227 
228 #ifndef NO_SHARED_LIBS
229 /* registry for loaded shared objects to close later */
230 struct dlreg {
231 	struct dlreg *next;
232 	void *handle;
233 };
234 static struct dlreg *dlreg = NULL;
235 
dlreg_add(void * handle)236 static int dlreg_add(void *handle)
237 {
238 	struct dlreg *new = malloc(sizeof(*new));
239 
240 	if (!new)
241 		return -1;
242 
243 	new->handle = handle;
244 	new->next = dlreg;
245 	dlreg = new;
246 	return 0;
247 }
248 
dlreg_free(void)249 static void dlreg_free(void)
250 {
251 	struct dlreg *next;
252 
253 	while (dlreg) {
254 		next = dlreg->next;
255 		dlclose(dlreg->handle);
256 		free(dlreg);
257 		dlreg = next;
258 	}
259 }
260 #endif
261 
262 struct notarget {
263 	struct hlist_node node;
264 	char name[];
265 };
266 
267 #define NOTARGET_HSIZE	512
268 static struct hlist_head notargets[NOTARGET_HSIZE];
269 
notargets_hlist_init(void)270 static void notargets_hlist_init(void)
271 {
272 	int i;
273 
274 	for (i = 0; i < NOTARGET_HSIZE; i++)
275 		INIT_HLIST_HEAD(&notargets[i]);
276 }
277 
notargets_hlist_free(void)278 static void notargets_hlist_free(void)
279 {
280 	struct hlist_node *pos, *n;
281 	struct notarget *cur;
282 	int i;
283 
284 	for (i = 0; i < NOTARGET_HSIZE; i++) {
285 		hlist_for_each_entry_safe(cur, pos, n, &notargets[i], node) {
286 			hlist_del(&cur->node);
287 			free(cur);
288 		}
289 	}
290 }
291 
djb_hash(const char * key)292 static uint32_t djb_hash(const char *key)
293 {
294 	uint32_t i, hash = 5381;
295 
296 	for (i = 0; i < strlen(key); i++)
297 		hash = ((hash << 5) + hash) + key[i];
298 
299 	return hash;
300 }
301 
notargets_hlist_lookup(const char * name)302 static struct notarget *notargets_hlist_lookup(const char *name)
303 {
304 	uint32_t key = djb_hash(name) % NOTARGET_HSIZE;
305 	struct hlist_node *node;
306 	struct notarget *cur;
307 
308 	hlist_for_each_entry(cur, node, &notargets[key], node) {
309 		if (!strcmp(name, cur->name))
310 			return cur;
311 	}
312 	return NULL;
313 }
314 
notargets_hlist_insert(const char * name)315 static void notargets_hlist_insert(const char *name)
316 {
317 	struct notarget *cur;
318 
319 	if (!name)
320 		return;
321 
322 	cur = xtables_malloc(sizeof(*cur) + strlen(name) + 1);
323 	strcpy(cur->name, name);
324 	hlist_add_head(&cur->node, &notargets[djb_hash(name) % NOTARGET_HSIZE]);
325 }
326 
xtables_announce_chain(const char * name)327 void xtables_announce_chain(const char *name)
328 {
329 	if (!notargets_hlist_lookup(name))
330 		notargets_hlist_insert(name);
331 }
332 
xtables_init(void)333 void xtables_init(void)
334 {
335 	/* xtables cannot be used with setuid in a safe way. */
336 	if (getuid() != geteuid())
337 		_exit(111);
338 
339 	xtables_libdir = getenv("XTABLES_LIBDIR");
340 	if (xtables_libdir != NULL)
341 		return;
342 	xtables_libdir = getenv("IPTABLES_LIB_DIR");
343 	if (xtables_libdir != NULL) {
344 		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
345 		        "use XTABLES_LIBDIR.\n");
346 		return;
347 	}
348 	/*
349 	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
350 	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
351 	 * for these env vars are deprecated anyhow, and in light of the
352 	 * (shared) libxt_*.so files, makes less sense to have
353 	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
354 	 */
355 	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
356 	if (xtables_libdir != NULL) {
357 		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
358 		        "use XTABLES_LIBDIR.\n");
359 		return;
360 	}
361 	xtables_libdir = XTABLES_LIBDIR;
362 
363 	notargets_hlist_init();
364 }
365 
xtables_fini(void)366 void xtables_fini(void)
367 {
368 #ifndef NO_SHARED_LIBS
369 	dlreg_free();
370 #endif
371 	notargets_hlist_free();
372 }
373 
xtables_set_nfproto(uint8_t nfproto)374 void xtables_set_nfproto(uint8_t nfproto)
375 {
376 	switch (nfproto) {
377 	case NFPROTO_IPV4:
378 		afinfo = &afinfo_ipv4;
379 		break;
380 	case NFPROTO_IPV6:
381 		afinfo = &afinfo_ipv6;
382 		break;
383 	case NFPROTO_BRIDGE:
384 		afinfo = &afinfo_bridge;
385 		break;
386 	case NFPROTO_ARP:
387 		afinfo = &afinfo_arp;
388 		break;
389 	default:
390 		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
391 		        __func__);
392 	}
393 }
394 
395 /**
396  * xtables_set_params - set the global parameters used by xtables
397  * @xtp:	input xtables_globals structure
398  *
399  * The app is expected to pass a valid xtables_globals data-filled
400  * with proper values
401  * @xtp cannot be NULL
402  *
403  * Returns -1 on failure to set and 0 on success
404  */
xtables_set_params(struct xtables_globals * xtp)405 int xtables_set_params(struct xtables_globals *xtp)
406 {
407 	if (!xtp) {
408 		fprintf(stderr, "%s: Illegal global params\n",__func__);
409 		return -1;
410 	}
411 
412 	xt_params = xtp;
413 
414 	if (!xt_params->exit_err)
415 		xt_params->exit_err = basic_exit_err;
416 
417 	return 0;
418 }
419 
xtables_init_all(struct xtables_globals * xtp,uint8_t nfproto)420 int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
421 {
422 	xtables_init();
423 	xtables_set_nfproto(nfproto);
424 	return xtables_set_params(xtp);
425 }
426 
427 /**
428  * xtables_*alloc - wrappers that exit on failure
429  */
xtables_calloc(size_t count,size_t size)430 void *xtables_calloc(size_t count, size_t size)
431 {
432 	void *p;
433 
434 	if ((p = calloc(count, size)) == NULL) {
435 		perror("ip[6]tables: calloc failed");
436 		exit(1);
437 	}
438 
439 	return p;
440 }
441 
xtables_malloc(size_t size)442 void *xtables_malloc(size_t size)
443 {
444 	void *p;
445 
446 	if ((p = malloc(size)) == NULL) {
447 		perror("ip[6]tables: malloc failed");
448 		exit(1);
449 	}
450 
451 	return p;
452 }
453 
xtables_realloc(void * ptr,size_t size)454 void *xtables_realloc(void *ptr, size_t size)
455 {
456 	void *p;
457 
458 	if ((p = realloc(ptr, size)) == NULL) {
459 		perror("ip[6]tables: realloc failed");
460 		exit(1);
461 	}
462 
463 	return p;
464 }
465 
xtables_strdup(const char * s)466 char *xtables_strdup(const char *s)
467 {
468 	char *dup = strdup(s);
469 
470 	if (!dup) {
471 		perror("ip[6]tables: strdup failed");
472 		exit(1);
473 	}
474 
475 	return dup;
476 }
477 
get_modprobe(void)478 static char *get_modprobe(void)
479 {
480 	int procfile;
481 	char *ret;
482 	int count;
483 
484 	procfile = open(PROC_SYS_MODPROBE, O_RDONLY | O_CLOEXEC);
485 	if (procfile < 0)
486 		return NULL;
487 
488 	ret = malloc(PATH_MAX);
489 	if (ret) {
490 		count = read(procfile, ret, PATH_MAX);
491 		if (count > 0 && count < PATH_MAX)
492 		{
493 			if (ret[count - 1] == '\n')
494 				ret[count - 1] = '\0';
495 			else
496 				ret[count] = '\0';
497 			close(procfile);
498 			return ret;
499 		}
500 	}
501 	free(ret);
502 	close(procfile);
503 	return NULL;
504 }
505 
xtables_insmod(const char * modname,const char * modprobe,bool quiet)506 int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
507 {
508 	char *buf = NULL;
509 	char *argv[4];
510 	int status;
511 	pid_t pid;
512 
513 	/* If they don't explicitly set it, read out of kernel */
514 	if (!modprobe) {
515 		buf = get_modprobe();
516 		if (!buf)
517 			return -1;
518 		modprobe = buf;
519 	}
520 
521 	argv[0] = (char *)modprobe;
522 	argv[1] = (char *)modname;
523 	argv[2] = quiet ? "-q" : NULL;
524 	argv[3] = NULL;
525 
526 	/*
527 	 * Need to flush the buffer, or the child may output it again
528 	 * when switching the program thru execv.
529 	 */
530 	fflush(stdout);
531 
532 	if (posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL)) {
533 		free(buf);
534 		return -1;
535 	} else {
536 		waitpid(pid, &status, 0);
537 	}
538 
539 	free(buf);
540 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
541 		return 0;
542 	return -1;
543 }
544 
545 /* return true if a given file exists within procfs */
proc_file_exists(const char * filename)546 static bool proc_file_exists(const char *filename)
547 {
548 	struct stat s;
549 	struct statfs f;
550 
551 	if (lstat(filename, &s))
552 		return false;
553 	if (!S_ISREG(s.st_mode))
554 		return false;
555 	if (statfs(filename, &f))
556 		return false;
557 	if (f.f_type != PROC_SUPER_MAGIC)
558 		return false;
559 	return true;
560 }
561 
xtables_load_ko(const char * modprobe,bool quiet)562 int xtables_load_ko(const char *modprobe, bool quiet)
563 {
564 	static bool loaded = false;
565 	int ret;
566 
567 	if (loaded)
568 		return 0;
569 
570 	if (proc_file_exists(afinfo->proc_exists)) {
571 		loaded = true;
572 		return 0;
573 	};
574 
575 	ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
576 	if (ret == 0)
577 		loaded = true;
578 
579 	return ret;
580 }
581 
582 /**
583  * xtables_strtou{i,l} - string to number conversion
584  * @s:	input string
585  * @end:	like strtoul's "end" pointer
586  * @value:	pointer for result
587  * @min:	minimum accepted value
588  * @max:	maximum accepted value
589  *
590  * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
591  * "15a" is rejected.
592  * In either case, the value obtained is compared for min-max compliance.
593  * Base is always 0, i.e. autodetect depending on @s.
594  *
595  * Returns true/false whether number was accepted. On failure, *value has
596  * undefined contents.
597  */
xtables_strtoul(const char * s,char ** end,uintmax_t * value,uintmax_t min,uintmax_t max)598 bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
599                      uintmax_t min, uintmax_t max)
600 {
601 	uintmax_t v;
602 	const char *p;
603 	char *my_end;
604 
605 	errno = 0;
606 	/* Since strtoul allows leading minus, we have to check for ourself. */
607 	for (p = s; isspace(*p); ++p)
608 		;
609 	if (*p == '-')
610 		return false;
611 	v = strtoumax(s, &my_end, 0);
612 	if (my_end == s)
613 		return false;
614 	if (end != NULL)
615 		*end = my_end;
616 
617 	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
618 		if (value != NULL)
619 			*value = v;
620 		if (end == NULL)
621 			return *my_end == '\0';
622 		return true;
623 	}
624 
625 	return false;
626 }
627 
xtables_strtoui(const char * s,char ** end,unsigned int * value,unsigned int min,unsigned int max)628 bool xtables_strtoui(const char *s, char **end, unsigned int *value,
629                      unsigned int min, unsigned int max)
630 {
631 	uintmax_t v;
632 	bool ret;
633 
634 	ret = xtables_strtoul(s, end, &v, min, max);
635 	if (ret && value != NULL)
636 		*value = v;
637 	return ret;
638 }
639 
xtables_service_to_port(const char * name,const char * proto)640 int xtables_service_to_port(const char *name, const char *proto)
641 {
642 	struct servent *service;
643 
644 	if ((service = getservbyname(name, proto)) != NULL)
645 		return ntohs((unsigned short) service->s_port);
646 
647 	return -1;
648 }
649 
xtables_parse_port(const char * port,const char * proto)650 uint16_t xtables_parse_port(const char *port, const char *proto)
651 {
652 	unsigned int portnum;
653 
654 	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
655 	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
656 		return portnum;
657 
658 	xt_params->exit_err(PARAMETER_PROBLEM,
659 		   "invalid port/service `%s' specified", port);
660 }
661 
xtables_parse_interface(const char * arg,char * vianame,unsigned char * mask)662 void xtables_parse_interface(const char *arg, char *vianame,
663 			     unsigned char *mask)
664 {
665 	unsigned int vialen = strlen(arg);
666 	unsigned int i;
667 
668 	memset(mask, 0, IFNAMSIZ);
669 	memset(vianame, 0, IFNAMSIZ);
670 
671 	if (vialen + 1 > IFNAMSIZ)
672 		xt_params->exit_err(PARAMETER_PROBLEM,
673 			   "interface name `%s' must be shorter than IFNAMSIZ"
674 			   " (%i)", arg, IFNAMSIZ-1);
675 
676 	strcpy(vianame, arg);
677 	if (vialen == 0)
678 		return;
679 	else if (vianame[vialen - 1] == '+') {
680 		memset(mask, 0xFF, vialen - 1);
681 		/* Don't remove `+' here! -HW */
682 	} else {
683 		/* Include nul-terminator in match */
684 		memset(mask, 0xFF, vialen + 1);
685 	}
686 
687 	/* Display warning on invalid characters */
688 	for (i = 0; vianame[i]; i++) {
689 		if (vianame[i] == '/' || vianame[i] == ' ') {
690 			fprintf(stderr,	"Warning: weird character in interface"
691 				" `%s' ('/' and ' ' are not allowed by the kernel).\n",
692 				vianame);
693 			break;
694 		}
695 	}
696 }
697 
698 #ifndef NO_SHARED_LIBS
load_extension(const char * search_path,const char * af_prefix,const char * name,bool is_target)699 static void *load_extension(const char *search_path, const char *af_prefix,
700     const char *name, bool is_target)
701 {
702 	const char *all_prefixes[] = {af_prefix, "libxt_", NULL};
703 	const char **prefix;
704 	const char *dir = search_path, *next;
705 	void *ptr = NULL;
706 	struct stat sb;
707 	char path[256];
708 
709 	do {
710 		next = strchr(dir, ':');
711 		if (next == NULL)
712 			next = dir + strlen(dir);
713 
714 		for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
715 			void *handle;
716 
717 			snprintf(path, sizeof(path), "%.*s/%s%s.so",
718 			         (unsigned int)(next - dir), dir,
719 			         *prefix, name);
720 
721 			if (stat(path, &sb) != 0) {
722 				if (errno == ENOENT)
723 					continue;
724 				fprintf(stderr, "%s: %s\n", path,
725 					strerror(errno));
726 				return NULL;
727 			}
728 			handle = dlopen(path, RTLD_NOW);
729 			if (handle == NULL) {
730 				fprintf(stderr, "%s: %s\n", path, dlerror());
731 				break;
732 			}
733 
734 			dlreg_add(handle);
735 
736 			if (is_target)
737 				ptr = xtables_find_target(name, XTF_DONT_LOAD);
738 			else
739 				ptr = xtables_find_match(name,
740 				      XTF_DONT_LOAD, NULL);
741 
742 			if (ptr != NULL)
743 				return ptr;
744 
745 			errno = ENOENT;
746 			return NULL;
747 		}
748 		dir = next + 1;
749 	} while (*next != '\0');
750 
751 	return NULL;
752 }
753 #endif
754 
extension_cmp(const char * name1,const char * name2,uint32_t family)755 static bool extension_cmp(const char *name1, const char *name2, uint32_t family)
756 {
757 	if (strcmp(name1, name2) == 0 &&
758 	    (family == afinfo->family ||
759 	     family == NFPROTO_UNSPEC))
760 		return true;
761 
762 	return false;
763 }
764 
765 struct xtables_match *
xtables_find_match(const char * name,enum xtables_tryload tryload,struct xtables_rule_match ** matches)766 xtables_find_match(const char *name, enum xtables_tryload tryload,
767 		   struct xtables_rule_match **matches)
768 {
769 	struct xtables_match *prev = NULL;
770 	struct xtables_match **dptr;
771 	struct xtables_match *ptr;
772 	const char *icmp6 = "icmp6";
773 	bool found = false;
774 	bool seen = false;
775 
776 	if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
777 		xtables_error(PARAMETER_PROBLEM,
778 			   "Invalid match name \"%s\" (%u chars max)",
779 			   name, XT_EXTENSION_MAXNAMELEN - 1);
780 
781 	/* This is ugly as hell. Nonetheless, there is no way of changing
782 	 * this without hurting backwards compatibility */
783 	if ( (strcmp(name,"icmpv6") == 0) ||
784 	     (strcmp(name,"ipv6-icmp") == 0) ||
785 	     (strcmp(name,"icmp6") == 0) )
786 		name = icmp6;
787 
788 	/* Trigger delayed initialization */
789 	for (dptr = &xtables_pending_matches; *dptr; ) {
790 		if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
791 			ptr = *dptr;
792 			*dptr = (*dptr)->next;
793 			seen = true;
794 			if (!found &&
795 			    xtables_fully_register_pending_match(ptr, prev)) {
796 				found = true;
797 				prev = ptr;
798 				continue;
799 			} else if (prev) {
800 				continue;
801 			}
802 			*dptr = ptr;
803 		}
804 		dptr = &((*dptr)->next);
805 	}
806 
807 	if (seen && !found)
808 		fprintf(stderr,
809 			"Warning: Extension %s is not supported, missing kernel module?\n",
810 			name);
811 
812 	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
813 		if (extension_cmp(name, ptr->name, ptr->family)) {
814 			struct xtables_match *clone;
815 
816 			/* First match of this type: */
817 			if (ptr->m == NULL)
818 				break;
819 
820 			/* Second and subsequent clones */
821 			clone = xtables_malloc(sizeof(struct xtables_match));
822 			memcpy(clone, ptr, sizeof(struct xtables_match));
823 			clone->udata = NULL;
824 			clone->mflags = 0;
825 			/* This is a clone: */
826 			clone->next = clone;
827 
828 			ptr = clone;
829 			break;
830 		}
831 	}
832 
833 #ifndef NO_SHARED_LIBS
834 	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
835 		ptr = load_extension(xtables_libdir, afinfo->libprefix,
836 		      name, false);
837 
838 		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
839 			xt_params->exit_err(PARAMETER_PROBLEM,
840 				   "Couldn't load match `%s':%s\n",
841 				   name, strerror(errno));
842 	}
843 #else
844 	if (ptr && !ptr->loaded) {
845 		if (tryload != XTF_DONT_LOAD)
846 			ptr->loaded = 1;
847 		else
848 			ptr = NULL;
849 	}
850 	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
851 		xt_params->exit_err(PARAMETER_PROBLEM,
852 			   "Couldn't find match `%s'\n", name);
853 	}
854 #endif
855 
856 	if (ptr && matches) {
857 		struct xtables_rule_match **i;
858 		struct xtables_rule_match *newentry;
859 
860 		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
861 
862 		for (i = matches; *i; i = &(*i)->next) {
863 			if (extension_cmp(name, (*i)->match->name,
864 					  (*i)->match->family))
865 				(*i)->completed = true;
866 		}
867 		newentry->match = ptr;
868 		newentry->completed = false;
869 		newentry->next = NULL;
870 		*i = newentry;
871 	}
872 
873 	return ptr;
874 }
875 
876 struct xtables_match *
xtables_find_match_revision(const char * name,enum xtables_tryload tryload,struct xtables_match * match,int revision)877 xtables_find_match_revision(const char *name, enum xtables_tryload tryload,
878 			    struct xtables_match *match, int revision)
879 {
880 	if (!match) {
881 		match = xtables_find_match(name, tryload, NULL);
882 		if (!match)
883 			return NULL;
884 	}
885 
886 	while (1) {
887 		if (match->revision == revision)
888 			return match;
889 		match = match->next;
890 		if (!match)
891 			return NULL;
892 		if (!extension_cmp(name, match->name, match->family))
893 			return NULL;
894 	}
895 }
896 
897 struct xtables_target *
xtables_find_target(const char * name,enum xtables_tryload tryload)898 xtables_find_target(const char *name, enum xtables_tryload tryload)
899 {
900 	struct xtables_target *prev = NULL;
901 	struct xtables_target **dptr;
902 	struct xtables_target *ptr;
903 	bool found = false;
904 	bool seen = false;
905 
906 	/* Standard target? */
907 	if (strcmp(name, "") == 0
908 	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
909 	    || strcmp(name, XTC_LABEL_DROP) == 0
910 	    || strcmp(name, XTC_LABEL_QUEUE) == 0
911 	    || strcmp(name, XTC_LABEL_RETURN) == 0)
912 		name = "standard";
913 	/* known non-target? */
914 	else if (notargets_hlist_lookup(name) &&
915 		 tryload != XTF_LOAD_MUST_SUCCEED)
916 		return NULL;
917 
918 	/* Trigger delayed initialization */
919 	for (dptr = &xtables_pending_targets; *dptr; ) {
920 		if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
921 			ptr = *dptr;
922 			*dptr = (*dptr)->next;
923 			seen = true;
924 			if (!found &&
925 			    xtables_fully_register_pending_target(ptr, prev)) {
926 				found = true;
927 				prev = ptr;
928 				continue;
929 			} else if (prev) {
930 				continue;
931 			}
932 			*dptr = ptr;
933 		}
934 		dptr = &((*dptr)->next);
935 	}
936 
937 	if (seen && !found)
938 		fprintf(stderr,
939 			"Warning: Extension %s is not supported, missing kernel module?\n",
940 			name);
941 
942 	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
943 		if (extension_cmp(name, ptr->name, ptr->family)) {
944 #if 0			/* Code block below causes memory leak.  (Bugs 162925719 and 168688680) */
945 			struct xtables_target *clone;
946 
947 			/* First target of this type: */
948 			if (ptr->t == NULL)
949 				break;
950 
951 			/* Second and subsequent clones */
952 			clone = xtables_malloc(sizeof(struct xtables_target));
953 			memcpy(clone, ptr, sizeof(struct xtables_target));
954 			clone->udata = NULL;
955 			clone->tflags = 0;
956 			/* This is a clone: */
957 			clone->next = clone;
958 
959 			ptr = clone;
960 #endif
961 			break;
962 		}
963 	}
964 
965 #ifndef NO_SHARED_LIBS
966 	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
967 		ptr = load_extension(xtables_libdir, afinfo->libprefix,
968 		      name, true);
969 
970 		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
971 			xt_params->exit_err(PARAMETER_PROBLEM,
972 				   "Couldn't load target `%s':%s\n",
973 				   name, strerror(errno));
974 	}
975 #else
976 	if (ptr && !ptr->loaded) {
977 		if (tryload != XTF_DONT_LOAD)
978 			ptr->loaded = 1;
979 		else
980 			ptr = NULL;
981 	}
982 	if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
983 		xt_params->exit_err(PARAMETER_PROBLEM,
984 			   "Couldn't find target `%s'\n", name);
985 	}
986 #endif
987 
988 	if (ptr)
989 		ptr->used = 1;
990 	else
991 		notargets_hlist_insert(name);
992 
993 	return ptr;
994 }
995 
996 struct xtables_target *
xtables_find_target_revision(const char * name,enum xtables_tryload tryload,struct xtables_target * target,int revision)997 xtables_find_target_revision(const char *name, enum xtables_tryload tryload,
998 			     struct xtables_target *target, int revision)
999 {
1000 	if (!target) {
1001 		target = xtables_find_target(name, tryload);
1002 		if (!target)
1003 			return NULL;
1004 	}
1005 
1006 	while (1) {
1007 		if (target->revision == revision)
1008 			return target;
1009 		target = target->next;
1010 		if (!target)
1011 			return NULL;
1012 		if (!extension_cmp(name, target->name, target->family))
1013 			return NULL;
1014 	}
1015 }
1016 
xtables_compatible_revision(const char * name,uint8_t revision,int opt)1017 int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
1018 {
1019 	struct xt_get_revision rev;
1020 	socklen_t s = sizeof(rev);
1021 	int max_rev, sockfd;
1022 
1023 	sockfd = socket(afinfo->family, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
1024 	if (sockfd < 0) {
1025 		if (errno == EPERM) {
1026 			/* revision 0 is always supported. */
1027 			if (revision != 0)
1028 				fprintf(stderr, "%s: Could not determine whether "
1029 						"revision %u is supported, "
1030 						"assuming it is.\n",
1031 					name, revision);
1032 			return 1;
1033 		}
1034 		fprintf(stderr, "Could not open socket to kernel: %s\n",
1035 			strerror(errno));
1036 		exit(1);
1037 	}
1038 
1039 	xtables_load_ko(xtables_modprobe_program, true);
1040 
1041 	strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
1042 	rev.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
1043 	rev.revision = revision;
1044 
1045 	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
1046 	if (max_rev < 0) {
1047 		/* Definitely don't support this? */
1048 		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
1049 			close(sockfd);
1050 			/* Pretend revision 0 support for better error messaging */
1051 			if (revision == 0)
1052 				fprintf(stderr,
1053 					"Warning: Extension %s revision 0 not supported, missing kernel module?\n",
1054 					name);
1055 			return (revision == 0);
1056 		} else if (errno == ENOPROTOOPT) {
1057 			close(sockfd);
1058 			/* Assume only revision 0 support (old kernel) */
1059 			return (revision == 0);
1060 		} else {
1061 			fprintf(stderr, "getsockopt failed strangely: %s\n",
1062 				strerror(errno));
1063 			exit(1);
1064 		}
1065 	}
1066 	close(sockfd);
1067 	return 1;
1068 }
1069 
1070 
compatible_match_revision(const char * name,uint8_t revision)1071 static int compatible_match_revision(const char *name, uint8_t revision)
1072 {
1073 	return xt_params->compat_rev(name, revision, afinfo->so_rev_match);
1074 }
1075 
compatible_target_revision(const char * name,uint8_t revision)1076 static int compatible_target_revision(const char *name, uint8_t revision)
1077 {
1078 	return xt_params->compat_rev(name, revision, afinfo->so_rev_target);
1079 }
1080 
xtables_check_options(const char * name,const struct option * opt)1081 static void xtables_check_options(const char *name, const struct option *opt)
1082 {
1083 	for (; opt->name != NULL; ++opt)
1084 		if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
1085 			fprintf(stderr, "%s: Extension %s uses invalid "
1086 			        "option value %d\n",xt_params->program_name,
1087 			        name, opt->val);
1088 			exit(1);
1089 		}
1090 }
1091 
1092 static int xtables_match_prefer(const struct xtables_match *a,
1093 				const struct xtables_match *b);
1094 
xtables_register_match(struct xtables_match * me)1095 void xtables_register_match(struct xtables_match *me)
1096 {
1097 	struct xtables_match **pos;
1098 	bool seen_myself = false;
1099 
1100 	if (me->next) {
1101 		fprintf(stderr, "%s: match \"%s\" already registered\n",
1102 			xt_params->program_name, me->name);
1103 		exit(1);
1104 	}
1105 
1106 	if (me->version == NULL) {
1107 		fprintf(stderr, "%s: match %s<%u> is missing a version\n",
1108 		        xt_params->program_name, me->name, me->revision);
1109 		exit(1);
1110 	}
1111 
1112 	if (me->size != XT_ALIGN(me->size)) {
1113 		fprintf(stderr, "%s: match \"%s\" has invalid size %u.\n",
1114 		        xt_params->program_name, me->name,
1115 		        (unsigned int)me->size);
1116 		exit(1);
1117 	}
1118 
1119 	if (strcmp(me->version, XTABLES_VERSION) != 0) {
1120 		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
1121 		        "but \"%s\" is required.\n",
1122 			xt_params->program_name, me->name,
1123 			me->version, XTABLES_VERSION);
1124 		exit(1);
1125 	}
1126 
1127 	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1128 		fprintf(stderr, "%s: match `%s' has invalid name\n",
1129 			xt_params->program_name, me->name);
1130 		exit(1);
1131 	}
1132 
1133 	if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
1134 		fprintf(stderr, "%s: match `%s' has invalid real name\n",
1135 			xt_params->program_name, me->real_name);
1136 		exit(1);
1137 	}
1138 
1139 	if (me->family >= NPROTO) {
1140 		fprintf(stderr,
1141 			"%s: BUG: match %s has invalid protocol family\n",
1142 			xt_params->program_name, me->name);
1143 		exit(1);
1144 	}
1145 
1146 	if (me->x6_options != NULL)
1147 		xtables_option_metavalidate(me->name, me->x6_options);
1148 	if (me->extra_opts != NULL)
1149 		xtables_check_options(me->name, me->extra_opts);
1150 
1151 	/* order into linked list of matches pending full registration */
1152 	for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
1153 		/* group by name and family */
1154 		if (strcmp(me->name, (*pos)->name) ||
1155 		    me->family != (*pos)->family) {
1156 			if (seen_myself)
1157 				break; /* end of own group, append to it */
1158 			continue;
1159 		}
1160 		/* found own group */
1161 		seen_myself = true;
1162 		if (xtables_match_prefer(me, *pos) >= 0)
1163 			break; /* put preferred items first in group */
1164 	}
1165 	/* if own group was not found, prepend item */
1166 	if (!*pos && !seen_myself)
1167 		pos = &xtables_pending_matches;
1168 
1169 	me->next = *pos;
1170 	*pos = me;
1171 #ifdef DEBUG
1172 	printf("%s: inserted match %s (family %d, revision %d):\n",
1173 			__func__, me->name, me->family, me->revision);
1174 	for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
1175 		printf("%s:\tmatch %s (family %d, revision %d)\n", __func__,
1176 		       (*pos)->name, (*pos)->family, (*pos)->revision);
1177 	}
1178 #endif
1179 }
1180 
1181 /**
1182  * Compare two actions for their preference
1183  * @a:	one action
1184  * @b: 	another
1185  *
1186  * Like strcmp, returns a negative number if @a is less preferred than @b,
1187  * positive number if @a is more preferred than @b, or zero if equally
1188  * preferred.
1189  */
1190 static int
xtables_mt_prefer(bool a_alias,unsigned int a_rev,unsigned int a_fam,bool b_alias,unsigned int b_rev,unsigned int b_fam)1191 xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam,
1192 		  bool b_alias, unsigned int b_rev, unsigned int b_fam)
1193 {
1194 	/*
1195 	 * Alias ranks higher than no alias.
1196 	 * (We want the new action to be used whenever possible.)
1197 	 */
1198 	if (!a_alias && b_alias)
1199 		return -1;
1200 	if (a_alias && !b_alias)
1201 		return 1;
1202 
1203 	/* Higher revision ranks higher. */
1204 	if (a_rev < b_rev)
1205 		return -1;
1206 	if (a_rev > b_rev)
1207 		return 1;
1208 
1209 	/* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */
1210 	if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC)
1211 		return -1;
1212 	if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC)
1213 		return 1;
1214 
1215 	/* Must be the same thing. */
1216 	return 0;
1217 }
1218 
xtables_match_prefer(const struct xtables_match * a,const struct xtables_match * b)1219 static int xtables_match_prefer(const struct xtables_match *a,
1220 				const struct xtables_match *b)
1221 {
1222 	return xtables_mt_prefer(a->real_name != NULL,
1223 				 a->revision, a->family,
1224 				 b->real_name != NULL,
1225 				 b->revision, b->family);
1226 }
1227 
xtables_target_prefer(const struct xtables_target * a,const struct xtables_target * b)1228 static int xtables_target_prefer(const struct xtables_target *a,
1229 				 const struct xtables_target *b)
1230 {
1231 	/*
1232 	 * Note that if x->real_name==NULL, it will be set to x->name in
1233 	 * xtables_register_*; the direct pointer comparison here is therefore
1234 	 * legitimate to detect an alias.
1235 	 */
1236 	return xtables_mt_prefer(a->real_name != NULL,
1237 				 a->revision, a->family,
1238 				 b->real_name != NULL,
1239 				 b->revision, b->family);
1240 }
1241 
xtables_fully_register_pending_match(struct xtables_match * me,struct xtables_match * prev)1242 static bool xtables_fully_register_pending_match(struct xtables_match *me,
1243 						 struct xtables_match *prev)
1244 {
1245 	struct xtables_match **i;
1246 	const char *rn;
1247 
1248 	/* See if new match can be used. */
1249 	rn = (me->real_name != NULL) ? me->real_name : me->name;
1250 	if (!compatible_match_revision(rn, me->revision))
1251 		return false;
1252 
1253 	if (!prev) {
1254 		/* Append to list. */
1255 		for (i = &xtables_matches; *i; i = &(*i)->next);
1256 	} else {
1257 		/* Append it */
1258 		i = &prev->next;
1259 		prev = prev->next;
1260 	}
1261 
1262 	me->next = prev;
1263 	*i = me;
1264 
1265 	me->m = NULL;
1266 	me->mflags = 0;
1267 
1268 	return true;
1269 }
1270 
xtables_register_matches(struct xtables_match * match,unsigned int n)1271 void xtables_register_matches(struct xtables_match *match, unsigned int n)
1272 {
1273 	int i;
1274 
1275 	for (i = 0; i < n; i++)
1276 		xtables_register_match(&match[i]);
1277 }
1278 
xtables_register_target(struct xtables_target * me)1279 void xtables_register_target(struct xtables_target *me)
1280 {
1281 	struct xtables_target **pos;
1282 	bool seen_myself = false;
1283 
1284 	if (me->next) {
1285 		fprintf(stderr, "%s: target \"%s\" already registered\n",
1286 			xt_params->program_name, me->name);
1287 		exit(1);
1288 	}
1289 
1290 	if (me->version == NULL) {
1291 		fprintf(stderr, "%s: target %s<%u> is missing a version\n",
1292 		        xt_params->program_name, me->name, me->revision);
1293 		exit(1);
1294 	}
1295 
1296 	if (me->size != XT_ALIGN(me->size)) {
1297 		fprintf(stderr, "%s: target \"%s\" has invalid size %u.\n",
1298 		        xt_params->program_name, me->name,
1299 		        (unsigned int)me->size);
1300 		exit(1);
1301 	}
1302 
1303 	if (strcmp(me->version, XTABLES_VERSION) != 0) {
1304 		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
1305 		        "but \"%s\" is required.\n",
1306 			xt_params->program_name, me->name,
1307 			me->version, XTABLES_VERSION);
1308 		exit(1);
1309 	}
1310 
1311 	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1312 		fprintf(stderr, "%s: target `%s' has invalid name\n",
1313 			xt_params->program_name, me->name);
1314 		exit(1);
1315 	}
1316 
1317 	if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
1318 		fprintf(stderr, "%s: target `%s' has invalid real name\n",
1319 			xt_params->program_name, me->real_name);
1320 		exit(1);
1321 	}
1322 
1323 	if (me->family >= NPROTO) {
1324 		fprintf(stderr,
1325 			"%s: BUG: target %s has invalid protocol family\n",
1326 			xt_params->program_name, me->name);
1327 		exit(1);
1328 	}
1329 
1330 	if (me->x6_options != NULL)
1331 		xtables_option_metavalidate(me->name, me->x6_options);
1332 	if (me->extra_opts != NULL)
1333 		xtables_check_options(me->name, me->extra_opts);
1334 
1335 	/* ignore not interested target */
1336 	if (me->family != afinfo->family && me->family != AF_UNSPEC)
1337 		return;
1338 
1339 	/* order into linked list of targets pending full registration */
1340 	for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
1341 		/* group by name */
1342 		if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) {
1343 			if (seen_myself)
1344 				break; /* end of own group, append to it */
1345 			continue;
1346 		}
1347 		/* found own group */
1348 		seen_myself = true;
1349 		if (xtables_target_prefer(me, *pos) >= 0)
1350 			break; /* put preferred items first in group */
1351 	}
1352 	/* if own group was not found, prepend item */
1353 	if (!*pos && !seen_myself)
1354 		pos = &xtables_pending_targets;
1355 
1356 	me->next = *pos;
1357 	*pos = me;
1358 #ifdef DEBUG
1359 	printf("%s: inserted target %s (family %d, revision %d):\n",
1360 			__func__, me->name, me->family, me->revision);
1361 	for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
1362 		printf("%s:\ttarget %s (family %d, revision %d)\n", __func__,
1363 		       (*pos)->name, (*pos)->family, (*pos)->revision);
1364 	}
1365 #endif
1366 }
1367 
xtables_fully_register_pending_target(struct xtables_target * me,struct xtables_target * prev)1368 static bool xtables_fully_register_pending_target(struct xtables_target *me,
1369 						  struct xtables_target *prev)
1370 {
1371 	struct xtables_target **i;
1372 	const char *rn;
1373 
1374 	if (strcmp(me->name, "standard") != 0) {
1375 		/* See if new target can be used. */
1376 		rn = (me->real_name != NULL) ? me->real_name : me->name;
1377 		if (!compatible_target_revision(rn, me->revision))
1378 			return false;
1379 	}
1380 
1381 	if (!prev) {
1382 		/* Prepend to list. */
1383 		i = &xtables_targets;
1384 		prev = xtables_targets;
1385 	} else {
1386 		/* Append it */
1387 		i = &prev->next;
1388 		prev = prev->next;
1389 	}
1390 
1391 	me->next = prev;
1392 	*i = me;
1393 
1394 	me->t = NULL;
1395 	me->tflags = 0;
1396 
1397 	return true;
1398 }
1399 
xtables_register_targets(struct xtables_target * target,unsigned int n)1400 void xtables_register_targets(struct xtables_target *target, unsigned int n)
1401 {
1402 	int i;
1403 
1404 	for (i = 0; i < n; i++)
1405 		xtables_register_target(&target[i]);
1406 }
1407 
1408 /* receives a list of xtables_rule_match, release them */
xtables_rule_matches_free(struct xtables_rule_match ** matches)1409 void xtables_rule_matches_free(struct xtables_rule_match **matches)
1410 {
1411 	struct xtables_rule_match *matchp, *tmp;
1412 
1413 	for (matchp = *matches; matchp;) {
1414 		tmp = matchp->next;
1415 		if (matchp->match->m) {
1416 			free(matchp->match->m);
1417 			matchp->match->m = NULL;
1418 		}
1419 		if (matchp->match == matchp->match->next) {
1420 			free(matchp->match);
1421 			matchp->match = NULL;
1422 		}
1423 		free(matchp);
1424 		matchp = tmp;
1425 	}
1426 
1427 	*matches = NULL;
1428 }
1429 
1430 /**
1431  * xtables_param_act - act on condition
1432  * @status:	a constant from enum xtables_exittype
1433  *
1434  * %XTF_ONLY_ONCE: print error message that option may only be used once.
1435  * @p1:		module name (e.g. "mark")
1436  * @p2(...):	option in conflict (e.g. "--mark")
1437  * @p3(...):	condition to match on (see extensions/ for examples)
1438  *
1439  * %XTF_NO_INVERT: option does not support inversion
1440  * @p1:		module name
1441  * @p2:		option in conflict
1442  * @p3:		condition to match on
1443  *
1444  * %XTF_BAD_VALUE: bad value for option
1445  * @p1:		module name
1446  * @p2:		option with which the problem occurred (e.g. "--mark")
1447  * @p3:		string the user passed in (e.g. "99999999999999")
1448  *
1449  * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1450  * @p1:		module name
1451  *
1452  * Displays an error message and exits the program.
1453  */
xtables_param_act(unsigned int status,const char * p1,...)1454 void xtables_param_act(unsigned int status, const char *p1, ...)
1455 {
1456 	const char *p2, *p3;
1457 	va_list args;
1458 	bool b;
1459 
1460 	va_start(args, p1);
1461 
1462 	switch (status) {
1463 	case XTF_ONLY_ONCE:
1464 		p2 = va_arg(args, const char *);
1465 		b  = va_arg(args, unsigned int);
1466 		if (!b) {
1467 			va_end(args);
1468 			return;
1469 		}
1470 		xt_params->exit_err(PARAMETER_PROBLEM,
1471 		           "%s: \"%s\" option may only be specified once",
1472 		           p1, p2);
1473 		break;
1474 	case XTF_NO_INVERT:
1475 		p2 = va_arg(args, const char *);
1476 		b  = va_arg(args, unsigned int);
1477 		if (!b) {
1478 			va_end(args);
1479 			return;
1480 		}
1481 		xt_params->exit_err(PARAMETER_PROBLEM,
1482 		           "%s: \"%s\" option cannot be inverted", p1, p2);
1483 		break;
1484 	case XTF_BAD_VALUE:
1485 		p2 = va_arg(args, const char *);
1486 		p3 = va_arg(args, const char *);
1487 		xt_params->exit_err(PARAMETER_PROBLEM,
1488 		           "%s: Bad value for \"%s\" option: \"%s\"",
1489 		           p1, p2, p3);
1490 		break;
1491 	case XTF_ONE_ACTION:
1492 		b = va_arg(args, unsigned int);
1493 		if (!b) {
1494 			va_end(args);
1495 			return;
1496 		}
1497 		xt_params->exit_err(PARAMETER_PROBLEM,
1498 		           "%s: At most one action is possible", p1);
1499 		break;
1500 	default:
1501 		xt_params->exit_err(status, p1, args);
1502 		break;
1503 	}
1504 
1505 	va_end(args);
1506 }
1507 
xtables_ipaddr_to_numeric(const struct in_addr * addrp)1508 const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
1509 {
1510 	static char buf[16];
1511 	const unsigned char *bytep = (const void *)&addrp->s_addr;
1512 
1513 	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
1514 	return buf;
1515 }
1516 
ipaddr_to_host(const struct in_addr * addr)1517 static const char *ipaddr_to_host(const struct in_addr *addr)
1518 {
1519 	static char hostname[NI_MAXHOST];
1520 	struct sockaddr_in saddr = {
1521 		.sin_family = AF_INET,
1522 		.sin_addr = *addr,
1523 	};
1524 	int err;
1525 
1526 
1527 	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in),
1528 		       hostname, sizeof(hostname) - 1, NULL, 0, 0);
1529 	if (err != 0)
1530 		return NULL;
1531 
1532 	return hostname;
1533 }
1534 
ipaddr_to_network(const struct in_addr * addr)1535 static const char *ipaddr_to_network(const struct in_addr *addr)
1536 {
1537 	struct netent *net;
1538 
1539 	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
1540 		return net->n_name;
1541 
1542 	return NULL;
1543 }
1544 
xtables_ipaddr_to_anyname(const struct in_addr * addr)1545 const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
1546 {
1547 	const char *name;
1548 
1549 	if ((name = ipaddr_to_host(addr)) != NULL ||
1550 	    (name = ipaddr_to_network(addr)) != NULL)
1551 		return name;
1552 
1553 	return xtables_ipaddr_to_numeric(addr);
1554 }
1555 
xtables_ipmask_to_cidr(const struct in_addr * mask)1556 int xtables_ipmask_to_cidr(const struct in_addr *mask)
1557 {
1558 	uint32_t maskaddr, bits;
1559 	int i;
1560 
1561 	maskaddr = ntohl(mask->s_addr);
1562 
1563 	for (i = 32, bits = (uint32_t)-1; i >= 0; i--, bits <<= 1) {
1564 		if (bits == maskaddr)
1565 			return i;
1566 	}
1567 
1568 	/* this mask cannot be converted to CIDR notation */
1569 	return -1;
1570 }
1571 
xtables_ipmask_to_numeric(const struct in_addr * mask)1572 const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
1573 {
1574 	static char buf[20];
1575 	uint32_t cidr;
1576 
1577 	cidr = xtables_ipmask_to_cidr(mask);
1578 	if (cidr == (unsigned int)-1) {
1579 		/* mask was not a decent combination of 1's and 0's */
1580 		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
1581 		return buf;
1582 	} else if (cidr == 32) {
1583 		/* we don't want to see "/32" */
1584 		return "";
1585 	}
1586 
1587 	sprintf(buf, "/%d", cidr);
1588 	return buf;
1589 }
1590 
__numeric_to_ipaddr(const char * dotted,bool is_mask)1591 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1592 {
1593 	static struct in_addr addr;
1594 	unsigned char *addrp;
1595 	unsigned int onebyte;
1596 	char buf[20], *p, *q;
1597 	int i;
1598 
1599 	/* copy dotted string, because we need to modify it */
1600 	strncpy(buf, dotted, sizeof(buf) - 1);
1601 	buf[sizeof(buf) - 1] = '\0';
1602 	addrp = (void *)&addr.s_addr;
1603 
1604 	p = buf;
1605 	for (i = 0; i < 3; ++i) {
1606 		if ((q = strchr(p, '.')) == NULL) {
1607 			if (is_mask)
1608 				return NULL;
1609 
1610 			/* autocomplete, this is a network address */
1611 			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1612 				return NULL;
1613 
1614 			addrp[i] = onebyte;
1615 			while (i < 3)
1616 				addrp[++i] = 0;
1617 
1618 			return &addr;
1619 		}
1620 
1621 		*q = '\0';
1622 		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1623 			return NULL;
1624 
1625 		addrp[i] = onebyte;
1626 		p = q + 1;
1627 	}
1628 
1629 	/* we have checked 3 bytes, now we check the last one */
1630 	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1631 		return NULL;
1632 
1633 	addrp[3] = onebyte;
1634 	return &addr;
1635 }
1636 
xtables_numeric_to_ipaddr(const char * dotted)1637 struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1638 {
1639 	return __numeric_to_ipaddr(dotted, false);
1640 }
1641 
xtables_numeric_to_ipmask(const char * dotted)1642 struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1643 {
1644 	return __numeric_to_ipaddr(dotted, true);
1645 }
1646 
network_to_ipaddr(const char * name)1647 static struct in_addr *network_to_ipaddr(const char *name)
1648 {
1649 	static struct in_addr addr;
1650 	struct netent *net;
1651 
1652 	if ((net = getnetbyname(name)) != NULL) {
1653 		if (net->n_addrtype != AF_INET)
1654 			return NULL;
1655 		addr.s_addr = htonl(net->n_net);
1656 		return &addr;
1657 	}
1658 
1659 	return NULL;
1660 }
1661 
host_to_ipaddr(const char * name,unsigned int * naddr)1662 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1663 {
1664 	struct in_addr *addr;
1665 	struct addrinfo hints;
1666 	struct addrinfo *res, *p;
1667 	int err;
1668 	unsigned int i;
1669 
1670 	memset(&hints, 0, sizeof(hints));
1671 	hints.ai_family   = AF_INET;
1672 	hints.ai_socktype = SOCK_RAW;
1673 
1674 	*naddr = 0;
1675 	err = getaddrinfo(name, NULL, &hints, &res);
1676 	if (err != 0)
1677 		return NULL;
1678 	for (p = res; p != NULL; p = p->ai_next)
1679 		++*naddr;
1680 	addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1681 	for (i = 0, p = res; p != NULL; p = p->ai_next)
1682 		memcpy(&addr[i++],
1683 		       &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
1684 		       sizeof(struct in_addr));
1685 	freeaddrinfo(res);
1686 	return addr;
1687 }
1688 
1689 static struct in_addr *
ipparse_hostnetwork(const char * name,unsigned int * naddrs)1690 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
1691 {
1692 	struct in_addr *addrptmp, *addrp;
1693 
1694 	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1695 	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1696 		addrp = xtables_malloc(sizeof(struct in_addr));
1697 		memcpy(addrp, addrptmp, sizeof(*addrp));
1698 		*naddrs = 1;
1699 		return addrp;
1700 	}
1701 	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1702 		return addrptmp;
1703 
1704 	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1705 }
1706 
parse_ipmask(const char * mask)1707 static struct in_addr *parse_ipmask(const char *mask)
1708 {
1709 	static struct in_addr maskaddr;
1710 	struct in_addr *addrp;
1711 	unsigned int bits;
1712 
1713 	if (mask == NULL) {
1714 		/* no mask at all defaults to 32 bits */
1715 		maskaddr.s_addr = 0xFFFFFFFF;
1716 		return &maskaddr;
1717 	}
1718 	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1719 		/* dotted_to_addr already returns a network byte order addr */
1720 		return addrp;
1721 	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1722 		xt_params->exit_err(PARAMETER_PROBLEM,
1723 			   "invalid mask `%s' specified", mask);
1724 	if (bits != 0) {
1725 		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1726 		return &maskaddr;
1727 	}
1728 
1729 	maskaddr.s_addr = 0U;
1730 	return &maskaddr;
1731 }
1732 
xtables_ipparse_multiple(const char * name,struct in_addr ** addrpp,struct in_addr ** maskpp,unsigned int * naddrs)1733 void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1734                               struct in_addr **maskpp, unsigned int *naddrs)
1735 {
1736 	struct in_addr *addrp;
1737 	char buf[256], *p, *next;
1738 	unsigned int len, i, j, n, count = 1;
1739 	const char *loop = name;
1740 
1741 	while ((loop = strchr(loop, ',')) != NULL) {
1742 		++count;
1743 		++loop; /* skip ',' */
1744 	}
1745 
1746 	*addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1747 	*maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1748 
1749 	loop = name;
1750 
1751 	for (i = 0; i < count; ++i) {
1752 		while (isspace(*loop))
1753 			++loop;
1754 		next = strchr(loop, ',');
1755 		if (next != NULL)
1756 			len = next - loop;
1757 		else
1758 			len = strlen(loop);
1759 		if (len > sizeof(buf) - 1)
1760 			xt_params->exit_err(PARAMETER_PROBLEM,
1761 				"Hostname too long");
1762 
1763 		strncpy(buf, loop, len);
1764 		buf[len] = '\0';
1765 		if ((p = strrchr(buf, '/')) != NULL) {
1766 			*p = '\0';
1767 			addrp = parse_ipmask(p + 1);
1768 		} else {
1769 			addrp = parse_ipmask(NULL);
1770 		}
1771 		memcpy(*maskpp + i, addrp, sizeof(*addrp));
1772 
1773 		/* if a null mask is given, the name is ignored, like in "any/0" */
1774 		if ((*maskpp + i)->s_addr == 0)
1775 			/*
1776 			 * A bit pointless to process multiple addresses
1777 			 * in this case...
1778 			 */
1779 			strcpy(buf, "0.0.0.0");
1780 
1781 		addrp = ipparse_hostnetwork(buf, &n);
1782 		if (n > 1) {
1783 			count += n - 1;
1784 			*addrpp = xtables_realloc(*addrpp,
1785 			          sizeof(struct in_addr) * count);
1786 			*maskpp = xtables_realloc(*maskpp,
1787 			          sizeof(struct in_addr) * count);
1788 			for (j = 0; j < n; ++j)
1789 				/* for each new addr */
1790 				memcpy(*addrpp + i + j, addrp + j,
1791 				       sizeof(*addrp));
1792 			for (j = 1; j < n; ++j)
1793 				/* for each new mask */
1794 				memcpy(*maskpp + i + j, *maskpp + i,
1795 				       sizeof(*addrp));
1796 			i += n - 1;
1797 		} else {
1798 			memcpy(*addrpp + i, addrp, sizeof(*addrp));
1799 		}
1800 		/* free what ipparse_hostnetwork had allocated: */
1801 		free(addrp);
1802 		if (next == NULL)
1803 			break;
1804 		loop = next + 1;
1805 	}
1806 	*naddrs = count;
1807 	for (i = 0; i < count; ++i)
1808 		(*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1809 }
1810 
1811 
1812 /**
1813  * xtables_ipparse_any - transform arbitrary name to in_addr
1814  *
1815  * Possible inputs (pseudo regex):
1816  * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1817  * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1818  */
xtables_ipparse_any(const char * name,struct in_addr ** addrpp,struct in_addr * maskp,unsigned int * naddrs)1819 void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1820                          struct in_addr *maskp, unsigned int *naddrs)
1821 {
1822 	unsigned int i, j, k, n;
1823 	struct in_addr *addrp;
1824 	char buf[256], *p;
1825 
1826 	strncpy(buf, name, sizeof(buf) - 1);
1827 	buf[sizeof(buf) - 1] = '\0';
1828 	if ((p = strrchr(buf, '/')) != NULL) {
1829 		*p = '\0';
1830 		addrp = parse_ipmask(p + 1);
1831 	} else {
1832 		addrp = parse_ipmask(NULL);
1833 	}
1834 	memcpy(maskp, addrp, sizeof(*maskp));
1835 
1836 	/* if a null mask is given, the name is ignored, like in "any/0" */
1837 	if (maskp->s_addr == 0U)
1838 		strcpy(buf, "0.0.0.0");
1839 
1840 	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1841 	n = *naddrs;
1842 	for (i = 0, j = 0; i < n; ++i) {
1843 		addrp[j++].s_addr &= maskp->s_addr;
1844 		for (k = 0; k < j - 1; ++k)
1845 			if (addrp[k].s_addr == addrp[j-1].s_addr) {
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 
xtables_ip6addr_to_numeric(const struct in6_addr * addrp)1858 const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1859 {
1860 	/* 0000:0000:0000:0000:0000:0000:000.000.000.000
1861 	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
1862 	static char buf[50+1];
1863 	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1864 }
1865 
ip6addr_to_host(const struct in6_addr * addr)1866 static const char *ip6addr_to_host(const struct in6_addr *addr)
1867 {
1868 	static char hostname[NI_MAXHOST];
1869 	struct sockaddr_in6 saddr;
1870 	int err;
1871 
1872 	memset(&saddr, 0, sizeof(struct sockaddr_in6));
1873 	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1874 	saddr.sin6_family = AF_INET6;
1875 
1876 	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1877 			hostname, sizeof(hostname) - 1, NULL, 0, 0);
1878 	if (err != 0)
1879 		return NULL;
1880 
1881 	return hostname;
1882 }
1883 
xtables_ip6addr_to_anyname(const struct in6_addr * addr)1884 const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1885 {
1886 	const char *name;
1887 
1888 	if ((name = ip6addr_to_host(addr)) != NULL)
1889 		return name;
1890 
1891 	return xtables_ip6addr_to_numeric(addr);
1892 }
1893 
xtables_ip6mask_to_cidr(const struct in6_addr * k)1894 int xtables_ip6mask_to_cidr(const struct in6_addr *k)
1895 {
1896 	unsigned int bits = 0;
1897 	uint32_t a, b, c, d;
1898 
1899 	a = ntohl(k->s6_addr32[0]);
1900 	b = ntohl(k->s6_addr32[1]);
1901 	c = ntohl(k->s6_addr32[2]);
1902 	d = ntohl(k->s6_addr32[3]);
1903 	while (a & 0x80000000U) {
1904 		++bits;
1905 		a <<= 1;
1906 		a  |= (b >> 31) & 1;
1907 		b <<= 1;
1908 		b  |= (c >> 31) & 1;
1909 		c <<= 1;
1910 		c  |= (d >> 31) & 1;
1911 		d <<= 1;
1912 	}
1913 	if (a != 0 || b != 0 || c != 0 || d != 0)
1914 		return -1;
1915 	return bits;
1916 }
1917 
xtables_ip6mask_to_numeric(const struct in6_addr * addrp)1918 const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1919 {
1920 	static char buf[50+2];
1921 	int l = xtables_ip6mask_to_cidr(addrp);
1922 
1923 	if (l == -1) {
1924 		strcpy(buf, "/");
1925 		strcat(buf, xtables_ip6addr_to_numeric(addrp));
1926 		return buf;
1927 	}
1928 	/* we don't want to see "/128" */
1929 	if (l == 128)
1930 		return "";
1931 	else
1932 		sprintf(buf, "/%d", l);
1933 	return buf;
1934 }
1935 
xtables_numeric_to_ip6addr(const char * num)1936 struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1937 {
1938 	static struct in6_addr ap;
1939 
1940 	if (inet_pton(AF_INET6, num, &ap) == 1)
1941 		return &ap;
1942 
1943 	return NULL;
1944 }
1945 
1946 static struct in6_addr *
host_to_ip6addr(const char * name,unsigned int * naddr)1947 host_to_ip6addr(const char *name, unsigned int *naddr)
1948 {
1949 	struct in6_addr *addr;
1950 	struct addrinfo hints;
1951 	struct addrinfo *res, *p;
1952 	int err;
1953 	unsigned int i;
1954 
1955 	memset(&hints, 0, sizeof(hints));
1956 	hints.ai_family   = AF_INET6;
1957 	hints.ai_socktype = SOCK_RAW;
1958 
1959 	*naddr = 0;
1960 	err = getaddrinfo(name, NULL, &hints, &res);
1961 	if (err != 0)
1962 		return NULL;
1963 	/* Find length of address chain */
1964 	for (p = res; p != NULL; p = p->ai_next)
1965 		++*naddr;
1966 	/* Copy each element of the address chain */
1967 	addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
1968 	for (i = 0, p = res; p != NULL; p = p->ai_next)
1969 		memcpy(&addr[i++],
1970 		       &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
1971 		       sizeof(struct in6_addr));
1972 	freeaddrinfo(res);
1973 	return addr;
1974 }
1975 
network_to_ip6addr(const char * name)1976 static struct in6_addr *network_to_ip6addr(const char *name)
1977 {
1978 	/*	abort();*/
1979 	/* TODO: not implemented yet, but the exception breaks the
1980 	 *       name resolvation */
1981 	return NULL;
1982 }
1983 
1984 static struct in6_addr *
ip6parse_hostnetwork(const char * name,unsigned int * naddrs)1985 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1986 {
1987 	struct in6_addr *addrp, *addrptmp;
1988 
1989 	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1990 	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1991 		addrp = xtables_malloc(sizeof(struct in6_addr));
1992 		memcpy(addrp, addrptmp, sizeof(*addrp));
1993 		*naddrs = 1;
1994 		return addrp;
1995 	}
1996 	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1997 		return addrp;
1998 
1999 	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
2000 }
2001 
parse_ip6mask(char * mask)2002 static struct in6_addr *parse_ip6mask(char *mask)
2003 {
2004 	static struct in6_addr maskaddr;
2005 	struct in6_addr *addrp;
2006 	unsigned int bits;
2007 
2008 	if (mask == NULL) {
2009 		/* no mask at all defaults to 128 bits */
2010 		memset(&maskaddr, 0xff, sizeof maskaddr);
2011 		return &maskaddr;
2012 	}
2013 	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
2014 		return addrp;
2015 	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
2016 		xt_params->exit_err(PARAMETER_PROBLEM,
2017 			   "invalid mask `%s' specified", mask);
2018 	if (bits != 0) {
2019 		char *p = (void *)&maskaddr;
2020 		memset(p, 0xff, bits / 8);
2021 		memset(p + ((bits + 7) / 8), 0, (128 - bits) / 8);
2022 		if (bits < 128)
2023 			p[bits/8] = 0xff << (8 - (bits & 7));
2024 		return &maskaddr;
2025 	}
2026 
2027 	memset(&maskaddr, 0, sizeof(maskaddr));
2028 	return &maskaddr;
2029 }
2030 
2031 void
xtables_ip6parse_multiple(const char * name,struct in6_addr ** addrpp,struct in6_addr ** maskpp,unsigned int * naddrs)2032 xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
2033 		      struct in6_addr **maskpp, unsigned int *naddrs)
2034 {
2035 	static const struct in6_addr zero_addr;
2036 	struct in6_addr *addrp;
2037 	char buf[256], *p, *next;
2038 	unsigned int len, i, j, n, count = 1;
2039 	const char *loop = name;
2040 
2041 	while ((loop = strchr(loop, ',')) != NULL) {
2042 		++count;
2043 		++loop; /* skip ',' */
2044 	}
2045 
2046 	*addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
2047 	*maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
2048 
2049 	loop = name;
2050 
2051 	for (i = 0; i < count /*NB: count can grow*/; ++i) {
2052 		while (isspace(*loop))
2053 			++loop;
2054 		next = strchr(loop, ',');
2055 		if (next != NULL)
2056 			len = next - loop;
2057 		else
2058 			len = strlen(loop);
2059 		if (len > sizeof(buf) - 1)
2060 			xt_params->exit_err(PARAMETER_PROBLEM,
2061 				"Hostname too long");
2062 
2063 		strncpy(buf, loop, len);
2064 		buf[len] = '\0';
2065 		if ((p = strrchr(buf, '/')) != NULL) {
2066 			*p = '\0';
2067 			addrp = parse_ip6mask(p + 1);
2068 		} else {
2069 			addrp = parse_ip6mask(NULL);
2070 		}
2071 		memcpy(*maskpp + i, addrp, sizeof(*addrp));
2072 
2073 		/* if a null mask is given, the name is ignored, like in "any/0" */
2074 		if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
2075 			strcpy(buf, "::");
2076 
2077 		addrp = ip6parse_hostnetwork(buf, &n);
2078 		if (n > 1) {
2079 			count += n - 1;
2080 			*addrpp = xtables_realloc(*addrpp,
2081 			          sizeof(struct in6_addr) * count);
2082 			*maskpp = xtables_realloc(*maskpp,
2083 			          sizeof(struct in6_addr) * count);
2084 			for (j = 0; j < n; ++j)
2085 				/* for each new addr */
2086 				memcpy(*addrpp + i + j, addrp + j,
2087 				       sizeof(*addrp));
2088 			for (j = 1; j < n; ++j)
2089 				/* for each new mask */
2090 				memcpy(*maskpp + i + j, *maskpp + i,
2091 				       sizeof(*addrp));
2092 			i += n - 1;
2093 		} else {
2094 			memcpy(*addrpp + i, addrp, sizeof(*addrp));
2095 		}
2096 		/* free what ip6parse_hostnetwork had allocated: */
2097 		free(addrp);
2098 		if (next == NULL)
2099 			break;
2100 		loop = next + 1;
2101 	}
2102 	*naddrs = count;
2103 	for (i = 0; i < count; ++i)
2104 		for (j = 0; j < 4; ++j)
2105 			(*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
2106 }
2107 
xtables_ip6parse_any(const char * name,struct in6_addr ** addrpp,struct in6_addr * maskp,unsigned int * naddrs)2108 void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
2109                           struct in6_addr *maskp, unsigned int *naddrs)
2110 {
2111 	static const struct in6_addr zero_addr;
2112 	struct in6_addr *addrp;
2113 	unsigned int i, j, k, n;
2114 	char buf[256], *p;
2115 
2116 	strncpy(buf, name, sizeof(buf) - 1);
2117 	buf[sizeof(buf)-1] = '\0';
2118 	if ((p = strrchr(buf, '/')) != NULL) {
2119 		*p = '\0';
2120 		addrp = parse_ip6mask(p + 1);
2121 	} else {
2122 		addrp = parse_ip6mask(NULL);
2123 	}
2124 	memcpy(maskp, addrp, sizeof(*maskp));
2125 
2126 	/* if a null mask is given, the name is ignored, like in "any/0" */
2127 	if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
2128 		strcpy(buf, "::");
2129 
2130 	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
2131 	n = *naddrs;
2132 	for (i = 0, j = 0; i < n; ++i) {
2133 		for (k = 0; k < 4; ++k)
2134 			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
2135 		++j;
2136 		for (k = 0; k < j - 1; ++k)
2137 			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
2138 				/*
2139 				 * Nuke the dup by copying an address from the
2140 				 * tail here, and check the current position
2141 				 * again (--j).
2142 				 */
2143 				memcpy(&addrp[--j], &addrp[--*naddrs],
2144 				       sizeof(struct in_addr));
2145 				break;
2146 			}
2147 	}
2148 }
2149 
xtables_save_string(const char * value)2150 void xtables_save_string(const char *value)
2151 {
2152 	static const char no_quote_chars[] = "_-0123456789"
2153 		"abcdefghijklmnopqrstuvwxyz"
2154 		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
2155 	static const char escape_chars[] = "\"\\'";
2156 	size_t length;
2157 	const char *p;
2158 
2159 	length = strspn(value, no_quote_chars);
2160 	if (length > 0 && value[length] == 0) {
2161 		/* no quoting required */
2162 		putchar(' ');
2163 		fputs(value, stdout);
2164 	} else {
2165 		/* there is at least one dangerous character in the
2166 		   value, which we have to quote.  Write double quotes
2167 		   around the value and escape special characters with
2168 		   a backslash */
2169 		printf(" \"");
2170 
2171 		for (p = strpbrk(value, escape_chars); p != NULL;
2172 		     p = strpbrk(value, escape_chars)) {
2173 			if (p > value)
2174 				fwrite(value, 1, p - value, stdout);
2175 			putchar('\\');
2176 			putchar(*p);
2177 			value = p + 1;
2178 		}
2179 
2180 		/* print the rest and finish the double quoted
2181 		   string */
2182 		fputs(value, stdout);
2183 		putchar('\"');
2184 	}
2185 }
2186 
2187 const struct xtables_pprot xtables_chain_protos[] = {
2188 	{"tcp",       IPPROTO_TCP},
2189 	{"sctp",      IPPROTO_SCTP},
2190 	{"udp",       IPPROTO_UDP},
2191 	{"udplite",   IPPROTO_UDPLITE},
2192 	{"icmp",      IPPROTO_ICMP},
2193 	{"ipv6-icmp", IPPROTO_ICMPV6},
2194 	{"icmpv6",    IPPROTO_ICMPV6},
2195 	{"esp",       IPPROTO_ESP},
2196 	{"ah",        IPPROTO_AH},
2197 	{"mobility-header", IPPROTO_MH},
2198 	{"ipv6-mh",   IPPROTO_MH},
2199 	{"mh",        IPPROTO_MH},
2200 	{"all",       0},
2201 	{NULL},
2202 };
2203 
2204 uint16_t
xtables_parse_protocol(const char * s)2205 xtables_parse_protocol(const char *s)
2206 {
2207 	const struct protoent *pent;
2208 	unsigned int proto, i;
2209 
2210 	if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
2211 		return proto;
2212 
2213 	for (i = 0; xtables_chain_protos[i].name != NULL; ++i) {
2214 		if (strcmp(s, xtables_chain_protos[i].name) == 0)
2215 			return xtables_chain_protos[i].num;
2216 	}
2217 
2218 	pent = getprotobyname(s);
2219 	if (pent != NULL)
2220 		return pent->p_proto;
2221 
2222 	xt_params->exit_err(PARAMETER_PROBLEM,
2223 		"unknown protocol \"%s\" specified", s);
2224 	return -1;
2225 }
2226 
xtables_print_num(uint64_t number,unsigned int format)2227 void xtables_print_num(uint64_t number, unsigned int format)
2228 {
2229 	if (!(format & FMT_KILOMEGAGIGA)) {
2230 		printf(FMT("%8llu ","%llu "), (unsigned long long)number);
2231 		return;
2232 	}
2233 	if (number <= 99999) {
2234 		printf(FMT("%5llu ","%llu "), (unsigned long long)number);
2235 		return;
2236 	}
2237 	number = (number + 500) / 1000;
2238 	if (number <= 9999) {
2239 		printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
2240 		return;
2241 	}
2242 	number = (number + 500) / 1000;
2243 	if (number <= 9999) {
2244 		printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
2245 		return;
2246 	}
2247 	number = (number + 500) / 1000;
2248 	if (number <= 9999) {
2249 		printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
2250 		return;
2251 	}
2252 	number = (number + 500) / 1000;
2253 	printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
2254 }
2255 
2256 static const unsigned char mac_type_unicast[ETH_ALEN] =   {};
2257 static const unsigned char msk_type_unicast[ETH_ALEN] =   {1};
2258 static const unsigned char mac_type_multicast[ETH_ALEN] = {1};
2259 static const unsigned char msk_type_multicast[ETH_ALEN] = {1};
2260 #define ALL_ONE_MAC {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
2261 static const unsigned char mac_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
2262 static const unsigned char msk_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
2263 static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01, 0x80, 0xc2};
2264 static const unsigned char msk_type_bridge_group[ETH_ALEN] = ALL_ONE_MAC;
2265 #undef ALL_ONE_MAC
2266 
xtables_parse_mac_and_mask(const char * from,void * to,void * mask)2267 int xtables_parse_mac_and_mask(const char *from, void *to, void *mask)
2268 {
2269 	char *p;
2270 	int i;
2271 	struct ether_addr *addr = NULL;
2272 
2273 	if (strcasecmp(from, "Unicast") == 0) {
2274 		memcpy(to, mac_type_unicast, ETH_ALEN);
2275 		memcpy(mask, msk_type_unicast, ETH_ALEN);
2276 		return 0;
2277 	}
2278 	if (strcasecmp(from, "Multicast") == 0) {
2279 		memcpy(to, mac_type_multicast, ETH_ALEN);
2280 		memcpy(mask, msk_type_multicast, ETH_ALEN);
2281 		return 0;
2282 	}
2283 	if (strcasecmp(from, "Broadcast") == 0) {
2284 		memcpy(to, mac_type_broadcast, ETH_ALEN);
2285 		memcpy(mask, msk_type_broadcast, ETH_ALEN);
2286 		return 0;
2287 	}
2288 	if (strcasecmp(from, "BGA") == 0) {
2289 		memcpy(to, mac_type_bridge_group, ETH_ALEN);
2290 		memcpy(mask, msk_type_bridge_group, ETH_ALEN);
2291 		return 0;
2292 	}
2293 	if ( (p = strrchr(from, '/')) != NULL) {
2294 		*p = '\0';
2295 		if (!(addr = ether_aton(p + 1)))
2296 			return -1;
2297 		memcpy(mask, addr, ETH_ALEN);
2298 	} else
2299 		memset(mask, 0xff, ETH_ALEN);
2300 	if (!(addr = ether_aton(from)))
2301 		return -1;
2302 	memcpy(to, addr, ETH_ALEN);
2303 	for (i = 0; i < ETH_ALEN; i++)
2304 		((char *)to)[i] &= ((char *)mask)[i];
2305 	return 0;
2306 }
2307 
xtables_print_well_known_mac_and_mask(const void * mac,const void * mask)2308 int xtables_print_well_known_mac_and_mask(const void *mac, const void *mask)
2309 {
2310 	if (!memcmp(mac, mac_type_unicast, ETH_ALEN) &&
2311 	    !memcmp(mask, msk_type_unicast, ETH_ALEN))
2312 		printf("Unicast");
2313 	else if (!memcmp(mac, mac_type_multicast, ETH_ALEN) &&
2314 	         !memcmp(mask, msk_type_multicast, ETH_ALEN))
2315 		printf("Multicast");
2316 	else if (!memcmp(mac, mac_type_broadcast, ETH_ALEN) &&
2317 	         !memcmp(mask, msk_type_broadcast, ETH_ALEN))
2318 		printf("Broadcast");
2319 	else if (!memcmp(mac, mac_type_bridge_group, ETH_ALEN) &&
2320 	         !memcmp(mask, msk_type_bridge_group, ETH_ALEN))
2321 		printf("BGA");
2322 	else
2323 		return -1;
2324 	return 0;
2325 }
2326 
xtables_print_mac(const unsigned char * macaddress)2327 void xtables_print_mac(const unsigned char *macaddress)
2328 {
2329 	unsigned int i;
2330 
2331 	printf("%02x", macaddress[0]);
2332 	for (i = 1; i < 6; ++i)
2333 		printf(":%02x", macaddress[i]);
2334 }
2335 
xtables_print_mac_and_mask(const unsigned char * mac,const unsigned char * mask)2336 void xtables_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
2337 {
2338 	static const char hlpmsk[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2339 
2340 	xtables_print_mac(mac);
2341 
2342 	if (memcmp(mask, hlpmsk, 6) == 0)
2343 		return;
2344 
2345 	printf("/");
2346 	xtables_print_mac(mask);
2347 }
2348 
xtables_parse_val_mask(struct xt_option_call * cb,unsigned int * val,unsigned int * mask,const struct xtables_lmap * lmap)2349 void xtables_parse_val_mask(struct xt_option_call *cb,
2350 			    unsigned int *val, unsigned int *mask,
2351 			    const struct xtables_lmap *lmap)
2352 {
2353 	char *end;
2354 
2355 	*mask = ~0U;
2356 
2357 	if (!xtables_strtoui(cb->arg, &end, val, 0, UINT32_MAX)) {
2358 		if (lmap)
2359 			goto name2val;
2360 		else
2361 			goto bad_val;
2362 	}
2363 
2364 	if (*end == '\0')
2365 		return;
2366 
2367 	if (*end != '/') {
2368 		if (lmap)
2369 			goto name2val;
2370 		else
2371 			goto garbage;
2372 	}
2373 
2374 	if (!xtables_strtoui(end + 1, &end, mask, 0, UINT32_MAX))
2375 		goto bad_val;
2376 
2377 	if (*end == '\0')
2378 		return;
2379 
2380 garbage:
2381 	xt_params->exit_err(PARAMETER_PROBLEM,
2382 			"%s: trailing garbage after value "
2383 			"for option \"--%s\".\n",
2384 			cb->ext_name, cb->entry->name);
2385 
2386 bad_val:
2387 	xt_params->exit_err(PARAMETER_PROBLEM,
2388 			"%s: bad integer value for option \"--%s\", "
2389 			"or out of range.\n",
2390 			cb->ext_name, cb->entry->name);
2391 
2392 name2val:
2393 	*val = xtables_lmap_name2id(lmap, cb->arg);
2394 	if ((int)*val == -1)
2395 		xt_params->exit_err(PARAMETER_PROBLEM,
2396 			"%s: could not map name %s to an integer value "
2397 			"for option \"--%s\".\n",
2398 			cb->ext_name, cb->arg, cb->entry->name);
2399 }
2400 
xtables_print_val_mask(unsigned int val,unsigned int mask,const struct xtables_lmap * lmap)2401 void xtables_print_val_mask(unsigned int val, unsigned int mask,
2402 			    const struct xtables_lmap *lmap)
2403 {
2404 	if (mask != ~0U) {
2405 		printf(" 0x%x/0x%x", val, mask);
2406 		return;
2407 	}
2408 
2409 	if (lmap) {
2410 		const char *name = xtables_lmap_id2name(lmap, val);
2411 
2412 		if (name) {
2413 			printf(" %s", name);
2414 			return;
2415 		}
2416 	}
2417 
2418 	printf(" 0x%x", val);
2419 }
2420 
2421 int kernel_version;
2422 
get_kernel_version(void)2423 void get_kernel_version(void)
2424 {
2425 	static struct utsname uts;
2426 	int x = 0, y = 0, z = 0;
2427 
2428 	if (uname(&uts) == -1) {
2429 		fprintf(stderr, "Unable to retrieve kernel version.\n");
2430 		xtables_free_opts(1);
2431 		exit(1);
2432 	}
2433 
2434 	sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
2435 	kernel_version = LINUX_VERSION(x, y, z);
2436 }
2437 
2438 #include <linux/netfilter/nf_tables.h>
2439 
2440 enum xt_xlate_type {
2441 	XT_XLATE_RULE = 0,
2442 	XT_XLATE_SET,
2443 	__XT_XLATE_MAX
2444 };
2445 
2446 struct xt_xlate {
2447 	struct xt_xlate_buf {
2448 		char	*data;
2449 		int	size;
2450 		int	rem;
2451 		int	off;
2452 	} buf[__XT_XLATE_MAX];
2453 	char comment[NFT_USERDATA_MAXLEN];
2454 	int family;
2455 };
2456 
xt_xlate_alloc(int size)2457 struct xt_xlate *xt_xlate_alloc(int size)
2458 {
2459 	struct xt_xlate *xl = xtables_malloc(sizeof(struct xt_xlate));
2460 	int i;
2461 
2462 	for (i = 0; i < __XT_XLATE_MAX; i++) {
2463 		xl->buf[i].data = xtables_malloc(size);
2464 		xl->buf[i].data[0] = '\0';
2465 		xl->buf[i].size = size;
2466 		xl->buf[i].rem = size;
2467 		xl->buf[i].off = 0;
2468 	}
2469 	xl->comment[0] = '\0';
2470 
2471 	return xl;
2472 }
2473 
xt_xlate_free(struct xt_xlate * xl)2474 void xt_xlate_free(struct xt_xlate *xl)
2475 {
2476 	int i;
2477 
2478 	for (i = 0; i < __XT_XLATE_MAX; i++)
2479 		free(xl->buf[i].data);
2480 
2481 	free(xl);
2482 }
2483 
isbrace(char c)2484 static bool isbrace(char c)
2485 {
2486 	switch (c) {
2487 	case '(':
2488 	case ')':
2489 	case '{':
2490 	case '}':
2491 	case '[':
2492 	case ']':
2493 		return true;
2494 	}
2495 	return false;
2496 }
2497 
__xt_xlate_add(struct xt_xlate * xl,enum xt_xlate_type type,bool space,const char * fmt,va_list ap)2498 static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type,
2499 			   bool space, const char *fmt, va_list ap)
2500 {
2501 	struct xt_xlate_buf *buf = &xl->buf[type];
2502 	char tmpbuf[1024] = "";
2503 	int len;
2504 
2505 	len = vsnprintf(tmpbuf, 1024, fmt, ap);
2506 	if (len < 0 || len >= buf->rem - 1)
2507 		xtables_error(RESOURCE_PROBLEM, "OOM");
2508 
2509 	if (space && buf->off &&
2510 	    !isspace(buf->data[buf->off - 1]) &&
2511 	    (isalnum(tmpbuf[0]) || isbrace(tmpbuf[0]))) {
2512 		buf->data[buf->off] = ' ';
2513 		buf->off++;
2514 		buf->rem--;
2515 	}
2516 	sprintf(buf->data + buf->off, "%s", tmpbuf);
2517 	buf->rem -= len;
2518 	buf->off += len;
2519 }
2520 
xt_xlate_rule_add(struct xt_xlate * xl,const char * fmt,...)2521 void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...)
2522 {
2523 	va_list ap;
2524 
2525 	va_start(ap, fmt);
2526 	__xt_xlate_add(xl, XT_XLATE_RULE, true, fmt, ap);
2527 	va_end(ap);
2528 }
2529 
xt_xlate_rule_add_nospc(struct xt_xlate * xl,const char * fmt,...)2530 void xt_xlate_rule_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
2531 {
2532 	va_list ap;
2533 
2534 	va_start(ap, fmt);
2535 	__xt_xlate_add(xl, XT_XLATE_RULE, false, fmt, ap);
2536 	va_end(ap);
2537 }
2538 
xt_xlate_set_add(struct xt_xlate * xl,const char * fmt,...)2539 void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...)
2540 {
2541 	va_list ap;
2542 
2543 	va_start(ap, fmt);
2544 	__xt_xlate_add(xl, XT_XLATE_SET, true, fmt, ap);
2545 	va_end(ap);
2546 }
2547 
xt_xlate_set_add_nospc(struct xt_xlate * xl,const char * fmt,...)2548 void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
2549 {
2550 	va_list ap;
2551 
2552 	va_start(ap, fmt);
2553 	__xt_xlate_add(xl, XT_XLATE_SET, false, fmt, ap);
2554 	va_end(ap);
2555 }
2556 
xt_xlate_add_comment(struct xt_xlate * xl,const char * comment)2557 void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
2558 {
2559 	strncpy(xl->comment, comment, NFT_USERDATA_MAXLEN - 1);
2560 	xl->comment[NFT_USERDATA_MAXLEN - 1] = '\0';
2561 }
2562 
xt_xlate_get_comment(struct xt_xlate * xl)2563 const char *xt_xlate_get_comment(struct xt_xlate *xl)
2564 {
2565 	return xl->comment[0] ? xl->comment : NULL;
2566 }
2567 
xl_xlate_set_family(struct xt_xlate * xl,uint8_t family)2568 void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family)
2569 {
2570 	xl->family = family;
2571 }
2572 
xt_xlate_get_family(struct xt_xlate * xl)2573 uint8_t xt_xlate_get_family(struct xt_xlate *xl)
2574 {
2575 	return xl->family;
2576 }
2577 
xt_xlate_get(struct xt_xlate * xl)2578 const char *xt_xlate_get(struct xt_xlate *xl)
2579 {
2580 	struct xt_xlate_buf *buf = &xl->buf[XT_XLATE_RULE];
2581 
2582 	while (buf->off && isspace(buf->data[buf->off - 1]))
2583 		buf->data[--buf->off] = '\0';
2584 
2585 	return buf->data;
2586 }
2587 
xt_xlate_set_get(struct xt_xlate * xl)2588 const char *xt_xlate_set_get(struct xt_xlate *xl)
2589 {
2590 	return xl->buf[XT_XLATE_SET].data;
2591 }
2592