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>
210b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt#include <inttypes.h>
2204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI#include <netdb.h>
23aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt#include <stdarg.h>
24cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt#include <stdbool.h>
253dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdio.h>
263dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdlib.h>
270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <string.h>
280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <unistd.h>
290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#include <sys/socket.h>
300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/stat.h>
31b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski#include <sys/statfs.h>
320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/types.h>
330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/wait.h>
3408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#include <arpa/inet.h>
35b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski#include <linux/magic.h> /* for PROC_SUPER_MAGIC */
363dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
375208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI#include <xtables.h>
384e41854423b529d3107c23b85434d50a75d08057Jan Engelhardt#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
3977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
4077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
41ef18e8147903885708d1c264904129af4fb636d6Jan Engelhardt#include <libiptc/libxtc.h>
423dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
435a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
445a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
455a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
46c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
47c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
48c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
49c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
50c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
51c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_MATCH	68
52c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_TARGET	69
53c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
5470581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim#include <getopt.h>
55aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt#include "iptables/internal.h"
561e128bd804b676ee91beca48312de9b251845d09Jan Engelhardt#include "xshared.h"
575a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#define NPROTO	255
590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
600b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#ifndef PROC_SYS_MODPROBE
610b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
620b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#endif
630b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
6437911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski/* we need this for ip6?tables-restore.  ip6?tables-restore.c sets line to the
6537911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * current line of the input file, in order  to give a more precise error
6637911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * message.  ip6?tables itself doesn't need this, so it is initialized to the
6737911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * magic number of -1 */
6837911de507d0597980ad218a044a482501a21b01Maciej Zenczykowskiint line = -1;
6937911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski
708b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salimvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
718b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim
7240a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salimstruct xtables_globals *xt_params = NULL;
7340a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
748b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salimvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...)
7540a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim{
7640a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_list args;
7740a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
7840a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_start(args, msg);
7940a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
8040a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	vfprintf(stderr, msg, args);
8140a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_end(args);
8240a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	fprintf(stderr, "\n");
8340a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	exit(status);
8440a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim}
8540a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
86600f38db82548a683775fd89b6e136673e924097Jan Engelhardtvoid xtables_free_opts(int unused)
8784c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim{
88df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt	if (xt_params->opts != xt_params->orig_opts) {
8959e8114c6792242e80785f4461d5e663fb9a3d64Jan Engelhardt		free(xt_params->opts);
90df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt		xt_params->opts = NULL;
91df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt	}
9284c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim}
9384c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim
94600f38db82548a683775fd89b6e136673e924097Jan Engelhardtstruct option *xtables_merge_options(struct option *orig_opts,
95600f38db82548a683775fd89b6e136673e924097Jan Engelhardt				     struct option *oldopts,
9670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim				     const struct option *newopts,
9770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim				     unsigned int *option_offset)
9870581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim{
99600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
100600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	struct option *merge, *mp;
10170581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
10270581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	if (newopts == NULL)
10370581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim		return oldopts;
10470581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
105600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
106600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	if (oldopts != NULL)
107600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		for (num_old = 0; oldopts[num_old].name; num_old++) ;
10870581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	for (num_new = 0; newopts[num_new].name; num_new++) ;
10970581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
1101dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	/*
1111dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 * Since @oldopts also has @orig_opts already (and does so at the
1121dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 * start), skip these entries.
1131dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 */
1141dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	oldopts += num_oold;
1151dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	num_old -= num_oold;
1161dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt
117600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
118600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	if (merge == NULL)
119600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		return NULL;
120600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
121600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Let the base options -[ADI...] have precedence over everything */
122600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
123600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	mp = merge + num_oold;
124600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
125600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Second, the new options */
1261e128bd804b676ee91beca48312de9b251845d09Jan Engelhardt	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
12770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	*option_offset = xt_params->option_offset;
128600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(mp, newopts, sizeof(*mp) * num_new);
12970581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
130600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	for (i = 0; i < num_new; ++i, ++mp)
131600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		mp->val += *option_offset;
132600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
133600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Third, the old options */
134600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(mp, oldopts, sizeof(*mp) * num_old);
135600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	mp += num_old;
136600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	xtables_free_opts(0);
13770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
138600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Clear trailing entry */
139600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memset(mp, 0, sizeof(*mp));
14070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	return merge;
14170581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim}
14270581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
14377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv4 = {
14477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip_tables",
145b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	.proc_exists   = "/proc/net/ip_tables_names",
14677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libipt_",
14777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family	       = NFPROTO_IPV4,
14877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IP,
14977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
15077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
15177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
15277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
15377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv6 = {
15477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip6_tables",
155b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	.proc_exists   = "/proc/net/ip6_tables_names",
15677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libip6t_",
15777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family        = NFPROTO_IPV6,
15877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IPV6,
15977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
16077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
16177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
16277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
163aa37acc1423126f555135935c687eb91995b9440Jan Engelhardtconst struct xtables_afinfo *afinfo;
16477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
16539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt/* Search path for Xtables .so files */
16639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtstatic const char *xtables_libdir;
1670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1680b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
169c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtconst char *xtables_modprobe_program;
1700b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1712c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Keep track of matches/targets pending full registration: linked lists. */
1722c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistruct xtables_match *xtables_pending_matches;
1732c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistruct xtables_target *xtables_pending_targets;
1742c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
1752c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Keep track of fully registered external matches/targets: linked lists. */
1760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
1770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
1780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1792c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Fully register a match/target which was previously partially registered. */
1802c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_match(struct xtables_match *me);
1812c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_target(struct xtables_target *me);
1822c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
18339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtvoid xtables_init(void)
18439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt{
18539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("XTABLES_LIBDIR");
18639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL)
18739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
18839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("IPTABLES_LIB_DIR");
18939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL) {
19039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
19139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		        "use XTABLES_LIBDIR.\n");
19239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
19339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	}
194ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	/*
195ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
196ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
197ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * for these env vars are deprecated anyhow, and in light of the
198ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * (shared) libxt_*.so files, makes less sense to have
199ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
200ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 */
201ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
202ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	if (xtables_libdir != NULL) {
203ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
204ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		        "use XTABLES_LIBDIR.\n");
205ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		return;
206ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	}
20739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = XTABLES_LIBDIR;
20839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt}
20939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt
21077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtvoid xtables_set_nfproto(uint8_t nfproto)
21177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt{
21277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	switch (nfproto) {
21377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV4:
21477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv4;
21577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
21677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV6:
21777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv6;
21877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
21977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	default:
22077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
22177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		        __func__);
22277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	}
22377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt}
22477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
225630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt/**
2267e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * xtables_set_params - set the global parameters used by xtables
2277e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * @xtp:	input xtables_globals structure
2287e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim *
2297e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * The app is expected to pass a valid xtables_globals data-filled
2307e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * with proper values
2317e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * @xtp cannot be NULL
2327e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim *
2337e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * Returns -1 on failure to set and 0 on success
2347e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim */
2357e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salimint xtables_set_params(struct xtables_globals *xtp)
2367e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim{
2377e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (!xtp) {
2387e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		fprintf(stderr, "%s: Illegal global params\n",__func__);
2397e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		return -1;
2407e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	}
2417e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2427e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xt_params = xtp;
2437e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2447e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (!xt_params->exit_err)
2457e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		xt_params->exit_err = basic_exit_err;
2467e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2477e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	return 0;
2487e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim}
2497e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2507e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salimint xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
2517e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim{
2527e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xtables_init();
2537e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xtables_set_nfproto(nfproto);
2547e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	return xtables_set_params(xtp);
2557e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim}
2567e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2577e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim/**
258630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt * xtables_*alloc - wrappers that exit on failure
259630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt */
260630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_calloc(size_t count, size_t size)
2613dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
2623dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
2633dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2643dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
2653dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
2663dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
2673dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
2683dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2693dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
2703dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
2713dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
272630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_malloc(size_t size)
2733dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
2743dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
2753dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2763dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
2773dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
2783dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
2793dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
2803dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2813dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
2823dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
2830b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
284332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid *xtables_realloc(void *ptr, size_t size)
285332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
286332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	void *p;
287332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
288332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	if ((p = realloc(ptr, size)) == NULL) {
289332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		perror("ip[6]tables: realloc failed");
290332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		exit(1);
291332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
292332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
293332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	return p;
294332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
295332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
2960b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
2970b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
2980b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
2990b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
3000b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3010b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROCFILE_BUFSIZ	1024
3020b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
3030b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
3040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
305a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
306a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		fprintf(stderr, "Could not set close on exec: %s\n",
307a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski			strerror(errno));
308a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		exit(1);
309a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	}
3100b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
311371cea299f0b2eb100b9fc9fb99089640d2d606fJan Engelhardt	ret = malloc(PROCFILE_BUFSIZ);
3120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
3130b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		memset(ret, 0, PROCFILE_BUFSIZ);
3140b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
3150b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case -1: goto fail;
3160b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
3170b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
3180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (ret[strlen(ret)-1]=='\n')
3190b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			ret[strlen(ret)-1]=0;
3200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		close(procfile);
3210b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return ret;
3220b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3230b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI fail:
3240b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
3250b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
3260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
3270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
3280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
329c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
3300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
3310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
3320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
3330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
3340b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
3360b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
3370b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
3380b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
3390b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
3400b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
3410b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3420b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
343c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	/*
344c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 * Need to flush the buffer, or the child may output it again
345c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 * when switching the program thru execv.
346c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 */
347c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	fflush(stdout);
348c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt
34994aa2ea67d7b8a669e8541f094661a1dc89722a3Jan Engelhardt	switch (vfork()) {
3500b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
3510b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
3520b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
3530b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
3540b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
3550b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
3560b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
3570b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
3580b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
3590b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
3600b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
3610b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3620b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
3630b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
3640b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
3650b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
3660b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3670b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
3680b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
3690b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3700b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3710b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
3720b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
3730b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
3740b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
3750b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
3760b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
377b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski/* return true if a given file exists within procfs */
378b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowskistatic bool proc_file_exists(const char *filename)
379b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski{
380b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	struct stat s;
381b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	struct statfs f;
382b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
383b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (lstat(filename, &s))
384b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
385b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (!S_ISREG(s.st_mode))
386b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
387b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (statfs(filename, &f))
388b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
389b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (f.f_type != PROC_SUPER_MAGIC)
390b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
391b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	return true;
392b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski}
393b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
394c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_load_ko(const char *modprobe, bool quiet)
3950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
396c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	static bool loaded = false;
397b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	int ret;
3980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
399b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (loaded)
400b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return 0;
401b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
402b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (proc_file_exists(afinfo->proc_exists)) {
403b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		loaded = true;
404b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return 0;
405b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	};
406b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
407b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
408b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (ret == 0)
409b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		loaded = true;
4100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
4120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
4130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4145f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt/**
4155f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * xtables_strtou{i,l} - string to number conversion
4165f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @s:	input string
4175f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @end:	like strtoul's "end" pointer
4185f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @value:	pointer for result
4195f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @min:	minimum accepted value
4205f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @max:	maximum accepted value
4215f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt *
4225f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
4235f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * "15a" is rejected.
4245f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * In either case, the value obtained is compared for min-max compliance.
4255f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Base is always 0, i.e. autodetect depending on @s.
426cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
4275f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Returns true/false whether number was accepted. On failure, *value has
4285f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * undefined contents.
429cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
4300b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardtbool xtables_strtoul(const char *s, char **end, uintmax_t *value,
4310b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt                     uintmax_t min, uintmax_t max)
432cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
4330b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt	uintmax_t v;
434d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	const char *p;
435cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
436cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
437cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
438d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	/* Since strtoul allows leading minus, we have to check for ourself. */
439d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	for (p = s; isspace(*p); ++p)
440d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt		;
441d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	if (*p == '-')
442d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt		return false;
4430b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt	v = strtoumax(s, &my_end, 0);
444cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
445cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
446cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
447cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
448cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
449cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
450cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
451cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
452cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
453cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
454cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
455cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
456cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
457cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
458cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
459cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
4605f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoui(const char *s, char **end, unsigned int *value,
4615f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned int min, unsigned int max)
462cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
4630b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt	uintmax_t v;
464cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
465cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
4665f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	ret = xtables_strtoul(s, end, &v, min, max);
467cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
468cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
469cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
470cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
471cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
472aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtint xtables_service_to_port(const char *name, const char *proto)
47304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
47404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
47504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
47604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
47704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
47804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
47904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
48004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
48104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4827ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtuint16_t xtables_parse_port(const char *port, const char *proto)
48304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
4847a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
48504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4865f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
487aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
488213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
48904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4908b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM,
49104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
49204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
49304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
494aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtvoid xtables_parse_interface(const char *arg, char *vianame,
495aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt			     unsigned char *mask)
49604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
497fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt	unsigned int vialen = strlen(arg);
49804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
49904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
50004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
50104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
50204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
50304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
5048b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
50504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
50604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
50704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
50804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
509fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt	if (vialen == 0)
51004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0, IFNAMSIZ);
51104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
51204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
51304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
51404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
51504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
51604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
51704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
51804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
51904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
520fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt			if (vianame[i] == '/' ||
521fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt			    vianame[i] == ' ') {
522aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
523aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
524fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt					" `%s' ('/' and ' ' are not allowed by the kernel).\n",
525aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
52604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
52704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
52804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
52904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
53004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
53104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
532cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
533927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardtstatic void *load_extension(const char *search_path, const char *af_prefix,
53421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
53521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
536927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt	const char *all_prefixes[] = {"libxt_", af_prefix, NULL};
537927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt	const char **prefix;
53821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
53921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
54021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
54121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
54221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
54321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
54421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
54521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
54621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
54721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
548927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt		for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
549927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			snprintf(path, sizeof(path), "%.*s/%s%s.so",
550927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			         (unsigned int)(next - dir), dir,
551927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			         *prefix, name);
552927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt
553927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (stat(path, &sb) != 0) {
554927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				if (errno == ENOENT)
555927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt					continue;
556927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				fprintf(stderr, "%s: %s\n", path,
557927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt					strerror(errno));
558927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				return NULL;
559927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			}
560927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (dlopen(path, RTLD_NOW) == NULL) {
561927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				fprintf(stderr, "%s: %s\n", path, dlerror());
562927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				break;
563927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			}
56421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
56521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
5662338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
56721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
5682338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
5692338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
57021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
571927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (ptr != NULL)
572927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				return ptr;
57321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
574927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			fprintf(stderr, "%s: no \"%s\" extension found for "
575927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				"this protocol\n", path, name);
576927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			errno = ENOENT;
577927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			return NULL;
578927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt		}
57921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
58021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
58121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
58221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
58321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
584cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
58521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
5862338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_match *
5872338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_match(const char *name, enum xtables_tryload tryload,
5882338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		   struct xtables_rule_match **matches)
5890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5902c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_match **dptr;
5910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
5920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
5930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5940cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
59521d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
59621d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt			   "Invalid match name \"%s\" (%u chars max)",
5970cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt			   name, XT_EXTENSION_MAXNAMELEN - 1);
59821d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt
5990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
6010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
6020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
6030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
6040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
6050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6062c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* Trigger delayed initialization */
6072c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	for (dptr = &xtables_pending_matches; *dptr; ) {
6082c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		if (strcmp(name, (*dptr)->name) == 0) {
6092c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr = *dptr;
6102c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			*dptr = (*dptr)->next;
6112c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr->next = NULL;
6122c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			xtables_fully_register_pending_match(ptr);
6132c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		} else {
6142c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			dptr = &((*dptr)->next);
6152c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		}
6162c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	}
6172c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
6180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
6190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
6200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
6210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
6230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
6240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
6250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
627630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt			clone = xtables_malloc(sizeof(struct xtables_match));
6280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
6290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
6300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
6310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
6320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
6340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
6392338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
64077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
64139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, false);
642170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
6432338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
6448b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
6450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
646927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				   name, strerror(errno));
6470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
6490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
6502338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
6510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
6520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
6530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
6540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6552338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
6568b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
6570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
6580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
6600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
6620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
6630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
6640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
665630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
6660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
6680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
6692338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				(*i)->completed = true;
6700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
6722338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		newentry->completed = false;
6730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
6740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
6780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6802338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_target *
6812338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_target(const char *name, enum xtables_tryload tryload)
6820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6832c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_target **dptr;
6840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
6850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
6870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
6880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
6890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
6900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
6910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
6920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
6930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6942c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* Trigger delayed initialization */
6952c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	for (dptr = &xtables_pending_targets; *dptr; ) {
6962c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		if (strcmp(name, (*dptr)->name) == 0) {
6972c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr = *dptr;
6982c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			*dptr = (*dptr)->next;
6992c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr->next = NULL;
7002c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			xtables_fully_register_pending_target(ptr);
7012c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		} else {
7022c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			dptr = &((*dptr)->next);
7032c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		}
7042c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	}
7052c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
7060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
7070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
7080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
7090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
7122338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
71377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
71439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, true);
715170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
7162338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
7178b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
7180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
719927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				   name, strerror(errno));
7200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
7220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
7232338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
7240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
7250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
7260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
7270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
728854d2d9bd7556cfd8a676b0bc18dc059a9a2dd25Peter Volkov	if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
7298b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
7300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
7310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
7330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
7350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
7360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
7380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7407ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_revision(const char *name, uint8_t revision, int opt)
7410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
7420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
7430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
7440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
7450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
74677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
7470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
748df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
749df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
750df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
751e1639b0bc28420ca01d733749c8db16d5a3fbd0cJan Engelhardt				fprintf(stderr, "%s: Could not determine whether "
752df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
753df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
754e1639b0bc28420ca01d733749c8db16d5a3fbd0cJan Engelhardt					name, revision);
755df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
756df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
7570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
7580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
7590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
762a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
763a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		fprintf(stderr, "Could not set close on exec: %s\n",
764a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski			strerror(errno));
765a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		exit(1);
766a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	}
767a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski
768c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	xtables_load_ko(xtables_modprobe_program, true);
7690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
7710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
7720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
77377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
7740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
7750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
7760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
7770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
7780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
7790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
7800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
7810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
7820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
7830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
7840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
7850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
7860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
7870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
7880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
7900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
7910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7947ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_match_revision(const char *name, uint8_t revision)
7950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
79677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_match);
7970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7997ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_target_revision(const char *name, uint8_t revision)
8000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
80177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_target);
8020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
8030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
804dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardtstatic void xtables_check_options(const char *name, const struct option *opt)
805dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt{
806dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	for (; opt->name != NULL; ++opt)
807dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
808dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			fprintf(stderr, "%s: Extension %s uses invalid "
809dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			        "option value %d\n",xt_params->program_name,
810dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			        name, opt->val);
811dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			exit(1);
812dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		}
813dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt}
814dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
8150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
8160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
817c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	if (me->version == NULL) {
818c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		fprintf(stderr, "%s: match %s<%u> is missing a version\n",
819c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		        xt_params->program_name, me->name, me->revision);
820c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		exit(1);
821c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	}
822dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
823dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
824dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
8255dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name,
826dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
8270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8300cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
831281439ba6b96b729ef1400a49ec53eda298bb9f8Li Yewang		fprintf(stderr, "%s: match `%s' has invalid name\n",
8325dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
8330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
8370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
8380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
8395dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
8400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
843aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt	if (me->x6_options != NULL)
844aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt		xtables_option_metavalidate(me->name, me->x6_options);
845dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	if (me->extra_opts != NULL)
846dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		xtables_check_options(me->name, me->extra_opts);
847dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
8480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
84977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
8500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
8510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8522c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* place on linked list of matches pending full registration */
8532c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	me->next = xtables_pending_matches;
8542c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	xtables_pending_matches = me;
8552c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski}
8562c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
8572c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_match(struct xtables_match *me)
8582c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski{
8592c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_match **i, *old;
8602c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
8612338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
8620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
86323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
86423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
8650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
8660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
8675dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim				xt_params->program_name, me->name);
8680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
8690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
8700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
8720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_match_revision(old->name, old->revision)
8730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
8740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
8750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
87623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
8770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_match_revision(me->name, me->revision))
8780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
8790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
88023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
88123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
88223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
88323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
8840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
8850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
8860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
8870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
8900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
8915dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        xt_params->program_name, me->name,
8925dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        (unsigned int)me->size);
8930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
8970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
8980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
8990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
9000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
9020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
9030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
9040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9059a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardtvoid xtables_register_matches(struct xtables_match *match, unsigned int n)
9069a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt{
9079a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	do {
9089a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt		xtables_register_match(&match[--n]);
9099a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	} while (n > 0);
9109a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt}
9119a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt
9120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
9130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
914c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	if (me->version == NULL) {
915c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		fprintf(stderr, "%s: target %s<%u> is missing a version\n",
916c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		        xt_params->program_name, me->name, me->revision);
917c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		exit(1);
918c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	}
919dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
920dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
921dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
9225dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name,
923dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
9240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9270cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
9280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
9295dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
9300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
9340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
9350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
9365dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
9370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
940aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt	if (me->x6_options != NULL)
941aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt		xtables_option_metavalidate(me->name, me->x6_options);
942dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	if (me->extra_opts != NULL)
943dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		xtables_check_options(me->name, me->extra_opts);
944dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
9450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
94677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
9470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
9480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9492c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* place on linked list of targets pending full registration */
9502c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	me->next = xtables_pending_targets;
9512c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	xtables_pending_targets = me;
9522c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski}
9532c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
9542c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_target(struct xtables_target *me)
9552c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski{
9562c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_target *old;
9572c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
9582338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_target(me->name, XTF_DURING_LOAD);
9590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
9600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
9610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
96223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
96323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
9640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
9650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
9665dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim				xt_params->program_name, me->name);
9670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
9680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
9690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
9710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_target_revision(old->name, old->revision)
9720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
9730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
9740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
97523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
9760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_target_revision(me->name, me->revision))
9770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
9780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
97923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
98023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
98123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
98223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
9830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
9840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
9850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
9860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
9890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
9905dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        xt_params->program_name, me->name,
9915dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        (unsigned int)me->size);
9920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
9960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
9970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
9980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
9990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
10000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
1001aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
10029a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardtvoid xtables_register_targets(struct xtables_target *target, unsigned int n)
10039a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt{
10049a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	do {
10059a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt		xtables_register_target(&target[--n]);
10069a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	} while (n > 0);
10079a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt}
10089a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt
1009a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt/**
1010a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * xtables_param_act - act on condition
1011a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @status:	a constant from enum xtables_exittype
1012a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1013a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONLY_ONCE: print error message that option may only be used once.
1014a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name (e.g. "mark")
1015a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2(...):	option in conflict (e.g. "--mark")
1016a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3(...):	condition to match on (see extensions/ for examples)
1017a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1018a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_NO_INVERT: option does not support inversion
1019a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1020a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option in conflict
1021a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		condition to match on
1022a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1023a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_BAD_VALUE: bad value for option
1024a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1025a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option with which the problem occured (e.g. "--mark")
1026a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		string the user passed in (e.g. "99999999999999")
1027a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1028a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1029a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1030a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1031a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * Displays an error message and exits the program.
1032a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt */
1033a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid xtables_param_act(unsigned int status, const char *p1, ...)
1034aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
1035aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
1036aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
1037aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
1038aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1039aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
1040aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1041aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
1042a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONLY_ONCE:
1043aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1044aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
1045aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
1046aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
10478b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1048aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
1049aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
1050aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1051a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_NO_INVERT:
1052aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1053aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
1054aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
1055aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
10568b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1057aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
1058aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1059a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_BAD_VALUE:
1060aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1061aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
10628b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1063aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
1064aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
1065aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1066a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONE_ACTION:
1067aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
1068aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
1069aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
10708b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1071aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
1072aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1073aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
10748b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(status, p1, args);
1075aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1076aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
1077aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1078aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
1079aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
108008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1081e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
108208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
108308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
108408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
108508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
108608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
108708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
108808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
108908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
109108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
109208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
109308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
109508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
109608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
109708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
109908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
110008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
110208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
110308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
110408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
110608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
110708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
110908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
111008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1111e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
111208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
111308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
111408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
111508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
111608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
111708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
111808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1119e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ipaddr_to_numeric(addr);
112008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
112108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1122e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
112308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
112408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
112508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
112608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
112708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
112808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
112908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
113008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
113108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* we don't want to see "/32" */
113208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return "";
113308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
113408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
113508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
113608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
113708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
113808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
113908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%d", i);
114008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	else
114108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
1142e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
114308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
114408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
114508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
114608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1147bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1148bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1149bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
1150bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
1151bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
1152bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
1153bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
1154bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1155bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
1156bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
1157bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1158bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
1159bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1160bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
1161bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
1162bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
1163bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
1164bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
1165bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1166bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
11675f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1168bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
1169bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1170bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
1171bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
1172bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
1173bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1174bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
1175bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
1176bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1177bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
11785f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1179bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1180bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1181bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
1182bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
1183bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1184bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1185bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
11865f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1187bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1188bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1189bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
1190bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
1191bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1192bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
11931e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1194bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1195bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
1196bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1197bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
11981e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1199bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1200bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
1201bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1202bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1203bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
1204bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1205bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
1206bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
1207bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1208bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
1209bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
1210bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1211bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
1212bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
1213bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1214bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1215bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1216bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1217bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1218bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1219bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1220bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
1221bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
1222bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
1223bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1224bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1225bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
1226bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
1227bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
1228bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1229bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1230bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
1231bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
123211e250ba02349cb1e34058673db3d0b54eb56c44Wes Campaigne		addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1233bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
1234bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
1235bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
1236bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1237bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1238bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1239bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1240bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1241bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1242bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
1243bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
1244bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1245bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
1246bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
12471e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1248bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1249630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in_addr));
1250bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1251bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1252bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1253bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1254bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1255bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
1256bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
12578b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1258bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1259bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1260bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
1261bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1262bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
1263bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1264bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1265bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1266bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1267bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
1268bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
1269bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1270bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
12711e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1272bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
1273bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
12745f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
12758b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1276bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1277bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1278bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1279bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1280bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1281bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1282bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
1283bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1284bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1285bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1286332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1287332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow                              struct in_addr **maskpp, unsigned int *naddrs)
1288332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
1289332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	struct in_addr *addrp;
1290332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	char buf[256], *p;
1291332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	unsigned int len, i, j, n, count = 1;
1292332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	const char *loop = name;
1293332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1294332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	while ((loop = strchr(loop, ',')) != NULL) {
1295332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++count;
1296332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++loop; /* skip ',' */
1297332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1298332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1299332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1300332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1301332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1302332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	loop = name;
1303332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1304332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	for (i = 0; i < count; ++i) {
1305332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (loop == NULL)
1306332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1307332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (*loop == ',')
1308332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			++loop;
1309332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (*loop == '\0')
1310332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1311332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		p = strchr(loop, ',');
1312332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (p != NULL)
1313332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = p - loop;
1314332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		else
1315332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = strlen(loop);
1316332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (len == 0 || sizeof(buf) - 1 < len)
1317332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1318332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1319332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		strncpy(buf, loop, len);
1320332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		buf[len] = '\0';
1321332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		loop += len;
1322332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((p = strrchr(buf, '/')) != NULL) {
1323332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*p = '\0';
1324332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ipmask(p + 1);
1325332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1326332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ipmask(NULL);
1327332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1328332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		memcpy(*maskpp + i, addrp, sizeof(*addrp));
1329332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1330332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* if a null mask is given, the name is ignored, like in "any/0" */
1331332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((*maskpp + i)->s_addr == 0)
1332332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			/*
1333332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 * A bit pointless to process multiple addresses
1334332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 * in this case...
1335332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 */
1336332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			strcpy(buf, "0.0.0.0");
1337332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1338332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		addrp = ipparse_hostnetwork(buf, &n);
1339332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (n > 1) {
1340332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			count += n - 1;
1341332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*addrpp = xtables_realloc(*addrpp,
1342332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in_addr) * count);
1343332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*maskpp = xtables_realloc(*maskpp,
1344332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in_addr) * count);
1345332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 0; j < n; ++j)
1346332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new addr */
1347332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*addrpp + i + j, addrp + j,
1348332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1349332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 1; j < n; ++j)
1350332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new mask */
1351332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*maskpp + i + j, *maskpp + i,
1352332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1353332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			i += n - 1;
1354332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1355332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			memcpy(*addrpp + i, addrp, sizeof(*addrp));
1356332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1357332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* free what ipparse_hostnetwork had allocated: */
1358332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		free(addrp);
1359332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1360332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*naddrs = count;
13614b110b426df7bf486a3e7884c56ebb3487023601Jan Engelhardt	for (i = 0; i < count; ++i)
1362332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		(*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1363332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
1364332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1365332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1366a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt/**
1367a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * xtables_ipparse_any - transform arbitrary name to in_addr
1368a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt *
1369a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * Possible inputs (pseudo regex):
1370a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1371a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1372a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt */
1373a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1374a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                         struct in_addr *maskp, unsigned int *naddrs)
1375bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1376bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1377bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1378bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1379bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1380bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1381bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1382bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1383bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1384bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
1385bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1386bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
1387bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1388bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1389bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1390bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1391bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
1392bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
1393bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1394bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1395bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1396bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1397bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
1398bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1399bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1400adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				/*
1401adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * Nuke the dup by copying an address from the
1402adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * tail here, and check the current position
1403adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * again (--j).
1404adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 */
1405adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				memcpy(&addrp[--j], &addrp[--*naddrs],
1406adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				       sizeof(struct in_addr));
1407bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1408bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1409bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1410bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1411bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1412e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
141308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
1414cf3e52d00b7d3fedf98ef7710c337c441270d936Maciej Zenczykowski	/* 0000:0000:0000:0000:0000:0000:000.000.000.000
141508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
141608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
141708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
141808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
141908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
142008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
142108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
142208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
142308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
142408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
142508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
142608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
142708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
142808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
142908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
143008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
143108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
143208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
143308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
143408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
143508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
143608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
143708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
143808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
143908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
144008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
144108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
144208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
144308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
144408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1445e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
144608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
144708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
144808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
144908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
145008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
145108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1452e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ip6addr_to_numeric(addr);
145308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
145408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
145508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic int ip6addr_prefix_length(const struct in6_addr *k)
145608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
145708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
145808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
145908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
146048607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
146148607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
146248607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
146348607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
146408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
146508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
146608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
146708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
146808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
146908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
147008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
147108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
147208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
147308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
147408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
147508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
147608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
147708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
147808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1479e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
148008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
148108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
148208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int l = ip6addr_prefix_length(addrp);
148308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
148408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
148508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
1486e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		strcat(buf, xtables_ip6addr_to_numeric(addrp));
148708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
148808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
148908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "/%d", l);
149008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
149108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1492bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
14931e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1494bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1495bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1496bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1497bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1498bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1499bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1500bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1501bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1502bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1503bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1504bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1505bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1506bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1507bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1508bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
15092ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	struct in6_addr *addr;
1510bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
15112ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	struct addrinfo *res, *p;
1512bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
15132ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	unsigned int i;
1514bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1515bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1516bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1517bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1518bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1519bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1520bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1521bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1522bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1523bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1524bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1525bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1526bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
15272ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		/* Find length of address chain */
15282ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		for (p = res; p != NULL; p = p->ai_next)
15292ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			++*naddr;
1530bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1531bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
153230290aea009cf3fd76f27336fb4370be3467c4daPatrick McHardy		        xtables_ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1533bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
15342ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		/* Copy each element of the address chain */
15352ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
15362ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		for (i = 0, p = res; p != NULL; p = p->ai_next)
15372ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			memcpy(&addr[i++],
15382ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			       &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
15392ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			       sizeof(struct in6_addr));
1540bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1541bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1542bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1543bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1544bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1545bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1546bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1547bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1548bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1549bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1550bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1551bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1552bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1553bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1554bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1555bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1556bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1557bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1558bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1559bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
15601e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1561bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1562630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in6_addr));
1563bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1564bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1565bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1566bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1567bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1568bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1569bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
15708b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1571bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1572bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1573bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1574bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1575bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1576bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1577bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1578bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1579bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1580bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1581bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1582bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1583bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
15841e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1585bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
15865f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
15878b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1588bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1589bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1590bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1591bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1592bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1593bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1594bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1595bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1596bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1597bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1598bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1599bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1600bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1601332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid
1602332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowxtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
1603332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		      struct in6_addr **maskpp, unsigned int *naddrs)
1604332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
160558df90174164fd673e8c4103f7ce0c4e55ef1aecOlaf Rempel	static const struct in6_addr zero_addr;
1606332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	struct in6_addr *addrp;
1607332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	char buf[256], *p;
1608332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	unsigned int len, i, j, n, count = 1;
1609332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	const char *loop = name;
1610332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1611332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	while ((loop = strchr(loop, ',')) != NULL) {
1612332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++count;
1613332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++loop; /* skip ',' */
1614332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1615332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1616332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
1617332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
1618332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1619332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	loop = name;
1620332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1621332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	for (i = 0; i < count /*NB: count can grow*/; ++i) {
1622332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (loop == NULL)
1623332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1624332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (*loop == ',')
1625332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			++loop;
1626332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (*loop == '\0')
1627332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1628332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		p = strchr(loop, ',');
1629332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (p != NULL)
1630332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = p - loop;
1631332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		else
1632332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = strlen(loop);
1633332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (len == 0 || sizeof(buf) - 1 < len)
1634332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			break;
1635332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1636332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		strncpy(buf, loop, len);
1637332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		buf[len] = '\0';
1638332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		loop += len;
1639332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((p = strrchr(buf, '/')) != NULL) {
1640332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*p = '\0';
1641332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ip6mask(p + 1);
1642332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1643332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ip6mask(NULL);
1644332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1645332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		memcpy(*maskpp + i, addrp, sizeof(*addrp));
1646332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1647332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* if a null mask is given, the name is ignored, like in "any/0" */
164858df90174164fd673e8c4103f7ce0c4e55ef1aecOlaf Rempel		if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
1649332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			strcpy(buf, "::");
1650332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1651332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		addrp = ip6parse_hostnetwork(buf, &n);
1652332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (n > 1) {
1653332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			count += n - 1;
1654332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*addrpp = xtables_realloc(*addrpp,
1655332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in6_addr) * count);
1656332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*maskpp = xtables_realloc(*maskpp,
1657332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in6_addr) * count);
1658332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 0; j < n; ++j)
1659332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new addr */
1660332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*addrpp + i + j, addrp + j,
1661332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1662332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 1; j < n; ++j)
1663332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new mask */
1664332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*maskpp + i + j, *maskpp + i,
1665332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1666332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			i += n - 1;
1667332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1668332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			memcpy(*addrpp + i, addrp, sizeof(*addrp));
1669332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1670332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* free what ip6parse_hostnetwork had allocated: */
1671332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		free(addrp);
1672332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1673332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*naddrs = count;
16744b110b426df7bf486a3e7884c56ebb3487023601Jan Engelhardt	for (i = 0; i < count; ++i)
1675332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		for (j = 0; j < 4; ++j)
1676332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			(*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
1677332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
1678332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1679a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1680a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                          struct in6_addr *maskp, unsigned int *naddrs)
1681bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
16829c0fa7d8c84dc2478bd36d31b328b697fbe4d0afJan Engelhardt	static const struct in6_addr zero_addr;
1683bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1684bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1685bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1686bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1687bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1688bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1689bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1690bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1691bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1692bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1693bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1694bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1695bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1696bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1697bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
16989c0fa7d8c84dc2478bd36d31b328b697fbe4d0afJan Engelhardt	if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
1699bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1700bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1701bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1702bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1703bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1704bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
17055a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1706bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1707bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1708bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1709adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				/*
1710adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * Nuke the dup by copying an address from the
1711adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * tail here, and check the current position
1712adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * again (--j).
1713adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 */
1714adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				memcpy(&addrp[--j], &addrp[--*naddrs],
1715adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				       sizeof(struct in_addr));
1716bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1717bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1718bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1719bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1720a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1721a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_save_string(const char *value)
1722a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1723a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1724a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1725a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1726a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1727a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1728a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1729a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
173087dc7c4c842deb1e2e3d38089ffcad9f238d98deMax Kellerman	length = strspn(value, no_quote_chars);
1731a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1732a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1733a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
173473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(value, stdout);
1735a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1736a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1737a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1738a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1739a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
174073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" \"");
1741a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1742a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1743a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1744a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1745a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1746a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1747a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1748a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1749a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1750a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1751a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1752a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1753a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
175473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		putchar('\"');
1755a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1756a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
17570f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
17580f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt/**
17590f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Check for option-intrapositional negation.
17600f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Do not use in new code.
17610f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt */
17620f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardtint xtables_check_inverse(const char option[], int *invert,
1763bf97128c7262f17a02fec41cdae75b472ba77f88Jan Engelhardt			  int *my_optind, int argc, char **argv)
17640f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt{
17652be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	if (option == NULL || strcmp(option, "!") != 0)
17662be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt		return false;
17670f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
17682be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	fprintf(stderr, "Using intrapositioned negation "
17692be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	        "(`--option ! this`) is deprecated in favor of "
17702be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	        "extrapositioned (`! --option this`).\n");
17710f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
17722be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	if (*invert)
17732be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt		xt_params->exit_err(PARAMETER_PROBLEM,
17742be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt			   "Multiple `!' flags not allowed");
17752be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	*invert = true;
17762be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	if (my_optind != NULL) {
1777bf97128c7262f17a02fec41cdae75b472ba77f88Jan Engelhardt		optarg = argv[*my_optind];
17782be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt		++*my_optind;
17792be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt		if (argc && *my_optind > argc)
17802be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt			xt_params->exit_err(PARAMETER_PROBLEM,
17812be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt				   "no argument following `!'");
17820f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	}
17832be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt
17842be22fb36dd1268baecb42ddf35b7a40a6de21d7Jan Engelhardt	return true;
17850f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt}
17861de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
17871de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtconst struct xtables_pprot xtables_chain_protos[] = {
17881de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"tcp",       IPPROTO_TCP},
17891de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"sctp",      IPPROTO_SCTP},
17901de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udp",       IPPROTO_UDP},
17911de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udplite",   IPPROTO_UDPLITE},
17921de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmp",      IPPROTO_ICMP},
17931de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmpv6",    IPPROTO_ICMPV6},
17941de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-icmp", IPPROTO_ICMPV6},
17951de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"esp",       IPPROTO_ESP},
17961de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ah",        IPPROTO_AH},
17971de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-mh",   IPPROTO_MH},
17981de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"mh",        IPPROTO_MH},
17991de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"all",       0},
18001de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{NULL},
18011de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt};
18021de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
18037ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtuint16_t
18041de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtxtables_parse_protocol(const char *s)
18051de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt{
180685f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	const struct protoent *pent;
180785f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	unsigned int proto, i;
18081de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
180985f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
181085f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return proto;
18111de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
181285f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	/* first deal with the special case of 'all' to prevent
181385f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * people from being able to redefine 'all' in nsswitch
181485f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * and/or provoke expensive [not working] ldap/nis/...
181585f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * lookups */
181685f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (strcmp(s, "all") == 0)
181785f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return 0;
18181de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
181985f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	pent = getprotobyname(s);
182085f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (pent != NULL)
182185f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return pent->p_proto;
1822e55cc4aaa6e35448c14370e5261c3387d26b257dPablo Neira Ayuso
182385f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
182485f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		if (xtables_chain_protos[i].name == NULL)
182585f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt			continue;
182685f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		if (strcmp(s, xtables_chain_protos[i].name) == 0)
182785f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt			return xtables_chain_protos[i].num;
18281de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	}
182985f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	xt_params->exit_err(PARAMETER_PROBLEM,
183085f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		"unknown protocol \"%s\" specified", s);
183185f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	return -1;
18321de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt}
1833