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