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