xtables.c revision 77f48c2f1ef21fa43aa68c25a1457db319ca2526
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
425a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#define NPROTO	255
440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#ifndef PROC_SYS_MODPROBE
460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
470b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#endif
480b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
49dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt/**
5077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * xtables_afinfo - protocol family dependent information
5177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @kmod:		kernel module basename (e.g. "ip_tables")
5277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @libprefix:		prefix of .so library name (e.g. "libipt_")
5377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @family:		nfproto family
5477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @ipproto:		used by setsockopt (e.g. IPPROTO_IP)
5577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @so_rev_match:	optname to check revision support of match
5677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @so_rev_target:	optname to check revision support of target
5777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt */
5877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstruct xtables_afinfo {
5977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	const char *kmod;
6077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	const char *libprefix;
6177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	uint8_t family;
6277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	uint8_t ipproto;
6377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	int so_rev_match;
6477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	int so_rev_target;
6577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
6677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
6777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv4 = {
6877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip_tables",
6977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libipt_",
7077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family	       = NFPROTO_IPV4,
7177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IP,
7277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
7377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
7477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
7577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
7677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv6 = {
7777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip6_tables",
7877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libip6t_",
7977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family        = NFPROTO_IPV6,
8077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IPV6,
8177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
8277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
8377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
8477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
8577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo *afinfo;
8677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
8777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt/**
88dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt * Program will set this to its own name.
89dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt */
90dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardtconst char *xtables_program_name;
91dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt
9239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt/* Search path for Xtables .so files */
9339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtstatic const char *xtables_libdir;
940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
950b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
96c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtconst char *xtables_modprobe_program;
970b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI/* Keeping track of external matches and targets: linked lists.  */
990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
1000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
1010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
10239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtvoid xtables_init(void)
10339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt{
10439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("XTABLES_LIBDIR");
10539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL)
10639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
10739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("IPTABLES_LIB_DIR");
10839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL) {
10939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
11039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		        "use XTABLES_LIBDIR.\n");
11139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
11239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	}
11339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = XTABLES_LIBDIR;
11439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt}
11539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt
11677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtvoid xtables_set_nfproto(uint8_t nfproto)
11777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt{
11877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	switch (nfproto) {
11977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV4:
12077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv4;
12177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
12277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV6:
12377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv6;
12477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
12577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	default:
12677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
12777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		        __func__);
12877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	}
12977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt}
13077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
131630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt/**
132630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt * xtables_*alloc - wrappers that exit on failure
133630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt */
134630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_calloc(size_t count, size_t size)
1353dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
1363dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
1373dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1383dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
1393dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
1403dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
1413dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
1423dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1433dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
1443dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
1453dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
146630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_malloc(size_t size)
1473dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
1483dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
1493dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1503dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
1513dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
1523dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
1533dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
1543dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1553dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
1563dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
1570b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1580b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
1590b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
1600b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
1610b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
1620b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1630b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROCFILE_BUFSIZ	1024
1640b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
1650b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
1660b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
1670b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1680b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	ret = (char *) malloc(PROCFILE_BUFSIZ);
1690b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
1700b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		memset(ret, 0, PROCFILE_BUFSIZ);
1710b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
1720b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case -1: goto fail;
1730b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
1740b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
1750b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (ret[strlen(ret)-1]=='\n')
1760b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			ret[strlen(ret)-1]=0;
1770b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		close(procfile);
1780b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return ret;
1790b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
1800b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI fail:
1810b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
1820b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
1830b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
1840b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
1850b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
186c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
1870b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
1880b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
1890b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
1900b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
1910b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1920b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
1930b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
1940b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
1950b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
1960b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
1970b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
1980b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
1990b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2000b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	switch (fork()) {
2010b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
2020b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
2030b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
2040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
2050b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
2060b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
2070b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
2080b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
2090b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
2100b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
2110b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
2120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2130b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
2140b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
2150b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
2160b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
2170b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
2190b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
2200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
2210b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2220b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
2230b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
2240b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
2250b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
2260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
2270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
228c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_load_ko(const char *modprobe, bool quiet)
2290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
230c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	static bool loaded = false;
2310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	static int ret = -1;
2320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (!loaded) {
23477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
2350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		loaded = (ret == 0);
2360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
2370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
2390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
2400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2415f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt/**
2425f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * xtables_strtou{i,l} - string to number conversion
2435f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @s:	input string
2445f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @end:	like strtoul's "end" pointer
2455f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @value:	pointer for result
2465f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @min:	minimum accepted value
2475f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @max:	maximum accepted value
2485f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt *
2495f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
2505f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * "15a" is rejected.
2515f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * In either case, the value obtained is compared for min-max compliance.
2525f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Base is always 0, i.e. autodetect depending on @s.
253cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
2545f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Returns true/false whether number was accepted. On failure, *value has
2555f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * undefined contents.
256cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
2575f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoul(const char *s, char **end, unsigned long *value,
2585f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned long min, unsigned long max)
259cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
260cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
261cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
262cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
263cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
264cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	v = strtoul(s, &my_end, 0);
265cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
266cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
267cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
268cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
269cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
270cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
271cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
272cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
273cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
274cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
275cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
276cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
277cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
278cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
279cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
280cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
281cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
2825f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoui(const char *s, char **end, unsigned int *value,
2835f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned int min, unsigned int max)
284cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
285cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
286cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
287cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
2885f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	ret = xtables_strtoul(s, end, &v, min, max);
289cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
290cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
291cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
292cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
293cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
294aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtint xtables_service_to_port(const char *name, const char *proto)
29504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
29604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
29704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
29804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
29904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
30004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
30104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
30204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
30304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
304aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtu_int16_t xtables_parse_port(const char *port, const char *proto)
30504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
3067a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
30704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
3085f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
309aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
310213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
31104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
31204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	exit_error(PARAMETER_PROBLEM,
31304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
31404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
31504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
316aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtvoid xtables_parse_interface(const char *arg, char *vianame,
317aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt			     unsigned char *mask)
31804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
31904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	int vialen = strlen(arg);
32004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
32104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
32204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
32304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
32404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
32504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
32604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
32704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
32804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
32904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
33004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
33104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
33204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0, IFNAMSIZ);
33304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
33404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
33504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
33604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
33704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
33804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
33904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
34004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
34104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
34204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			if (vianame[i] == ':' ||
34304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '!' ||
34404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '*') {
345aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
346aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
347aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					" `%s' (No aliases, :, ! or *).\n",
348aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
34904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
35004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
35104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
35204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
35304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
35404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
355cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
35621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardtstatic void *load_extension(const char *search_path, const char *prefix,
35721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
35821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
35921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
36021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
36121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
36221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
36321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
36421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
36521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
36621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
36721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
36821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
3692c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, name);
37021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
37121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
37221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			/* Found library.  If it didn't register itself,
37321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			   maybe they specified target as match. */
37421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
3752338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
37621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
3772338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
3782338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
37921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
38021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
38121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
38221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
38321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
38421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
38521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
38621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/%s%s.so",
3872c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, prefix, name);
38821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
38921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
3902338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
39121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
3922338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
3932338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
39421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
39521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
39621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
39721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
39821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
39921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
40021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
40121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
40221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
40321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
40421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
40521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
406cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
40721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
4082338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_match *
4092338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_match(const char *name, enum xtables_tryload tryload,
4102338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		   struct xtables_rule_match **matches)
4110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
4120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
4130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
4140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
4160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
4170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
4180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
4190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
4200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
4210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
4230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
4240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
4250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
4270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
4280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
4290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
431630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt			clone = xtables_malloc(sizeof(struct xtables_match));
4320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
4330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
4340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
4350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
4360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
4380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
4390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
4400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
4432338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
44477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
44539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, false);
446170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
4472338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
4480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
4490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
4500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
4510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
4530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
4542338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
4550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
4560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
4570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
4580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4592338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
4600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
4610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
4620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
4640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
4660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
4670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
4680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
469630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
4700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
4720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
4732338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				(*i)->completed = true;
4740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
4750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
4762338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		newentry->completed = false;
4770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
4780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
4790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
4820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
4830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4842338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_target *
4852338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_target(const char *name, enum xtables_tryload tryload)
4860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
4870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
4880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
4900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
4910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
4920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
4930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
4940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
4950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
4960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
4980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
4990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
5000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
5032338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
50477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
50539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, true);
506170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
5072338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
5080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
5090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
5100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
5110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
5130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
5142338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
5150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
5160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
5170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
5180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
5200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
5210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
5220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
5240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
5260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
5270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
5290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_revision(const char *name, u_int8_t revision, int opt)
5320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
5340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
5350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
5360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
53777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
5380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
539df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
540df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
541df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
542df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy				fprintf(stderr, "Could not determine whether "
543df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
544df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
545df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy					revision);
546df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
547df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
5480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
5490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
5500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
553c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	xtables_load_ko(xtables_modprobe_program, true);
5540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
5560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
5570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
55877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
5590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
5600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
5610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
5620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
5640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
5650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
5670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
5680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
5690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
5700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
5710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
5720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
5730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
5750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
5760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_match_revision(const char *name, u_int8_t revision)
5800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
58177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_match);
5820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_target_revision(const char *name, u_int8_t revision)
5850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
58677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_target);
5870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
5900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match **i, *old;
5920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
593dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
594dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
595dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
596dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
597dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
5980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
6020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
6030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
604dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
6090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
6100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
611dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
61677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
6170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
6180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6192338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
6200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
62123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
62223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
6230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
6240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
625dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
6260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
6270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
6300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_match_revision(old->name, old->revision)
6310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
6320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
63423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_match_revision(me->name, me->revision))
6360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
63823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
63923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
64023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
64123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
6420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
6430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
6440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
6450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
6480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
649dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
6500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
6540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
6550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
6560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
6570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
6590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
6600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
6630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *old;
6650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
666dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
667dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
668dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
669dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
670dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
6710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
677dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
6820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
6830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
684dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
68977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
6900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
6910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6922338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_target(me->name, XTF_DURING_LOAD);
6930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
6940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
6950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
69623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
69723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
6980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
6990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
700dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
7010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
7020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
7030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
7050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_target_revision(old->name, old->revision)
7060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
7070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
7080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
70923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
7100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_target_revision(me->name, me->revision))
7110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
7120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
71323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
71423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
71523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
71623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
7170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
7180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
7190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
7200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
7230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
724dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
7250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
7290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
7300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
7310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
7320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
7330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
734aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
735a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt/**
736a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * xtables_param_act - act on condition
737a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @status:	a constant from enum xtables_exittype
738a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
739a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONLY_ONCE: print error message that option may only be used once.
740a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name (e.g. "mark")
741a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2(...):	option in conflict (e.g. "--mark")
742a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3(...):	condition to match on (see extensions/ for examples)
743a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
744a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_NO_INVERT: option does not support inversion
745a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
746a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option in conflict
747a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		condition to match on
748a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
749a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_BAD_VALUE: bad value for option
750a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
751a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option with which the problem occured (e.g. "--mark")
752a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		string the user passed in (e.g. "99999999999999")
753a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
754a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
755a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
756a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
757a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * Displays an error message and exits the program.
758a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt */
759a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid xtables_param_act(unsigned int status, const char *p1, ...)
760aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
761aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
762aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
763aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
764aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
765aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
766aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
767aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
768a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONLY_ONCE:
769aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
770aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
771aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
772aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
773aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
774aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
775aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
776aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
777a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_NO_INVERT:
778aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
779aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
780aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
781aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
782aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
783aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
784aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
785a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_BAD_VALUE:
786aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
787aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
788aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
789aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
790aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
791aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
792a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONE_ACTION:
793aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
794aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
795aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
796aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
797aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
798aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
799aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
800aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(status, p1, args);
801aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
802aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
803aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
804aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
805aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
80608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
807e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
80808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
80908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
81008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
81108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
81208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
81308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
81408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
81508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
81608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
81708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
81808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
81908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
82008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
82108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
82208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
82308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
82408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
82508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
82608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
82708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
82808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
82908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
83008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
83108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
83208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
83308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
83408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
83508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
83608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
837e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
83808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
83908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
84008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
84108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
84208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
84308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
84408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
845e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ipaddr_to_numeric(addr);
84608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
84708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
848e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
84908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
85008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
85108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
85208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
85308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
85408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
85508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
85608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
85708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* we don't want to see "/32" */
85808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return "";
85908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
86008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
86108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
86208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
86308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
86408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
86508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%d", i);
86608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	else
86708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
868e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
86908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
87008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
87108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
87208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
873bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
874bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
875bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
876bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
877bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
878bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
879bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
880bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
881bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
882bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
883bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
884bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
885bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
886bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
887bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
888bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
889bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
890bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
891bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
892bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
8935f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
894bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
895bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
896bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
897bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
898bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
899bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
900bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
901bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
902bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
903bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
9045f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
905bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
906bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
907bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
908bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
909bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
910bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
911bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
9125f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
913bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
914bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
915bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
916bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
917bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
918bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
9191e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
920bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
921bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
922bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
923bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
9241e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipmask(const char *dotted)
925bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
926bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
927bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
928bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
929bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
930bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
931bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
932bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
933bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
934bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
935bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
936bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
937bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
938bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
939bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
940bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
941bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
942bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
943bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
944bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
945bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
946bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
947bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
948bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
949bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
950bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
951bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
952bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
953bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
954bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
955bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
956bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
957bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
958630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
959bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
960bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
961bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
962bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
963bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
964bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
965bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
966bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
967bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
968bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
969bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
970bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
971bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
972bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
9731e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
974bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
975630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in_addr));
976bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
977bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
978bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
979bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
980bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
981bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
982bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
983bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
984bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
985bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
986bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
987bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
988bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
989bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
990bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
991bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
992bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
993bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
994bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
995bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
996bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
9971e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
998bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
999bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
10005f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1001bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
1002bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1003bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1004bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1005bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1006bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1007bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1008bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
1009bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1010bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1011bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1012a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt/**
1013a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * xtables_ipparse_any - transform arbitrary name to in_addr
1014a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt *
1015a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * Possible inputs (pseudo regex):
1016a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1017a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1018a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt */
1019a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1020a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                         struct in_addr *maskp, unsigned int *naddrs)
1021bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1022bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1023bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1024bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1025bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1026bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1027bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1028bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1029bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1030bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
1031bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1032bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
1033bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1034bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1035bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1036bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1037bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
1038bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
1039bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1040bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1041bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1042bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1043bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
1044bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1045bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1046bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1047bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1048bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1049bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1050bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1051bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1052bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1053e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
105408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
105508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	/* 0000:0000:0000:0000:0000:000.000.000.000
105608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
105708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
105808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
105908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
106008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
106108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
106208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
106308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
106408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
106508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
106608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
106708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
106808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
106908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
107008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
107108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
107208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
107308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
107408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
107508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
107608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
107708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
107808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
107908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
108008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
108108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
108208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
108308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
108408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
108508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1086e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
108708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
108808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
108908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
109108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
109208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1093e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ip6addr_to_numeric(addr);
109408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
109508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic int ip6addr_prefix_length(const struct in6_addr *k)
109708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
109808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
109908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
110008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110148607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
110248607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
110348607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
110448607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
110508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
110608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
110708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
110808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
110908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
111008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
111108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
111208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
111308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
111408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
111508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
111608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
111708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
111808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
111908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1120e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
112108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
112208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
112308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int l = ip6addr_prefix_length(addrp);
112408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
112508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
112608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
1127e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		strcat(buf, xtables_ip6addr_to_numeric(addrp));
112808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
112908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
113008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "/%d", l);
113108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
113208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1133bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
11341e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1135bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1136bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1137bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1138bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1139bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1140bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1141bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1142bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1143bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1144bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1145bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1146bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1147bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1148bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1149bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1150bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr *addr;
1151bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
1152bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo *res;
1153bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1154bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1155bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1156bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1157bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1158bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1159bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_protocol = IPPROTO_IPV6;
1160bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_next     = NULL;
1161bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1162bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1163bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1164bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1165bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1166bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1167bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1168bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1169bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (res->ai_family != AF_INET6 ||
1170bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1171bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1172bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1173bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1174bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1175bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1176bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1177bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* Get the first element of the address-chain */
1178630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_malloc(sizeof(struct in6_addr));
1179bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1180bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		       sizeof(struct in6_addr));
1181bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1182bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddr = 1;
1183bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1184bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1185bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1186bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1187bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1188bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1189bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1190bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1191bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1192bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1193bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1194bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1195bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1196bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1197bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1198bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1199bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1200bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1201bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
12021e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1203bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1204630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in6_addr));
1205bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1206bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1207bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1208bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1209bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1210bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1211bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1212bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1213bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1214bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1215bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1216bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1217bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1218bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1219bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1220bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1221bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1222bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1223bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1224bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1225bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
12261e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1227bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
12285f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1229bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
1230bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1231bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1232bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1233bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1234bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1235bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1236bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1237bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1238bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1239bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1240bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1241bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1242bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1243a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1244a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                          struct in6_addr *maskp, unsigned int *naddrs)
1245bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1246bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1247bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1248bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1249bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1250bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1251bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1252bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1253bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1254bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1255bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1256bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1257bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1258bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1259bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1260bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1261bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1262bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1263bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1264bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1265bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1266bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1267bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
12685a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1269bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1270bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1271bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1272bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1273bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1274bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1275bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1276bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1277bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1278a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1279a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_save_string(const char *value)
1280a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1281a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1282a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1283a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1284a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1285a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1286a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1287a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1288a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	length = strcspn(value, no_quote_chars);
1289a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1290a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1291a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1292a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
1293a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1294a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1295a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1296a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1297a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
1298a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar('"');
1299a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1300a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1301a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1302a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1303a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1304a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1305a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1306a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1307a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1308a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1309a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1310a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1311a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1312a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		printf("\" ");
1313a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1314a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
13150f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13160f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt/**
13170f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Check for option-intrapositional negation.
13180f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Do not use in new code.
13190f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt */
13200f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardtint xtables_check_inverse(const char option[], int *invert,
13210f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			  int *my_optind, int argc)
13220f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt{
13230f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	if (option && strcmp(option, "!") == 0) {
13240f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		fprintf(stderr, "Using intrapositioned negation "
13250f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		        "(`--option ! this`) is deprecated in favor of "
13260f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		        "extrapositioned (`! --option this`).\n");
13270f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13280f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		if (*invert)
13290f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			exit_error(PARAMETER_PROBLEM,
13300f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt				   "Multiple `!' flags not allowed");
13310f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		*invert = true;
13320f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		if (my_optind != NULL) {
13330f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			++*my_optind;
13340f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			if (argc && *my_optind > argc)
13350f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt				exit_error(PARAMETER_PROBLEM,
13360f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt					   "no argument following `!'");
13370f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		}
13380f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13390f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		return true;
13400f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	}
13410f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	return false;
13420f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt}
13431de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13441de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtconst struct xtables_pprot xtables_chain_protos[] = {
13451de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"tcp",       IPPROTO_TCP},
13461de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"sctp",      IPPROTO_SCTP},
13471de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udp",       IPPROTO_UDP},
13481de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udplite",   IPPROTO_UDPLITE},
13491de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmp",      IPPROTO_ICMP},
13501de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmpv6",    IPPROTO_ICMPV6},
13511de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-icmp", IPPROTO_ICMPV6},
13521de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"esp",       IPPROTO_ESP},
13531de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ah",        IPPROTO_AH},
13541de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-mh",   IPPROTO_MH},
13551de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"mh",        IPPROTO_MH},
13561de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"all",       0},
13571de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{NULL},
13581de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt};
13591de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13601de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtu_int16_t
13611de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtxtables_parse_protocol(const char *s)
13621de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt{
13631de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	unsigned int proto;
13641de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13651de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	if (!xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) {
13661de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		struct protoent *pent;
13671de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13681de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		/* first deal with the special case of 'all' to prevent
13691de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * people from being able to redefine 'all' in nsswitch
13701de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * and/or provoke expensive [not working] ldap/nis/...
13711de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * lookups */
13721de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		if (!strcmp(s, "all"))
13731de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			return 0;
13741de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13751de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		if ((pent = getprotobyname(s)))
13761de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			proto = pent->p_proto;
13771de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		else {
13781de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			unsigned int i;
13791de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
13801de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				if (strcmp(s, xtables_chain_protos[i].name) == 0) {
13811de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					proto = xtables_chain_protos[i].num;
13821de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					break;
13831de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				}
13841de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			}
13851de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			if (i == ARRAY_SIZE(xtables_chain_protos))
13861de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				exit_error(PARAMETER_PROBLEM,
13871de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					   "unknown protocol `%s' specified",
13881de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					   s);
13891de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		}
13901de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	}
13911de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13921de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	return proto;
13931de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt}
1394