xtables.c revision c31870f9bebb3d4d082016fcfaf8c2177ae32eb2
15208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI/*
25208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
35208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
45208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	This program is free software; you can redistribute it and/or modify
55208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	it under the terms of the GNU General Public License as published by
65208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	the Free Software Foundation; either version 2 of the License, or
75208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	(at your option) any later version.
85208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
95208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	This program is distributed in the hope that it will be useful,
105208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	but WITHOUT ANY WARRANTY; without even the implied warranty of
115208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
125208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	GNU General Public License for more details.
135208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
145208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	You should have received a copy of the GNU General Public License
155208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	along with this program; if not, write to the Free Software
165208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
175208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI */
185208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI
193dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <errno.h>
200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <fcntl.h>
2104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI#include <netdb.h>
22aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt#include <stdarg.h>
23cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt#include <stdbool.h>
243dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdio.h>
253dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdlib.h>
260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <string.h>
270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <unistd.h>
280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#include <sys/socket.h>
290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/stat.h>
300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/types.h>
310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/wait.h>
3208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#include <arpa/inet.h>
333dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
345208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI#include <xtables.h>
3577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
3677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
37ef18e8147903885708d1c264904129af4fb636d6Jan Engelhardt#include <libiptc/libxtc.h>
383dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
395a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
405a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
415a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
42c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
43c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
44c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
45c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
46c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
47c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_MATCH	68
48c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_TARGET	69
49c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
50c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt
515a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#define NPROTO	255
530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
540b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#ifndef PROC_SYS_MODPROBE
550b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
560b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#endif
570b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
58dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt/**
5977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * xtables_afinfo - protocol family dependent information
6077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @kmod:		kernel module basename (e.g. "ip_tables")
6177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @libprefix:		prefix of .so library name (e.g. "libipt_")
6277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @family:		nfproto family
6377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @ipproto:		used by setsockopt (e.g. IPPROTO_IP)
6477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @so_rev_match:	optname to check revision support of match
6577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @so_rev_target:	optname to check revision support of target
6677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt */
6777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstruct xtables_afinfo {
6877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	const char *kmod;
6977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	const char *libprefix;
7077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	uint8_t family;
7177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	uint8_t ipproto;
7277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	int so_rev_match;
7377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	int so_rev_target;
7477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
7577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
7677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv4 = {
7777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip_tables",
7877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libipt_",
7977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family	       = NFPROTO_IPV4,
8077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IP,
8177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
8277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
8377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
8477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
8577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv6 = {
8677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip6_tables",
8777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libip6t_",
8877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family        = NFPROTO_IPV6,
8977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IPV6,
9077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
9177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
9277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
9377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
9477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo *afinfo;
9577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
9677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt/**
97dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt * Program will set this to its own name.
98dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt */
99dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardtconst char *xtables_program_name;
100dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt
10139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt/* Search path for Xtables .so files */
10239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtstatic const char *xtables_libdir;
1030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
105c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtconst char *xtables_modprobe_program;
1060b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI/* Keeping track of external matches and targets: linked lists.  */
1080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
1090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
1100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
11139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtvoid xtables_init(void)
11239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt{
11339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("XTABLES_LIBDIR");
11439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL)
11539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
11639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("IPTABLES_LIB_DIR");
11739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL) {
11839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
11939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		        "use XTABLES_LIBDIR.\n");
12039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
12139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	}
122ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	/*
123ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
124ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
125ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * for these env vars are deprecated anyhow, and in light of the
126ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * (shared) libxt_*.so files, makes less sense to have
127ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
128ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 */
129ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
130ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	if (xtables_libdir != NULL) {
131ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
132ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		        "use XTABLES_LIBDIR.\n");
133ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		return;
134ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	}
13539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = XTABLES_LIBDIR;
13639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt}
13739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt
13877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtvoid xtables_set_nfproto(uint8_t nfproto)
13977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt{
14077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	switch (nfproto) {
14177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV4:
14277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv4;
14377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
14477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV6:
14577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv6;
14677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
14777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	default:
14877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
14977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		        __func__);
15077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	}
15177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt}
15277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
153630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt/**
154630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt * xtables_*alloc - wrappers that exit on failure
155630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt */
156630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_calloc(size_t count, size_t size)
1573dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
1583dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
1593dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1603dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
1613dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
1623dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
1633dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
1643dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1653dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
1663dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
1673dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
168630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_malloc(size_t size)
1693dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
1703dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
1713dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1723dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
1733dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
1743dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
1753dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
1763dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1773dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
1783dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
1790b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1800b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
1810b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
1820b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
1830b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
1840b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1850b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROCFILE_BUFSIZ	1024
1860b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
1870b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
1880b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
1890b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1900b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	ret = (char *) malloc(PROCFILE_BUFSIZ);
1910b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
1920b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		memset(ret, 0, PROCFILE_BUFSIZ);
1930b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
1940b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case -1: goto fail;
1950b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
1960b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
1970b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (ret[strlen(ret)-1]=='\n')
1980b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			ret[strlen(ret)-1]=0;
1990b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		close(procfile);
2000b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return ret;
2010b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
2020b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI fail:
2030b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
2040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
2050b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
2060b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
2070b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
208c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
2090b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
2100b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
2110b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
2120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
2130b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2140b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
2150b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
2160b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
2170b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
2180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
2190b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
2200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
2210b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2220b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	switch (fork()) {
2230b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
2240b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
2250b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
2260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
2270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
2280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
2290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
2300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
2310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
2320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
2330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
2340b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
2360b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
2370b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
2380b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
2390b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2400b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
2410b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
2420b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
2430b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2440b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
2450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
2460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
2470b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
2480b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
2490b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
250c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_load_ko(const char *modprobe, bool quiet)
2510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
252c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	static bool loaded = false;
2530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	static int ret = -1;
2540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (!loaded) {
25677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
2570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		loaded = (ret == 0);
2580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
2590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
2610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
2620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2635f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt/**
2645f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * xtables_strtou{i,l} - string to number conversion
2655f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @s:	input string
2665f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @end:	like strtoul's "end" pointer
2675f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @value:	pointer for result
2685f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @min:	minimum accepted value
2695f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @max:	maximum accepted value
2705f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt *
2715f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
2725f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * "15a" is rejected.
2735f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * In either case, the value obtained is compared for min-max compliance.
2745f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Base is always 0, i.e. autodetect depending on @s.
275cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
2765f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Returns true/false whether number was accepted. On failure, *value has
2775f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * undefined contents.
278cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
2795f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoul(const char *s, char **end, unsigned long *value,
2805f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned long min, unsigned long max)
281cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
282cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
283cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
284cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
285cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
286cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	v = strtoul(s, &my_end, 0);
287cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
288cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
289cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
290cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
291cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
292cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
293cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
294cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
295cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
296cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
297cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
298cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
299cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
300cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
301cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
302cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
303cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
3045f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoui(const char *s, char **end, unsigned int *value,
3055f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned int min, unsigned int max)
306cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
307cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
308cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
309cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
3105f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	ret = xtables_strtoul(s, end, &v, min, max);
311cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
312cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
313cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
314cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
315cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
316aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtint xtables_service_to_port(const char *name, const char *proto)
31704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
31804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
31904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
32004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
32104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
32204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
32304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
32404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
32504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
326aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtu_int16_t xtables_parse_port(const char *port, const char *proto)
32704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
3287a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
32904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
3305f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
331aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
332213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
33304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
33404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	exit_error(PARAMETER_PROBLEM,
33504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
33604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
33704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
338aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtvoid xtables_parse_interface(const char *arg, char *vianame,
339aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt			     unsigned char *mask)
34004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
34104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	int vialen = strlen(arg);
34204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
34304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
34404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
34504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
34604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
34704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
34804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
34904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
35004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
35104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
35204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
35304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
35404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0, IFNAMSIZ);
35504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
35604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
35704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
35804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
35904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
36004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
36104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
36204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
36304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
36404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			if (vianame[i] == ':' ||
36504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '!' ||
36604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '*') {
367aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
368aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
369aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					" `%s' (No aliases, :, ! or *).\n",
370aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
37104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
37204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
37304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
37404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
37504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
37604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
377cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
37821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardtstatic void *load_extension(const char *search_path, const char *prefix,
37921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
38021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
38121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
38221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
38321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
38421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
38521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
38621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
38721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
38821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
38921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
39021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
3912c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, name);
39221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
39321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
39421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			/* Found library.  If it didn't register itself,
39521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			   maybe they specified target as match. */
39621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
3972338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
39821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
3992338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
4002338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
40121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
40221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
40321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
40421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
40521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
40621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
40721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
40821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/%s%s.so",
4092c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, prefix, name);
41021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
41121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
4122338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
41321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
4142338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
4152338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
41621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
41721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
41821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
41921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
42021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
42121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
42221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
42321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
42421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
42521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
42621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
42721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
428cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
42921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
4302338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_match *
4312338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_match(const char *name, enum xtables_tryload tryload,
4322338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		   struct xtables_rule_match **matches)
4330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
4340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
4350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
4360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
4380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
4390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
4400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
4410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
4420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
4430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
4450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
4460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
4470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
4490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
4500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
4510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
453630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt			clone = xtables_malloc(sizeof(struct xtables_match));
4540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
4550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
4560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
4570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
4580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
4600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
4610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
4620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
4652338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
46677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
46739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, false);
468170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
4692338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
4700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
4710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
4720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
4730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
4750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
4762338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
4770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
4780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
4790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
4800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4812338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
4820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
4830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
4840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
4860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
4880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
4890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
4900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
491630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
4920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
4940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
4952338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				(*i)->completed = true;
4960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
4970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
4982338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		newentry->completed = false;
4990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
5000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
5010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
5040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5062338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_target *
5072338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_target(const char *name, enum xtables_tryload tryload)
5080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
5100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
5120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
5130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
5140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
5150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
5160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
5170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
5180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
5200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
5210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
5220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
5252338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
52677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
52739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, true);
528170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
5292338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
5300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
5310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
5320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
5330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
5350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
5362338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
5370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
5380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
5390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
5400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
5420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
5430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
5440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
5460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
5480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
5490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
5510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_revision(const char *name, u_int8_t revision, int opt)
5540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
5560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
5570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
5580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
55977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
5600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
561df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
562df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
563df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
564df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy				fprintf(stderr, "Could not determine whether "
565df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
566df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
567df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy					revision);
568df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
569df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
5700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
5710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
5720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
575c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	xtables_load_ko(xtables_modprobe_program, true);
5760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
5780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
5790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
58077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
5810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
5820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
5830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
5840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
5860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
5870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
5890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
5900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
5910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
5920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
5930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
5940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
5950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
5970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
5980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_match_revision(const char *name, u_int8_t revision)
6020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
60377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_match);
6040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_target_revision(const char *name, u_int8_t revision)
6070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
60877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_target);
6090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
6120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match **i, *old;
6140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
615dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
616dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
617dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
618dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
619dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
6200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
6240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
6250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
626dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
6310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
6320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
633dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
63877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
6390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
6400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6412338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
6420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
64323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
64423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
6450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
6460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
647dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
6480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
6490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
6520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_match_revision(old->name, old->revision)
6530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
6540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
65623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
6570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_match_revision(me->name, me->revision))
6580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
66023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
66123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
66223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
66323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
6640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
6650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
6660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
6670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
6700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
671dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
6720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
6770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
6780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
6790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
6810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
6820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
6850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *old;
6870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
688dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
689dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
690dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
691dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
692dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
6930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
6970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
6980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
699dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
7000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
7040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
7050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
706dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
7070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
71177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
7120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
7130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7142338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_target(me->name, XTF_DURING_LOAD);
7150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
7160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
7170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
71823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
71923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
7200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
7210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
722dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
7230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
7240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
7250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
7270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_target_revision(old->name, old->revision)
7280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
7290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
7300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
73123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
7320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_target_revision(me->name, me->revision))
7330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
7340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
73523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
73623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
73723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
73823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
7390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
7400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
7410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
7420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
7450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
746dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
7470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
7510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
7520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
7530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
7540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
7550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
756aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
757a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt/**
758a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * xtables_param_act - act on condition
759a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @status:	a constant from enum xtables_exittype
760a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
761a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONLY_ONCE: print error message that option may only be used once.
762a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name (e.g. "mark")
763a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2(...):	option in conflict (e.g. "--mark")
764a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3(...):	condition to match on (see extensions/ for examples)
765a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
766a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_NO_INVERT: option does not support inversion
767a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
768a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option in conflict
769a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		condition to match on
770a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
771a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_BAD_VALUE: bad value for option
772a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
773a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option with which the problem occured (e.g. "--mark")
774a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		string the user passed in (e.g. "99999999999999")
775a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
776a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
777a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
778a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
779a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * Displays an error message and exits the program.
780a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt */
781a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid xtables_param_act(unsigned int status, const char *p1, ...)
782aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
783aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
784aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
785aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
786aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
787aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
788aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
789aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
790a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONLY_ONCE:
791aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
792aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
793aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
794aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
795aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
796aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
797aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
798aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
799a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_NO_INVERT:
800aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
801aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
802aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
803aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
804aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
805aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
806aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
807a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_BAD_VALUE:
808aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
809aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
810aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
811aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
812aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
813aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
814a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONE_ACTION:
815aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
816aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
817aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
818aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
819aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
820aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
821aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
822aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(status, p1, args);
823aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
824aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
825aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
826aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
827aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
82808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
829e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
83008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
83108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
83208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
83308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
83408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
83508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
83608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
83708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
83808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
83908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
84008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
84108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
84208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
84308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
84408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
84508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
84608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
84708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
84808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
84908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
85008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
85108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
85208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
85308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
85408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
85508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
85608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
85708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
85808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
859e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
86008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
86108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
86208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
86308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
86408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
86508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
86608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
867e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ipaddr_to_numeric(addr);
86808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
86908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
870e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
87108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
87208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
87308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
87408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
87508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
87608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
87708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
87808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
87908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* we don't want to see "/32" */
88008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return "";
88108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
88208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
88308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
88408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
88508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
88608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
88708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%d", i);
88808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	else
88908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
890e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
89108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
89208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
89308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
89408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
895bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
896bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
897bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
898bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
899bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
900bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
901bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
902bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
903bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
904bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
905bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
906bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
907bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
908bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
909bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
910bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
911bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
912bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
913bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
914bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
9155f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
916bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
917bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
918bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
919bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
920bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
921bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
922bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
923bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
924bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
925bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
9265f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
927bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
928bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
929bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
930bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
931bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
932bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
933bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
9345f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
935bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
936bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
937bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
938bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
939bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
940bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
9411e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
942bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
943bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
944bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
945bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
9461e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipmask(const char *dotted)
947bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
948bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
949bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
950bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
951bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
952bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
953bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
954bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
955bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
956bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
957bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
958bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
959bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
960bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
961bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
962bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
963bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
964bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
965bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
966bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
967bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
968bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
969bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
970bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
971bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
972bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
973bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
974bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
975bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
976bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
977bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
978bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
979bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
980630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
981bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
982bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
983bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
984bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
985bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
986bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
987bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
988bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
989bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
990bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
991bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
992bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
993bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
994bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
9951e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
996bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
997630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in_addr));
998bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
999bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1000bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1001bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1002bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1003bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
1004bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1005bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1006bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1007bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1008bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
1009bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1010bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
1011bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1012bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1013bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1014bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1015bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
1016bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
1017bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1018bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
10191e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1020bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
1021bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
10225f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1023bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
1024bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1025bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1026bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1027bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1028bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1029bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1030bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
1031bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1032bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1033bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1034a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt/**
1035a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * xtables_ipparse_any - transform arbitrary name to in_addr
1036a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt *
1037a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * Possible inputs (pseudo regex):
1038a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1039a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1040a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt */
1041a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1042a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                         struct in_addr *maskp, unsigned int *naddrs)
1043bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1044bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1045bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1046bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1047bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1048bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1049bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1050bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1051bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1052bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
1053bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1054bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
1055bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1056bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1057bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1058bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1059bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
1060bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
1061bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1062bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1063bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1064bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1065bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
1066bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1067bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1068bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1069bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1070bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1071bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1072bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1073bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1074bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1075e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
107608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
107708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	/* 0000:0000:0000:0000:0000:000.000.000.000
107808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
107908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
108008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
108108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
108208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
108308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
108408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
108508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
108608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
108708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
108808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
108908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
109008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
109108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
109208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
109408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
109508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
109608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
109708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
109808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
109908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
110008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
110108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
110308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
110408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
110508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
110608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
110708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1108e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
110908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
111008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
111108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
111208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
111308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
111408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1115e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ip6addr_to_numeric(addr);
111608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
111708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
111808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic int ip6addr_prefix_length(const struct in6_addr *k)
111908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
112008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
112108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
112208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
112348607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
112448607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
112548607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
112648607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
112708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
112808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
112908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
113008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
113108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
113208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
113308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
113408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
113508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
113608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
113708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
113808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
113908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
114008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
114108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1142e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
114308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
114408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
114508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int l = ip6addr_prefix_length(addrp);
114608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
114708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
114808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
1149e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		strcat(buf, xtables_ip6addr_to_numeric(addrp));
115008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
115108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
115208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "/%d", l);
115308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
115408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1155bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
11561e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1157bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1158bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1159bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1160bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1161bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1162bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1163bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1164bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1165bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1166bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1167bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1168bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1169bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1170bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1171bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1172bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr *addr;
1173bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
1174bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo *res;
1175bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1176bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1177bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1178bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1179bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1180bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1181bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_protocol = IPPROTO_IPV6;
1182bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_next     = NULL;
1183bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1184bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1185bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1186bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1187bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1188bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1189bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1190bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1191bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (res->ai_family != AF_INET6 ||
1192bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1193bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1194bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1195bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1196bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1197bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1198bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1199bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* Get the first element of the address-chain */
1200630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_malloc(sizeof(struct in6_addr));
1201bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1202bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		       sizeof(struct in6_addr));
1203bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1204bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddr = 1;
1205bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1206bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1207bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1208bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1209bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1210bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1211bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1212bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1213bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1214bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1215bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1216bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1217bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1218bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1219bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1220bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1221bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1222bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1223bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
12241e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1225bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1226630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in6_addr));
1227bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1228bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1229bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1230bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1231bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1232bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1233bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1234bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1235bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1236bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1237bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1238bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1239bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1240bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1241bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1242bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1243bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1244bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1245bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1246bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1247bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
12481e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1249bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
12505f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1251bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
1252bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1253bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1254bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1255bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1256bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1257bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1258bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1259bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1260bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1261bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1262bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1263bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1264bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1265a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1266a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                          struct in6_addr *maskp, unsigned int *naddrs)
1267bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1268bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1269bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1270bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1271bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1272bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1273bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1274bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1275bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1276bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1277bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1278bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1279bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1280bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1281bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1282bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1283bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1284bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1285bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1286bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1287bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1288bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1289bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
12905a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1291bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1292bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1293bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1294bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1295bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1296bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1297bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1298bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1299bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1300a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1301a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_save_string(const char *value)
1302a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1303a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1304a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1305a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1306a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1307a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1308a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1309a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1310a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	length = strcspn(value, no_quote_chars);
1311a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1312a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1313a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1314a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
1315a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1316a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1317a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1318a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1319a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
1320a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar('"');
1321a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1322a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1323a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1324a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1325a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1326a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1327a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1328a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1329a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1330a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1331a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1332a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1333a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1334a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		printf("\" ");
1335a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1336a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
13370f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13380f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt/**
13390f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Check for option-intrapositional negation.
13400f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Do not use in new code.
13410f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt */
13420f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardtint xtables_check_inverse(const char option[], int *invert,
13430f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			  int *my_optind, int argc)
13440f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt{
13450f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	if (option && strcmp(option, "!") == 0) {
13460f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		fprintf(stderr, "Using intrapositioned negation "
13470f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		        "(`--option ! this`) is deprecated in favor of "
13480f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		        "extrapositioned (`! --option this`).\n");
13490f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13500f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		if (*invert)
13510f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			exit_error(PARAMETER_PROBLEM,
13520f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt				   "Multiple `!' flags not allowed");
13530f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		*invert = true;
13540f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		if (my_optind != NULL) {
13550f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			++*my_optind;
13560f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			if (argc && *my_optind > argc)
13570f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt				exit_error(PARAMETER_PROBLEM,
13580f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt					   "no argument following `!'");
13590f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		}
13600f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13610f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		return true;
13620f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	}
13630f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	return false;
13640f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt}
13651de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13661de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtconst struct xtables_pprot xtables_chain_protos[] = {
13671de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"tcp",       IPPROTO_TCP},
13681de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"sctp",      IPPROTO_SCTP},
13691de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udp",       IPPROTO_UDP},
13701de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udplite",   IPPROTO_UDPLITE},
13711de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmp",      IPPROTO_ICMP},
13721de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmpv6",    IPPROTO_ICMPV6},
13731de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-icmp", IPPROTO_ICMPV6},
13741de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"esp",       IPPROTO_ESP},
13751de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ah",        IPPROTO_AH},
13761de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-mh",   IPPROTO_MH},
13771de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"mh",        IPPROTO_MH},
13781de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"all",       0},
13791de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{NULL},
13801de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt};
13811de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13821de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtu_int16_t
13831de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtxtables_parse_protocol(const char *s)
13841de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt{
13851de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	unsigned int proto;
13861de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13871de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	if (!xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) {
13881de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		struct protoent *pent;
13891de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13901de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		/* first deal with the special case of 'all' to prevent
13911de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * people from being able to redefine 'all' in nsswitch
13921de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * and/or provoke expensive [not working] ldap/nis/...
13931de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * lookups */
13941de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		if (!strcmp(s, "all"))
13951de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			return 0;
13961de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13971de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		if ((pent = getprotobyname(s)))
13981de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			proto = pent->p_proto;
13991de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		else {
14001de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			unsigned int i;
14011de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
14021de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				if (strcmp(s, xtables_chain_protos[i].name) == 0) {
14031de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					proto = xtables_chain_protos[i].num;
14041de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					break;
14051de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				}
14061de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			}
14071de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			if (i == ARRAY_SIZE(xtables_chain_protos))
14081de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				exit_error(PARAMETER_PROBLEM,
14091de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					   "unknown protocol `%s' specified",
14101de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					   s);
14111de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		}
14121de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	}
14131de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
14141de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	return proto;
14151de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt}
1416