• 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 			struct xtables_target *clone;
950 
951 			/* First target of this type: */
952 			if (ptr->t == NULL)
953 				break;
954 
955 			/* Second and subsequent clones */
956 			clone = xtables_malloc(sizeof(struct xtables_target));
957 			memcpy(clone, ptr, sizeof(struct xtables_target));
958 			clone->udata = NULL;
959 			clone->tflags = 0;
960 			/* This is a clone: */
961 			clone->next = clone;
962 
963 			ptr = clone;
964 			break;
965 		}
966 	}
967 
968 #ifndef NO_SHARED_LIBS
969 	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
970 		ptr = load_extension(xtables_libdir, afinfo->libprefix,
971 		      name, true);
972 
973 		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
974 			xt_params->exit_err(PARAMETER_PROBLEM,
975 				   "Couldn't load target `%s':%s\n",
976 				   name, strerror(errno));
977 	}
978 #else
979 	if (ptr && !ptr->loaded) {
980 		if (tryload != XTF_DONT_LOAD)
981 			ptr->loaded = 1;
982 		else
983 			ptr = NULL;
984 	}
985 	if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
986 		xt_params->exit_err(PARAMETER_PROBLEM,
987 			   "Couldn't find target `%s'\n", name);
988 	}
989 #endif
990 
991 	if (ptr)
992 		ptr->used = 1;
993 	else
994 		notargets_hlist_insert(name);
995 
996 	return ptr;
997 }
998 
999 struct xtables_target *
xtables_find_target_revision(const char * name,enum xtables_tryload tryload,struct xtables_target * target,int revision)1000 xtables_find_target_revision(const char *name, enum xtables_tryload tryload,
1001 			     struct xtables_target *target, int revision)
1002 {
1003 	if (!target) {
1004 		target = xtables_find_target(name, tryload);
1005 		if (!target)
1006 			return NULL;
1007 	}
1008 
1009 	while (1) {
1010 		if (target->revision == revision)
1011 			return target;
1012 		target = target->next;
1013 		if (!target)
1014 			return NULL;
1015 		if (!extension_cmp(name, target->name, target->family))
1016 			return NULL;
1017 	}
1018 }
1019 
xtables_compatible_revision(const char * name,uint8_t revision,int opt)1020 int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
1021 {
1022 	struct xt_get_revision rev;
1023 	socklen_t s = sizeof(rev);
1024 	int max_rev, sockfd;
1025 
1026 	sockfd = socket(afinfo->family, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
1027 	if (sockfd < 0) {
1028 		if (errno == EPERM) {
1029 			/* revision 0 is always supported. */
1030 			if (revision != 0)
1031 				fprintf(stderr, "%s: Could not determine whether "
1032 						"revision %u is supported, "
1033 						"assuming it is.\n",
1034 					name, revision);
1035 			return 1;
1036 		}
1037 		fprintf(stderr, "Could not open socket to kernel: %s\n",
1038 			strerror(errno));
1039 		exit(1);
1040 	}
1041 
1042 	xtables_load_ko(xtables_modprobe_program, true);
1043 
1044 	strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
1045 	rev.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
1046 	rev.revision = revision;
1047 
1048 	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
1049 	if (max_rev < 0) {
1050 		/* Definitely don't support this? */
1051 		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
1052 			close(sockfd);
1053 			/* Pretend revision 0 support for better error messaging */
1054 			if (revision == 0)
1055 				fprintf(stderr,
1056 					"Warning: Extension %s revision 0 not supported, missing kernel module?\n",
1057 					name);
1058 			return (revision == 0);
1059 		} else if (errno == ENOPROTOOPT) {
1060 			close(sockfd);
1061 			/* Assume only revision 0 support (old kernel) */
1062 			return (revision == 0);
1063 		} else {
1064 			fprintf(stderr, "getsockopt failed strangely: %s\n",
1065 				strerror(errno));
1066 			exit(1);
1067 		}
1068 	}
1069 	close(sockfd);
1070 	return 1;
1071 }
1072 
1073 
compatible_match_revision(const char * name,uint8_t revision)1074 static int compatible_match_revision(const char *name, uint8_t revision)
1075 {
1076 	return xt_params->compat_rev(name, revision, afinfo->so_rev_match);
1077 }
1078 
compatible_target_revision(const char * name,uint8_t revision)1079 static int compatible_target_revision(const char *name, uint8_t revision)
1080 {
1081 	return xt_params->compat_rev(name, revision, afinfo->so_rev_target);
1082 }
1083 
xtables_check_options(const char * name,const struct option * opt)1084 static void xtables_check_options(const char *name, const struct option *opt)
1085 {
1086 	for (; opt->name != NULL; ++opt)
1087 		if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
1088 			fprintf(stderr, "%s: Extension %s uses invalid "
1089 			        "option value %d\n",xt_params->program_name,
1090 			        name, opt->val);
1091 			exit(1);
1092 		}
1093 }
1094 
1095 static int xtables_match_prefer(const struct xtables_match *a,
1096 				const struct xtables_match *b);
1097 
xtables_register_match(struct xtables_match * me)1098 void xtables_register_match(struct xtables_match *me)
1099 {
1100 	struct xtables_match **pos;
1101 	bool seen_myself = false;
1102 
1103 	if (me->next) {
1104 		fprintf(stderr, "%s: match \"%s\" already registered\n",
1105 			xt_params->program_name, me->name);
1106 		exit(1);
1107 	}
1108 
1109 	if (me->version == NULL) {
1110 		fprintf(stderr, "%s: match %s<%u> is missing a version\n",
1111 		        xt_params->program_name, me->name, me->revision);
1112 		exit(1);
1113 	}
1114 
1115 	if (me->size != XT_ALIGN(me->size)) {
1116 		fprintf(stderr, "%s: match \"%s\" has invalid size %u.\n",
1117 		        xt_params->program_name, me->name,
1118 		        (unsigned int)me->size);
1119 		exit(1);
1120 	}
1121 
1122 	if (strcmp(me->version, XTABLES_VERSION) != 0) {
1123 		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
1124 		        "but \"%s\" is required.\n",
1125 			xt_params->program_name, me->name,
1126 			me->version, XTABLES_VERSION);
1127 		exit(1);
1128 	}
1129 
1130 	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1131 		fprintf(stderr, "%s: match `%s' has invalid name\n",
1132 			xt_params->program_name, me->name);
1133 		exit(1);
1134 	}
1135 
1136 	if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
1137 		fprintf(stderr, "%s: match `%s' has invalid real name\n",
1138 			xt_params->program_name, me->real_name);
1139 		exit(1);
1140 	}
1141 
1142 	if (me->family >= NPROTO) {
1143 		fprintf(stderr,
1144 			"%s: BUG: match %s has invalid protocol family\n",
1145 			xt_params->program_name, me->name);
1146 		exit(1);
1147 	}
1148 
1149 	if (me->x6_options != NULL)
1150 		xtables_option_metavalidate(me->name, me->x6_options);
1151 	if (me->extra_opts != NULL)
1152 		xtables_check_options(me->name, me->extra_opts);
1153 
1154 	/* order into linked list of matches pending full registration */
1155 	for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
1156 		/* group by name and family */
1157 		if (strcmp(me->name, (*pos)->name) ||
1158 		    me->family != (*pos)->family) {
1159 			if (seen_myself)
1160 				break; /* end of own group, append to it */
1161 			continue;
1162 		}
1163 		/* found own group */
1164 		seen_myself = true;
1165 		if (xtables_match_prefer(me, *pos) >= 0)
1166 			break; /* put preferred items first in group */
1167 	}
1168 	/* if own group was not found, prepend item */
1169 	if (!*pos && !seen_myself)
1170 		pos = &xtables_pending_matches;
1171 
1172 	me->next = *pos;
1173 	*pos = me;
1174 #ifdef DEBUG
1175 #define printmatch(m, sfx)						\
1176 	printf("match %s (", (m)->name);				\
1177 	if ((m)->real_name)						\
1178 		printf("alias %s, ", (m)->real_name);			\
1179 	printf("family %d, revision %d)%s", (m)->family, (m)->revision, sfx);
1180 
1181 	{
1182 		int i = 1;
1183 
1184 		printf("%s: inserted ", __func__);
1185 		printmatch(me, ":\n");
1186 		for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
1187 			printf("pos %d:\t", i++);
1188 			printmatch(*pos, "\n");
1189 		}
1190 	}
1191 #endif
1192 }
1193 
1194 /**
1195  * Compare two actions for their preference
1196  * @a:	one action
1197  * @b: 	another
1198  *
1199  * Like strcmp, returns a negative number if @a is less preferred than @b,
1200  * positive number if @a is more preferred than @b, or zero if equally
1201  * preferred.
1202  */
1203 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)1204 xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam,
1205 		  bool b_alias, unsigned int b_rev, unsigned int b_fam)
1206 {
1207 	/*
1208 	 * Alias ranks higher than no alias.
1209 	 * (We want the new action to be used whenever possible.)
1210 	 */
1211 	if (!a_alias && b_alias)
1212 		return -1;
1213 	if (a_alias && !b_alias)
1214 		return 1;
1215 
1216 	/* Higher revision ranks higher. */
1217 	if (a_rev < b_rev)
1218 		return -1;
1219 	if (a_rev > b_rev)
1220 		return 1;
1221 
1222 	/* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */
1223 	if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC)
1224 		return -1;
1225 	if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC)
1226 		return 1;
1227 
1228 	/* Must be the same thing. */
1229 	return 0;
1230 }
1231 
xtables_match_prefer(const struct xtables_match * a,const struct xtables_match * b)1232 static int xtables_match_prefer(const struct xtables_match *a,
1233 				const struct xtables_match *b)
1234 {
1235 	return xtables_mt_prefer(a->real_name != NULL,
1236 				 a->revision, a->family,
1237 				 b->real_name != NULL,
1238 				 b->revision, b->family);
1239 }
1240 
xtables_target_prefer(const struct xtables_target * a,const struct xtables_target * b)1241 static int xtables_target_prefer(const struct xtables_target *a,
1242 				 const struct xtables_target *b)
1243 {
1244 	/*
1245 	 * Note that if x->real_name==NULL, it will be set to x->name in
1246 	 * xtables_register_*; the direct pointer comparison here is therefore
1247 	 * legitimate to detect an alias.
1248 	 */
1249 	return xtables_mt_prefer(a->real_name != NULL,
1250 				 a->revision, a->family,
1251 				 b->real_name != NULL,
1252 				 b->revision, b->family);
1253 }
1254 
xtables_fully_register_pending_match(struct xtables_match * me,struct xtables_match * prev)1255 static bool xtables_fully_register_pending_match(struct xtables_match *me,
1256 						 struct xtables_match *prev)
1257 {
1258 	struct xtables_match **i;
1259 	const char *rn;
1260 
1261 	/* See if new match can be used. */
1262 	rn = (me->real_name != NULL) ? me->real_name : me->name;
1263 	if (!compatible_match_revision(rn, me->revision))
1264 		return false;
1265 
1266 	if (!prev) {
1267 		/* Append to list. */
1268 		for (i = &xtables_matches; *i; i = &(*i)->next);
1269 	} else {
1270 		/* Append it */
1271 		i = &prev->next;
1272 		prev = prev->next;
1273 	}
1274 
1275 	me->next = prev;
1276 	*i = me;
1277 
1278 	me->m = NULL;
1279 	me->mflags = 0;
1280 
1281 	return true;
1282 }
1283 
xtables_register_matches(struct xtables_match * match,unsigned int n)1284 void xtables_register_matches(struct xtables_match *match, unsigned int n)
1285 {
1286 	int i;
1287 
1288 	for (i = 0; i < n; i++)
1289 		xtables_register_match(&match[i]);
1290 }
1291 
xtables_register_target(struct xtables_target * me)1292 void xtables_register_target(struct xtables_target *me)
1293 {
1294 	struct xtables_target **pos;
1295 	bool seen_myself = false;
1296 
1297 	if (me->next) {
1298 		fprintf(stderr, "%s: target \"%s\" already registered\n",
1299 			xt_params->program_name, me->name);
1300 		exit(1);
1301 	}
1302 
1303 	if (me->version == NULL) {
1304 		fprintf(stderr, "%s: target %s<%u> is missing a version\n",
1305 		        xt_params->program_name, me->name, me->revision);
1306 		exit(1);
1307 	}
1308 
1309 	if (me->size != XT_ALIGN(me->size)) {
1310 		fprintf(stderr, "%s: target \"%s\" has invalid size %u.\n",
1311 		        xt_params->program_name, me->name,
1312 		        (unsigned int)me->size);
1313 		exit(1);
1314 	}
1315 
1316 	if (strcmp(me->version, XTABLES_VERSION) != 0) {
1317 		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
1318 		        "but \"%s\" is required.\n",
1319 			xt_params->program_name, me->name,
1320 			me->version, XTABLES_VERSION);
1321 		exit(1);
1322 	}
1323 
1324 	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1325 		fprintf(stderr, "%s: target `%s' has invalid name\n",
1326 			xt_params->program_name, me->name);
1327 		exit(1);
1328 	}
1329 
1330 	if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
1331 		fprintf(stderr, "%s: target `%s' has invalid real name\n",
1332 			xt_params->program_name, me->real_name);
1333 		exit(1);
1334 	}
1335 
1336 	if (me->family >= NPROTO) {
1337 		fprintf(stderr,
1338 			"%s: BUG: target %s has invalid protocol family\n",
1339 			xt_params->program_name, me->name);
1340 		exit(1);
1341 	}
1342 
1343 	if (me->x6_options != NULL)
1344 		xtables_option_metavalidate(me->name, me->x6_options);
1345 	if (me->extra_opts != NULL)
1346 		xtables_check_options(me->name, me->extra_opts);
1347 
1348 	/* ignore not interested target */
1349 	if (me->family != afinfo->family && me->family != AF_UNSPEC)
1350 		return;
1351 
1352 	/* order into linked list of targets pending full registration */
1353 	for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
1354 		/* group by name */
1355 		if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) {
1356 			if (seen_myself)
1357 				break; /* end of own group, append to it */
1358 			continue;
1359 		}
1360 		/* found own group */
1361 		seen_myself = true;
1362 		if (xtables_target_prefer(me, *pos) >= 0)
1363 			break; /* put preferred items first in group */
1364 	}
1365 	/* if own group was not found, prepend item */
1366 	if (!*pos && !seen_myself)
1367 		pos = &xtables_pending_targets;
1368 
1369 	me->next = *pos;
1370 	*pos = me;
1371 #ifdef DEBUG
1372 	printf("%s: inserted target %s (family %d, revision %d):\n",
1373 			__func__, me->name, me->family, me->revision);
1374 	for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
1375 		printf("%s:\ttarget %s (family %d, revision %d)\n", __func__,
1376 		       (*pos)->name, (*pos)->family, (*pos)->revision);
1377 	}
1378 #endif
1379 }
1380 
xtables_fully_register_pending_target(struct xtables_target * me,struct xtables_target * prev)1381 static bool xtables_fully_register_pending_target(struct xtables_target *me,
1382 						  struct xtables_target *prev)
1383 {
1384 	struct xtables_target **i;
1385 	const char *rn;
1386 
1387 	if (strcmp(me->name, "standard") != 0) {
1388 		/* See if new target can be used. */
1389 		rn = (me->real_name != NULL) ? me->real_name : me->name;
1390 		if (!compatible_target_revision(rn, me->revision))
1391 			return false;
1392 	}
1393 
1394 	if (!prev) {
1395 		/* Prepend to list. */
1396 		i = &xtables_targets;
1397 		prev = xtables_targets;
1398 	} else {
1399 		/* Append it */
1400 		i = &prev->next;
1401 		prev = prev->next;
1402 	}
1403 
1404 	me->next = prev;
1405 	*i = me;
1406 
1407 	me->t = NULL;
1408 	me->tflags = 0;
1409 
1410 	return true;
1411 }
1412 
xtables_register_targets(struct xtables_target * target,unsigned int n)1413 void xtables_register_targets(struct xtables_target *target, unsigned int n)
1414 {
1415 	int i;
1416 
1417 	for (i = 0; i < n; i++)
1418 		xtables_register_target(&target[i]);
1419 }
1420 
1421 /* receives a list of xtables_rule_match, release them */
xtables_rule_matches_free(struct xtables_rule_match ** matches)1422 void xtables_rule_matches_free(struct xtables_rule_match **matches)
1423 {
1424 	struct xtables_rule_match *matchp, *tmp;
1425 
1426 	for (matchp = *matches; matchp;) {
1427 		tmp = matchp->next;
1428 		if (matchp->match->m) {
1429 			free(matchp->match->m);
1430 			matchp->match->m = NULL;
1431 		}
1432 		if (matchp->match->udata_size) {
1433 			free(matchp->match->udata);
1434 			matchp->match->udata = NULL;
1435 		}
1436 		if (matchp->match == matchp->match->next) {
1437 			free(matchp->match);
1438 			matchp->match = NULL;
1439 		}
1440 		free(matchp);
1441 		matchp = tmp;
1442 	}
1443 
1444 	*matches = NULL;
1445 }
1446 
1447 /**
1448  * xtables_param_act - act on condition
1449  * @status:	a constant from enum xtables_exittype
1450  *
1451  * %XTF_ONLY_ONCE: print error message that option may only be used once.
1452  * @p1:		module name (e.g. "mark")
1453  * @p2(...):	option in conflict (e.g. "--mark")
1454  * @p3(...):	condition to match on (see extensions/ for examples)
1455  *
1456  * %XTF_NO_INVERT: option does not support inversion
1457  * @p1:		module name
1458  * @p2:		option in conflict
1459  * @p3:		condition to match on
1460  *
1461  * %XTF_BAD_VALUE: bad value for option
1462  * @p1:		module name
1463  * @p2:		option with which the problem occurred (e.g. "--mark")
1464  * @p3:		string the user passed in (e.g. "99999999999999")
1465  *
1466  * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1467  * @p1:		module name
1468  *
1469  * Displays an error message and exits the program.
1470  */
xtables_param_act(unsigned int status,const char * p1,...)1471 void xtables_param_act(unsigned int status, const char *p1, ...)
1472 {
1473 	const char *p2, *p3;
1474 	va_list args;
1475 	bool b;
1476 
1477 	va_start(args, p1);
1478 
1479 	switch (status) {
1480 	case XTF_ONLY_ONCE:
1481 		p2 = va_arg(args, const char *);
1482 		b  = va_arg(args, unsigned int);
1483 		if (!b) {
1484 			va_end(args);
1485 			return;
1486 		}
1487 		xt_params->exit_err(PARAMETER_PROBLEM,
1488 		           "%s: \"%s\" option may only be specified once",
1489 		           p1, p2);
1490 		break;
1491 	case XTF_NO_INVERT:
1492 		p2 = va_arg(args, const char *);
1493 		b  = va_arg(args, unsigned int);
1494 		if (!b) {
1495 			va_end(args);
1496 			return;
1497 		}
1498 		xt_params->exit_err(PARAMETER_PROBLEM,
1499 		           "%s: \"%s\" option cannot be inverted", p1, p2);
1500 		break;
1501 	case XTF_BAD_VALUE:
1502 		p2 = va_arg(args, const char *);
1503 		p3 = va_arg(args, const char *);
1504 		xt_params->exit_err(PARAMETER_PROBLEM,
1505 		           "%s: Bad value for \"%s\" option: \"%s\"",
1506 		           p1, p2, p3);
1507 		break;
1508 	case XTF_ONE_ACTION:
1509 		b = va_arg(args, unsigned int);
1510 		if (!b) {
1511 			va_end(args);
1512 			return;
1513 		}
1514 		xt_params->exit_err(PARAMETER_PROBLEM,
1515 		           "%s: At most one action is possible", p1);
1516 		break;
1517 	default:
1518 		xt_params->exit_err(status, p1, args);
1519 		break;
1520 	}
1521 
1522 	va_end(args);
1523 }
1524 
xtables_ipaddr_to_numeric(const struct in_addr * addrp)1525 const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
1526 {
1527 	static char buf[INET_ADDRSTRLEN];
1528 
1529 	return inet_ntop(AF_INET, addrp, buf, sizeof(buf));
1530 }
1531 
ipaddr_to_host(const struct in_addr * addr)1532 static const char *ipaddr_to_host(const struct in_addr *addr)
1533 {
1534 	static char hostname[NI_MAXHOST];
1535 	struct sockaddr_in saddr = {
1536 		.sin_family = AF_INET,
1537 		.sin_addr = *addr,
1538 	};
1539 	int err;
1540 
1541 
1542 	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in),
1543 		       hostname, sizeof(hostname) - 1, NULL, 0, 0);
1544 	if (err != 0)
1545 		return NULL;
1546 
1547 	return hostname;
1548 }
1549 
ipaddr_to_network(const struct in_addr * addr)1550 static const char *ipaddr_to_network(const struct in_addr *addr)
1551 {
1552 	struct netent *net;
1553 
1554 	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
1555 		return net->n_name;
1556 
1557 	return NULL;
1558 }
1559 
xtables_ipaddr_to_anyname(const struct in_addr * addr)1560 const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
1561 {
1562 	const char *name;
1563 
1564 	if ((name = ipaddr_to_host(addr)) != NULL ||
1565 	    (name = ipaddr_to_network(addr)) != NULL)
1566 		return name;
1567 
1568 	return xtables_ipaddr_to_numeric(addr);
1569 }
1570 
xtables_ipmask_to_cidr(const struct in_addr * mask)1571 int xtables_ipmask_to_cidr(const struct in_addr *mask)
1572 {
1573 	uint32_t maskaddr, bits;
1574 	int i;
1575 
1576 	maskaddr = ntohl(mask->s_addr);
1577 
1578 	for (i = 32, bits = (uint32_t)-1; i >= 0; i--, bits <<= 1) {
1579 		if (bits == maskaddr)
1580 			return i;
1581 	}
1582 
1583 	/* this mask cannot be converted to CIDR notation */
1584 	return -1;
1585 }
1586 
xtables_ipmask_to_numeric(const struct in_addr * mask)1587 const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
1588 {
1589 	static char buf[INET_ADDRSTRLEN + 1];
1590 	uint32_t cidr;
1591 
1592 	cidr = xtables_ipmask_to_cidr(mask);
1593 	if (cidr == (unsigned int)-1) {
1594 		/* mask was not a decent combination of 1's and 0's */
1595 		buf[0] = '/';
1596 		inet_ntop(AF_INET, mask, buf + 1, sizeof(buf) - 1);
1597 		return buf;
1598 	} else if (cidr == 32) {
1599 		/* we don't want to see "/32" */
1600 		return "";
1601 	}
1602 
1603 	sprintf(buf, "/%d", cidr);
1604 	return buf;
1605 }
1606 
__numeric_to_ipaddr(const char * dotted,bool is_mask)1607 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1608 {
1609 	static struct in_addr addr;
1610 	unsigned char *addrp;
1611 	unsigned int onebyte;
1612 	char buf[20], *p, *q;
1613 	int i;
1614 
1615 	/* copy dotted string, because we need to modify it */
1616 	strncpy(buf, dotted, sizeof(buf) - 1);
1617 	buf[sizeof(buf) - 1] = '\0';
1618 	addrp = (void *)&addr.s_addr;
1619 
1620 	p = buf;
1621 	for (i = 0; i < 3; ++i) {
1622 		if ((q = strchr(p, '.')) == NULL) {
1623 			if (is_mask)
1624 				return NULL;
1625 
1626 			/* autocomplete, this is a network address */
1627 			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1628 				return NULL;
1629 
1630 			addrp[i] = onebyte;
1631 			while (i < 3)
1632 				addrp[++i] = 0;
1633 
1634 			return &addr;
1635 		}
1636 
1637 		*q = '\0';
1638 		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1639 			return NULL;
1640 
1641 		addrp[i] = onebyte;
1642 		p = q + 1;
1643 	}
1644 
1645 	/* we have checked 3 bytes, now we check the last one */
1646 	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1647 		return NULL;
1648 
1649 	addrp[3] = onebyte;
1650 	return &addr;
1651 }
1652 
xtables_numeric_to_ipaddr(const char * dotted)1653 struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1654 {
1655 	return __numeric_to_ipaddr(dotted, false);
1656 }
1657 
xtables_numeric_to_ipmask(const char * dotted)1658 struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1659 {
1660 	return __numeric_to_ipaddr(dotted, true);
1661 }
1662 
network_to_ipaddr(const char * name)1663 static struct in_addr *network_to_ipaddr(const char *name)
1664 {
1665 	static struct in_addr addr;
1666 	struct netent *net;
1667 
1668 	if ((net = getnetbyname(name)) != NULL) {
1669 		if (net->n_addrtype != AF_INET)
1670 			return NULL;
1671 		addr.s_addr = htonl(net->n_net);
1672 		return &addr;
1673 	}
1674 
1675 	return NULL;
1676 }
1677 
host_to_ipaddr(const char * name,unsigned int * naddr)1678 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1679 {
1680 	struct in_addr *addr;
1681 	struct addrinfo hints;
1682 	struct addrinfo *res, *p;
1683 	int err;
1684 	unsigned int i;
1685 
1686 	memset(&hints, 0, sizeof(hints));
1687 	hints.ai_family   = AF_INET;
1688 	hints.ai_socktype = SOCK_RAW;
1689 
1690 	*naddr = 0;
1691 	err = getaddrinfo(name, NULL, &hints, &res);
1692 	if (err != 0)
1693 		return NULL;
1694 	for (p = res; p != NULL; p = p->ai_next)
1695 		++*naddr;
1696 	addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1697 	for (i = 0, p = res; p != NULL; p = p->ai_next)
1698 		memcpy(&addr[i++],
1699 		       &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
1700 		       sizeof(struct in_addr));
1701 	freeaddrinfo(res);
1702 	return addr;
1703 }
1704 
1705 static struct in_addr *
ipparse_hostnetwork(const char * name,unsigned int * naddrs)1706 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
1707 {
1708 	struct in_addr *addrptmp, *addrp;
1709 
1710 	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1711 	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1712 		addrp = xtables_malloc(sizeof(struct in_addr));
1713 		memcpy(addrp, addrptmp, sizeof(*addrp));
1714 		*naddrs = 1;
1715 		return addrp;
1716 	}
1717 	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1718 		return addrptmp;
1719 
1720 	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1721 }
1722 
parse_ipmask(const char * mask)1723 static struct in_addr *parse_ipmask(const char *mask)
1724 {
1725 	static struct in_addr maskaddr;
1726 	struct in_addr *addrp;
1727 	unsigned int bits;
1728 
1729 	if (mask == NULL) {
1730 		/* no mask at all defaults to 32 bits */
1731 		maskaddr.s_addr = 0xFFFFFFFF;
1732 		return &maskaddr;
1733 	}
1734 	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1735 		/* dotted_to_addr already returns a network byte order addr */
1736 		return addrp;
1737 	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1738 		xt_params->exit_err(PARAMETER_PROBLEM,
1739 			   "invalid mask `%s' specified", mask);
1740 	if (bits != 0) {
1741 		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1742 		return &maskaddr;
1743 	}
1744 
1745 	maskaddr.s_addr = 0U;
1746 	return &maskaddr;
1747 }
1748 
xtables_ipparse_multiple(const char * name,struct in_addr ** addrpp,struct in_addr ** maskpp,unsigned int * naddrs)1749 void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1750                               struct in_addr **maskpp, unsigned int *naddrs)
1751 {
1752 	struct in_addr *addrp;
1753 	char buf[256], *p, *next;
1754 	unsigned int len, i, j, n, count = 1;
1755 	const char *loop = name;
1756 
1757 	while ((loop = strchr(loop, ',')) != NULL) {
1758 		++count;
1759 		++loop; /* skip ',' */
1760 	}
1761 
1762 	*addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1763 	*maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1764 
1765 	loop = name;
1766 
1767 	for (i = 0; i < count; ++i) {
1768 		while (isspace(*loop))
1769 			++loop;
1770 		next = strchr(loop, ',');
1771 		if (next != NULL)
1772 			len = next - loop;
1773 		else
1774 			len = strlen(loop);
1775 		if (len > sizeof(buf) - 1)
1776 			xt_params->exit_err(PARAMETER_PROBLEM,
1777 				"Hostname too long");
1778 
1779 		strncpy(buf, loop, len);
1780 		buf[len] = '\0';
1781 		if ((p = strrchr(buf, '/')) != NULL) {
1782 			*p = '\0';
1783 			addrp = parse_ipmask(p + 1);
1784 		} else {
1785 			addrp = parse_ipmask(NULL);
1786 		}
1787 		memcpy(*maskpp + i, addrp, sizeof(*addrp));
1788 
1789 		/* if a null mask is given, the name is ignored, like in "any/0" */
1790 		if ((*maskpp + i)->s_addr == 0)
1791 			/*
1792 			 * A bit pointless to process multiple addresses
1793 			 * in this case...
1794 			 */
1795 			strcpy(buf, "0.0.0.0");
1796 
1797 		addrp = ipparse_hostnetwork(buf, &n);
1798 		if (n > 1) {
1799 			count += n - 1;
1800 			*addrpp = xtables_realloc(*addrpp,
1801 			          sizeof(struct in_addr) * count);
1802 			*maskpp = xtables_realloc(*maskpp,
1803 			          sizeof(struct in_addr) * count);
1804 			for (j = 0; j < n; ++j)
1805 				/* for each new addr */
1806 				memcpy(*addrpp + i + j, addrp + j,
1807 				       sizeof(*addrp));
1808 			for (j = 1; j < n; ++j)
1809 				/* for each new mask */
1810 				memcpy(*maskpp + i + j, *maskpp + i,
1811 				       sizeof(*addrp));
1812 			i += n - 1;
1813 		} else {
1814 			memcpy(*addrpp + i, addrp, sizeof(*addrp));
1815 		}
1816 		/* free what ipparse_hostnetwork had allocated: */
1817 		free(addrp);
1818 		if (next == NULL)
1819 			break;
1820 		loop = next + 1;
1821 	}
1822 	*naddrs = count;
1823 	for (i = 0; i < count; ++i)
1824 		(*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1825 }
1826 
1827 
1828 /**
1829  * xtables_ipparse_any - transform arbitrary name to in_addr
1830  *
1831  * Possible inputs (pseudo regex):
1832  * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1833  * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1834  */
xtables_ipparse_any(const char * name,struct in_addr ** addrpp,struct in_addr * maskp,unsigned int * naddrs)1835 void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1836                          struct in_addr *maskp, unsigned int *naddrs)
1837 {
1838 	unsigned int i, j, k, n;
1839 	struct in_addr *addrp;
1840 	char buf[256], *p;
1841 
1842 	strncpy(buf, name, sizeof(buf) - 1);
1843 	buf[sizeof(buf) - 1] = '\0';
1844 	if ((p = strrchr(buf, '/')) != NULL) {
1845 		*p = '\0';
1846 		addrp = parse_ipmask(p + 1);
1847 	} else {
1848 		addrp = parse_ipmask(NULL);
1849 	}
1850 	memcpy(maskp, addrp, sizeof(*maskp));
1851 
1852 	/* if a null mask is given, the name is ignored, like in "any/0" */
1853 	if (maskp->s_addr == 0U)
1854 		strcpy(buf, "0.0.0.0");
1855 
1856 	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1857 	n = *naddrs;
1858 	for (i = 0, j = 0; i < n; ++i) {
1859 		addrp[j++].s_addr &= maskp->s_addr;
1860 		for (k = 0; k < j - 1; ++k)
1861 			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1862 				/*
1863 				 * Nuke the dup by copying an address from the
1864 				 * tail here, and check the current position
1865 				 * again (--j).
1866 				 */
1867 				memcpy(&addrp[--j], &addrp[--*naddrs],
1868 				       sizeof(struct in_addr));
1869 				break;
1870 			}
1871 	}
1872 }
1873 
xtables_ip6addr_to_numeric(const struct in6_addr * addrp)1874 const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1875 {
1876 	static char buf[INET6_ADDRSTRLEN];
1877 
1878 	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1879 }
1880 
ip6addr_to_host(const struct in6_addr * addr)1881 static const char *ip6addr_to_host(const struct in6_addr *addr)
1882 {
1883 	static char hostname[NI_MAXHOST];
1884 	struct sockaddr_in6 saddr;
1885 	int err;
1886 
1887 	memset(&saddr, 0, sizeof(struct sockaddr_in6));
1888 	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1889 	saddr.sin6_family = AF_INET6;
1890 
1891 	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1892 			hostname, sizeof(hostname) - 1, NULL, 0, 0);
1893 	if (err != 0)
1894 		return NULL;
1895 
1896 	return hostname;
1897 }
1898 
xtables_ip6addr_to_anyname(const struct in6_addr * addr)1899 const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1900 {
1901 	const char *name;
1902 
1903 	if ((name = ip6addr_to_host(addr)) != NULL)
1904 		return name;
1905 
1906 	return xtables_ip6addr_to_numeric(addr);
1907 }
1908 
xtables_ip6mask_to_cidr(const struct in6_addr * k)1909 int xtables_ip6mask_to_cidr(const struct in6_addr *k)
1910 {
1911 	unsigned int bits = 0;
1912 	uint32_t a, b, c, d;
1913 
1914 	a = ntohl(k->s6_addr32[0]);
1915 	b = ntohl(k->s6_addr32[1]);
1916 	c = ntohl(k->s6_addr32[2]);
1917 	d = ntohl(k->s6_addr32[3]);
1918 	while (a & 0x80000000U) {
1919 		++bits;
1920 		a <<= 1;
1921 		a  |= (b >> 31) & 1;
1922 		b <<= 1;
1923 		b  |= (c >> 31) & 1;
1924 		c <<= 1;
1925 		c  |= (d >> 31) & 1;
1926 		d <<= 1;
1927 	}
1928 	if (a != 0 || b != 0 || c != 0 || d != 0)
1929 		return -1;
1930 	return bits;
1931 }
1932 
xtables_ip6mask_to_numeric(const struct in6_addr * addrp)1933 const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1934 {
1935 	static char buf[INET6_ADDRSTRLEN + 1];
1936 	int l = xtables_ip6mask_to_cidr(addrp);
1937 
1938 	if (l == -1) {
1939 		strcpy(buf, "/");
1940 		inet_ntop(AF_INET6, addrp, buf + 1, sizeof(buf) - 1);
1941 		return buf;
1942 	}
1943 	/* we don't want to see "/128" */
1944 	if (l == 128)
1945 		return "";
1946 	else
1947 		sprintf(buf, "/%d", l);
1948 	return buf;
1949 }
1950 
xtables_numeric_to_ip6addr(const char * num)1951 struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1952 {
1953 	static struct in6_addr ap;
1954 
1955 	if (inet_pton(AF_INET6, num, &ap) == 1)
1956 		return &ap;
1957 
1958 	return NULL;
1959 }
1960 
1961 static struct in6_addr *
host_to_ip6addr(const char * name,unsigned int * naddr)1962 host_to_ip6addr(const char *name, unsigned int *naddr)
1963 {
1964 	struct in6_addr *addr;
1965 	struct addrinfo hints;
1966 	struct addrinfo *res, *p;
1967 	int err;
1968 	unsigned int i;
1969 
1970 	memset(&hints, 0, sizeof(hints));
1971 	hints.ai_family   = AF_INET6;
1972 	hints.ai_socktype = SOCK_RAW;
1973 
1974 	*naddr = 0;
1975 	err = getaddrinfo(name, NULL, &hints, &res);
1976 	if (err != 0)
1977 		return NULL;
1978 	/* Find length of address chain */
1979 	for (p = res; p != NULL; p = p->ai_next)
1980 		++*naddr;
1981 	/* Copy each element of the address chain */
1982 	addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
1983 	for (i = 0, p = res; p != NULL; p = p->ai_next)
1984 		memcpy(&addr[i++],
1985 		       &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
1986 		       sizeof(struct in6_addr));
1987 	freeaddrinfo(res);
1988 	return addr;
1989 }
1990 
network_to_ip6addr(const char * name)1991 static struct in6_addr *network_to_ip6addr(const char *name)
1992 {
1993 	/*	abort();*/
1994 	/* TODO: not implemented yet, but the exception breaks the
1995 	 *       name resolvation */
1996 	return NULL;
1997 }
1998 
1999 static struct in6_addr *
ip6parse_hostnetwork(const char * name,unsigned int * naddrs)2000 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
2001 {
2002 	struct in6_addr *addrp, *addrptmp;
2003 
2004 	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
2005 	    (addrptmp = network_to_ip6addr(name)) != NULL) {
2006 		addrp = xtables_malloc(sizeof(struct in6_addr));
2007 		memcpy(addrp, addrptmp, sizeof(*addrp));
2008 		*naddrs = 1;
2009 		return addrp;
2010 	}
2011 	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
2012 		return addrp;
2013 
2014 	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
2015 }
2016 
parse_ip6mask(char * mask)2017 static struct in6_addr *parse_ip6mask(char *mask)
2018 {
2019 	static struct in6_addr maskaddr;
2020 	struct in6_addr *addrp;
2021 	unsigned int bits;
2022 
2023 	if (mask == NULL) {
2024 		/* no mask at all defaults to 128 bits */
2025 		memset(&maskaddr, 0xff, sizeof maskaddr);
2026 		return &maskaddr;
2027 	}
2028 	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
2029 		return addrp;
2030 	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
2031 		xt_params->exit_err(PARAMETER_PROBLEM,
2032 			   "invalid mask `%s' specified", mask);
2033 	if (bits != 0) {
2034 		char *p = (void *)&maskaddr;
2035 		memset(p, 0xff, bits / 8);
2036 		memset(p + ((bits + 7) / 8), 0, (128 - bits) / 8);
2037 		if (bits < 128)
2038 			p[bits/8] = 0xff << (8 - (bits & 7));
2039 		return &maskaddr;
2040 	}
2041 
2042 	memset(&maskaddr, 0, sizeof(maskaddr));
2043 	return &maskaddr;
2044 }
2045 
2046 void
xtables_ip6parse_multiple(const char * name,struct in6_addr ** addrpp,struct in6_addr ** maskpp,unsigned int * naddrs)2047 xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
2048 		      struct in6_addr **maskpp, unsigned int *naddrs)
2049 {
2050 	static const struct in6_addr zero_addr;
2051 	struct in6_addr *addrp;
2052 	char buf[256], *p, *next;
2053 	unsigned int len, i, j, n, count = 1;
2054 	const char *loop = name;
2055 
2056 	while ((loop = strchr(loop, ',')) != NULL) {
2057 		++count;
2058 		++loop; /* skip ',' */
2059 	}
2060 
2061 	*addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
2062 	*maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
2063 
2064 	loop = name;
2065 
2066 	for (i = 0; i < count /*NB: count can grow*/; ++i) {
2067 		while (isspace(*loop))
2068 			++loop;
2069 		next = strchr(loop, ',');
2070 		if (next != NULL)
2071 			len = next - loop;
2072 		else
2073 			len = strlen(loop);
2074 		if (len > sizeof(buf) - 1)
2075 			xt_params->exit_err(PARAMETER_PROBLEM,
2076 				"Hostname too long");
2077 
2078 		strncpy(buf, loop, len);
2079 		buf[len] = '\0';
2080 		if ((p = strrchr(buf, '/')) != NULL) {
2081 			*p = '\0';
2082 			addrp = parse_ip6mask(p + 1);
2083 		} else {
2084 			addrp = parse_ip6mask(NULL);
2085 		}
2086 		memcpy(*maskpp + i, addrp, sizeof(*addrp));
2087 
2088 		/* if a null mask is given, the name is ignored, like in "any/0" */
2089 		if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
2090 			strcpy(buf, "::");
2091 
2092 		addrp = ip6parse_hostnetwork(buf, &n);
2093 		if (n > 1) {
2094 			count += n - 1;
2095 			*addrpp = xtables_realloc(*addrpp,
2096 			          sizeof(struct in6_addr) * count);
2097 			*maskpp = xtables_realloc(*maskpp,
2098 			          sizeof(struct in6_addr) * count);
2099 			for (j = 0; j < n; ++j)
2100 				/* for each new addr */
2101 				memcpy(*addrpp + i + j, addrp + j,
2102 				       sizeof(*addrp));
2103 			for (j = 1; j < n; ++j)
2104 				/* for each new mask */
2105 				memcpy(*maskpp + i + j, *maskpp + i,
2106 				       sizeof(*addrp));
2107 			i += n - 1;
2108 		} else {
2109 			memcpy(*addrpp + i, addrp, sizeof(*addrp));
2110 		}
2111 		/* free what ip6parse_hostnetwork had allocated: */
2112 		free(addrp);
2113 		if (next == NULL)
2114 			break;
2115 		loop = next + 1;
2116 	}
2117 	*naddrs = count;
2118 	for (i = 0; i < count; ++i)
2119 		for (j = 0; j < 4; ++j)
2120 			(*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
2121 }
2122 
xtables_ip6parse_any(const char * name,struct in6_addr ** addrpp,struct in6_addr * maskp,unsigned int * naddrs)2123 void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
2124                           struct in6_addr *maskp, unsigned int *naddrs)
2125 {
2126 	static const struct in6_addr zero_addr;
2127 	struct in6_addr *addrp;
2128 	unsigned int i, j, k, n;
2129 	char buf[256], *p;
2130 
2131 	strncpy(buf, name, sizeof(buf) - 1);
2132 	buf[sizeof(buf)-1] = '\0';
2133 	if ((p = strrchr(buf, '/')) != NULL) {
2134 		*p = '\0';
2135 		addrp = parse_ip6mask(p + 1);
2136 	} else {
2137 		addrp = parse_ip6mask(NULL);
2138 	}
2139 	memcpy(maskp, addrp, sizeof(*maskp));
2140 
2141 	/* if a null mask is given, the name is ignored, like in "any/0" */
2142 	if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
2143 		strcpy(buf, "::");
2144 
2145 	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
2146 	n = *naddrs;
2147 	for (i = 0, j = 0; i < n; ++i) {
2148 		for (k = 0; k < 4; ++k)
2149 			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
2150 		++j;
2151 		for (k = 0; k < j - 1; ++k)
2152 			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
2153 				/*
2154 				 * Nuke the dup by copying an address from the
2155 				 * tail here, and check the current position
2156 				 * again (--j).
2157 				 */
2158 				memcpy(&addrp[--j], &addrp[--*naddrs],
2159 				       sizeof(struct in_addr));
2160 				break;
2161 			}
2162 	}
2163 }
2164 
xtables_save_string(const char * value)2165 void xtables_save_string(const char *value)
2166 {
2167 	static const char no_quote_chars[] = "_-0123456789"
2168 		"abcdefghijklmnopqrstuvwxyz"
2169 		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
2170 	static const char escape_chars[] = "\"\\'";
2171 	size_t length;
2172 	const char *p;
2173 
2174 	length = strspn(value, no_quote_chars);
2175 	if (length > 0 && value[length] == 0) {
2176 		/* no quoting required */
2177 		putchar(' ');
2178 		fputs(value, stdout);
2179 	} else {
2180 		/* there is at least one dangerous character in the
2181 		   value, which we have to quote.  Write double quotes
2182 		   around the value and escape special characters with
2183 		   a backslash */
2184 		printf(" \"");
2185 
2186 		for (p = strpbrk(value, escape_chars); p != NULL;
2187 		     p = strpbrk(value, escape_chars)) {
2188 			if (p > value)
2189 				fwrite(value, 1, p - value, stdout);
2190 			putchar('\\');
2191 			putchar(*p);
2192 			value = p + 1;
2193 		}
2194 
2195 		/* print the rest and finish the double quoted
2196 		   string */
2197 		fputs(value, stdout);
2198 		putchar('\"');
2199 	}
2200 }
2201 
2202 const struct xtables_pprot xtables_chain_protos[] = {
2203 	{"tcp",       IPPROTO_TCP},
2204 	{"sctp",      IPPROTO_SCTP},
2205 	{"udp",       IPPROTO_UDP},
2206 	{"udplite",   IPPROTO_UDPLITE},
2207 	{"icmp",      IPPROTO_ICMP},
2208 	{"ipv6-icmp", IPPROTO_ICMPV6},
2209 	{"icmpv6",    IPPROTO_ICMPV6},
2210 	{"esp",       IPPROTO_ESP},
2211 	{"ah",        IPPROTO_AH},
2212 	{"mobility-header", IPPROTO_MH},
2213 	{"ipv6-mh",   IPPROTO_MH},
2214 	{"mh",        IPPROTO_MH},
2215 	{"dccp",      IPPROTO_DCCP},
2216 	{"ipcomp",    IPPROTO_COMP},
2217 	{"all",       0},
2218 	{NULL},
2219 };
2220 
2221 uint16_t
xtables_parse_protocol(const char * s)2222 xtables_parse_protocol(const char *s)
2223 {
2224 	const struct protoent *pent;
2225 	unsigned int proto, i;
2226 
2227 	if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
2228 		return proto;
2229 
2230 	for (i = 0; xtables_chain_protos[i].name != NULL; ++i) {
2231 		if (strcmp(s, xtables_chain_protos[i].name) == 0)
2232 			return xtables_chain_protos[i].num;
2233 	}
2234 
2235 	pent = getprotobyname(s);
2236 	if (pent != NULL)
2237 		return pent->p_proto;
2238 
2239 	xt_params->exit_err(PARAMETER_PROBLEM,
2240 		"unknown protocol \"%s\" specified", s);
2241 	return -1;
2242 }
2243 
xtables_print_num(uint64_t number,unsigned int format)2244 void xtables_print_num(uint64_t number, unsigned int format)
2245 {
2246 	if (!(format & FMT_KILOMEGAGIGA)) {
2247 		printf(FMT("%8llu ","%llu "), (unsigned long long)number);
2248 		return;
2249 	}
2250 	if (number <= 99999) {
2251 		printf(FMT("%5llu ","%llu "), (unsigned long long)number);
2252 		return;
2253 	}
2254 	number = (number + 500) / 1000;
2255 	if (number <= 9999) {
2256 		printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
2257 		return;
2258 	}
2259 	number = (number + 500) / 1000;
2260 	if (number <= 9999) {
2261 		printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
2262 		return;
2263 	}
2264 	number = (number + 500) / 1000;
2265 	if (number <= 9999) {
2266 		printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
2267 		return;
2268 	}
2269 	number = (number + 500) / 1000;
2270 	printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
2271 }
2272 
2273 static const unsigned char mac_type_unicast[ETH_ALEN] =   {};
2274 static const unsigned char msk_type_unicast[ETH_ALEN] =   {1};
2275 static const unsigned char mac_type_multicast[ETH_ALEN] = {1};
2276 static const unsigned char msk_type_multicast[ETH_ALEN] = {1};
2277 #define ALL_ONE_MAC {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
2278 static const unsigned char mac_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
2279 static const unsigned char msk_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
2280 static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01, 0x80, 0xc2};
2281 static const unsigned char msk_type_bridge_group[ETH_ALEN] = ALL_ONE_MAC;
2282 #undef ALL_ONE_MAC
2283 
xtables_parse_mac_and_mask(const char * from,void * to,void * mask)2284 int xtables_parse_mac_and_mask(const char *from, void *to, void *mask)
2285 {
2286 	char *p;
2287 	int i;
2288 	struct ether_addr *addr = NULL;
2289 
2290 	if (strcasecmp(from, "Unicast") == 0) {
2291 		memcpy(to, mac_type_unicast, ETH_ALEN);
2292 		memcpy(mask, msk_type_unicast, ETH_ALEN);
2293 		return 0;
2294 	}
2295 	if (strcasecmp(from, "Multicast") == 0) {
2296 		memcpy(to, mac_type_multicast, ETH_ALEN);
2297 		memcpy(mask, msk_type_multicast, ETH_ALEN);
2298 		return 0;
2299 	}
2300 	if (strcasecmp(from, "Broadcast") == 0) {
2301 		memcpy(to, mac_type_broadcast, ETH_ALEN);
2302 		memcpy(mask, msk_type_broadcast, ETH_ALEN);
2303 		return 0;
2304 	}
2305 	if (strcasecmp(from, "BGA") == 0) {
2306 		memcpy(to, mac_type_bridge_group, ETH_ALEN);
2307 		memcpy(mask, msk_type_bridge_group, ETH_ALEN);
2308 		return 0;
2309 	}
2310 	if ( (p = strrchr(from, '/')) != NULL) {
2311 		*p = '\0';
2312 		if (!(addr = ether_aton(p + 1)))
2313 			return -1;
2314 		memcpy(mask, addr, ETH_ALEN);
2315 	} else
2316 		memset(mask, 0xff, ETH_ALEN);
2317 	if (!(addr = ether_aton(from)))
2318 		return -1;
2319 	memcpy(to, addr, ETH_ALEN);
2320 	for (i = 0; i < ETH_ALEN; i++)
2321 		((char *)to)[i] &= ((char *)mask)[i];
2322 	return 0;
2323 }
2324 
xtables_print_well_known_mac_and_mask(const void * mac,const void * mask)2325 int xtables_print_well_known_mac_and_mask(const void *mac, const void *mask)
2326 {
2327 	if (!memcmp(mac, mac_type_unicast, ETH_ALEN) &&
2328 	    !memcmp(mask, msk_type_unicast, ETH_ALEN))
2329 		printf("Unicast");
2330 	else if (!memcmp(mac, mac_type_multicast, ETH_ALEN) &&
2331 	         !memcmp(mask, msk_type_multicast, ETH_ALEN))
2332 		printf("Multicast");
2333 	else if (!memcmp(mac, mac_type_broadcast, ETH_ALEN) &&
2334 	         !memcmp(mask, msk_type_broadcast, ETH_ALEN))
2335 		printf("Broadcast");
2336 	else if (!memcmp(mac, mac_type_bridge_group, ETH_ALEN) &&
2337 	         !memcmp(mask, msk_type_bridge_group, ETH_ALEN))
2338 		printf("BGA");
2339 	else
2340 		return -1;
2341 	return 0;
2342 }
2343 
xtables_print_mac(const unsigned char * macaddress)2344 void xtables_print_mac(const unsigned char *macaddress)
2345 {
2346 	unsigned int i;
2347 
2348 	printf("%02x", macaddress[0]);
2349 	for (i = 1; i < 6; ++i)
2350 		printf(":%02x", macaddress[i]);
2351 }
2352 
xtables_print_mac_and_mask(const unsigned char * mac,const unsigned char * mask)2353 void xtables_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
2354 {
2355 	static const char hlpmsk[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2356 
2357 	xtables_print_mac(mac);
2358 
2359 	if (memcmp(mask, hlpmsk, 6) == 0)
2360 		return;
2361 
2362 	printf("/");
2363 	xtables_print_mac(mask);
2364 }
2365 
xtables_parse_val_mask(struct xt_option_call * cb,unsigned int * val,unsigned int * mask,const struct xtables_lmap * lmap)2366 void xtables_parse_val_mask(struct xt_option_call *cb,
2367 			    unsigned int *val, unsigned int *mask,
2368 			    const struct xtables_lmap *lmap)
2369 {
2370 	char *end;
2371 
2372 	*mask = ~0U;
2373 
2374 	if (!xtables_strtoui(cb->arg, &end, val, 0, UINT32_MAX)) {
2375 		if (lmap)
2376 			goto name2val;
2377 		else
2378 			goto bad_val;
2379 	}
2380 
2381 	if (*end == '\0')
2382 		return;
2383 
2384 	if (*end != '/') {
2385 		if (lmap)
2386 			goto name2val;
2387 		else
2388 			goto garbage;
2389 	}
2390 
2391 	if (!xtables_strtoui(end + 1, &end, mask, 0, UINT32_MAX))
2392 		goto bad_val;
2393 
2394 	if (*end == '\0')
2395 		return;
2396 
2397 garbage:
2398 	xt_params->exit_err(PARAMETER_PROBLEM,
2399 			"%s: trailing garbage after value "
2400 			"for option \"--%s\".\n",
2401 			cb->ext_name, cb->entry->name);
2402 
2403 bad_val:
2404 	xt_params->exit_err(PARAMETER_PROBLEM,
2405 			"%s: bad integer value for option \"--%s\", "
2406 			"or out of range.\n",
2407 			cb->ext_name, cb->entry->name);
2408 
2409 name2val:
2410 	*val = xtables_lmap_name2id(lmap, cb->arg);
2411 	if ((int)*val == -1)
2412 		xt_params->exit_err(PARAMETER_PROBLEM,
2413 			"%s: could not map name %s to an integer value "
2414 			"for option \"--%s\".\n",
2415 			cb->ext_name, cb->arg, cb->entry->name);
2416 }
2417 
xtables_print_val_mask(unsigned int val,unsigned int mask,const struct xtables_lmap * lmap)2418 void xtables_print_val_mask(unsigned int val, unsigned int mask,
2419 			    const struct xtables_lmap *lmap)
2420 {
2421 	if (mask != ~0U) {
2422 		printf(" 0x%x/0x%x", val, mask);
2423 		return;
2424 	}
2425 
2426 	if (lmap) {
2427 		const char *name = xtables_lmap_id2name(lmap, val);
2428 
2429 		if (name) {
2430 			printf(" %s", name);
2431 			return;
2432 		}
2433 	}
2434 
2435 	printf(" 0x%x", val);
2436 }
2437 
2438 int kernel_version;
2439 
get_kernel_version(void)2440 void get_kernel_version(void)
2441 {
2442 	static struct utsname uts;
2443 	int x = 0, y = 0, z = 0;
2444 
2445 	if (uname(&uts) == -1) {
2446 		fprintf(stderr, "Unable to retrieve kernel version.\n");
2447 		xtables_free_opts(1);
2448 		exit(1);
2449 	}
2450 
2451 	sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
2452 	kernel_version = LINUX_VERSION(x, y, z);
2453 }
2454 
2455 #include <linux/netfilter/nf_tables.h>
2456 
2457 enum xt_xlate_type {
2458 	XT_XLATE_RULE = 0,
2459 	XT_XLATE_SET,
2460 	__XT_XLATE_MAX
2461 };
2462 
2463 struct xt_xlate {
2464 	struct xt_xlate_buf {
2465 		char	*data;
2466 		int	size;
2467 		int	rem;
2468 		int	off;
2469 	} buf[__XT_XLATE_MAX];
2470 	char comment[NFT_USERDATA_MAXLEN];
2471 	int family;
2472 };
2473 
xt_xlate_alloc(int size)2474 struct xt_xlate *xt_xlate_alloc(int size)
2475 {
2476 	struct xt_xlate *xl = xtables_malloc(sizeof(struct xt_xlate));
2477 	int i;
2478 
2479 	for (i = 0; i < __XT_XLATE_MAX; i++) {
2480 		xl->buf[i].data = xtables_malloc(size);
2481 		xl->buf[i].data[0] = '\0';
2482 		xl->buf[i].size = size;
2483 		xl->buf[i].rem = size;
2484 		xl->buf[i].off = 0;
2485 	}
2486 	xl->comment[0] = '\0';
2487 
2488 	return xl;
2489 }
2490 
xt_xlate_free(struct xt_xlate * xl)2491 void xt_xlate_free(struct xt_xlate *xl)
2492 {
2493 	int i;
2494 
2495 	for (i = 0; i < __XT_XLATE_MAX; i++)
2496 		free(xl->buf[i].data);
2497 
2498 	free(xl);
2499 }
2500 
isbrace(char c)2501 static bool isbrace(char c)
2502 {
2503 	switch (c) {
2504 	case '(':
2505 	case ')':
2506 	case '{':
2507 	case '}':
2508 	case '[':
2509 	case ']':
2510 		return true;
2511 	}
2512 	return false;
2513 }
2514 
__xt_xlate_add(struct xt_xlate * xl,enum xt_xlate_type type,bool space,const char * fmt,va_list ap)2515 static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type,
2516 			   bool space, const char *fmt, va_list ap)
2517 {
2518 	struct xt_xlate_buf *buf = &xl->buf[type];
2519 	char tmpbuf[1024] = "";
2520 	int len;
2521 
2522 	len = vsnprintf(tmpbuf, 1024, fmt, ap);
2523 	if (len < 0 || len >= buf->rem - 1)
2524 		xtables_error(RESOURCE_PROBLEM, "OOM");
2525 
2526 	if (space && buf->off &&
2527 	    !isspace(buf->data[buf->off - 1]) &&
2528 	    (isalnum(tmpbuf[0]) || isbrace(tmpbuf[0]))) {
2529 		buf->data[buf->off] = ' ';
2530 		buf->off++;
2531 		buf->rem--;
2532 	}
2533 	sprintf(buf->data + buf->off, "%s", tmpbuf);
2534 	buf->rem -= len;
2535 	buf->off += len;
2536 }
2537 
xt_xlate_rule_add(struct xt_xlate * xl,const char * fmt,...)2538 void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...)
2539 {
2540 	va_list ap;
2541 
2542 	va_start(ap, fmt);
2543 	__xt_xlate_add(xl, XT_XLATE_RULE, true, fmt, ap);
2544 	va_end(ap);
2545 }
2546 
xt_xlate_rule_add_nospc(struct xt_xlate * xl,const char * fmt,...)2547 void xt_xlate_rule_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
2548 {
2549 	va_list ap;
2550 
2551 	va_start(ap, fmt);
2552 	__xt_xlate_add(xl, XT_XLATE_RULE, false, fmt, ap);
2553 	va_end(ap);
2554 }
2555 
xt_xlate_set_add(struct xt_xlate * xl,const char * fmt,...)2556 void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...)
2557 {
2558 	va_list ap;
2559 
2560 	va_start(ap, fmt);
2561 	__xt_xlate_add(xl, XT_XLATE_SET, true, fmt, ap);
2562 	va_end(ap);
2563 }
2564 
xt_xlate_set_add_nospc(struct xt_xlate * xl,const char * fmt,...)2565 void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
2566 {
2567 	va_list ap;
2568 
2569 	va_start(ap, fmt);
2570 	__xt_xlate_add(xl, XT_XLATE_SET, false, fmt, ap);
2571 	va_end(ap);
2572 }
2573 
xt_xlate_add_comment(struct xt_xlate * xl,const char * comment)2574 void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
2575 {
2576 	strncpy(xl->comment, comment, NFT_USERDATA_MAXLEN - 1);
2577 	xl->comment[NFT_USERDATA_MAXLEN - 1] = '\0';
2578 }
2579 
xt_xlate_get_comment(struct xt_xlate * xl)2580 const char *xt_xlate_get_comment(struct xt_xlate *xl)
2581 {
2582 	return xl->comment[0] ? xl->comment : NULL;
2583 }
2584 
xl_xlate_set_family(struct xt_xlate * xl,uint8_t family)2585 void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family)
2586 {
2587 	xl->family = family;
2588 }
2589 
xt_xlate_get_family(struct xt_xlate * xl)2590 uint8_t xt_xlate_get_family(struct xt_xlate *xl)
2591 {
2592 	return xl->family;
2593 }
2594 
xt_xlate_get(struct xt_xlate * xl)2595 const char *xt_xlate_get(struct xt_xlate *xl)
2596 {
2597 	struct xt_xlate_buf *buf = &xl->buf[XT_XLATE_RULE];
2598 
2599 	while (buf->off && isspace(buf->data[buf->off - 1]))
2600 		buf->data[--buf->off] = '\0';
2601 
2602 	return buf->data;
2603 }
2604 
xt_xlate_set_get(struct xt_xlate * xl)2605 const char *xt_xlate_set_get(struct xt_xlate *xl)
2606 {
2607 	return xl->buf[XT_XLATE_SET].data;
2608 }
2609