xtables.c revision 5dd19de34380c91ad07bbe79a34726e59891cf54
1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/*
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	This program is free software; you can redistribute it and/or modify
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	it under the terms of the GNU General Public License as published by
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	the Free Software Foundation; either version 2 of the License, or
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	(at your option) any later version.
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	This program is distributed in the hope that it will be useful,
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	but WITHOUT ANY WARRANTY; without even the implied warranty of
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	GNU General Public License for more details.
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	You should have received a copy of the GNU General Public License
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	along with this program; if not, write to the Free Software
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <errno.h>
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <fcntl.h>
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <netdb.h>
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <stdarg.h>
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <stdbool.h>
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <stdio.h>
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <stdlib.h>
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <string.h>
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <unistd.h>
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <sys/socket.h>
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <sys/stat.h>
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <sys/types.h>
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <sys/wait.h>
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <arpa/inet.h>
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <xtables.h>
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <linux/netfilter_ipv4/ip_tables.h>
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <linux/netfilter_ipv6/ip6_tables.h>
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <libiptc/libxtc.h>
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef NO_SHARED_LIBS
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <dlfcn.h>
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#	define IP6T_SO_GET_REVISION_MATCH	68
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#	define IP6T_SO_GET_REVISION_TARGET	69
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <getopt.h>
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define NPROTO	255
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef PROC_SYS_MODPROBE
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct xtables_globals *xt_params = NULL;
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...)
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	va_list args;
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	va_start(args, msg);
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	vfprintf(stderr, msg, args);
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	va_end(args);
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	fprintf(stderr, "\n");
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	exit(status);
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_free_opts(int reset_offset)
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (xt_params->opts != xt_params->orig_opts) {
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		free(xt_params->opts);
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->opts = xt_params->orig_opts;
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (reset_offset)
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->option_offset = 0;
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct option *xtables_merge_options(struct option *oldopts,
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				     const struct option *newopts,
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				     unsigned int *option_offset)
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int num_old, num_new, i;
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct option *merge;
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (newopts == NULL)
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return oldopts;
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (num_old = 0; oldopts[num_old].name; num_old++) ;
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (num_new = 0; newopts[num_new].name; num_new++) ;
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xt_params->option_offset += OPTION_OFFSET;
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	*option_offset = xt_params->option_offset;
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (merge == NULL)
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return NULL;
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memcpy(merge, oldopts, num_old * sizeof(struct option));
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_free_opts(0);	/* Release any old options merged  */
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (i = 0; i < num_new; i++) {
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		merge[num_old + i] = newopts[i];
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		merge[num_old + i].val += *option_offset;
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memset(merge + num_old + num_new, 0, sizeof(struct option));
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return merge;
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_set_revision(char *name, u_int8_t revision)
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* Old kernel sources don't have ".revision" field,
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	*            but we stole a byte from name. */
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	name[XT_FUNCTION_MAXNAMELEN - 2] = '\0';
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	name[XT_FUNCTION_MAXNAMELEN - 1] = revision;
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * xtables_afinfo - protocol family dependent information
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @kmod:		kernel module basename (e.g. "ip_tables")
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @libprefix:		prefix of .so library name (e.g. "libipt_")
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @family:		nfproto family
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @ipproto:		used by setsockopt (e.g. IPPROTO_IP)
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @so_rev_match:	optname to check revision support of match
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @so_rev_target:	optname to check revision support of target
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct xtables_afinfo {
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const char *kmod;
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const char *libprefix;
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	uint8_t family;
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	uint8_t ipproto;
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int so_rev_match;
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int so_rev_target;
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const struct xtables_afinfo afinfo_ipv4 = {
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.kmod          = "ip_tables",
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.libprefix     = "libipt_",
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.family	       = NFPROTO_IPV4,
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.ipproto       = IPPROTO_IP,
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const struct xtables_afinfo afinfo_ipv6 = {
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.kmod          = "ip6_tables",
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.libprefix     = "libip6t_",
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.family        = NFPROTO_IPV6,
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.ipproto       = IPPROTO_IPV6,
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const struct xtables_afinfo *afinfo;
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* Search path for Xtables .so files */
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const char *xtables_libdir;
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* the path to command to load kernel module */
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst char *xtables_modprobe_program;
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* Keeping track of external matches and targets: linked lists.  */
169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct xtables_match *xtables_matches;
170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct xtables_target *xtables_targets;
171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_init(void)
173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_libdir = getenv("XTABLES_LIBDIR");
175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (xtables_libdir != NULL)
176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return;
177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_libdir = getenv("IPTABLES_LIB_DIR");
178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (xtables_libdir != NULL) {
179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        "use XTABLES_LIBDIR.\n");
181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return;
182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/*
184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * for these env vars are deprecated anyhow, and in light of the
187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * (shared) libxt_*.so files, makes less sense to have
188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 */
190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (xtables_libdir != NULL) {
192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        "use XTABLES_LIBDIR.\n");
194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return;
195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_libdir = XTABLES_LIBDIR;
197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_set_nfproto(uint8_t nfproto)
200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	switch (nfproto) {
202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	case NFPROTO_IPV4:
203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		afinfo = &afinfo_ipv4;
204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		break;
205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	case NFPROTO_IPV6:
206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		afinfo = &afinfo_ipv6;
207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		break;
208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	default:
209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        __func__);
211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * xtables_set_params - set the global parameters used by xtables
216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @xtp:	input xtables_globals structure
217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * The app is expected to pass a valid xtables_globals data-filled
219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * with proper values
220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @xtp cannot be NULL
221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Returns -1 on failure to set and 0 on success
223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint xtables_set_params(struct xtables_globals *xtp)
225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!xtp) {
227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "%s: Illegal global params\n",__func__);
228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return -1;
229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xt_params = xtp;
232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!xt_params->exit_err)
234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err = basic_exit_err;
235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return 0;
237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_init();
242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_set_nfproto(nfproto);
243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return xtables_set_params(xtp);
244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * xtables_*alloc - wrappers that exit on failure
248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid *xtables_calloc(size_t count, size_t size)
250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	void *p;
252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((p = calloc(count, size)) == NULL) {
254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		perror("ip[6]tables: calloc failed");
255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return p;
259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
260f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
261f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid *xtables_malloc(size_t size)
262f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
263f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	void *p;
264f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
265f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((p = malloc(size)) == NULL) {
266f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		perror("ip[6]tables: malloc failed");
267f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
268f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
269f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
270f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return p;
271f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
272f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
273f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic char *get_modprobe(void)
274f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
275f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int procfile;
276f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	char *ret;
277f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
278f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define PROCFILE_BUFSIZ	1024
279f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
280f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (procfile < 0)
281f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return NULL;
282f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
283f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	ret = (char *) malloc(PROCFILE_BUFSIZ);
284f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (ret) {
285f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(ret, 0, PROCFILE_BUFSIZ);
286f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
287f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		case -1: goto fail;
288f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
289f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
290f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (ret[strlen(ret)-1]=='\n')
291f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			ret[strlen(ret)-1]=0;
292f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		close(procfile);
293f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return ret;
294f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
295f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fail:
296f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	free(ret);
297f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	close(procfile);
298f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return NULL;
299f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
300f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
301f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
302f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
303f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	char *buf = NULL;
304f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	char *argv[4];
305f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int status;
306f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
307f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* If they don't explicitly set it, read out of kernel */
308f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!modprobe) {
309f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		buf = get_modprobe();
310f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (!buf)
311f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return -1;
312f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		modprobe = buf;
313f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
314f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
315f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/*
316f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * Need to flush the buffer, or the child may output it again
317f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * when switching the program thru execv.
318f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 */
319f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	fflush(stdout);
320f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
321f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	switch (fork()) {
322f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	case 0:
323f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		argv[0] = (char *)modprobe;
324f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		argv[1] = (char *)modname;
325f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (quiet) {
326f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			argv[2] = "-q";
327f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			argv[3] = NULL;
328f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		} else {
329f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			argv[2] = NULL;
330f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			argv[3] = NULL;
331f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
332f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		execv(argv[0], argv);
333f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
334f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* not usually reached */
335f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
336f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	case -1:
337f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return -1;
338f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
339f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	default: /* parent */
340f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		wait(&status);
341f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
342f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
343f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	free(buf);
344f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
345f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return 0;
346f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return -1;
347f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
348f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
349f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint xtables_load_ko(const char *modprobe, bool quiet)
350f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
351f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static bool loaded = false;
352f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static int ret = -1;
353f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
354f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!loaded) {
355f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
356f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		loaded = (ret == 0);
357f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
358f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
359f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return ret;
360f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
361f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
362f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
363f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * xtables_strtou{i,l} - string to number conversion
364f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @s:	input string
365f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @end:	like strtoul's "end" pointer
366f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @value:	pointer for result
367f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @min:	minimum accepted value
368f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @max:	maximum accepted value
369f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
370f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
371f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * "15a" is rejected.
372f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * In either case, the value obtained is compared for min-max compliance.
373f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Base is always 0, i.e. autodetect depending on @s.
374f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
375f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Returns true/false whether number was accepted. On failure, *value has
376f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * undefined contents.
377f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
378f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool xtables_strtoul(const char *s, char **end, unsigned long *value,
379f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                     unsigned long min, unsigned long max)
380f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
381f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned long v;
382f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	char *my_end;
383f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
384f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	errno = 0;
385f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	v = strtoul(s, &my_end, 0);
386f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
387f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (my_end == s)
388f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return false;
389f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (end != NULL)
390f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*end = my_end;
391f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
392f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
393f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (value != NULL)
394f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			*value = v;
395f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (end == NULL)
396f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return *my_end == '\0';
397f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return true;
398f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
399f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
400f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return false;
401f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
402f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
403f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool xtables_strtoui(const char *s, char **end, unsigned int *value,
404f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                     unsigned int min, unsigned int max)
405f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
406f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned long v;
407f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	bool ret;
408f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
409f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	ret = xtables_strtoul(s, end, &v, min, max);
410f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (value != NULL)
411f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*value = v;
412f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return ret;
413f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
414f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
415f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint xtables_service_to_port(const char *name, const char *proto)
416f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
417f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct servent *service;
418f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
419f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((service = getservbyname(name, proto)) != NULL)
420f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return ntohs((unsigned short) service->s_port);
421f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
422f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return -1;
423f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
424f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
425f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgu_int16_t xtables_parse_port(const char *port, const char *proto)
426f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
427f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int portnum;
428f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
429f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
430f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
431f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return portnum;
432f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
433f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xt_params->exit_err(PARAMETER_PROBLEM,
434f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		   "invalid port/service `%s' specified", port);
435f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
436f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
437f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_parse_interface(const char *arg, char *vianame,
438f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			     unsigned char *mask)
439f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
440f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int vialen = strlen(arg);
441f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int i;
442f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
443f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memset(mask, 0, IFNAMSIZ);
444f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memset(vianame, 0, IFNAMSIZ);
445f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
446f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (vialen + 1 > IFNAMSIZ)
447f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
448f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			   "interface name `%s' must be shorter than IFNAMSIZ"
449f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			   " (%i)", arg, IFNAMSIZ-1);
450f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
451f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	strcpy(vianame, arg);
452f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
453f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(mask, 0, IFNAMSIZ);
454f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	else if (vianame[vialen - 1] == '+') {
455f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(mask, 0xFF, vialen - 1);
456f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
457f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Don't remove `+' here! -HW */
458f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	} else {
459f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Include nul-terminator in match */
460f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(mask, 0xFF, vialen + 1);
461f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
462f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (i = 0; vianame[i]; i++) {
463f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (vianame[i] == ':' ||
464f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			    vianame[i] == '!' ||
465f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			    vianame[i] == '*') {
466f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				fprintf(stderr,
467f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					"Warning: weird character in interface"
468f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					" `%s' (No aliases, :, ! or *).\n",
469f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					vianame);
470f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				break;
471f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			}
472f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
473f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
474f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
475f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
476f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef NO_SHARED_LIBS
477f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void *load_extension(const char *search_path, const char *prefix,
478f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    const char *name, bool is_target)
479f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
480f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const char *dir = search_path, *next;
481f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	void *ptr = NULL;
482f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct stat sb;
483f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	char path[256];
484f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
485f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	do {
486f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		next = strchr(dir, ':');
487f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (next == NULL)
488f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			next = dir + strlen(dir);
489f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
490f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		         (unsigned int)(next - dir), dir, name);
491f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
492f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (dlopen(path, RTLD_NOW) != NULL) {
493f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			/* Found library.  If it didn't register itself,
494f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			   maybe they specified target as match. */
495f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (is_target)
496f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				ptr = xtables_find_target(name, XTF_DONT_LOAD);
497f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			else
498f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				ptr = xtables_find_match(name,
499f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				      XTF_DONT_LOAD, NULL);
500f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		} else if (stat(path, &sb) == 0) {
501f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			fprintf(stderr, "%s: %s\n", path, dlerror());
502f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
503f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
504f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (ptr != NULL)
505f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return ptr;
506f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
507f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		snprintf(path, sizeof(path), "%.*s/%s%s.so",
508f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		         (unsigned int)(next - dir), dir, prefix, name);
509f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (dlopen(path, RTLD_NOW) != NULL) {
510f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (is_target)
511f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				ptr = xtables_find_target(name, XTF_DONT_LOAD);
512f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			else
513f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				ptr = xtables_find_match(name,
514f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				      XTF_DONT_LOAD, NULL);
515f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		} else if (stat(path, &sb) == 0) {
516f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			fprintf(stderr, "%s: %s\n", path, dlerror());
517f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
518f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
519f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (ptr != NULL)
520f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return ptr;
521f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
522f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		dir = next + 1;
523f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	} while (*next != '\0');
524f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
525f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return NULL;
526f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
527f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
528f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
529f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct xtables_match *
530f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgxtables_find_match(const char *name, enum xtables_tryload tryload,
531f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		   struct xtables_rule_match **matches)
532f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
533f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct xtables_match *ptr;
534f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const char *icmp6 = "icmp6";
535f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
536f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* This is ugly as hell. Nonetheless, there is no way of changing
537f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * this without hurting backwards compatibility */
538f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ( (strcmp(name,"icmpv6") == 0) ||
539f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	     (strcmp(name,"ipv6-icmp") == 0) ||
540f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	     (strcmp(name,"icmp6") == 0) )
541f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		name = icmp6;
542f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
543f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
544f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (strcmp(name, ptr->name) == 0) {
545f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			struct xtables_match *clone;
546f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
547f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			/* First match of this type: */
548f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (ptr->m == NULL)
549f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				break;
550f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
551f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			/* Second and subsequent clones */
552f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			clone = xtables_malloc(sizeof(struct xtables_match));
553f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			memcpy(clone, ptr, sizeof(struct xtables_match));
554f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			clone->mflags = 0;
555f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			/* This is a clone: */
556f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			clone->next = clone;
557f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
558f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			ptr = clone;
559f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			break;
560f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
561f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
562f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
563f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef NO_SHARED_LIBS
564f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
565f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		ptr = load_extension(xtables_libdir, afinfo->libprefix,
566f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		      name, false);
567f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
568f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
569f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->exit_err(PARAMETER_PROBLEM,
570f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				   "Couldn't load match `%s':%s\n",
571f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				   name, dlerror());
572f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
573f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#else
574f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (ptr && !ptr->loaded) {
575f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (tryload != XTF_DONT_LOAD)
576f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			ptr->loaded = 1;
577f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		else
578f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			ptr = NULL;
579f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
580f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
581f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
582f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			   "Couldn't find match `%s'\n", name);
583f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
584f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
585f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
586f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (ptr && matches) {
587f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		struct xtables_rule_match **i;
588f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		struct xtables_rule_match *newentry;
589f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
590f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
591f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
592f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (i = matches; *i; i = &(*i)->next) {
593f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (strcmp(name, (*i)->match->name) == 0)
594f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				(*i)->completed = true;
595f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
596f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		newentry->match = ptr;
597f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		newentry->completed = false;
598f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		newentry->next = NULL;
599f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*i = newentry;
600f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
601f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
602f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return ptr;
603f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
604f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
605f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct xtables_target *
606f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgxtables_find_target(const char *name, enum xtables_tryload tryload)
607f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
608f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct xtables_target *ptr;
609f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
610f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* Standard target? */
611f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (strcmp(name, "") == 0
612f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
613f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	    || strcmp(name, XTC_LABEL_DROP) == 0
614f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	    || strcmp(name, XTC_LABEL_QUEUE) == 0
615f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	    || strcmp(name, XTC_LABEL_RETURN) == 0)
616f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		name = "standard";
617f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
618f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
619f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (strcmp(name, ptr->name) == 0)
620f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			break;
621f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
622f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
623f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef NO_SHARED_LIBS
624f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
625f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		ptr = load_extension(xtables_libdir, afinfo->libprefix,
626f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		      name, true);
627f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
628f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
629f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->exit_err(PARAMETER_PROBLEM,
630f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				   "Couldn't load target `%s':%s\n",
631f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				   name, dlerror());
632f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
633f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#else
634f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (ptr && !ptr->loaded) {
635f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (tryload != XTF_DONT_LOAD)
636f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			ptr->loaded = 1;
637f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		else
638f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			ptr = NULL;
639f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
640f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
641f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
642f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			   "Couldn't find target `%s'\n", name);
643f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
644f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
645f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
646f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (ptr)
647f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		ptr->used = 1;
648f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
649f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return ptr;
650f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
651f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
652f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic int compatible_revision(const char *name, u_int8_t revision, int opt)
653f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
654f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct xt_get_revision rev;
655f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	socklen_t s = sizeof(rev);
656f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int max_rev, sockfd;
657f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
658f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
659f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (sockfd < 0) {
660f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (errno == EPERM) {
661f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			/* revision 0 is always supported. */
662f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (revision != 0)
663f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				fprintf(stderr, "Could not determine whether "
664f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org						"revision %u is supported, "
665f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org						"assuming it is.\n",
666f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					revision);
667f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return 1;
668f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
669f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "Could not open socket to kernel: %s\n",
670f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			strerror(errno));
671f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
672f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
673f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
674f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_load_ko(xtables_modprobe_program, true);
675f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
676f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	strcpy(rev.name, name);
677f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	rev.revision = revision;
678f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
679f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
680f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (max_rev < 0) {
681f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Definitely don't support this? */
682f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
683f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			close(sockfd);
684f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return 0;
685f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		} else if (errno == ENOPROTOOPT) {
686f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			close(sockfd);
687f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			/* Assume only revision 0 support (old kernel) */
688f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return (revision == 0);
689f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		} else {
690f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			fprintf(stderr, "getsockopt failed strangely: %s\n",
691f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				strerror(errno));
692f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			exit(1);
693f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
694f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
695f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	close(sockfd);
696f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return 1;
697f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
698f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
699f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
700f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic int compatible_match_revision(const char *name, u_int8_t revision)
701f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
702f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return compatible_revision(name, revision, afinfo->so_rev_match);
703f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
704f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
705f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic int compatible_target_revision(const char *name, u_int8_t revision)
706f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
707f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return compatible_revision(name, revision, afinfo->so_rev_target);
708f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
709f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
710f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_register_match(struct xtables_match *me)
711f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
712f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct xtables_match **i, *old;
713f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
714f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (strcmp(me->version, XTABLES_VERSION) != 0) {
715f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
716f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        "but \"%s\" is required.\n",
717f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->program_name, me->name,
718f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			me->version, XTABLES_VERSION);
719f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
720f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
721f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
722f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* Revision field stole a char from name. */
723f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
724f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "%s: target `%s' has invalid name\n",
725f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->program_name, me->name);
726f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
727f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
728f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
729f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (me->family >= NPROTO) {
730f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr,
731f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			"%s: BUG: match %s has invalid protocol family\n",
732f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->program_name, me->name);
733f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
734f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
735f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
736f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* ignore not interested match */
737f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (me->family != afinfo->family && me->family != AF_UNSPEC)
738f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return;
739f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
740f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
741f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (old) {
742f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (old->revision == me->revision &&
743f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		    old->family == me->family) {
744f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			fprintf(stderr,
745f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				"%s: match `%s' already registered.\n",
746f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				xt_params->program_name, me->name);
747f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			exit(1);
748f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
749f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
750f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Now we have two (or more) options, check compatibility. */
751f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (compatible_match_revision(old->name, old->revision)
752f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		    && old->revision > me->revision)
753f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
754f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
755f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* See if new match can be used. */
756f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (!compatible_match_revision(me->name, me->revision))
757f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
758f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
759f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
760f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (old->revision == me->revision && me->family == AF_UNSPEC)
761f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
762f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
763f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Delete old one. */
764f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
765f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*i = old->next;
766f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
767f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
768f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (me->size != XT_ALIGN(me->size)) {
769f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
770f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        xt_params->program_name, me->name,
771f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        (unsigned int)me->size);
772f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
773f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
774f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
775f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* Append to list. */
776f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (i = &xtables_matches; *i; i = &(*i)->next);
777f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	me->next = NULL;
778f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	*i = me;
779f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
780f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	me->m = NULL;
781f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	me->mflags = 0;
782f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
783f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
784f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_register_target(struct xtables_target *me)
785f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
786f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct xtables_target *old;
787f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
788f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (strcmp(me->version, XTABLES_VERSION) != 0) {
789f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
790f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        "but \"%s\" is required.\n",
791f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->program_name, me->name,
792f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			me->version, XTABLES_VERSION);
793f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
794f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
795f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
796f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* Revision field stole a char from name. */
797f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
798f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "%s: target `%s' has invalid name\n",
799f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->program_name, me->name);
800f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
801f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
802f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
803f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (me->family >= NPROTO) {
804f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr,
805f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			"%s: BUG: target %s has invalid protocol family\n",
806f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->program_name, me->name);
807f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
808f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
809f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
810f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* ignore not interested target */
811f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (me->family != afinfo->family && me->family != AF_UNSPEC)
812f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return;
813f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
814f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	old = xtables_find_target(me->name, XTF_DURING_LOAD);
815f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (old) {
816f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		struct xtables_target **i;
817f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
818f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (old->revision == me->revision &&
819f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		    old->family == me->family) {
820f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			fprintf(stderr,
821f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				"%s: target `%s' already registered.\n",
822f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				xt_params->program_name, me->name);
823f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			exit(1);
824f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
825f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
826f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Now we have two (or more) options, check compatibility. */
827f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (compatible_target_revision(old->name, old->revision)
828f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		    && old->revision > me->revision)
829f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
830f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
831f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* See if new target can be used. */
832f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (!compatible_target_revision(me->name, me->revision))
833f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
834f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
835f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
836f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (old->revision == me->revision && me->family == AF_UNSPEC)
837f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
838f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
839f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Delete old one. */
840f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
841f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*i = old->next;
842f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
843f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
844f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (me->size != XT_ALIGN(me->size)) {
845f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
846f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        xt_params->program_name, me->name,
847f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        (unsigned int)me->size);
848f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		exit(1);
849f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
850f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
851f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* Prepend to list. */
852f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	me->next = xtables_targets;
853f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xtables_targets = me;
854f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	me->t = NULL;
855f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	me->tflags = 0;
856f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
857f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
858f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
859f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * xtables_param_act - act on condition
860f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @status:	a constant from enum xtables_exittype
861f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
862f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * %XTF_ONLY_ONCE: print error message that option may only be used once.
863f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p1:		module name (e.g. "mark")
864f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p2(...):	option in conflict (e.g. "--mark")
865f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p3(...):	condition to match on (see extensions/ for examples)
866f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
867f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * %XTF_NO_INVERT: option does not support inversion
868f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p1:		module name
869f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p2:		option in conflict
870f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p3:		condition to match on
871f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
872f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * %XTF_BAD_VALUE: bad value for option
873f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p1:		module name
874f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p2:		option with which the problem occured (e.g. "--mark")
875f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p3:		string the user passed in (e.g. "99999999999999")
876f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
877f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
878f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @p1:		module name
879f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
880f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Displays an error message and exits the program.
881f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
882f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_param_act(unsigned int status, const char *p1, ...)
883f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
884f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const char *p2, *p3;
885f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	va_list args;
886f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	bool b;
887f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
888f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	va_start(args, p1);
889f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
890f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	switch (status) {
891f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	case XTF_ONLY_ONCE:
892f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		p2 = va_arg(args, const char *);
893f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		b  = va_arg(args, unsigned int);
894f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (!b)
895f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
896f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
897f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		           "%s: \"%s\" option may only be specified once",
898f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		           p1, p2);
899f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		break;
900f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	case XTF_NO_INVERT:
901f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		p2 = va_arg(args, const char *);
902f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		b  = va_arg(args, unsigned int);
903f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (!b)
904f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
905f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
906f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		           "%s: \"%s\" option cannot be inverted", p1, p2);
907f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		break;
908f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	case XTF_BAD_VALUE:
909f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		p2 = va_arg(args, const char *);
910f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		p3 = va_arg(args, const char *);
911f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
912f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		           "%s: Bad value for \"%s\" option: \"%s\"",
913f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		           p1, p2, p3);
914f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		break;
915f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	case XTF_ONE_ACTION:
916f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		b = va_arg(args, unsigned int);
917f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (!b)
918f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return;
919f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
920f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		           "%s: At most one action is possible", p1);
921f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		break;
922f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	default:
923f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(status, p1, args);
924f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		break;
925f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
926f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
927f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	va_end(args);
928f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
929f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
930f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
931f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
932f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static char buf[20];
933f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const unsigned char *bytep = (const void *)&addrp->s_addr;
934f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
935f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
936f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return buf;
937f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
938f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
939f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const char *ipaddr_to_host(const struct in_addr *addr)
940f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
941f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct hostent *host;
942f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
943f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
944f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (host == NULL)
945f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return NULL;
946f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
947f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return host->h_name;
948f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
949f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
950f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const char *ipaddr_to_network(const struct in_addr *addr)
951f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
952f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct netent *net;
953f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
954f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
955f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return net->n_name;
956f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
957f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return NULL;
958f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
959f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
960f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
961f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
962f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const char *name;
963f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
964f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((name = ipaddr_to_host(addr)) != NULL ||
965f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	    (name = ipaddr_to_network(addr)) != NULL)
966f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return name;
967f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
968f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return xtables_ipaddr_to_numeric(addr);
969f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
970f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
971f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
972f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
973f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static char buf[20];
974f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	uint32_t maskaddr, bits;
975f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int i;
976f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
977f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	maskaddr = ntohl(mask->s_addr);
978f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
979f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (maskaddr == 0xFFFFFFFFL)
980f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* we don't want to see "/32" */
981f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return "";
982f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
983f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	i = 32;
984f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	bits = 0xFFFFFFFEL;
985f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	while (--i >= 0 && maskaddr != bits)
986f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		bits <<= 1;
987f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (i >= 0)
988f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		sprintf(buf, "/%d", i);
989f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	else
990f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* mask was not a decent combination of 1's and 0's */
991f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
992f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
993f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return buf;
994f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
995f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
996f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
997f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
998f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static struct in_addr addr;
999f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned char *addrp;
1000f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int onebyte;
1001f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	char buf[20], *p, *q;
1002f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int i;
1003f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1004f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* copy dotted string, because we need to modify it */
1005f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	strncpy(buf, dotted, sizeof(buf) - 1);
1006f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	buf[sizeof(buf) - 1] = '\0';
1007f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	addrp = (void *)&addr.s_addr;
1008f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1009f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	p = buf;
1010f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (i = 0; i < 3; ++i) {
1011f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if ((q = strchr(p, '.')) == NULL) {
1012f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (is_mask)
1013f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				return NULL;
1014f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1015f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			/* autocomplete, this is a network address */
1016f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1017f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				return NULL;
1018f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1019f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			addrp[i] = onebyte;
1020f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			while (i < 3)
1021f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				addrp[++i] = 0;
1022f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1023f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return &addr;
1024f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
1025f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1026f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*q = '\0';
1027f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1028f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return NULL;
1029f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1030f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addrp[i] = onebyte;
1031f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		p = q + 1;
1032f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1033f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1034f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* we have checked 3 bytes, now we check the last one */
1035f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1036f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return NULL;
1037f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1038f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	addrp[3] = onebyte;
1039f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return &addr;
1040f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1041f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1042f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1043f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1044f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return __numeric_to_ipaddr(dotted, false);
1045f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1046f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1047f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1048f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1049f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return __numeric_to_ipaddr(dotted, true);
1050f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1051f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1052f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in_addr *network_to_ipaddr(const char *name)
1053f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1054f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static struct in_addr addr;
1055f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct netent *net;
1056f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1057f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((net = getnetbyname(name)) != NULL) {
1058f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (net->n_addrtype != AF_INET)
1059f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return NULL;
1060f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addr.s_addr = htonl(net->n_net);
1061f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return &addr;
1062f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1063f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1064f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return NULL;
1065f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1066f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1067f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1068f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1069f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct hostent *host;
1070f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct in_addr *addr;
1071f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int i;
1072f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1073f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	*naddr = 0;
1074f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((host = gethostbyname(name)) != NULL) {
1075f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (host->h_addrtype != AF_INET ||
1076f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		    host->h_length != sizeof(struct in_addr))
1077f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return NULL;
1078f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1079f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		while (host->h_addr_list[*naddr] != NULL)
1080f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			++*naddr;
1081f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
1082f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (i = 0; i < *naddr; i++)
1083f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			memcpy(&addr[i], host->h_addr_list[i],
1084f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			       sizeof(struct in_addr));
1085f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return addr;
1086f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1087f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1088f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return NULL;
1089f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1090f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1091f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in_addr *
1092f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgipparse_hostnetwork(const char *name, unsigned int *naddrs)
1093f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1094f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct in_addr *addrptmp, *addrp;
1095f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1096f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1097f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1098f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addrp = xtables_malloc(sizeof(struct in_addr));
1099f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memcpy(addrp, addrptmp, sizeof(*addrp));
1100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*naddrs = 1;
1101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return addrp;
1102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return addrptmp;
1105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in_addr *parse_ipmask(const char *mask)
1110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static struct in_addr maskaddr;
1112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct in_addr *addrp;
1113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int bits;
1114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (mask == NULL) {
1116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* no mask at all defaults to 32 bits */
1117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		maskaddr.s_addr = 0xFFFFFFFF;
1118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return &maskaddr;
1119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* dotted_to_addr already returns a network byte order addr */
1122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return addrp;
1123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
1125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			   "invalid mask `%s' specified", mask);
1126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (bits != 0) {
1127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return &maskaddr;
1129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	maskaddr.s_addr = 0U;
1132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return &maskaddr;
1133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
1136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * xtables_ipparse_any - transform arbitrary name to in_addr
1137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
1138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Possible inputs (pseudo regex):
1139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
1142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         struct in_addr *maskp, unsigned int *naddrs)
1144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int i, j, k, n;
1146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct in_addr *addrp;
1147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	char buf[256], *p;
1148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	strncpy(buf, name, sizeof(buf) - 1);
1150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	buf[sizeof(buf) - 1] = '\0';
1151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((p = strrchr(buf, '/')) != NULL) {
1152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*p = '\0';
1153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addrp = parse_ipmask(p + 1);
1154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	} else {
1155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addrp = parse_ipmask(NULL);
1156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memcpy(maskp, addrp, sizeof(*maskp));
1158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* if a null mask is given, the name is ignored, like in "any/0" */
1160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (maskp->s_addr == 0U)
1161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		strcpy(buf, "0.0.0.0");
1162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	n = *naddrs;
1165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (i = 0, j = 0; i < n; ++i) {
1166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addrp[j++].s_addr &= maskp->s_addr;
1167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (k = 0; k < j - 1; ++k)
1168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				--*naddrs;
1170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				--j;
1171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				break;
1172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			}
1173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* 0000:0000:0000:0000:0000:000.000.000.000
1179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
1180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static char buf[50+1];
1181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const char *ip6addr_to_host(const struct in6_addr *addr)
1185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static char hostname[NI_MAXHOST];
1187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct sockaddr_in6 saddr;
1188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int err;
1189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memset(&saddr, 0, sizeof(struct sockaddr_in6));
1191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	saddr.sin6_family = AF_INET6;
1193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
1196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (err != 0) {
1197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifdef DEBUG
1198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
1199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
1200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return NULL;
1201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifdef DEBUG
1204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	fprintf (stderr, "\naddr2host: %s\n", hostname);
1205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
1206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return hostname;
1207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const char *name;
1212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((name = ip6addr_to_host(addr)) != NULL)
1214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return name;
1215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return xtables_ip6addr_to_numeric(addr);
1217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic int ip6addr_prefix_length(const struct in6_addr *k)
1220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int bits = 0;
1222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	uint32_t a, b, c, d;
1223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	a = ntohl(k->s6_addr32[0]);
1225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	b = ntohl(k->s6_addr32[1]);
1226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	c = ntohl(k->s6_addr32[2]);
1227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	d = ntohl(k->s6_addr32[3]);
1228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	while (a & 0x80000000U) {
1229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		++bits;
1230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		a <<= 1;
1231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		a  |= (b >> 31) & 1;
1232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		b <<= 1;
1233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		b  |= (c >> 31) & 1;
1234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		c <<= 1;
1235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		c  |= (d >> 31) & 1;
1236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		d <<= 1;
1237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (a != 0 || b != 0 || c != 0 || d != 0)
1239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return -1;
1240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return bits;
1241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static char buf[50+2];
1246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int l = ip6addr_prefix_length(addrp);
1247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (l == -1) {
1249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		strcpy(buf, "/");
1250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		strcat(buf, xtables_ip6addr_to_numeric(addrp));
1251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return buf;
1252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	sprintf(buf, "/%d", l);
1254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return buf;
1255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static struct in6_addr ap;
1260f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int err;
1261f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1262f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1263f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return &ap;
1264f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifdef DEBUG
1265f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1266f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
1267f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return NULL;
1268f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1269f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1270f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in6_addr *
1271f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orghost_to_ip6addr(const char *name, unsigned int *naddr)
1272f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1273f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static struct in6_addr *addr;
1274f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct addrinfo hints;
1275f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct addrinfo *res;
1276f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	int err;
1277f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1278f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memset(&hints, 0, sizeof(hints));
1279f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	hints.ai_flags    = AI_CANONNAME;
1280f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	hints.ai_family   = AF_INET6;
1281f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	hints.ai_socktype = SOCK_RAW;
1282f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	hints.ai_protocol = IPPROTO_IPV6;
1283f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	hints.ai_next     = NULL;
1284f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1285f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	*naddr = 0;
1286f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1287f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifdef DEBUG
1288f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1289f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
1290f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return NULL;
1291f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	} else {
1292f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (res->ai_family != AF_INET6 ||
1293f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1294f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return NULL;
1295f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1296f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifdef DEBUG
1297f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1298f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1299f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
1300f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* Get the first element of the address-chain */
1301f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addr = xtables_malloc(sizeof(struct in6_addr));
1302f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1303f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		       sizeof(struct in6_addr));
1304f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		freeaddrinfo(res);
1305f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*naddr = 1;
1306f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return addr;
1307f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1308f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1309f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return NULL;
1310f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1311f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1312f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in6_addr *network_to_ip6addr(const char *name)
1313f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1314f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/*	abort();*/
1315f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* TODO: not implemented yet, but the exception breaks the
1316f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	 *       name resolvation */
1317f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return NULL;
1318f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1319f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1320f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in6_addr *
1321f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1322f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1323f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct in6_addr *addrp, *addrptmp;
1324f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1325f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1326f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1327f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addrp = xtables_malloc(sizeof(struct in6_addr));
1328f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memcpy(addrp, addrptmp, sizeof(*addrp));
1329f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*naddrs = 1;
1330f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return addrp;
1331f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1332f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1333f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return addrp;
1334f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1335f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1336f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1337f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1338f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct in6_addr *parse_ip6mask(char *mask)
1339f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1340f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static struct in6_addr maskaddr;
1341f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct in6_addr *addrp;
1342f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int bits;
1343f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1344f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (mask == NULL) {
1345f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* no mask at all defaults to 128 bits */
1346f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(&maskaddr, 0xff, sizeof maskaddr);
1347f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return &maskaddr;
1348f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1349f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1350f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return addrp;
1351f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1352f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		xt_params->exit_err(PARAMETER_PROBLEM,
1353f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			   "invalid mask `%s' specified", mask);
1354f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (bits != 0) {
1355f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		char *p = (void *)&maskaddr;
1356f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(p, 0xff, bits / 8);
1357f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1358f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		p[bits/8] = 0xff << (8 - (bits & 7));
1359f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return &maskaddr;
1360f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1361f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1362f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memset(&maskaddr, 0, sizeof(maskaddr));
1363f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return &maskaddr;
1364f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1365f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1366f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1367f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          struct in6_addr *maskp, unsigned int *naddrs)
1368f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1369f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	struct in6_addr *addrp;
1370f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int i, j, k, n;
1371f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	char buf[256], *p;
1372f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1373f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	strncpy(buf, name, sizeof(buf) - 1);
1374f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	buf[sizeof(buf)-1] = '\0';
1375f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if ((p = strrchr(buf, '/')) != NULL) {
1376f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*p = '\0';
1377f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addrp = parse_ip6mask(p + 1);
1378f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	} else {
1379f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		addrp = parse_ip6mask(NULL);
1380f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1381f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	memcpy(maskp, addrp, sizeof(*maskp));
1382f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1383f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	/* if a null mask is given, the name is ignored, like in "any/0" */
1384f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1385f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		strcpy(buf, "::");
1386f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1387f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1388f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	n = *naddrs;
1389f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	for (i = 0, j = 0; i < n; ++i) {
1390f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (k = 0; k < 4; ++k)
1391f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1392f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		++j;
1393f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (k = 0; k < j - 1; ++k)
1394f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1395f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				--*naddrs;
1396f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				--j;
1397f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				break;
1398f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			}
1399f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1400f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1401f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1402f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid xtables_save_string(const char *value)
1403f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1404f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static const char no_quote_chars[] = "_-0123456789"
1405f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		"abcdefghijklmnopqrstuvwxyz"
1406f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1407f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	static const char escape_chars[] = "\"\\'";
1408f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	size_t length;
1409f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	const char *p;
1410f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1411f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	length = strcspn(value, no_quote_chars);
1412f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (length > 0 && value[length] == 0) {
1413f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* no quoting required */
1414f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fputs(value, stdout);
1415f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		putchar(' ');
1416f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	} else {
1417f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* there is at least one dangerous character in the
1418f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		   value, which we have to quote.  Write double quotes
1419f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		   around the value and escape special characters with
1420f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		   a backslash */
1421f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		putchar('"');
1422f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1423f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		for (p = strpbrk(value, escape_chars); p != NULL;
1424f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		     p = strpbrk(value, escape_chars)) {
1425f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (p > value)
1426f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				fwrite(value, 1, p - value, stdout);
1427f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			putchar('\\');
1428f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			putchar(*p);
1429f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			value = p + 1;
1430f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
1431f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1432f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* print the rest and finish the double quoted
1433f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		   string */
1434f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fputs(value, stdout);
1435f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		printf("\" ");
1436f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1437f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1438f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1439f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
1440f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Check for option-intrapositional negation.
1441f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Do not use in new code.
1442f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
1443f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint xtables_check_inverse(const char option[], int *invert,
1444f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			  int *my_optind, int argc)
1445f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1446f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (option && strcmp(option, "!") == 0) {
1447f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		fprintf(stderr, "Using intrapositioned negation "
1448f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        "(`--option ! this`) is deprecated in favor of "
1449f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		        "extrapositioned (`! --option this`).\n");
1450f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1451f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (*invert)
1452f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			xt_params->exit_err(PARAMETER_PROBLEM,
1453f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				   "Multiple `!' flags not allowed");
1454f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		*invert = true;
1455f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (my_optind != NULL) {
1456f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			++*my_optind;
1457f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (argc && *my_optind > argc)
1458f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				xt_params->exit_err(PARAMETER_PROBLEM,
1459f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					   "no argument following `!'");
1460f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
1461f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1462f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		return true;
1463f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1464f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return false;
1465f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1466f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1467f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst struct xtables_pprot xtables_chain_protos[] = {
1468f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"tcp",       IPPROTO_TCP},
1469f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"sctp",      IPPROTO_SCTP},
1470f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"udp",       IPPROTO_UDP},
1471f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"udplite",   IPPROTO_UDPLITE},
1472f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"icmp",      IPPROTO_ICMP},
1473f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"icmpv6",    IPPROTO_ICMPV6},
1474f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"ipv6-icmp", IPPROTO_ICMPV6},
1475f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"esp",       IPPROTO_ESP},
1476f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"ah",        IPPROTO_AH},
1477f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"ipv6-mh",   IPPROTO_MH},
1478f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"mh",        IPPROTO_MH},
1479f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{"all",       0},
1480f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	{NULL},
1481f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
1482f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1483f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgu_int16_t
1484f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgxtables_parse_protocol(const char *s)
1485f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1486f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	unsigned int proto;
1487f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1488f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	if (!xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) {
1489f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		struct protoent *pent;
1490f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1491f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		/* first deal with the special case of 'all' to prevent
1492f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		 * people from being able to redefine 'all' in nsswitch
1493f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		 * and/or provoke expensive [not working] ldap/nis/...
1494f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		 * lookups */
1495f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if (!strcmp(s, "all"))
1496f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			return 0;
1497f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1498f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		if ((pent = getprotobyname(s)))
1499f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			proto = pent->p_proto;
1500f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		else {
1501f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			unsigned int i;
1502f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
1503f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				if (strcmp(s, xtables_chain_protos[i].name) == 0) {
1504f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					proto = xtables_chain_protos[i].num;
1505f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					break;
1506f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				}
1507f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			}
1508f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org			if (i == ARRAY_SIZE(xtables_chain_protos))
1509f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org				xt_params->exit_err(PARAMETER_PROBLEM,
1510f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					   "unknown protocol `%s' specified",
1511f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org					   s);
1512f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org		}
1513f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	}
1514f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1515f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org	return proto;
1516f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1517f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org