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 */
183c871010888e1479ef8fca2048485b979ec2661aJan Engelhardt#include "config.h"
19d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt#include <ctype.h>
203dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <errno.h>
210b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <fcntl.h>
220b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt#include <inttypes.h>
2304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI#include <netdb.h>
24aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt#include <stdarg.h>
25cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt#include <stdbool.h>
263dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdio.h>
273dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdlib.h>
280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <string.h>
290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <unistd.h>
300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#include <sys/socket.h>
310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/stat.h>
32b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski#include <sys/statfs.h>
330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/types.h>
34f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt#include <sys/utsname.h>
350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/wait.h>
3608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#include <arpa/inet.h>
373c871010888e1479ef8fca2048485b979ec2661aJan Engelhardt#if defined(HAVE_LINUX_MAGIC_H)
383c871010888e1479ef8fca2048485b979ec2661aJan Engelhardt#	include <linux/magic.h> /* for PROC_SUPER_MAGIC */
393c871010888e1479ef8fca2048485b979ec2661aJan Engelhardt#elif defined(HAVE_LINUX_PROC_FS_H)
403c871010888e1479ef8fca2048485b979ec2661aJan Engelhardt#	include <linux/proc_fs.h>	/* Linux 2.4 */
4141a9b481693b4c43c16d0588cc558dd455168af0Jan Engelhardt#else
4241a9b481693b4c43c16d0588cc558dd455168af0Jan Engelhardt#	define PROC_SUPER_MAGIC	0x9fa0
433c871010888e1479ef8fca2048485b979ec2661aJan Engelhardt#endif
443dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
455208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI#include <xtables.h>
464e41854423b529d3107c23b85434d50a75d08057Jan Engelhardt#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
4777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
4877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
49ef18e8147903885708d1c264904129af4fb636d6Jan Engelhardt#include <libiptc/libxtc.h>
503dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
515a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
525a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
535a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
54c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
55c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
56c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
57c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
58c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
59c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_MATCH	68
60c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_TARGET	69
61c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
6270581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim#include <getopt.h>
63aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt#include "iptables/internal.h"
641e128bd804b676ee91beca48312de9b251845d09Jan Engelhardt#include "xshared.h"
655a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#define NPROTO	255
670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
680b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#ifndef PROC_SYS_MODPROBE
690b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
700b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#endif
710b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
7237911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski/* we need this for ip6?tables-restore.  ip6?tables-restore.c sets line to the
7337911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * current line of the input file, in order  to give a more precise error
7437911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * message.  ip6?tables itself doesn't need this, so it is initialized to the
7537911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski * magic number of -1 */
7637911de507d0597980ad218a044a482501a21b01Maciej Zenczykowskiint line = -1;
7737911de507d0597980ad218a044a482501a21b01Maciej Zenczykowski
788b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salimvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
798b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim
8040a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salimstruct xtables_globals *xt_params = NULL;
8140a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
828b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salimvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...)
8340a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim{
8440a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_list args;
8540a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
8640a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_start(args, msg);
8740a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
8840a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	vfprintf(stderr, msg, args);
8940a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_end(args);
9040a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	fprintf(stderr, "\n");
9140a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	exit(status);
9240a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim}
9340a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
94600f38db82548a683775fd89b6e136673e924097Jan Engelhardtvoid xtables_free_opts(int unused)
9584c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim{
96df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt	if (xt_params->opts != xt_params->orig_opts) {
9759e8114c6792242e80785f4461d5e663fb9a3d64Jan Engelhardt		free(xt_params->opts);
98df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt		xt_params->opts = NULL;
99df288236cd254798be3759fef4cbc3e535f5a1c3Jan Engelhardt	}
10084c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim}
10184c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim
102600f38db82548a683775fd89b6e136673e924097Jan Engelhardtstruct option *xtables_merge_options(struct option *orig_opts,
103600f38db82548a683775fd89b6e136673e924097Jan Engelhardt				     struct option *oldopts,
10470581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim				     const struct option *newopts,
10570581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim				     unsigned int *option_offset)
10670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim{
107600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
108600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	struct option *merge, *mp;
10970581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
11070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	if (newopts == NULL)
11170581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim		return oldopts;
11270581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
113600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
114600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	if (oldopts != NULL)
115600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		for (num_old = 0; oldopts[num_old].name; num_old++) ;
11670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	for (num_new = 0; newopts[num_new].name; num_new++) ;
11770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
1181dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	/*
1191dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 * Since @oldopts also has @orig_opts already (and does so at the
1201dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 * start), skip these entries.
1211dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	 */
1221dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	oldopts += num_oold;
1231dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt	num_old -= num_oold;
1241dc27393b7ba401e6228a5ee2472a6eb72836c43Jan Engelhardt
125600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
126600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	if (merge == NULL)
127600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		return NULL;
128600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
129600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Let the base options -[ADI...] have precedence over everything */
130600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
131600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	mp = merge + num_oold;
132600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
133600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Second, the new options */
1341e128bd804b676ee91beca48312de9b251845d09Jan Engelhardt	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
13570581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	*option_offset = xt_params->option_offset;
136600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(mp, newopts, sizeof(*mp) * num_new);
13770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
138600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	for (i = 0; i < num_new; ++i, ++mp)
139600f38db82548a683775fd89b6e136673e924097Jan Engelhardt		mp->val += *option_offset;
140600f38db82548a683775fd89b6e136673e924097Jan Engelhardt
141600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Third, the old options */
142600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memcpy(mp, oldopts, sizeof(*mp) * num_old);
143600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	mp += num_old;
144600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	xtables_free_opts(0);
14570581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
146600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	/* Clear trailing entry */
147600f38db82548a683775fd89b6e136673e924097Jan Engelhardt	memset(mp, 0, sizeof(*mp));
14870581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	return merge;
14970581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim}
15070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
15177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv4 = {
15277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip_tables",
153b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	.proc_exists   = "/proc/net/ip_tables_names",
15477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libipt_",
15577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family	       = NFPROTO_IPV4,
15677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IP,
15777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
15877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
15977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
16077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
16177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv6 = {
16277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip6_tables",
163b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	.proc_exists   = "/proc/net/ip6_tables_names",
16477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libip6t_",
16577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family        = NFPROTO_IPV6,
16677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IPV6,
16777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
16877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
16977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
17077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
171aa37acc1423126f555135935c687eb91995b9440Jan Engelhardtconst struct xtables_afinfo *afinfo;
17277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
17339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt/* Search path for Xtables .so files */
17439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtstatic const char *xtables_libdir;
1750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1760b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
177c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtconst char *xtables_modprobe_program;
1780b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1792c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Keep track of matches/targets pending full registration: linked lists. */
1802c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistruct xtables_match *xtables_pending_matches;
1812c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistruct xtables_target *xtables_pending_targets;
1822c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
1832c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Keep track of fully registered external matches/targets: linked lists. */
1840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
1850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
1860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1872c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski/* Fully register a match/target which was previously partially registered. */
1882c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_match(struct xtables_match *me);
1892c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_target(struct xtables_target *me);
1902c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
19139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtvoid xtables_init(void)
19239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt{
19339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("XTABLES_LIBDIR");
19439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL)
19539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
19639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("IPTABLES_LIB_DIR");
19739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL) {
19839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
19939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		        "use XTABLES_LIBDIR.\n");
20039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
20139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	}
202ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	/*
203ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
204ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
205ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * for these env vars are deprecated anyhow, and in light of the
206ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * (shared) libxt_*.so files, makes less sense to have
207ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
208ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 */
209ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
210ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	if (xtables_libdir != NULL) {
211ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
212ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		        "use XTABLES_LIBDIR.\n");
213ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		return;
214ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	}
21539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = XTABLES_LIBDIR;
21639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt}
21739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt
21877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtvoid xtables_set_nfproto(uint8_t nfproto)
21977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt{
22077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	switch (nfproto) {
22177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV4:
22277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv4;
22377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
22477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV6:
22577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv6;
22677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
22777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	default:
22877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
22977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		        __func__);
23077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	}
23177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt}
23277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
233630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt/**
2347e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * xtables_set_params - set the global parameters used by xtables
2357e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * @xtp:	input xtables_globals structure
2367e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim *
2377e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * The app is expected to pass a valid xtables_globals data-filled
2387e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * with proper values
2397e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * @xtp cannot be NULL
2407e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim *
2417e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * Returns -1 on failure to set and 0 on success
2427e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim */
2437e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salimint xtables_set_params(struct xtables_globals *xtp)
2447e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim{
2457e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (!xtp) {
2467e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		fprintf(stderr, "%s: Illegal global params\n",__func__);
2477e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		return -1;
2487e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	}
2497e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2507e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xt_params = xtp;
2517e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2527e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (!xt_params->exit_err)
2537e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		xt_params->exit_err = basic_exit_err;
2547e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2557e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	return 0;
2567e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim}
2577e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2587e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salimint xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
2597e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim{
2607e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xtables_init();
2617e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xtables_set_nfproto(nfproto);
2627e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	return xtables_set_params(xtp);
2637e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim}
2647e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2657e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim/**
266630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt * xtables_*alloc - wrappers that exit on failure
267630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt */
268630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_calloc(size_t count, size_t size)
2693dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
2703dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
2713dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2723dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
2733dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
2743dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
2753dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
2763dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2773dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
2783dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
2793dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
280630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_malloc(size_t size)
2813dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
2823dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
2833dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2843dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
2853dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
2863dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
2873dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
2883dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2893dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
2903dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
2910b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
292332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid *xtables_realloc(void *ptr, size_t size)
293332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
294332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	void *p;
295332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
296332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	if ((p = realloc(ptr, size)) == NULL) {
297332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		perror("ip[6]tables: realloc failed");
298332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		exit(1);
299332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
300332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
301332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	return p;
302332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
303332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
3040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
3050b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
3060b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
3070b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
30817fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester	int count;
3090b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3100b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
3110b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
3120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
313a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
314a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		fprintf(stderr, "Could not set close on exec: %s\n",
315a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski			strerror(errno));
316a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		exit(1);
317a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	}
3180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
31917fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester	ret = malloc(PATH_MAX);
3200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
32117fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester		count = read(procfile, ret, PATH_MAX);
32217fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester		if (count > 0 && count < PATH_MAX)
32317fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester		{
32417fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester			if (ret[count - 1] == '\n')
32517fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester				ret[count - 1] = '\0';
32617fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester			else
32717fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester				ret[count] = '\0';
32817fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester			close(procfile);
32917fd36631d3ca17b581be9acb8ab054931b5a917Phil Oester			return ret;
3300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
3310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
3330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
3340b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
3350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
3360b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
337c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
3380b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
3390b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
3400b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
3410b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
3420b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3430b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
3440b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
3450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
3460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
3470b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
3480b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
3490b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3500b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
351c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	/*
352c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 * Need to flush the buffer, or the child may output it again
353c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 * when switching the program thru execv.
354c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 */
355c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	fflush(stdout);
356c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt
35794aa2ea67d7b8a669e8541f094661a1dc89722a3Jan Engelhardt	switch (vfork()) {
3580b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
3590b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
3600b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
3610b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
3620b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
3630b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
3640b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
3650b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
3660b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
3670b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
3680b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
3690b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3700b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
3710b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
3720b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
373f53710b16c2bae1843c3f5fee390f496dfa82526Jiri Popelka		free(buf);
3740b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
3750b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3760b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
3770b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
3780b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3790b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3800b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
3810b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
3820b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
3830b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
3840b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
3850b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
386b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski/* return true if a given file exists within procfs */
387b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowskistatic bool proc_file_exists(const char *filename)
388b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski{
389b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	struct stat s;
390b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	struct statfs f;
391b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
392b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (lstat(filename, &s))
393b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
394b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (!S_ISREG(s.st_mode))
395b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
396b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (statfs(filename, &f))
397b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
398b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (f.f_type != PROC_SUPER_MAGIC)
399b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return false;
400b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	return true;
401b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski}
402b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
403c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_load_ko(const char *modprobe, bool quiet)
4040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
405c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	static bool loaded = false;
406b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	int ret;
4070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
408b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (loaded)
409b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return 0;
410b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
411b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (proc_file_exists(afinfo->proc_exists)) {
412b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		loaded = true;
413b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		return 0;
414b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	};
415b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski
416b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
417b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski	if (ret == 0)
418b32b361a725c8fe3a3aa494e6cdec09a80785aacMaciej Zenczykowski		loaded = true;
4190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
4210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
4220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4235f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt/**
4245f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * xtables_strtou{i,l} - string to number conversion
4255f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @s:	input string
4265f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @end:	like strtoul's "end" pointer
4275f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @value:	pointer for result
4285f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @min:	minimum accepted value
4295f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @max:	maximum accepted value
4305f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt *
4315f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
4325f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * "15a" is rejected.
4335f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * In either case, the value obtained is compared for min-max compliance.
4345f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Base is always 0, i.e. autodetect depending on @s.
435cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
4365f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Returns true/false whether number was accepted. On failure, *value has
4375f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * undefined contents.
438cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
4390b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardtbool xtables_strtoul(const char *s, char **end, uintmax_t *value,
4400b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt                     uintmax_t min, uintmax_t max)
441cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
4420b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt	uintmax_t v;
443d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	const char *p;
444cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
445cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
446cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
447d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	/* Since strtoul allows leading minus, we have to check for ourself. */
448d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	for (p = s; isspace(*p); ++p)
449d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt		;
450d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt	if (*p == '-')
451d61b02fbbbe7f6e643aad8649c8559c175c68c52Jan Engelhardt		return false;
4520b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt	v = strtoumax(s, &my_end, 0);
453cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
454cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
455cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
456cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
457cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
458cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
459cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
460cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
461cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
462cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
463cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
464cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
465cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
466cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
467cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
468cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
4695f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoui(const char *s, char **end, unsigned int *value,
4705f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned int min, unsigned int max)
471cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
4720b7a140944738d67b9c4e6f09992c8407eefb18aJan Engelhardt	uintmax_t v;
473cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
474cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
4755f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	ret = xtables_strtoul(s, end, &v, min, max);
476cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
477cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
478cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
479cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
480cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
481aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtint xtables_service_to_port(const char *name, const char *proto)
48204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
48304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
48404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
48504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
48604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
48704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
48804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
48904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
49004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4917ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtuint16_t xtables_parse_port(const char *port, const char *proto)
49204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
4937a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
49404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4955f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
496aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
497213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
49804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4998b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM,
50004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
50104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
50204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
503aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtvoid xtables_parse_interface(const char *arg, char *vianame,
504aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt			     unsigned char *mask)
50504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
506fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt	unsigned int vialen = strlen(arg);
50704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
50804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
50904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
51004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
51104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
51204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
5138b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
51404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
51504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
51604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
51704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
518fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt	if (vialen == 0)
5192ca6273c73b42e8c74afd5f8b1fe10c5c93ce363Richard Weinberger		return;
52004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
52104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
52204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
52304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
52404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
52504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
52604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
527fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt			if (vianame[i] == '/' ||
528fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt			    vianame[i] == ' ') {
529aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
530aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
531fcf5723f415c81fcb2c93094cdcc39b35a316ff2Jan Engelhardt					" `%s' ('/' and ' ' are not allowed by the kernel).\n",
532aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
53304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
53404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
53504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
53604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
53704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
53804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
539cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
540927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardtstatic void *load_extension(const char *search_path, const char *af_prefix,
54121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
54221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
543927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt	const char *all_prefixes[] = {"libxt_", af_prefix, NULL};
544927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt	const char **prefix;
54521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
54621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
54721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
54821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
54921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
55021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
55121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
55221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
55321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
55421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
555927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt		for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
556927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			snprintf(path, sizeof(path), "%.*s/%s%s.so",
557927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			         (unsigned int)(next - dir), dir,
558927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			         *prefix, name);
559927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt
560927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (stat(path, &sb) != 0) {
561927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				if (errno == ENOENT)
562927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt					continue;
563927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				fprintf(stderr, "%s: %s\n", path,
564927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt					strerror(errno));
565927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				return NULL;
566927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			}
567927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (dlopen(path, RTLD_NOW) == NULL) {
568927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				fprintf(stderr, "%s: %s\n", path, dlerror());
569927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				break;
570927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			}
57121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
57221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
5732338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
57421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
5752338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
5762338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
57721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
578927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			if (ptr != NULL)
579927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				return ptr;
58021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
581927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			fprintf(stderr, "%s: no \"%s\" extension found for "
582927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				"this protocol\n", path, name);
583927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			errno = ENOENT;
584927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt			return NULL;
585927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt		}
58621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
58721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
58821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
58921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
59021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
591cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
59221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
5932338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_match *
5942338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_match(const char *name, enum xtables_tryload tryload,
5952338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		   struct xtables_rule_match **matches)
5960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5972c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_match **dptr;
5980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
5990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6010cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
60221d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
60321d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt			   "Invalid match name \"%s\" (%u chars max)",
6040cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt			   name, XT_EXTENSION_MAXNAMELEN - 1);
60521d1283750d9c4df7ca80165d2b9dc0b9bd214ebJan Engelhardt
6060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
6070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
6080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
6090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
6100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
6110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
6120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6132c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* Trigger delayed initialization */
6142c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	for (dptr = &xtables_pending_matches; *dptr; ) {
6152c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		if (strcmp(name, (*dptr)->name) == 0) {
6162c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr = *dptr;
6172c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			*dptr = (*dptr)->next;
6182c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr->next = NULL;
6192c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			xtables_fully_register_pending_match(ptr);
6202c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		} else {
6212c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			dptr = &((*dptr)->next);
6222c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		}
6232c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	}
6242c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
6250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
6260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
6270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
6280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
6300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
6310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
6320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
634630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt			clone = xtables_malloc(sizeof(struct xtables_match));
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
6363eab786d6a687187556c92b3dc0f0664d8352471Jan Engelhardt			clone->udata = NULL;
6370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
6380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
6390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
6400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
6420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
6430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
6472338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
64877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
64939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, false);
650170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
6512338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
6528b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
6530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
654927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				   name, strerror(errno));
6550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
6570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
6582338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
6590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
6600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
6610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
6620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6632338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
6648b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
6650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
6660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
6680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
6700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
6710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
6720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
673630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
6740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
6772338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				(*i)->completed = true;
6780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
6802338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		newentry->completed = false;
6810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
6820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
6830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
6860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6882338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_target *
6892338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_target(const char *name, enum xtables_tryload tryload)
6900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6912c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_target **dptr;
6920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
6930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
6950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
6960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
6970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
6980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
6990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
7000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
7010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7022c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* Trigger delayed initialization */
7032c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	for (dptr = &xtables_pending_targets; *dptr; ) {
7042c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		if (strcmp(name, (*dptr)->name) == 0) {
7052c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr = *dptr;
7062c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			*dptr = (*dptr)->next;
7072c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			ptr->next = NULL;
7082c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			xtables_fully_register_pending_target(ptr);
7092c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		} else {
7102c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski			dptr = &((*dptr)->next);
7112c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski		}
7122c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	}
7132c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
7140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
7150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
7160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
7170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
7202338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
72177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
72239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, true);
723170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
7242338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
7258b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
7260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
727927385017047dce3f01c0aee73ab2989b108bbf0Jan Engelhardt				   name, strerror(errno));
7280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
7300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
7312338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
7320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
7330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
7340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
7350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
736854d2d9bd7556cfd8a676b0bc18dc059a9a2dd25Peter Volkov	if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
7378b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
7380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
7390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
7410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
7430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
7440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
7460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7487ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_revision(const char *name, uint8_t revision, int opt)
7490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
7500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
7510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
7520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
7530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
75477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
7550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
756df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
757df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
758df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
759e1639b0bc28420ca01d733749c8db16d5a3fbd0cJan Engelhardt				fprintf(stderr, "%s: Could not determine whether "
760df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
761df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
762e1639b0bc28420ca01d733749c8db16d5a3fbd0cJan Engelhardt					name, revision);
763df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
764df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
7650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
7660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
7670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
770a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
771a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		fprintf(stderr, "Could not set close on exec: %s\n",
772a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski			strerror(errno));
773a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski		exit(1);
774a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	}
775a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski
776c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	xtables_load_ko(xtables_modprobe_program, true);
7770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
7790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
7800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
78177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
7820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
7830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
7840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
7850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
7860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
7870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
7880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
7890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
7900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
7910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
7920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
7930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
7940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
7950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
7960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
7980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
7990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
8000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8027ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_match_revision(const char *name, uint8_t revision)
8030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
80477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_match);
8050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
8060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8077ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic int compatible_target_revision(const char *name, uint8_t revision)
8080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
80977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_target);
8100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
8110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
812dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardtstatic void xtables_check_options(const char *name, const struct option *opt)
813dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt{
814dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	for (; opt->name != NULL; ++opt)
815dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
816dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			fprintf(stderr, "%s: Extension %s uses invalid "
817dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			        "option value %d\n",xt_params->program_name,
818dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			        name, opt->val);
819dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt			exit(1);
820dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		}
821dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt}
822dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
8230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
8240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
825c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	if (me->version == NULL) {
826c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		fprintf(stderr, "%s: match %s<%u> is missing a version\n",
827c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		        xt_params->program_name, me->name, me->revision);
828c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		exit(1);
829c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	}
830dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
831dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
832dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
8335dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name,
834dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
8350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8380cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
839281439ba6b96b729ef1400a49ec53eda298bb9f8Li Yewang		fprintf(stderr, "%s: match `%s' has invalid name\n",
8405dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
8410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
8450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
8460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
8475dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
8480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
851aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt	if (me->x6_options != NULL)
852aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt		xtables_option_metavalidate(me->name, me->x6_options);
853dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	if (me->extra_opts != NULL)
854dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		xtables_check_options(me->name, me->extra_opts);
855dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
8560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
85777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
8580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
8590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8602c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* place on linked list of matches pending full registration */
8612c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	me->next = xtables_pending_matches;
8622c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	xtables_pending_matches = me;
8632c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski}
8642c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
865954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt/**
866954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt * Compare two actions for their preference
867954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt * @a:	one action
868954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt * @b: 	another
869954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt *
870954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt * Like strcmp, returns a negative number if @a is less preferred than @b,
871954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt * positive number if @a is more preferred than @b, or zero if equally
872954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt * preferred.
873954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt */
874954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardtstatic int
875cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardtxtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam,
876cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt		  bool b_alias, unsigned int b_rev, unsigned int b_fam)
877954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt{
878cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	/*
879cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	 * Alias ranks higher than no alias.
880cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	 * (We want the new action to be used whenever possible.)
881cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	 */
882cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	if (!a_alias && b_alias)
883cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt		return -1;
884cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	if (a_alias && !b_alias)
885cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt		return 1;
886cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt
887954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	/* Higher revision ranks higher. */
888954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	if (a_rev < b_rev)
889954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		return -1;
890954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	if (a_rev > b_rev)
891954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		return 1;
892954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt
893954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	/* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */
894954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC)
895954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		return -1;
896954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC)
897954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		return 1;
898954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt
899954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	/* Must be the same thing. */
900954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	return 0;
901954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt}
902954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt
903954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardtstatic int xtables_match_prefer(const struct xtables_match *a,
904954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt				const struct xtables_match *b)
905954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt{
906dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt	return xtables_mt_prefer(a->real_name != NULL,
907c436dad7cfdd80ca4a05ceed556c39babc266f55Jan Engelhardt				 a->revision, a->family,
908dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt				 b->real_name != NULL,
909c436dad7cfdd80ca4a05ceed556c39babc266f55Jan Engelhardt				 b->revision, b->family);
910954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt}
911954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt
912954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardtstatic int xtables_target_prefer(const struct xtables_target *a,
913954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt				 const struct xtables_target *b)
914954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt{
915cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	/*
916cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	 * Note that if x->real_name==NULL, it will be set to x->name in
917cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	 * xtables_register_*; the direct pointer comparison here is therefore
918cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	 * legitimate to detect an alias.
919cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt	 */
920dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt	return xtables_mt_prefer(a->real_name != NULL,
921cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adfJan Engelhardt				 a->revision, a->family,
922dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt				 b->real_name != NULL,
923954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt				 b->revision, b->family);
924954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt}
925954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt
9262c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_match(struct xtables_match *me)
9272c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski{
9282c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_match **i, *old;
929dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt	const char *rn;
930954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	int compare;
9312c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
9322338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
9330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
934954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		compare = xtables_match_prefer(old, me);
935954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		if (compare == 0) {
9360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
9370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
9385dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim				xt_params->program_name, me->name);
9390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
9400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
9410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
943dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt		rn = (old->real_name != NULL) ? old->real_name : old->name;
944954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		if (compare > 0 &&
945dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt		    compatible_match_revision(rn, old->revision))
9460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
9470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
94823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
949dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt		rn = (me->real_name != NULL) ? me->real_name : me->name;
950dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt		if (!compatible_match_revision(rn, me->revision))
9510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
9520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
9540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
9550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
9560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
9590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
9605dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        xt_params->program_name, me->name,
9615dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        (unsigned int)me->size);
9620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
9660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
9670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
9680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
9690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
9710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
9720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
9730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9749a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardtvoid xtables_register_matches(struct xtables_match *match, unsigned int n)
9759a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt{
9769a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	do {
9779a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt		xtables_register_match(&match[--n]);
9789a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	} while (n > 0);
9799a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt}
9809a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt
9810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
9820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
983c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	if (me->version == NULL) {
984c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		fprintf(stderr, "%s: target %s<%u> is missing a version\n",
985c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		        xt_params->program_name, me->name, me->revision);
986c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt		exit(1);
987c284de545d03aad9a04a4e17cfb55d911a96810cJan Engelhardt	}
988dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
989dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
990dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
9915dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name,
992dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
9930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
9940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
9950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
9960cb675b8f18c4b074d4c69461638820708e98100Jan Engelhardt	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
9970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
9985dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
9990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
10000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
10010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
10020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
10030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
10040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
10055dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim			xt_params->program_name, me->name);
10060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
10070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
10080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1009aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt	if (me->x6_options != NULL)
1010aa37acc1423126f555135935c687eb91995b9440Jan Engelhardt		xtables_option_metavalidate(me->name, me->x6_options);
1011dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt	if (me->extra_opts != NULL)
1012dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt		xtables_check_options(me->name, me->extra_opts);
1013dfbedfedf610210c4ee3f00e9c4f9ea24c4ffe23Jan Engelhardt
10140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
101577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
10160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
10170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
10182c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	/* place on linked list of targets pending full registration */
10192c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	me->next = xtables_pending_targets;
10202c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	xtables_pending_targets = me;
10212c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski}
10222c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
10232c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowskistatic void xtables_fully_register_pending_target(struct xtables_target *me)
10242c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski{
10252c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski	struct xtables_target *old;
1026dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt	const char *rn;
1027954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt	int compare;
10282c6ac071a9c660b61a76565d1024d372deac8a98Maciej Zenczykowski
10292338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_target(me->name, XTF_DURING_LOAD);
10300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
10310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
10320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1033954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		compare = xtables_target_prefer(old, me);
1034954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		if (compare == 0) {
10350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
10360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
10375dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim				xt_params->program_name, me->name);
10380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
10390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
10400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
10410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
1042dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt		rn = (old->real_name != NULL) ? old->real_name : old->name;
1043954b76c317f641b7faf33cc26931d45585cc0deaJan Engelhardt		if (compare > 0 &&
1044dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt		    compatible_target_revision(rn, old->revision))
10450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
10460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
104723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
1048dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt		rn = (me->real_name != NULL) ? me->real_name : me->name;
1049dd43527cb6bdf3d469100850ca10dcd2fb761304Jan Engelhardt		if (!compatible_target_revision(rn, me->revision))
10500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
10510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
10520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
10530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
10540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
10550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
10560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
10570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
10580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
10595dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        xt_params->program_name, me->name,
10605dd19de34380c91ad07bbe79a34726e59891cf54Jamal Hadi Salim		        (unsigned int)me->size);
10610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
10620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
10630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
10640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
10650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
10660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
10670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
10680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
10690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
1070aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
10719a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardtvoid xtables_register_targets(struct xtables_target *target, unsigned int n)
10729a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt{
10739a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	do {
10749a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt		xtables_register_target(&target[--n]);
10759a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt	} while (n > 0);
10769a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt}
10779a8fc4f89ef120d7beda3724994a1544346b947dJan Engelhardt
1078d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso/* receives a list of xtables_rule_match, release them */
1079d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayusovoid xtables_rule_matches_free(struct xtables_rule_match **matches)
1080d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso{
1081d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso	struct xtables_rule_match *matchp, *tmp;
1082d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso
1083d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso	for (matchp = *matches; matchp;) {
1084d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso		tmp = matchp->next;
1085d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso		if (matchp->match->m) {
1086d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso			free(matchp->match->m);
1087d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso			matchp->match->m = NULL;
1088d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso		}
1089d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso		if (matchp->match == matchp->match->next) {
1090d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso			free(matchp->match);
1091d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso			matchp->match = NULL;
1092d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso		}
1093d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso		free(matchp);
1094d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso		matchp = tmp;
1095d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso	}
1096d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso
1097d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso	*matches = NULL;
1098d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso}
1099d1e7922a587a239e16e0dbe654e63f76e1375e49Pablo Neira Ayuso
1100a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt/**
1101a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * xtables_param_act - act on condition
1102a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @status:	a constant from enum xtables_exittype
1103a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1104a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONLY_ONCE: print error message that option may only be used once.
1105a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name (e.g. "mark")
1106a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2(...):	option in conflict (e.g. "--mark")
1107a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3(...):	condition to match on (see extensions/ for examples)
1108a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1109a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_NO_INVERT: option does not support inversion
1110a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1111a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option in conflict
1112a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		condition to match on
1113a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1114a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_BAD_VALUE: bad value for option
1115a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1116a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option with which the problem occured (e.g. "--mark")
1117a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		string the user passed in (e.g. "99999999999999")
1118a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1119a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1120a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
1121a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
1122a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * Displays an error message and exits the program.
1123a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt */
1124a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid xtables_param_act(unsigned int status, const char *p1, ...)
1125aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
1126aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
1127aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
1128aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
1129aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1130aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
1131aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1132aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
1133a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONLY_ONCE:
1134aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1135aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
1136d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka		if (!b) {
1137d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka			va_end(args);
1138aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
1139d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka		}
11408b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1141aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
1142aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
1143aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1144a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_NO_INVERT:
1145aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1146aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
1147d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka		if (!b) {
1148d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka			va_end(args);
1149aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
1150d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka		}
11518b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1152aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
1153aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1154a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_BAD_VALUE:
1155aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
1156aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
11578b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1158aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
1159aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
1160aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1161a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONE_ACTION:
1162aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
1163d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka		if (!b) {
1164d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka			va_end(args);
1165aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
1166d0101690d9ae347d8a8ee9e340c5db72480046a3Jiri Popelka		}
11678b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1168aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
1169aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1170aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
11718b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(status, p1, args);
1172aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
1173aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
1174aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
1175aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
1176aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
117708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1178e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
117908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
118008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
118108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
118208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
118308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
118408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
118508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
118608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
118708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
118808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
118908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
119008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
119108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
119208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
119308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
119408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
119508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
119608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
119708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
119808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
119908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
120008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
120108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
120208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
120308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
120408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
120508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
120608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
120708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1208e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
120908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
121008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
121108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
121208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
121308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
121408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
121508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1216e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ipaddr_to_numeric(addr);
121708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
121808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1219a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayusoint xtables_ipmask_to_cidr(const struct in_addr *mask)
122008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
122108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
122208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
122308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
122408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
1225a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	/* shortcut for /32 networks */
122608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
1227a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso		return 32;
122808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
122908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
123008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
123108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
123208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
123308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
1234a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso		return i;
1235a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso
1236a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	/* this mask cannot be converted to CIDR notation */
1237a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	return -1;
1238a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso}
1239a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso
1240a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayusoconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
1241a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso{
1242a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	static char buf[20];
1243a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	uint32_t cidr;
1244a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso
1245a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	cidr = xtables_ipmask_to_cidr(mask);
1246a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	if (cidr < 0) {
124708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
1248e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
1249a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso		return buf;
1250a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	} else if (cidr == 32) {
1251a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso		/* we don't want to see "/32" */
1252a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso		return "";
1253a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	}
125408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1255a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	sprintf(buf, "/%d", cidr);
125608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
125708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
125808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1259bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1260bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1261bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
1262bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
1263bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
1264bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
1265bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
1266bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1267bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
1268bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
1269bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1270bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
1271bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1272bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
1273bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
1274bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
1275bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
1276bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
1277bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1278bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
12795f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1280bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
1281bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1282bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
1283bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
1284bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
1285bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1286bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
1287bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
1288bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1289bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
12905f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1291bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1292bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1293bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
1294bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
1295bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1296bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1297bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
12985f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1299bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1300bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1301bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
1302bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
1303bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1304bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
13051e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1306bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1307bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
1308bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1309bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
13101e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1311bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1312bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
1313bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1314bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1315bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
1316bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1317bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
1318bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
1319bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1320bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
1321bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
1322bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1323bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
1324bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
1325bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1326bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1327bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1328bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1329bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1330bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1331bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1332bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
1333bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
1334bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
1335bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1336bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1337bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
1338bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
1339bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
1340bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1341bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1342bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
1343bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
134411e250ba02349cb1e34058673db3d0b54eb56c44Wes Campaigne		addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1345bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
1346bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
1347bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
1348bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1349bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1350bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1351bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1352bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1353bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1354bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
1355bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
1356bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1357bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
1358bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
13591e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1360bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1361630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in_addr));
1362bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1363bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1364bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1365bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1366bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1367bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
1368bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
13698b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1370bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1371bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1372bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
1373bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1374bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
1375bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1376bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1377bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1378bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1379bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
1380bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
1381bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1382bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
13831e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1384bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
1385bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
13865f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
13878b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1388bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1389bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1390bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1391bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1392bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1393bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1394bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
1395bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1396bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1397bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1398332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1399332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow                              struct in_addr **maskpp, unsigned int *naddrs)
1400332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
1401332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	struct in_addr *addrp;
1402c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt	char buf[256], *p, *next;
1403332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	unsigned int len, i, j, n, count = 1;
1404332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	const char *loop = name;
1405332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1406332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	while ((loop = strchr(loop, ',')) != NULL) {
1407332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++count;
1408332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++loop; /* skip ',' */
1409332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1410332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1411332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1412332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1413332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1414332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	loop = name;
1415332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1416332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	for (i = 0; i < count; ++i) {
14170c384449ae9511157cd9b34d73f8f4cb71123a45Jan Engelhardt		while (isspace(*loop))
14180c384449ae9511157cd9b34d73f8f4cb71123a45Jan Engelhardt			++loop;
1419c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		next = strchr(loop, ',');
1420c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		if (next != NULL)
1421c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt			len = next - loop;
1422332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		else
1423332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = strlen(loop);
1424c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		if (len > sizeof(buf) - 1)
1425c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt			xt_params->exit_err(PARAMETER_PROBLEM,
1426c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt				"Hostname too long");
1427332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1428332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		strncpy(buf, loop, len);
1429332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		buf[len] = '\0';
1430332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((p = strrchr(buf, '/')) != NULL) {
1431332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*p = '\0';
1432332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ipmask(p + 1);
1433332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1434332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ipmask(NULL);
1435332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1436332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		memcpy(*maskpp + i, addrp, sizeof(*addrp));
1437332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1438332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* if a null mask is given, the name is ignored, like in "any/0" */
1439332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((*maskpp + i)->s_addr == 0)
1440332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			/*
1441332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 * A bit pointless to process multiple addresses
1442332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 * in this case...
1443332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			 */
1444332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			strcpy(buf, "0.0.0.0");
1445332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1446332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		addrp = ipparse_hostnetwork(buf, &n);
1447332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (n > 1) {
1448332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			count += n - 1;
1449332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*addrpp = xtables_realloc(*addrpp,
1450332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in_addr) * count);
1451332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*maskpp = xtables_realloc(*maskpp,
1452332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in_addr) * count);
1453332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 0; j < n; ++j)
1454332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new addr */
1455332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*addrpp + i + j, addrp + j,
1456332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1457332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 1; j < n; ++j)
1458332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new mask */
1459332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*maskpp + i + j, *maskpp + i,
1460332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1461332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			i += n - 1;
1462332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1463332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			memcpy(*addrpp + i, addrp, sizeof(*addrp));
1464332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1465332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* free what ipparse_hostnetwork had allocated: */
1466332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		free(addrp);
1467c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		if (next == NULL)
1468c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt			break;
1469c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		loop = next + 1;
1470332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1471332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*naddrs = count;
14724b110b426df7bf486a3e7884c56ebb3487023601Jan Engelhardt	for (i = 0; i < count; ++i)
1473332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		(*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1474332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
1475332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1476332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1477a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt/**
1478a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * xtables_ipparse_any - transform arbitrary name to in_addr
1479a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt *
1480a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * Possible inputs (pseudo regex):
1481a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1482a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1483a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt */
1484a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1485a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                         struct in_addr *maskp, unsigned int *naddrs)
1486bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1487bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1488bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1489bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1490bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1491bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1492bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1493bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1494bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1495bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
1496bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1497bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
1498bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1499bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1500bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1501bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1502bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
1503bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
1504bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1505bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1506bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1507bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1508bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
1509bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1510bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1511adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				/*
1512adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * Nuke the dup by copying an address from the
1513adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * tail here, and check the current position
1514adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * again (--j).
1515adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 */
1516adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				memcpy(&addrp[--j], &addrp[--*naddrs],
1517adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				       sizeof(struct in_addr));
1518bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1519bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1520bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1521bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1522bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1523e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
152408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
1525cf3e52d00b7d3fedf98ef7710c337c441270d936Maciej Zenczykowski	/* 0000:0000:0000:0000:0000:0000:000.000.000.000
152608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
152708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
152808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
152908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
153008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
153108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
153208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
153308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
153408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
153508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
153608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
153708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
153808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
153908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
154008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
154108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
154208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
154308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
154408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
154508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
154608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
154708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
154808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
154908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
155008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
155108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
155208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
155308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
155408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
155508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1556e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
155708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
155808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
155908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
156008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
156108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
156208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1563e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ip6addr_to_numeric(addr);
156408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
156508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1566a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayusoint xtables_ip6mask_to_cidr(const struct in6_addr *k)
156708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
156808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
156908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
157008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
157148607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
157248607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
157348607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
157448607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
157508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
157608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
157708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
157808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
157908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
158008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
158108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
158208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
158308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
158408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
158508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
158608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
158708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
158808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
158908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1590e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
159108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
159208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
1593a96166c24eaac1c91bed4815c09e91733409d888Pablo Neira Ayuso	int l = xtables_ip6mask_to_cidr(addrp);
159408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
159508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
159608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
1597e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		strcat(buf, xtables_ip6addr_to_numeric(addrp));
159808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
159908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
1600945353a25bbb2dbf88128c27a9169851da6ebf05Phil Oester	/* we don't want to see "/128" */
1601945353a25bbb2dbf88128c27a9169851da6ebf05Phil Oester	if (l == 128)
1602945353a25bbb2dbf88128c27a9169851da6ebf05Phil Oester		return "";
1603945353a25bbb2dbf88128c27a9169851da6ebf05Phil Oester	else
1604945353a25bbb2dbf88128c27a9169851da6ebf05Phil Oester		sprintf(buf, "/%d", l);
160508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
160608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1607bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
16081e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1609bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1610bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1611bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1612bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1613bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1614bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1615bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1616bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1617bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1618bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1619bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1620bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1621bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1622bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1623bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
16242ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	struct in6_addr *addr;
1625bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
16262ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	struct addrinfo *res, *p;
1627bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
16282ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne	unsigned int i;
1629bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1630bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1631bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1632bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1633bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1634bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1635bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1636bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1637bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1638bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1639bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1640bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1641bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
16422ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		/* Find length of address chain */
16432ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		for (p = res; p != NULL; p = p->ai_next)
16442ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			++*naddr;
1645bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1646bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
164730290aea009cf3fd76f27336fb4370be3467c4daPatrick McHardy		        xtables_ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1648bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
16492ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		/* Copy each element of the address chain */
16502ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
16512ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne		for (i = 0, p = res; p != NULL; p = p->ai_next)
16522ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			memcpy(&addr[i++],
16532ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			       &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
16542ad8dc895ec28a173c629c695c2e11c41b625b6eWes Campaigne			       sizeof(struct in6_addr));
1655bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1656bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1657bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1658bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1659bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1660bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1661bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1662bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1663bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1664bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1665bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1666bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1667bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1668bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1669bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1670bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1671bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1672bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1673bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1674bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
16751e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1676bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1677630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in6_addr));
1678bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1679bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1680bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1681bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1682bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1683bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1684bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
16858b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1686bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1687bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1688bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1689bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1690bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1691bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1692bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1693bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1694bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1695bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1696bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1697bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1698bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
16991e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1700bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
17015f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
17028b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1703bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1704bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1705bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1706bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1707bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1708bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1709bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1710bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1711bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1712bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1713bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1714bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1715bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1716332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowvoid
1717332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzowxtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
1718332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		      struct in6_addr **maskpp, unsigned int *naddrs)
1719332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow{
172058df90174164fd673e8c4103f7ce0c4e55ef1aecOlaf Rempel	static const struct in6_addr zero_addr;
1721332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	struct in6_addr *addrp;
1722c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt	char buf[256], *p, *next;
1723332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	unsigned int len, i, j, n, count = 1;
1724332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	const char *loop = name;
1725332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1726332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	while ((loop = strchr(loop, ',')) != NULL) {
1727332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++count;
1728332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		++loop; /* skip ',' */
1729332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1730332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1731332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
1732332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
1733332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1734332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	loop = name;
1735332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1736332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	for (i = 0; i < count /*NB: count can grow*/; ++i) {
17370c384449ae9511157cd9b34d73f8f4cb71123a45Jan Engelhardt		while (isspace(*loop))
17380c384449ae9511157cd9b34d73f8f4cb71123a45Jan Engelhardt			++loop;
1739c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		next = strchr(loop, ',');
1740c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		if (next != NULL)
1741c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt			len = next - loop;
1742332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		else
1743332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			len = strlen(loop);
1744c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		if (len > sizeof(buf) - 1)
1745c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt			xt_params->exit_err(PARAMETER_PROBLEM,
1746c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt				"Hostname too long");
1747332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1748332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		strncpy(buf, loop, len);
1749332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		buf[len] = '\0';
1750332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if ((p = strrchr(buf, '/')) != NULL) {
1751332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*p = '\0';
1752332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ip6mask(p + 1);
1753332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1754332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			addrp = parse_ip6mask(NULL);
1755332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1756332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		memcpy(*maskpp + i, addrp, sizeof(*addrp));
1757332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1758332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* if a null mask is given, the name is ignored, like in "any/0" */
175958df90174164fd673e8c4103f7ce0c4e55ef1aecOlaf Rempel		if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
1760332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			strcpy(buf, "::");
1761332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1762332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		addrp = ip6parse_hostnetwork(buf, &n);
1763332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		if (n > 1) {
1764332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			count += n - 1;
1765332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*addrpp = xtables_realloc(*addrpp,
1766332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in6_addr) * count);
1767332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			*maskpp = xtables_realloc(*maskpp,
1768332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			          sizeof(struct in6_addr) * count);
1769332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 0; j < n; ++j)
1770332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new addr */
1771332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*addrpp + i + j, addrp + j,
1772332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1773332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			for (j = 1; j < n; ++j)
1774332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				/* for each new mask */
1775332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				memcpy(*maskpp + i + j, *maskpp + i,
1776332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow				       sizeof(*addrp));
1777332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			i += n - 1;
1778332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		} else {
1779332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			memcpy(*addrpp + i, addrp, sizeof(*addrp));
1780332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		}
1781332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		/* free what ip6parse_hostnetwork had allocated: */
1782332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		free(addrp);
1783c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		if (next == NULL)
1784c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt			break;
1785c0e69db337540b22a3b3f739b1143341e7b759b7Jan Engelhardt		loop = next + 1;
1786332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	}
1787332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow	*naddrs = count;
17884b110b426df7bf486a3e7884c56ebb3487023601Jan Engelhardt	for (i = 0; i < count; ++i)
1789332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow		for (j = 0; j < 4; ++j)
1790332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow			(*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
1791332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow}
1792332e4acc574e3a348fe611d55bf642de0d50fbdaMichael Granzow
1793a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1794a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                          struct in6_addr *maskp, unsigned int *naddrs)
1795bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
17969c0fa7d8c84dc2478bd36d31b328b697fbe4d0afJan Engelhardt	static const struct in6_addr zero_addr;
1797bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1798bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1799bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1800bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1801bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1802bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1803bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1804bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1805bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1806bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1807bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1808bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1809bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1810bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1811bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
18129c0fa7d8c84dc2478bd36d31b328b697fbe4d0afJan Engelhardt	if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
1813bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1814bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1815bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1816bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1817bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1818bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
18195a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1820bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1821bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1822bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1823adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				/*
1824adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * Nuke the dup by copying an address from the
1825adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * tail here, and check the current position
1826adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 * again (--j).
1827adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				 */
1828adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				memcpy(&addrp[--j], &addrp[--*naddrs],
1829adcb28101d53c2a7f372de256b1af50804fee899Wes Campaigne				       sizeof(struct in_addr));
1830bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1831bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1832bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1833bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1834a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1835a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_save_string(const char *value)
1836a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1837a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1838a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1839a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1840a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1841a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1842a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1843a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
184487dc7c4c842deb1e2e3d38089ffcad9f238d98deMax Kellerman	length = strspn(value, no_quote_chars);
1845a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1846a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1847a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
184873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(value, stdout);
1849a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1850a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1851a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1852a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1853a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
185473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" \"");
1855a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1856a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1857a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1858a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1859a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1860a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1861a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1862a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1863a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1864a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1865a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1866a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1867a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
186873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		putchar('\"');
1869a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1870a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
18710f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
18721de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtconst struct xtables_pprot xtables_chain_protos[] = {
18731de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"tcp",       IPPROTO_TCP},
18741de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"sctp",      IPPROTO_SCTP},
18751de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udp",       IPPROTO_UDP},
18761de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udplite",   IPPROTO_UDPLITE},
18771de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmp",      IPPROTO_ICMP},
18781de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmpv6",    IPPROTO_ICMPV6},
18791de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-icmp", IPPROTO_ICMPV6},
18801de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"esp",       IPPROTO_ESP},
18811de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ah",        IPPROTO_AH},
18821de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-mh",   IPPROTO_MH},
18831de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"mh",        IPPROTO_MH},
18841de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"all",       0},
18851de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{NULL},
18861de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt};
18871de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
18887ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtuint16_t
18891de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtxtables_parse_protocol(const char *s)
18901de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt{
189185f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	const struct protoent *pent;
189285f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	unsigned int proto, i;
18931de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
189485f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
189585f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return proto;
18961de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
189785f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	/* first deal with the special case of 'all' to prevent
189885f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * people from being able to redefine 'all' in nsswitch
189985f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * and/or provoke expensive [not working] ldap/nis/...
190085f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	 * lookups */
190185f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (strcmp(s, "all") == 0)
190285f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return 0;
19031de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
190485f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	pent = getprotobyname(s);
190585f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	if (pent != NULL)
190685f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		return pent->p_proto;
1907e55cc4aaa6e35448c14370e5261c3387d26b257dPablo Neira Ayuso
190885f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
190985f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		if (xtables_chain_protos[i].name == NULL)
191085f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt			continue;
191185f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		if (strcmp(s, xtables_chain_protos[i].name) == 0)
191285f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt			return xtables_chain_protos[i].num;
19131de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	}
191485f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	xt_params->exit_err(PARAMETER_PROBLEM,
191585f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt		"unknown protocol \"%s\" specified", s);
191685f423addb46736e414f70b59c9f885e99aeb488Jan Engelhardt	return -1;
19171de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt}
1918f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt
19192f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayusovoid xtables_print_num(uint64_t number, unsigned int format)
19202f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso{
19212f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	if (!(format & FMT_KILOMEGAGIGA)) {
19222f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		printf(FMT("%8llu ","%llu "), (unsigned long long)number);
19232f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		return;
19242f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	}
19252f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	if (number <= 99999) {
19262f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		printf(FMT("%5llu ","%llu "), (unsigned long long)number);
19272f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		return;
19282f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	}
19292f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	number = (number + 500) / 1000;
19302f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	if (number <= 9999) {
19312f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
19322f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		return;
19332f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	}
19342f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	number = (number + 500) / 1000;
19352f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	if (number <= 9999) {
19362f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
19372f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		return;
19382f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	}
19392f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	number = (number + 500) / 1000;
19402f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	if (number <= 9999) {
19412f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
19422f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso		return;
19432f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	}
19442f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	number = (number + 500) / 1000;
19452f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso	printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
19462f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso}
19472f655ede64e07a861e3ec50150f572ed98755013Pablo Neira Ayuso
1948f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardtint kernel_version;
1949f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt
1950f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardtvoid get_kernel_version(void)
1951f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt{
1952f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt	static struct utsname uts;
1953f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt	int x = 0, y = 0, z = 0;
1954f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt
1955f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt	if (uname(&uts) == -1) {
1956f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt		fprintf(stderr, "Unable to retrieve kernel version.\n");
1957f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt		xtables_free_opts(1);
1958f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt		exit(1);
1959f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt	}
1960f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt
1961f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt	sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
1962f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt	kernel_version = LINUX_VERSION(x, y, z);
1963f56b8a8bf4b1041cb875fd8439778f35276bdb30Jan Engelhardt}
1964