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