xtables.c revision 7e4db2f50133007f549f222468bde4f3adcf41ac
15208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI/*
25208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
35208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
45208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	This program is free software; you can redistribute it and/or modify
55208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	it under the terms of the GNU General Public License as published by
65208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	the Free Software Foundation; either version 2 of the License, or
75208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	(at your option) any later version.
85208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
95208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	This program is distributed in the hope that it will be useful,
105208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	but WITHOUT ANY WARRANTY; without even the implied warranty of
115208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
125208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	GNU General Public License for more details.
135208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
145208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	You should have received a copy of the GNU General Public License
155208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	along with this program; if not, write to the Free Software
165208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
175208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI */
185208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI
193dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <errno.h>
200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <fcntl.h>
2104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI#include <netdb.h>
22aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt#include <stdarg.h>
23cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt#include <stdbool.h>
243dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdio.h>
253dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdlib.h>
260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <string.h>
270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <unistd.h>
280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#include <sys/socket.h>
290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/stat.h>
300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/types.h>
310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/wait.h>
3208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#include <arpa/inet.h>
333dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
345208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI#include <xtables.h>
3577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
3677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
37ef18e8147903885708d1c264904129af4fb636d6Jan Engelhardt#include <libiptc/libxtc.h>
383dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
395a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
405a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
415a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
42c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
43c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
44c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
45c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
46c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
47c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_MATCH	68
48c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#	define IP6T_SO_GET_REVISION_TARGET	69
49c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt#endif
5070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim#include <getopt.h>
51c31870f9bebb3d4d082016fcfaf8c2177ae32eb2Jan Engelhardt
525a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#define NPROTO	255
540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
550b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#ifndef PROC_SYS_MODPROBE
560b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
570b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#endif
580b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
598b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salimvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
608b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim
6140a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salimstruct xtables_globals *xt_params = NULL;
6240a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
638b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salimvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...)
6440a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim{
6540a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_list args;
6640a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
6740a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_start(args, msg);
6840a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
6940a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	vfprintf(stderr, msg, args);
7040a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	va_end(args);
7140a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	fprintf(stderr, "\n");
7240a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim	exit(status);
7340a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim}
7440a8343d3ad0cdbc3a7e69c8d970ad75807c29edJamal Hadi Salim
758b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim
76139b3fe4bd5121501e60fe07963ea527d7f0bd36Jamal Hadi Salimvoid xtables_free_opts(int reset_offset)
7784c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim{
78139b3fe4bd5121501e60fe07963ea527d7f0bd36Jamal Hadi Salim	if (xt_params->opts != xt_params->orig_opts) {
79139b3fe4bd5121501e60fe07963ea527d7f0bd36Jamal Hadi Salim		free(xt_params->opts);
80139b3fe4bd5121501e60fe07963ea527d7f0bd36Jamal Hadi Salim		xt_params->opts = xt_params->orig_opts;
8184c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim		if (reset_offset)
8284c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim			xt_params->option_offset = 0;
8384c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim	}
8484c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim}
8584c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim
8670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salimstruct option *xtables_merge_options(struct option *oldopts,
8770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim				     const struct option *newopts,
8870581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim				     unsigned int *option_offset)
8970581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim{
9070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	unsigned int num_old, num_new, i;
9170581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	struct option *merge;
9270581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
9370581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	if (newopts == NULL)
9470581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim		return oldopts;
9570581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
9670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	for (num_old = 0; oldopts[num_old].name; num_old++) ;
9770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	for (num_new = 0; newopts[num_new].name; num_new++) ;
9870581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
9970581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	xt_params->option_offset += OPTION_OFFSET;
10070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	*option_offset = xt_params->option_offset;
10170581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
10270581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
10370581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	if (merge == NULL)
10470581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim		return NULL;
10570581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	memcpy(merge, oldopts, num_old * sizeof(struct option));
10670581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	xtables_free_opts(0);	/* Release any old options merged  */
10770581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	for (i = 0; i < num_new; i++) {
10870581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim		merge[num_old + i] = newopts[i];
10970581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim		merge[num_old + i].val += *option_offset;
11070581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	}
11170581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	memset(merge + num_old + num_new, 0, sizeof(struct option));
11270581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
11370581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim	return merge;
11470581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim}
11570581922f873a88306dd5b1cb83c5081ee239eb8Jamal Hadi Salim
116853322131026d62df3f8d77d67e5c63be496303cJamal Hadi Salimvoid xtables_set_revision(char *name, u_int8_t revision)
117853322131026d62df3f8d77d67e5c63be496303cJamal Hadi Salim{
118853322131026d62df3f8d77d67e5c63be496303cJamal Hadi Salim	/* Old kernel sources don't have ".revision" field,
119853322131026d62df3f8d77d67e5c63be496303cJamal Hadi Salim	*            but we stole a byte from name. */
120853322131026d62df3f8d77d67e5c63be496303cJamal Hadi Salim	name[XT_FUNCTION_MAXNAMELEN - 2] = '\0';
121853322131026d62df3f8d77d67e5c63be496303cJamal Hadi Salim	name[XT_FUNCTION_MAXNAMELEN - 1] = revision;
122853322131026d62df3f8d77d67e5c63be496303cJamal Hadi Salim}
123853322131026d62df3f8d77d67e5c63be496303cJamal Hadi Salim
124dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt/**
12577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * xtables_afinfo - protocol family dependent information
12677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @kmod:		kernel module basename (e.g. "ip_tables")
12777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @libprefix:		prefix of .so library name (e.g. "libipt_")
12877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @family:		nfproto family
12977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @ipproto:		used by setsockopt (e.g. IPPROTO_IP)
13077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @so_rev_match:	optname to check revision support of match
13177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @so_rev_target:	optname to check revision support of target
13277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt */
13377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstruct xtables_afinfo {
13477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	const char *kmod;
13577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	const char *libprefix;
13677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	uint8_t family;
13777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	uint8_t ipproto;
13877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	int so_rev_match;
13977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	int so_rev_target;
14077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
14177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
14277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv4 = {
14377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip_tables",
14477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libipt_",
14577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family	       = NFPROTO_IPV4,
14677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IP,
14777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
14877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
14977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
15077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
15177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv6 = {
15277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip6_tables",
15377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libip6t_",
15477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family        = NFPROTO_IPV6,
15577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IPV6,
15677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
15777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
15877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
15977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
16077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo *afinfo;
16177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
16277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt/**
163dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt * Program will set this to its own name.
164dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt */
165dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardtconst char *xtables_program_name;
166dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt
16739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt/* Search path for Xtables .so files */
16839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtstatic const char *xtables_libdir;
1690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1700b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
171c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtconst char *xtables_modprobe_program;
1720b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI/* Keeping track of external matches and targets: linked lists.  */
1740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
1750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
1760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
17739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtvoid xtables_init(void)
17839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt{
17939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("XTABLES_LIBDIR");
18039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL)
18139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
18239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("IPTABLES_LIB_DIR");
18339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL) {
18439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
18539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		        "use XTABLES_LIBDIR.\n");
18639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
18739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	}
188ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	/*
189ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
190ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
191ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * for these env vars are deprecated anyhow, and in light of the
192ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * (shared) libxt_*.so files, makes less sense to have
193ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
194ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	 */
195ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
196ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	if (xtables_libdir != NULL) {
197ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
198ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		        "use XTABLES_LIBDIR.\n");
199ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt		return;
200ec934198bd6ee2f21171dba440ca96334b0d874bJan Engelhardt	}
20139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = XTABLES_LIBDIR;
20239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt}
20339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt
20477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtvoid xtables_set_nfproto(uint8_t nfproto)
20577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt{
20677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	switch (nfproto) {
20777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV4:
20877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv4;
20977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
21077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV6:
21177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv6;
21277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
21377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	default:
21477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
21577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		        __func__);
21677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	}
21777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt}
21877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
219630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt/**
2207e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * xtables_set_params - set the global parameters used by xtables
2217e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * @xtp:	input xtables_globals structure
2227e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim *
2237e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * The app is expected to pass a valid xtables_globals data-filled
2247e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * with proper values
2257e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * @xtp cannot be NULL
2267e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim *
2277e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim * Returns -1 on failure to set and 0 on success
2287e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim */
2297e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salimint xtables_set_params(struct xtables_globals *xtp)
2307e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim{
2317e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (!xtp) {
2327e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		fprintf(stderr, "%s: Illegal global params\n",__func__);
2337e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		return -1;
2347e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	}
2357e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2367e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xt_params = xtp;
2377e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2387e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (!xt_params->exit_err)
2397e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		xt_params->exit_err = basic_exit_err;
2407e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2417e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	return 0;
2427e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim}
2437e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2447e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salimint xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
2457e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim{
2467e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xtables_init();
2477e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	xtables_set_nfproto(nfproto);
2487e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	return xtables_set_params(xtp);
2497e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim}
2507e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim
2517e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim/**
252630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt * xtables_*alloc - wrappers that exit on failure
253630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt */
254630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_calloc(size_t count, size_t size)
2553dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
2563dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
2573dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2583dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
2593dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
2603dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
2613dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
2623dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2633dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
2643dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
2653dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
266630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_malloc(size_t size)
2673dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
2683dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
2693dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2703dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
2713dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
2723dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
2733dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
2743dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
2753dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
2763dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
2770b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2780b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
2790b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
2800b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
2810b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
2820b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2830b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROCFILE_BUFSIZ	1024
2840b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
2850b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
2860b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
2870b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2880b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	ret = (char *) malloc(PROCFILE_BUFSIZ);
2890b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
2900b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		memset(ret, 0, PROCFILE_BUFSIZ);
2910b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
2920b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case -1: goto fail;
2930b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
2940b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
2950b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (ret[strlen(ret)-1]=='\n')
2960b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			ret[strlen(ret)-1]=0;
2970b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		close(procfile);
2980b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return ret;
2990b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3000b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI fail:
3010b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
3020b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
3030b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
3040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
3050b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
306c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
3070b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
3080b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
3090b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
3100b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
3110b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
3130b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
3140b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
3150b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
3160b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
3170b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
3180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3190b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
320c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	/*
321c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 * Need to flush the buffer, or the child may output it again
322c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 * when switching the program thru execv.
323c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	 */
324c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt	fflush(stdout);
325c19f880d8aac7c0372381e29d7cea09accd0db26Jan Engelhardt
3260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	switch (fork()) {
3270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
3280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
3290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
3300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
3310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
3320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
3330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
3340b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
3350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
3360b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
3370b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
3380b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3390b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
3400b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
3410b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
3420b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
3430b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3440b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
3450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
3460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
3470b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
3480b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
3490b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
3500b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
3510b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
3520b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
3530b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
354c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_load_ko(const char *modprobe, bool quiet)
3550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
356c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	static bool loaded = false;
3570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	static int ret = -1;
3580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (!loaded) {
36077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
3610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		loaded = (ret == 0);
3620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
3630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
3650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
3660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3675f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt/**
3685f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * xtables_strtou{i,l} - string to number conversion
3695f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @s:	input string
3705f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @end:	like strtoul's "end" pointer
3715f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @value:	pointer for result
3725f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @min:	minimum accepted value
3735f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @max:	maximum accepted value
3745f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt *
3755f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
3765f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * "15a" is rejected.
3775f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * In either case, the value obtained is compared for min-max compliance.
3785f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Base is always 0, i.e. autodetect depending on @s.
379cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
3805f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Returns true/false whether number was accepted. On failure, *value has
3815f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * undefined contents.
382cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
3835f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoul(const char *s, char **end, unsigned long *value,
3845f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned long min, unsigned long max)
385cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
386cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
387cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
388cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
389cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
390cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	v = strtoul(s, &my_end, 0);
391cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
392cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
393cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
394cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
395cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
396cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
397cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
398cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
399cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
400cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
401cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
402cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
403cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
404cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
405cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
406cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
407cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
4085f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoui(const char *s, char **end, unsigned int *value,
4095f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned int min, unsigned int max)
410cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
411cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
412cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
413cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
4145f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	ret = xtables_strtoul(s, end, &v, min, max);
415cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
416cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
417cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
418cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
419cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
420aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtint xtables_service_to_port(const char *name, const char *proto)
42104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
42204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
42304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
42404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
42504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
42604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
42704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
42804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
42904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
430aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtu_int16_t xtables_parse_port(const char *port, const char *proto)
43104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
4327a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
43304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4345f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
435aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
436213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
43704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
4388b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM,
43904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
44004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
44104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
442aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtvoid xtables_parse_interface(const char *arg, char *vianame,
443aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt			     unsigned char *mask)
44404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
44504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	int vialen = strlen(arg);
44604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
44704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
44804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
44904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
45004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
45104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
4528b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
45304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
45404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
45504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
45604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
45704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
45804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0, IFNAMSIZ);
45904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
46004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
46104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
46204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
46304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
46404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
46504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
46604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
46704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
46804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			if (vianame[i] == ':' ||
46904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '!' ||
47004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '*') {
471aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
472aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
473aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					" `%s' (No aliases, :, ! or *).\n",
474aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
47504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
47604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
47704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
47804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
47904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
48004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
481cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
48221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardtstatic void *load_extension(const char *search_path, const char *prefix,
48321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
48421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
48521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
48621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
48721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
48821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
48921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
49021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
49121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
49221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
49321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
49421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
4952c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, name);
49621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
49721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
49821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			/* Found library.  If it didn't register itself,
49921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			   maybe they specified target as match. */
50021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
5012338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
50221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
5032338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
5042338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
50521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
50621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
50721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
50821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
50921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
51021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
51121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
51221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/%s%s.so",
5132c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, prefix, name);
51421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
51521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
5162338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
51721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
5182338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
5192338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
52021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
52121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
52221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
52321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
52421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
52521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
52621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
52721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
52821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
52921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
53021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
53121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
532cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
53321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
5342338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_match *
5352338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_match(const char *name, enum xtables_tryload tryload,
5362338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		   struct xtables_rule_match **matches)
5370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
5390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
5400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
5420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
5430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
5440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
5450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
5460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
5470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
5490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
5500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
5510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
5530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
5540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
5550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
557630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt			clone = xtables_malloc(sizeof(struct xtables_match));
5580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
5590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
5600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
5610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
5620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
5640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
5650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
5660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
5692338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
57077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
57139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, false);
572170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
5732338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
5748b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
5750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
5760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
5770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
5790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
5802338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
5810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
5820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
5830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
5840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5852338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
5868b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
5870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
5880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
5900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
5920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
5930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
5940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
595630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
5960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
5980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
5992338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				(*i)->completed = true;
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
6022338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		newentry->completed = false;
6030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
6040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
6050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
6080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6102338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_target *
6112338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_target(const char *name, enum xtables_tryload tryload)
6120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
6140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
6160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
6170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
6180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
6190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
6200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
6210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
6220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
6240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
6250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
6260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
6292338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
63077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
63139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, true);
632170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
6332338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
6348b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
6360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
6370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
6390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
6402338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
6410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
6420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
6430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
6440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
6468b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
6470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
6480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
6500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
6520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
6530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
6550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_revision(const char *name, u_int8_t revision, int opt)
6580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
6600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
6610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
6620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
66377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
6640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
665df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
666df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
667df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
668df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy				fprintf(stderr, "Could not determine whether "
669df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
670df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
671df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy					revision);
672df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
673df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
6740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
679c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	xtables_load_ko(xtables_modprobe_program, true);
6800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
6820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
6830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
68477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
6850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
6860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
6870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
6880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
6890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
6900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
6910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
6920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
6930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
6940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
6950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
6960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
6970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
6980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
7010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
7020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_match_revision(const char *name, u_int8_t revision)
7060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
70777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_match);
7080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_target_revision(const char *name, u_int8_t revision)
7110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
71277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_target);
7130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
7160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
7170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match **i, *old;
7180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
719dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
720dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
721dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
722dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
723dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
7240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
7280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
7290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
730dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
7310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
7350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
7360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
737dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
7380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
74277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
7430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
7440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7452338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
7460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
74723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
74823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
7490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
7500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
751dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
7520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
7530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
7540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
7560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_match_revision(old->name, old->revision)
7570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
7580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
7590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
76023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
7610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_match_revision(me->name, me->revision))
7620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
7630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
76423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
76523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
76623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
76723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
7680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
7690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
7700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
7710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
7740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
775dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
7760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
7800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
7810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
7820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
7830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
7850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
7860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
7870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
7890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
7900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *old;
7910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
792dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
793dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
794dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
795dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
796dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
7970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
8010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
8020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
803dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
8040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
8080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
8090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
810dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
8110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
81577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
8160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
8170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8182338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_target(me->name, XTF_DURING_LOAD);
8190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
8200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
8210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
82223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
82323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
8240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
8250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
826dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
8270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
8280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
8290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
8310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_target_revision(old->name, old->revision)
8320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
8330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
8340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
83523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
8360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_target_revision(me->name, me->revision))
8370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
8380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
83923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
84023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
84123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
84223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
8430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
8440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
8450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
8460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
8490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
850dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
8510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
8520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
8530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
8540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
8550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
8560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
8570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
8580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
8590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
860aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
861a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt/**
862a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * xtables_param_act - act on condition
863a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @status:	a constant from enum xtables_exittype
864a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
865a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONLY_ONCE: print error message that option may only be used once.
866a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name (e.g. "mark")
867a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2(...):	option in conflict (e.g. "--mark")
868a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3(...):	condition to match on (see extensions/ for examples)
869a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
870a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_NO_INVERT: option does not support inversion
871a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
872a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option in conflict
873a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		condition to match on
874a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
875a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_BAD_VALUE: bad value for option
876a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
877a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option with which the problem occured (e.g. "--mark")
878a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		string the user passed in (e.g. "99999999999999")
879a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
880a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
881a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
882a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
883a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * Displays an error message and exits the program.
884a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt */
885a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid xtables_param_act(unsigned int status, const char *p1, ...)
886aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
887aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
888aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
889aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
890aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
891aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
892aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
893aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
894a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONLY_ONCE:
895aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
896aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
897aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
898aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
8998b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
900aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
901aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
902aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
903a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_NO_INVERT:
904aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
905aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
906aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
907aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
9088b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
909aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
910aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
911a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_BAD_VALUE:
912aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
913aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
9148b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
915aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
916aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
917aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
918a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONE_ACTION:
919aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
920aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
921aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
9228b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
923aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
924aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
925aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
9268b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(status, p1, args);
927aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
928aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
929aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
930aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
931aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
93208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
933e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
93408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
93508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
93608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
93708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
93808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
93908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
94008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
94108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
94208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
94308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
94408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
94508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
94608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
94708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
94808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
94908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
95008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
95108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
95208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
95308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
95408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
95508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
95608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
95708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
95808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
95908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
96008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
96108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
96208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
963e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
96408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
96508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
96608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
96708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
96808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
96908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
97008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
971e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ipaddr_to_numeric(addr);
97208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
97308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
974e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
97508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
97608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
97708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
97808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
97908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
98008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
98108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
98208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
98308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* we don't want to see "/32" */
98408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return "";
98508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
98608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
98708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
98808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
98908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
99008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
99108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%d", i);
99208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	else
99308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
994e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
99508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
99608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
99708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
99808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
999bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1000bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1001bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
1002bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
1003bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
1004bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
1005bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
1006bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1007bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
1008bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
1009bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1010bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
1011bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1012bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
1013bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
1014bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
1015bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
1016bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
1017bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1018bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
10195f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1020bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
1021bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1022bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
1023bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
1024bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
1025bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1026bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
1027bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
1028bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1029bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
10305f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1031bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1032bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1033bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
1034bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
1035bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1036bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1037bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
10385f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1039bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1040bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1041bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
1042bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
1043bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1044bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
10451e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1046bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1047bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
1048bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1049bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
10501e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1051bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1052bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
1053bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1054bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1055bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
1056bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1057bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
1058bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
1059bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1060bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
1061bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
1062bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1063bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
1064bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
1065bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1066bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1067bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1068bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1069bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1070bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1071bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1072bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
1073bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
1074bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
1075bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1076bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1077bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
1078bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
1079bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
1080bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1081bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1082bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
1083bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
1084630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
1085bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
1086bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
1087bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
1088bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1089bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1090bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1091bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1092bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1093bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1094bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
1095bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
1096bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1097bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
1098bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
10991e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1100bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1101630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in_addr));
1102bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1103bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1104bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1105bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1106bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1107bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
1108bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
11098b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1110bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1111bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1112bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
1113bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1114bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
1115bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1116bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1117bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1118bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1119bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
1120bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
1121bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1122bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
11231e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1124bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
1125bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
11265f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
11278b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1128bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1129bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1130bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1131bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1132bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1133bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1134bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
1135bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1136bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1137bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1138a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt/**
1139a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * xtables_ipparse_any - transform arbitrary name to in_addr
1140a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt *
1141a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * Possible inputs (pseudo regex):
1142a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1143a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1144a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt */
1145a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1146a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                         struct in_addr *maskp, unsigned int *naddrs)
1147bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1148bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1149bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1150bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1151bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1152bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1153bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1154bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1155bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1156bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
1157bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1158bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
1159bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1160bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1161bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1162bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1163bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
1164bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
1165bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1166bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1167bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1168bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1169bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
1170bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1171bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1172bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1173bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1174bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1175bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1176bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1177bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1178bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1179e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
118008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
118108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	/* 0000:0000:0000:0000:0000:000.000.000.000
118208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
118308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
118408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
118508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
118608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
118708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
118808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
118908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
119008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
119108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
119208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
119308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
119408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
119508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
119608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
119708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
119808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
119908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
120008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
120108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
120208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
120308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
120408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
120508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
120608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
120708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
120808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
120908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
121008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
121108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1212e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
121308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
121408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
121508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
121608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
121708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
121808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1219e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ip6addr_to_numeric(addr);
122008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
122108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
122208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic int ip6addr_prefix_length(const struct in6_addr *k)
122308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
122408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
122508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
122608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
122748607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
122848607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
122948607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
123048607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
123108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
123208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
123308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
123408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
123508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
123608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
123708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
123808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
123908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
124008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
124108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
124208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
124308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
124408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
124508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1246e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
124708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
124808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
124908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int l = ip6addr_prefix_length(addrp);
125008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
125108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
125208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
1253e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		strcat(buf, xtables_ip6addr_to_numeric(addrp));
125408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
125508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
125608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "/%d", l);
125708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
125808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1259bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
12601e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1261bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1262bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1263bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1264bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1265bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1266bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1267bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1268bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1269bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1270bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1271bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1272bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1273bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1274bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1275bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1276bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr *addr;
1277bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
1278bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo *res;
1279bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1280bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1281bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1282bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1283bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1284bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1285bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_protocol = IPPROTO_IPV6;
1286bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_next     = NULL;
1287bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1288bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1289bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1290bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1291bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1292bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1293bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1294bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1295bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (res->ai_family != AF_INET6 ||
1296bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1297bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1298bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1299bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1300bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1301bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1302bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1303bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* Get the first element of the address-chain */
1304630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_malloc(sizeof(struct in6_addr));
1305bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1306bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		       sizeof(struct in6_addr));
1307bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1308bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddr = 1;
1309bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1310bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1311bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1312bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1313bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1314bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1315bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1316bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1317bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1318bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1319bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1320bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1321bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1322bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1323bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1324bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1325bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1326bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1327bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
13281e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1329bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1330630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in6_addr));
1331bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1332bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1333bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1334bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1335bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1336bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1337bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
13388b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1339bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1340bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1341bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1342bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1343bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1344bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1345bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1346bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1347bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1348bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1349bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1350bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1351bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
13521e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1353bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
13545f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
13558b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim		xt_params->exit_err(PARAMETER_PROBLEM,
1356bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1357bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1358bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1359bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1360bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1361bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1362bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1363bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1364bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1365bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1366bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1367bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1368bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1369a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1370a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                          struct in6_addr *maskp, unsigned int *naddrs)
1371bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1372bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1373bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1374bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1375bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1376bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1377bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1378bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1379bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1380bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1381bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1382bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1383bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1384bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1385bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1386bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1387bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1388bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1389bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1390bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1391bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1392bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1393bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
13945a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1395bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1396bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1397bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1398bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1399bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1400bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1401bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1402bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1403bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1404a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1405a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_save_string(const char *value)
1406a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1407a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1408a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1409a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1410a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1411a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1412a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1413a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1414a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	length = strcspn(value, no_quote_chars);
1415a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1416a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1417a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1418a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
1419a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1420a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1421a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1422a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1423a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
1424a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar('"');
1425a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1426a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1427a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1428a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1429a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1430a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1431a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1432a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1433a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1434a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1435a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1436a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1437a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1438a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		printf("\" ");
1439a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1440a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
14410f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
14420f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt/**
14430f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Check for option-intrapositional negation.
14440f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Do not use in new code.
14450f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt */
14460f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardtint xtables_check_inverse(const char option[], int *invert,
14470f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			  int *my_optind, int argc)
14480f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt{
14490f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	if (option && strcmp(option, "!") == 0) {
14500f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		fprintf(stderr, "Using intrapositioned negation "
14510f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		        "(`--option ! this`) is deprecated in favor of "
14520f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		        "extrapositioned (`! --option this`).\n");
14530f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
14540f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		if (*invert)
14558b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim			xt_params->exit_err(PARAMETER_PROBLEM,
14560f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt				   "Multiple `!' flags not allowed");
14570f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		*invert = true;
14580f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		if (my_optind != NULL) {
14590f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			++*my_optind;
14600f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			if (argc && *my_optind > argc)
14618b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim				xt_params->exit_err(PARAMETER_PROBLEM,
14620f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt					   "no argument following `!'");
14630f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		}
14640f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
14650f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		return true;
14660f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	}
14670f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	return false;
14680f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt}
14691de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
14701de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtconst struct xtables_pprot xtables_chain_protos[] = {
14711de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"tcp",       IPPROTO_TCP},
14721de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"sctp",      IPPROTO_SCTP},
14731de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udp",       IPPROTO_UDP},
14741de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udplite",   IPPROTO_UDPLITE},
14751de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmp",      IPPROTO_ICMP},
14761de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmpv6",    IPPROTO_ICMPV6},
14771de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-icmp", IPPROTO_ICMPV6},
14781de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"esp",       IPPROTO_ESP},
14791de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ah",        IPPROTO_AH},
14801de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-mh",   IPPROTO_MH},
14811de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"mh",        IPPROTO_MH},
14821de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"all",       0},
14831de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{NULL},
14841de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt};
14851de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
14861de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtu_int16_t
14871de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtxtables_parse_protocol(const char *s)
14881de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt{
14891de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	unsigned int proto;
14901de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
14911de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	if (!xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) {
14921de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		struct protoent *pent;
14931de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
14941de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		/* first deal with the special case of 'all' to prevent
14951de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * people from being able to redefine 'all' in nsswitch
14961de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * and/or provoke expensive [not working] ldap/nis/...
14971de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * lookups */
14981de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		if (!strcmp(s, "all"))
14991de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			return 0;
15001de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
15011de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		if ((pent = getprotobyname(s)))
15021de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			proto = pent->p_proto;
15031de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		else {
15041de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			unsigned int i;
15051de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
15061de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				if (strcmp(s, xtables_chain_protos[i].name) == 0) {
15071de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					proto = xtables_chain_protos[i].num;
15081de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					break;
15091de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				}
15101de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			}
15111de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			if (i == ARRAY_SIZE(xtables_chain_protos))
15128b7baebc93989106fd5d26b262d0ce191f8ef7c0Jamal Hadi Salim				xt_params->exit_err(PARAMETER_PROBLEM,
15131de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					   "unknown protocol `%s' specified",
15141de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					   s);
15151de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		}
15161de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	}
15171de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
15181de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	return proto;
15191de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt}
1520