xtables.c revision d61b02fbbbe7f6e643aad8649c8559c175c68c52
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 */
18d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt#include <ctype.h>
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>
30b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski#include <sys/statfs.h>
310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/types.h>
320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/wait.h>
3308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#include <arpa/inet.h>
34b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski#include <linux/magic.h> /* for PROC_SUPER_MAGIC */
353dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
365208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI#include <xtables.h>
374e41854423b529d3107c23b85434d50a75d08057Jan Engelhardt#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
3877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
3977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
40ef18e8147903885708d1c264904129af4fb636d6Jan Engelhardt#include <libiptc/libxtc.h>
413dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
425a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
435a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
445a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
45c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
46c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
47c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
48c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
49c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
50c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_MATCH	68
51c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_TARGET	69
52c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
5370581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim#include <getopt.h>
54aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt#include "iptables/internal.h"
551e128bd804b676ee91beca48312de9b251845d09Jan Engelhardt#include "xshared.h"
565a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#define NPROTO	255
580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
590b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#ifndef PROC_SYS_MODPROBE
600b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
610b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#endif
620b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
6337911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski/* we need this for ip6?tables-restore.  ip6?tables-restore.c sets line to the
6437911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * current line of the input file, in order  to give a more precise error
6537911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * message.  ip6?tables itself doesn't need this, so it is initialized to the
6637911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * magic number of -1 */
6737911de507d0597980ad218a044a482501a21b01Maciej Zenczykowskiint line = -1;
6837911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski
698b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salimvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
708b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim
7140a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salimstruct xtables_globals *xt_params = NULL;
7240a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
738b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salimvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...)
7440a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim{
7540a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_list args;
7640a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
7740a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_start(args, msg);
7840a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
7940a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	vfprintf(stderr, msg, args);
8040a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_end(args);
8140a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	fprintf(stderr, "\n");
8240a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	exit(status);
8340a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim}
8440a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
85600f38db82548a683775fd89b6e136673e924097Jan Engelhardtvoid xtables_free_opts(int unused)
8684c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim{
87df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt	if (xt_params->opts != xt_params->orig_opts) {
8859e8114c6792242e80785f4461d5e663fb9a3d64Jan Engelhardt		free(xt_params->opts);
89df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt		xt_params->opts = NULL;
90df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt	}
9184c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim}
9284c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim
93600f38db82548a683775fd89b6e136673e924097Jan Engelhardtstruct option *xtables_merge_options(struct option *orig_opts,
94600f38db82548a683775fd89b6e136673e924097Jan Engelhardt				     struct option *oldopts,
9570581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim				     const struct option *newopts,
9670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim				     unsigned int *option_offset)
9770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim{
98600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
99600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	struct option *merge, *mp;
10070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
10170581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	if (newopts == NULL)
10270581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim		return oldopts;
10370581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
104600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
105600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	if (oldopts != NULL)
106600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		for (num_old = 0; oldopts[num_old].name; num_old++) ;
10770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	for (num_new = 0; newopts[num_new].name; num_new++) ;
10870581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
1091dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	/*
1101dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 * Since @oldopts also has @orig_opts already (and does so at the
1111dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 * start), skip these entries.
1121dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 */
1131dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	oldopts += num_oold;
1141dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	num_old -= num_oold;
1151dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt
116600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
117600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	if (merge == NULL)
118600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		return NULL;
119600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
120600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Let the base options -[ADI...] have precedence over everything */
121600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
122600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	mp = merge + num_oold;
123600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
124600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Second, the new options */
1251e128bd804b676ee91beca48312de9b251845d09Jan Engelhardt	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
12670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	*option_offset = xt_params->option_offset;
127600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(mp, newopts, sizeof(*mp) * num_new);
12870581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
129600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	for (i = 0; i < num_new; ++i, ++mp)
130600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		mp->val += *option_offset;
131600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
132600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Third, the old options */
133600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(mp, oldopts, sizeof(*mp) * num_old);
134600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	mp += num_old;
135600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	xtables_free_opts(0);
13670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
137600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Clear trailing entry */
138600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memset(mp, 0, sizeof(*mp));
13970581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	return merge;
14070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim}
14170581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
14277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv4 = {
14377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip_tables",
144b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	.proc_exists   = "/proc/net/ip_tables_names",
14577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libipt_",
14677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family	       = NFPROTO_IPV4,
14777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IP,
14877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
14977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
15077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
15177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
15277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv6 = {
15377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip6_tables",
154b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	.proc_exists   = "/proc/net/ip6_tables_names",
15577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libip6t_",
15677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family        = NFPROTO_IPV6,
15777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IPV6,
15877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
15977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
16077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
16177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
162aa37acc1423126f555135935c687eb91995b9440Jan Engelhardtconst struct xtables_afinfo *afinfo;
16377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
16439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt/* Search path for Xtables .so files */
16539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtstatic const char *xtables_libdir;
1660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1670b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
168c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtconst char *xtables_modprobe_program;
1690b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1702c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Keep track of matches/targets pending full registration: linked lists. */
1712c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistruct xtables_match *xtables_pending_matches;
1722c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistruct xtables_target *xtables_pending_targets;
1732c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
1742c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Keep track of fully registered external matches/targets: linked lists. */
1750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
1760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
1770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1782c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Fully register a match/target which was previously partially registered. */
1792c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_match(struct xtables_match *me);
1802c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_target(struct xtables_target *me);
1812c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
18239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtvoid xtables_init(void)
18339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt{
18439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("XTABLES_LIBDIR");
18539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL)
18639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
18739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("IPTABLES_LIB_DIR");
18839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL) {
18939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
19039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		        "use XTABLES_LIBDIR.\n");
19139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
19239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	}
193ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	/*
194ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
195ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
196ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * for these env vars are deprecated anyhow, and in light of the
197ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * (shared) libxt_*.so files, makes less sense to have
198ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
199ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 */
200ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
201ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	if (xtables_libdir != NULL) {
202ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
203ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		        "use XTABLES_LIBDIR.\n");
204ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		return;
205ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	}
20639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = XTABLES_LIBDIR;
20739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt}
20839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt
20977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtvoid xtables_set_nfproto(uint8_t nfproto)
21077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt{
21177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	switch (nfproto) {
21277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV4:
21377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv4;
21477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
21577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV6:
21677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv6;
21777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
21877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	default:
21977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
22077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		        __func__);
22177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	}
22277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt}
22377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
224630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt/**
2257e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * xtables_set_params - set the global parameters used by xtables
2267e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * @xtp:	input xtables_globals structure
2277e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim *
2287e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * The app is expected to pass a valid xtables_globals data-filled
2297e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * with proper values
2307e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * @xtp cannot be NULL
2317e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim *
2327e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * Returns -1 on failure to set and 0 on success
2337e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim */
2347e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salimint xtables_set_params(struct xtables_globals *xtp)
2357e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim{
2367e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (!xtp) {
2377e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		fprintf(stderr, "%s: Illegal global params\n",__func__);
2387e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		return -1;
2397e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	}
2407e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2417e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xt_params = xtp;
2427e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2437e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (!xt_params->exit_err)
2447e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		xt_params->exit_err = basic_exit_err;
2457e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2467e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	return 0;
2477e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim}
2487e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2497e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salimint xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
2507e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim{
2517e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xtables_init();
2527e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xtables_set_nfproto(nfproto);
2537e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	return xtables_set_params(xtp);
2547e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim}
2557e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2567e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim/**
257630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt * xtables_*alloc - wrappers that exit on failure
258630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt */
259630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_calloc(size_t count, size_t size)
2603dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
2613dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
2623dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2633dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
2643dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
2653dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
2663dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
2673dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2683dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
2693dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
2703dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
271630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_malloc(size_t size)
2723dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
2733dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
2743dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2753dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
2763dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
2773dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
2783dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
2793dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2803dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
2813dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
2820b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
283332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid *xtables_realloc(void *ptr, size_t size)
284332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
285332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	void *p;
286332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
287332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	if ((p = realloc(ptr, size)) == NULL) {
288332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		perror("ip[6]tables: realloc failed");
289332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		exit(1);
290332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
291332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
292332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	return p;
293332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
294332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
2950b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
2960b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
2970b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
2980b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
2990b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3000b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROCFILE_BUFSIZ	1024
3010b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
3020b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
3030b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
304a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
305a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		fprintf(stderr, "Could not set close on exec: %s\n",
306a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski			strerror(errno));
307a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		exit(1);
308a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	}
3090b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
310371cea299f0b2eb100b9fc9fb99089640d2d606fJan Engelhardt	ret = malloc(PROCFILE_BUFSIZ);
3110b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
3120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		memset(ret, 0, PROCFILE_BUFSIZ);
3130b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
3140b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case -1: goto fail;
3150b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
3160b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
3170b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (ret[strlen(ret)-1]=='\n')
3180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			ret[strlen(ret)-1]=0;
3190b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		close(procfile);
3200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return ret;
3210b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3220b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI fail:
3230b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
3240b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
3250b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
3260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
3270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
328c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
3290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
3300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
3310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
3320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
3330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3340b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
3350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
3360b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
3370b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
3380b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
3390b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
3400b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3410b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
342c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	/*
343c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 * Need to flush the buffer, or the child may output it again
344c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 * when switching the program thru execv.
345c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 */
346c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	fflush(stdout);
347c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt
34894aa2ea67d7b8a669e8541f094661a1dc89722a3Jan Engelhardt	switch (vfork()) {
3490b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
3500b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
3510b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
3520b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
3530b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
3540b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
3550b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
3560b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
3570b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
3580b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
3590b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
3600b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3610b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
3620b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
3630b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
3640b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
3650b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3660b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
3670b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
3680b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3690b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3700b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
3710b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
3720b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
3730b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
3740b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
3750b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
376b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski/* return true if a given file exists within procfs */
377b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowskistatic bool proc_file_exists(const char *filename)
378b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski{
379b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	struct stat s;
380b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	struct statfs f;
381b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
382b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (lstat(filename, &s))
383b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
384b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (!S_ISREG(s.st_mode))
385b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
386b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (statfs(filename, &f))
387b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
388b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (f.f_type != PROC_SUPER_MAGIC)
389b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
390b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	return true;
391b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski}
392b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
393c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_load_ko(const char *modprobe, bool quiet)
3940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
395c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	static bool loaded = false;
396b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	int ret;
3970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
398b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (loaded)
399b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return 0;
400b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
401b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (proc_file_exists(afinfo->proc_exists)) {
402b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		loaded = true;
403b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return 0;
404b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	};
405b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
406b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
407b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (ret == 0)
408b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		loaded = true;
4090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
4110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
4120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4135f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt/**
4145f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * xtables_strtou{i,l} - string to number conversion
4155f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @s:	input string
4165f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @end:	like strtoul's "end" pointer
4175f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @value:	pointer for result
4185f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @min:	minimum accepted value
4195f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @max:	maximum accepted value
4205f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt *
4215f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
4225f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * "15a" is rejected.
4235f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * In either case, the value obtained is compared for min-max compliance.
4245f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Base is always 0, i.e. autodetect depending on @s.
425cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
4265f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Returns true/false whether number was accepted. On failure, *value has
4275f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * undefined contents.
428cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
4292305d5fb42fc059f38fc1bdf53411dbeecdb310bJP Abgrallbool xtables_strtoul(const char *s, char **end, unsigned long long *value,
4305f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned long min, unsigned long max)
431cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
432cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
433d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	const char *p;
434cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
435cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
436cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
437d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	/* Since strtoul allows leading minus, we have to check for ourself. */
438d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	for (p = s; isspace(*p); ++p)
439d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt		;
440d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	if (*p == '-')
441d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt		return false;
442cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	v = strtoul(s, &my_end, 0);
443cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
444cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
445cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
446cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
447cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
448cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
449cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
450cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
451cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
452cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
453cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
454cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
455cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
456cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
457cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
458cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
4595f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoui(const char *s, char **end, unsigned int *value,
4605f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned int min, unsigned int max)
461cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
4622305d5fb42fc059f38fc1bdf53411dbeecdb310bJP Abgrall	unsigned long long v;
463cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
464cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
4655f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	ret = xtables_strtoul(s, end, &v, min, max);
466cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
467cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
468cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
469cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
470cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
471aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtint xtables_service_to_port(const char *name, const char *proto)
47204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
47304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
47404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
47504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
47604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
47704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
47804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
47904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
48004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4817ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtuint16_t xtables_parse_port(const char *port, const char *proto)
48204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
4837a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
48404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4855f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
486aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
487213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
48804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4898b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM,
49004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
49104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
49204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
493aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtvoid xtables_parse_interface(const char *arg, char *vianame,
494aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt			     unsigned char *mask)
49504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
496fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt	unsigned int vialen = strlen(arg);
49704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
49804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
49904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
50004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
50104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
50204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
5038b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
50404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
50504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
50604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
50704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
508fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt	if (vialen == 0)
50904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0, IFNAMSIZ);
51004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
51104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
51204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
51304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
51404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
51504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
51604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
51704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
51804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
519fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt			if (vianame[i] == '/' ||
520fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt			    vianame[i] == ' ') {
521aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
522aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
523fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt					" `%s' ('/' and ' ' are not allowed by the kernel).\n",
524aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
52504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
52604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
52704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
52804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
52904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
53004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
531cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
532927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardtstatic void *load_extension(const char *search_path, const char *af_prefix,
53321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
53421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
535927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt	const char *all_prefixes[] = {"libxt_", af_prefix, NULL};
536927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt	const char **prefix;
53721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
53821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
53921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
54021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
54121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
54221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
54321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
54421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
54521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
54621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
547927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt		for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
548927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			snprintf(path, sizeof(path), "%.*s/%s%s.so",
549927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			         (unsigned int)(next - dir), dir,
550927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			         *prefix, name);
551927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt
552927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (stat(path, &sb) != 0) {
553927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				if (errno == ENOENT)
554927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt					continue;
555927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				fprintf(stderr, "%s: %s\n", path,
556927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt					strerror(errno));
557927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				return NULL;
558927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			}
559927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (dlopen(path, RTLD_NOW) == NULL) {
560927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				fprintf(stderr, "%s: %s\n", path, dlerror());
561927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				break;
562927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			}
56321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
56421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
5652338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
56621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
5672338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
5682338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
56921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
570927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (ptr != NULL)
571927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				return ptr;
57221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
573927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			fprintf(stderr, "%s: no \"%s\" extension found for "
574927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				"this protocol\n", path, name);
575927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			errno = ENOENT;
576927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			return NULL;
577927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt		}
57821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
57921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
58021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
58121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
58221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
583cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
58421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
5852338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_match *
5862338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_match(const char *name, enum xtables_tryload tryload,
5872338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		   struct xtables_rule_match **matches)
5880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5892c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_match **dptr;
5900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
5910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
5920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5930cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
59421d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
59521d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt			   "Invalid match name \"%s\" (%u chars max)",
5960cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt			   name, XT_EXTENSION_MAXNAMELEN - 1);
59721d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt
5980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
5990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
6010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
6020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
6030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
6040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6052c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* Trigger delayed initialization */
6062c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	for (dptr = &xtables_pending_matches; *dptr; ) {
6072c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		if (strcmp(name, (*dptr)->name) == 0) {
6082c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr = *dptr;
6092c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			*dptr = (*dptr)->next;
6102c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr->next = NULL;
6112c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			xtables_fully_register_pending_match(ptr);
6122c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		} else {
6132c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			dptr = &((*dptr)->next);
6142c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		}
6152c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	}
6162c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
6170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
6180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
6190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
6200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
6220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
6230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
6240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
626630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt			clone = xtables_malloc(sizeof(struct xtables_match));
6270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
6280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
6290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
6300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
6310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
6330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
6340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
6382338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
63977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
64039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, false);
641170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
6422338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
6438b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
6440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
645927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				   name, strerror(errno));
6460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
6480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
6492338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
6500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
6510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
6520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
6530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6542338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
6558b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
6560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
6570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
6590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
6610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
6620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
6630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
664630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
6650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
6670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
6682338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				(*i)->completed = true;
6690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
6712338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		newentry->completed = false;
6720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
6730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
6740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
6770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6792338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_target *
6802338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_target(const char *name, enum xtables_tryload tryload)
6810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6822c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_target **dptr;
6830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
6840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
6860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
6870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
6880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
6890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
6900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
6910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
6920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6932c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* Trigger delayed initialization */
6942c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	for (dptr = &xtables_pending_targets; *dptr; ) {
6952c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		if (strcmp(name, (*dptr)->name) == 0) {
6962c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr = *dptr;
6972c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			*dptr = (*dptr)->next;
6982c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr->next = NULL;
6992c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			xtables_fully_register_pending_target(ptr);
7002c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		} else {
7012c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			dptr = &((*dptr)->next);
7022c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		}
7032c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	}
7042c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
7050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
7060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
7070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
7080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
7112338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
71277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
71339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, true);
714170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
7152338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
7168b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
7170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
718927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				   name, strerror(errno));
7190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
7210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
7222338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
7230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
7240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
7250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
7260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
727854d2d9bd7556cfd8a676b0bc18dc059a9a2dd25Peter Volkov	if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
7288b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
7290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
7300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
7320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
7340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
7350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
7370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7397ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_revision(const char *name, uint8_t revision, int opt)
7400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
7410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
7420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
7430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
7440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
74577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
7460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
747df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
748df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
749df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
750e1639b0bc28420ca01d733749c8db16d5a3fbd0cJan Engelhardt				fprintf(stderr, "%s: Could not determine whether "
751df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
752df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
753e1639b0bc28420ca01d733749c8db16d5a3fbd0cJan Engelhardt					name, revision);
754df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
755df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
7560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
7570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
7580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
761a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
762a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		fprintf(stderr, "Could not set close on exec: %s\n",
763a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski			strerror(errno));
764a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		exit(1);
765a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	}
766a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski
767c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	xtables_load_ko(xtables_modprobe_program, true);
7680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
7700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
7710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
77277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
7730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
7740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
7750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
7760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
7770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
7780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
7790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
7800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
7810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
7820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
7830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
7840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
7850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
7860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
7870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
7890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
7900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7937ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_match_revision(const char *name, uint8_t revision)
7940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
79577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_match);
7960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7987ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_target_revision(const char *name, uint8_t revision)
7990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
80077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_target);
8010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
8020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
803dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardtstatic void xtables_check_options(const char *name, const struct option *opt)
804dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt{
805dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	for (; opt->name != NULL; ++opt)
806dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
807dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			fprintf(stderr, "%s: Extension %s uses invalid "
808dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			        "option value %d\n",xt_params->program_name,
809dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			        name, opt->val);
810dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			exit(1);
811dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		}
812dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt}
813dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
8140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
8150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
816c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	if (me->version == NULL) {
817c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		fprintf(stderr, "%s: match %s<%u> is missing a version\n",
818c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		        xt_params->program_name, me->name, me->revision);
819c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		exit(1);
820c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	}
821dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
822dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
823dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
8245dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name,
825dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
8260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8290cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
830281439ba6b96b729ef1400a49ec53eda298bb9f8Li Yewang		fprintf(stderr, "%s: match `%s' has invalid name\n",
8315dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
8320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
8360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
8370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
8385dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
8390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
842aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt	if (me->x6_options != NULL)
843aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt		xtables_option_metavalidate(me->name, me->x6_options);
844dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	if (me->extra_opts != NULL)
845dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		xtables_check_options(me->name, me->extra_opts);
846dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
8470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
84877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
8490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
8500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8512c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* place on linked list of matches pending full registration */
8522c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	me->next = xtables_pending_matches;
8532c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	xtables_pending_matches = me;
8542c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski}
8552c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
8562c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_match(struct xtables_match *me)
8572c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski{
8582c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_match **i, *old;
8592c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
8602338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
8610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
86223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
86323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
8640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
8650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
8665dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim				xt_params->program_name, me->name);
8670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
8680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
8690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
8710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_match_revision(old->name, old->revision)
8720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
8730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
8740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
87523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
8760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_match_revision(me->name, me->revision))
8770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
8780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
87923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
88023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
88123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
88223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
8830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
8840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
8850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
8860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
8890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
8905dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        xt_params->program_name, me->name,
8915dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        (unsigned int)me->size);
8920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
8960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
8970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
8980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
8990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
9010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
9020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
9030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9049a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardtvoid xtables_register_matches(struct xtables_match *match, unsigned int n)
9059a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt{
9069a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	do {
9079a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt		xtables_register_match(&match[--n]);
9089a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	} while (n > 0);
9099a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt}
9109a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt
9110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
9120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
913c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	if (me->version == NULL) {
914c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		fprintf(stderr, "%s: target %s<%u> is missing a version\n",
915c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		        xt_params->program_name, me->name, me->revision);
916c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		exit(1);
917c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	}
918dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
919dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
920dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
9215dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name,
922dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
9230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9260cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
9270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
9285dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
9290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
9330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
9340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
9355dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
9360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
939aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt	if (me->x6_options != NULL)
940aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt		xtables_option_metavalidate(me->name, me->x6_options);
941dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	if (me->extra_opts != NULL)
942dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		xtables_check_options(me->name, me->extra_opts);
943dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
9440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
94577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
9460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
9470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9482c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* place on linked list of targets pending full registration */
9492c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	me->next = xtables_pending_targets;
9502c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	xtables_pending_targets = me;
9512c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski}
9522c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
9532c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_target(struct xtables_target *me)
9542c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski{
9552c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_target *old;
9562c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
9572338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_target(me->name, XTF_DURING_LOAD);
9580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
9590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
9600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
96123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
96223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
9630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
9640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
9655dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim				xt_params->program_name, me->name);
9660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
9670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
9680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
9700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_target_revision(old->name, old->revision)
9710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
9720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
9730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
97423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
9750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_target_revision(me->name, me->revision))
9760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
9770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
97823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
97923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
98023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
98123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
9820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
9830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
9840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
9850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
9880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
9895dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        xt_params->program_name, me->name,
9905dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        (unsigned int)me->size);
9910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
9950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
9960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
9970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
9980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
9990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
1000aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
10019a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardtvoid xtables_register_targets(struct xtables_target *target, unsigned int n)
10029a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt{
10039a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	do {
10049a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt		xtables_register_target(&target[--n]);
10059a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	} while (n > 0);
10069a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt}
10079a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt
1008a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt/**
1009a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * xtables_param_act - act on condition
1010a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @status:	a constant from enum xtables_exittype
1011a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1012a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONLY_ONCE: print error message that option may only be used once.
1013a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name (e.g. "mark")
1014a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2(...):	option in conflict (e.g. "--mark")
1015a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3(...):	condition to match on (see extensions/ for examples)
1016a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1017a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_NO_INVERT: option does not support inversion
1018a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1019a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option in conflict
1020a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		condition to match on
1021a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1022a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_BAD_VALUE: bad value for option
1023a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1024a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option with which the problem occured (e.g. "--mark")
1025a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		string the user passed in (e.g. "99999999999999")
1026a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1027a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1028a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1029a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1030a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * Displays an error message and exits the program.
1031a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt */
1032a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid xtables_param_act(unsigned int status, const char *p1, ...)
1033aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
1034aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
1035aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
1036aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
1037aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1038aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
1039aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1040aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
1041a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONLY_ONCE:
1042aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1043aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
1044aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
1045aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
10468b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1047aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
1048aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
1049aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1050a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_NO_INVERT:
1051aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1052aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
1053aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
1054aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
10558b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1056aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
1057aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1058a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_BAD_VALUE:
1059aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1060aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
10618b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1062aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
1063aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
1064aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1065a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONE_ACTION:
1066aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
1067aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
1068aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
10698b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1070aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
1071aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1072aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
10738b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(status, p1, args);
1074aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1075aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
1076aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1077aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
1078aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
107908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1080e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
108108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
108208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
108308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
108408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
108508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
108608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
108708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
108808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
108908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
109008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
109108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
109208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
109408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
109508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
109608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
109808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
109908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
110108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
110208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
110308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
110508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
110608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
110808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
110908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1110e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
111108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
111208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
111308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
111408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
111508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
111608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
111708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1118e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ipaddr_to_numeric(addr);
111908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
112008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1121e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
112208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
112308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
112408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
112508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
112608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
112708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
112808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
112908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
113008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* we don't want to see "/32" */
113108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return "";
113208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
113308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
113408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
113508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
113608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
113708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
113808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%d", i);
113908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	else
114008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
1141e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
114208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
114308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
114408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
114508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1146bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1147bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1148bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
1149bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
1150bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
1151bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
1152bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
1153bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1154bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
1155bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
1156bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1157bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
1158bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1159bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
1160bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
1161bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
1162bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
1163bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
1164bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1165bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
11665f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1167bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
1168bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1169bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
1170bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
1171bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
1172bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1173bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
1174bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
1175bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1176bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
11775f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1178bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1179bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1180bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
1181bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
1182bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1183bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1184bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
11855f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1186bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1187bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1188bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
1189bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
1190bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1191bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
11921e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1193bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1194bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
1195bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1196bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
11971e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1198bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1199bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
1200bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1201bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1202bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
1203bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1204bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
1205bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
1206bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1207bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
1208bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
1209bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1210bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
1211bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
1212bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1213bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1214bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1215bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1216bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1217bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1218bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1219bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
1220bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
1221bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
1222bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1223bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1224bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
1225bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
1226bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
1227bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1228bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1229bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
1230bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
123111e250ba02349cb1e34058673db3d0b54eb56c44Wes Campaigne		addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1232bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
1233bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
1234bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
1235bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1236bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1237bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1238bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1239bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1240bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1241bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
1242bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
1243bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1244bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
1245bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
12461e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1247bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1248630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in_addr));
1249bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1250bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1251bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1252bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1253bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1254bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
1255bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
12568b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1257bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1258bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1259bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
1260bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1261bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
1262bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1263bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1264bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1265bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1266bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
1267bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
1268bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1269bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
12701e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1271bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
1272bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
12735f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
12748b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1275bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1276bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1277bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1278bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1279bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1280bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1281bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
1282bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1283bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1284bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1285332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1286332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow                              struct in_addr **maskpp, unsigned int *naddrs)
1287332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
1288332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	struct in_addr *addrp;
1289332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	char buf[256], *p;
1290332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	unsigned int len, i, j, n, count = 1;
1291332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	const char *loop = name;
1292332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1293332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	while ((loop = strchr(loop, ',')) != NULL) {
1294332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++count;
1295332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++loop; /* skip ',' */
1296332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1297332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1298332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1299332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1300332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1301332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	loop = name;
1302332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1303332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	for (i = 0; i < count; ++i) {
1304332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (loop == NULL)
1305332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1306332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (*loop == ',')
1307332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			++loop;
1308332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (*loop == '\0')
1309332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1310332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		p = strchr(loop, ',');
1311332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (p != NULL)
1312332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = p - loop;
1313332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		else
1314332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = strlen(loop);
1315332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (len == 0 || sizeof(buf) - 1 < len)
1316332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1317332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1318332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		strncpy(buf, loop, len);
1319332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		buf[len] = '\0';
1320332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		loop += len;
1321332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((p = strrchr(buf, '/')) != NULL) {
1322332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*p = '\0';
1323332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ipmask(p + 1);
1324332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1325332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ipmask(NULL);
1326332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1327332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		memcpy(*maskpp + i, addrp, sizeof(*addrp));
1328332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1329332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* if a null mask is given, the name is ignored, like in "any/0" */
1330332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((*maskpp + i)->s_addr == 0)
1331332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			/*
1332332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 * A bit pointless to process multiple addresses
1333332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 * in this case...
1334332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 */
1335332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			strcpy(buf, "0.0.0.0");
1336332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1337332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		addrp = ipparse_hostnetwork(buf, &n);
1338332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (n > 1) {
1339332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			count += n - 1;
1340332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*addrpp = xtables_realloc(*addrpp,
1341332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in_addr) * count);
1342332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*maskpp = xtables_realloc(*maskpp,
1343332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in_addr) * count);
1344332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 0; j < n; ++j)
1345332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new addr */
1346332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*addrpp + i + j, addrp + j,
1347332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1348332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 1; j < n; ++j)
1349332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new mask */
1350332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*maskpp + i + j, *maskpp + i,
1351332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1352332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			i += n - 1;
1353332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1354332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			memcpy(*addrpp + i, addrp, sizeof(*addrp));
1355332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1356332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* free what ipparse_hostnetwork had allocated: */
1357332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		free(addrp);
1358332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1359332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*naddrs = count;
13604b110b426df7bf486a3e7884c56ebb3487023601Jan Engelhardt	for (i = 0; i < count; ++i)
1361332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		(*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1362332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
1363332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1364332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1365a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt/**
1366a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * xtables_ipparse_any - transform arbitrary name to in_addr
1367a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt *
1368a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * Possible inputs (pseudo regex):
1369a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1370a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1371a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt */
1372a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1373a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                         struct in_addr *maskp, unsigned int *naddrs)
1374bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1375bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1376bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1377bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1378bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1379bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1380bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1381bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1382bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1383bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
1384bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1385bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
1386bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1387bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1388bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1389bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1390bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
1391bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
1392bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1393bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1394bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1395bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1396bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
1397bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1398bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1399adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				/*
1400adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * Nuke the dup by copying an address from the
1401adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * tail here, and check the current position
1402adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * again (--j).
1403adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 */
1404adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				memcpy(&addrp[--j], &addrp[--*naddrs],
1405adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				       sizeof(struct in_addr));
1406bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1407bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1408bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1409bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1410bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1411e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
141208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
1413cf3e52d00b7d3fedf98ef7710c337c441270d936Maciej Zenczykowski	/* 0000:0000:0000:0000:0000:0000:000.000.000.000
141408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
141508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
141608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
141708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
141808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
141908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
142008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
142108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
142208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
142308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
142408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
142508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
142608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
142708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
142808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
142908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
143008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
143108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
143208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
143308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
143408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
143508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
143608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
143708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
143808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
143908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
144008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
144108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
144208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
144308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1444e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
144508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
144608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
144708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
144808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
144908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
145008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1451e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ip6addr_to_numeric(addr);
145208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
145308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
145408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic int ip6addr_prefix_length(const struct in6_addr *k)
145508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
145608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
145708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
145808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
145948607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
146048607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
146148607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
146248607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
146308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
146408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
146508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
146608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
146708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
146808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
146908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
147008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
147108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
147208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
147308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
147408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
147508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
147608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
147708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1478e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
147908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
148008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
148108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int l = ip6addr_prefix_length(addrp);
148208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
148308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
148408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
1485e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		strcat(buf, xtables_ip6addr_to_numeric(addrp));
148608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
148708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
148808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "/%d", l);
148908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
149008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1491bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
14921e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1493bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1494bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1495bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1496bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1497bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1498bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1499bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1500bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1501bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1502bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1503bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1504bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1505bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1506bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1507bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
15082ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	struct in6_addr *addr;
1509bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
15102ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	struct addrinfo *res, *p;
1511bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
15122ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	unsigned int i;
1513bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1514bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1515bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1516bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1517bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1518bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1519bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1520bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1521bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1522bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1523bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1524bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1525bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
15262ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		/* Find length of address chain */
15272ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		for (p = res; p != NULL; p = p->ai_next)
15282ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			++*naddr;
1529bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1530bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
153130290aea009cf3fd76f27336fb4370be3467c4daPatrick McHardy		        xtables_ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1532bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
15332ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		/* Copy each element of the address chain */
15342ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
15352ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		for (i = 0, p = res; p != NULL; p = p->ai_next)
15362ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			memcpy(&addr[i++],
15372ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			       &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
15382ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			       sizeof(struct in6_addr));
1539bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1540bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1541bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1542bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1543bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1544bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1545bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1546bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1547bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1548bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1549bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1550bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1551bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1552bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1553bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1554bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1555bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1556bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1557bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1558bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
15591e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1560bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1561630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in6_addr));
1562bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1563bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1564bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1565bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1566bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1567bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1568bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
15698b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1570bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1571bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1572bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1573bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1574bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1575bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1576bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1577bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1578bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1579bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1580bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1581bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1582bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
15831e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1584bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
15855f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
15868b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1587bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1588bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1589bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1590bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1591bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1592bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1593bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1594bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1595bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1596bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1597bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1598bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1599bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1600332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid
1601332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowxtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
1602332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		      struct in6_addr **maskpp, unsigned int *naddrs)
1603332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
160458df90174164fd673e8c4103f7ce0c4e55ef1aecOlaf Rempel	static const struct in6_addr zero_addr;
1605332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	struct in6_addr *addrp;
1606332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	char buf[256], *p;
1607332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	unsigned int len, i, j, n, count = 1;
1608332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	const char *loop = name;
1609332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1610332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	while ((loop = strchr(loop, ',')) != NULL) {
1611332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++count;
1612332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++loop; /* skip ',' */
1613332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1614332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1615332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
1616332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
1617332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1618332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	loop = name;
1619332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1620332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	for (i = 0; i < count /*NB: count can grow*/; ++i) {
1621332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (loop == NULL)
1622332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1623332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (*loop == ',')
1624332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			++loop;
1625332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (*loop == '\0')
1626332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1627332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		p = strchr(loop, ',');
1628332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (p != NULL)
1629332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = p - loop;
1630332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		else
1631332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = strlen(loop);
1632332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (len == 0 || sizeof(buf) - 1 < len)
1633332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1634332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1635332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		strncpy(buf, loop, len);
1636332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		buf[len] = '\0';
1637332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		loop += len;
1638332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((p = strrchr(buf, '/')) != NULL) {
1639332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*p = '\0';
1640332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ip6mask(p + 1);
1641332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1642332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ip6mask(NULL);
1643332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1644332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		memcpy(*maskpp + i, addrp, sizeof(*addrp));
1645332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1646332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* if a null mask is given, the name is ignored, like in "any/0" */
164758df90174164fd673e8c4103f7ce0c4e55ef1aecOlaf Rempel		if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
1648332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			strcpy(buf, "::");
1649332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1650332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		addrp = ip6parse_hostnetwork(buf, &n);
1651332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (n > 1) {
1652332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			count += n - 1;
1653332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*addrpp = xtables_realloc(*addrpp,
1654332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in6_addr) * count);
1655332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*maskpp = xtables_realloc(*maskpp,
1656332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in6_addr) * count);
1657332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 0; j < n; ++j)
1658332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new addr */
1659332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*addrpp + i + j, addrp + j,
1660332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1661332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 1; j < n; ++j)
1662332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new mask */
1663332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*maskpp + i + j, *maskpp + i,
1664332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1665332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			i += n - 1;
1666332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1667332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			memcpy(*addrpp + i, addrp, sizeof(*addrp));
1668332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1669332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* free what ip6parse_hostnetwork had allocated: */
1670332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		free(addrp);
1671332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1672332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*naddrs = count;
16734b110b426df7bf486a3e7884c56ebb3487023601Jan Engelhardt	for (i = 0; i < count; ++i)
1674332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		for (j = 0; j < 4; ++j)
1675332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			(*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
1676332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
1677332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1678a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1679a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                          struct in6_addr *maskp, unsigned int *naddrs)
1680bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
16819c0fa7d8c84dc2478bd36d31b328b697fbe4d0afJan Engelhardt	static const struct in6_addr zero_addr;
1682bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1683bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1684bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1685bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1686bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1687bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1688bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1689bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1690bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1691bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1692bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1693bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1694bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1695bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1696bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
16979c0fa7d8c84dc2478bd36d31b328b697fbe4d0afJan Engelhardt	if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
1698bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1699bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1700bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1701bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1702bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1703bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
17045a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1705bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1706bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1707bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1708adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				/*
1709adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * Nuke the dup by copying an address from the
1710adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * tail here, and check the current position
1711adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * again (--j).
1712adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 */
1713adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				memcpy(&addrp[--j], &addrp[--*naddrs],
1714adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				       sizeof(struct in_addr));
1715bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1716bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1717bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1718bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1719a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1720a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_save_string(const char *value)
1721a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1722a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1723a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1724a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1725a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1726a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1727a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1728a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
172987dc7c4c842deb1e2e3d38089ffcad9f238d98deMax Kellerman	length = strspn(value, no_quote_chars);
1730a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1731a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1732a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
173373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(value, stdout);
1734a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1735a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1736a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1737a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1738a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
173973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" \"");
1740a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1741a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1742a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1743a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1744a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1745a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1746a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1747a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1748a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1749a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1750a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1751a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1752a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
175373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		putchar('\"');
1754a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1755a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
17560f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
17570f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt/**
17580f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Check for option-intrapositional negation.
17590f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Do not use in new code.
17600f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt */
17610f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardtint xtables_check_inverse(const char option[], int *invert,
1762bf97128c7262f17a02fec41cdae75b472ba77f88Jan Engelhardt			  int *my_optind, int argc, char **argv)
17630f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt{
17642be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	if (option == NULL || strcmp(option, "!") != 0)
17652be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt		return false;
17660f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
17672be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	fprintf(stderr, "Using intrapositioned negation "
17682be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	        "(`--option ! this`) is deprecated in favor of "
17692be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	        "extrapositioned (`! --option this`).\n");
17700f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
17712be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	if (*invert)
17722be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt		xt_params->exit_err(PARAMETER_PROBLEM,
17732be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt			   "Multiple `!' flags not allowed");
17742be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	*invert = true;
17752be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	if (my_optind != NULL) {
1776bf97128c7262f17a02fec41cdae75b472ba77f88Jan Engelhardt		optarg = argv[*my_optind];
17772be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt		++*my_optind;
17782be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt		if (argc && *my_optind > argc)
17792be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt			xt_params->exit_err(PARAMETER_PROBLEM,
17802be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt				   "no argument following `!'");
17810f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	}
17822be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt
17832be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	return true;
17840f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt}
17851de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
17861de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtconst struct xtables_pprot xtables_chain_protos[] = {
17871de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"tcp",       IPPROTO_TCP},
17881de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"sctp",      IPPROTO_SCTP},
17891de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udp",       IPPROTO_UDP},
17901de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udplite",   IPPROTO_UDPLITE},
17911de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmp",      IPPROTO_ICMP},
17921de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmpv6",    IPPROTO_ICMPV6},
17931de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-icmp", IPPROTO_ICMPV6},
17941de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"esp",       IPPROTO_ESP},
17951de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ah",        IPPROTO_AH},
17961de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-mh",   IPPROTO_MH},
17971de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"mh",        IPPROTO_MH},
17981de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"all",       0},
17991de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{NULL},
18001de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt};
18011de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
18027ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtuint16_t
18031de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtxtables_parse_protocol(const char *s)
18041de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt{
180585f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	const struct protoent *pent;
180685f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	unsigned int proto, i;
18071de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
180885f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
180985f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return proto;
18101de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
181185f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	/* first deal with the special case of 'all' to prevent
181285f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * people from being able to redefine 'all' in nsswitch
181385f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * and/or provoke expensive [not working] ldap/nis/...
181485f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * lookups */
181585f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (strcmp(s, "all") == 0)
181685f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return 0;
18171de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
181885f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	pent = getprotobyname(s);
181985f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (pent != NULL)
182085f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return pent->p_proto;
1821e55cc4aaa6e35448c14370e5261c3387d26b257dPablo Neira Ayuso
182285f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
182385f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		if (xtables_chain_protos[i].name == NULL)
182485f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt			continue;
182585f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		if (strcmp(s, xtables_chain_protos[i].name) == 0)
182685f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt			return xtables_chain_protos[i].num;
18271de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	}
182885f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	xt_params->exit_err(PARAMETER_PROBLEM,
182985f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		"unknown protocol \"%s\" specified", s);
183085f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	return -1;
18311de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt}
1832