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