xtables.c revision 84c3055bf08d0a8fe5db6e5f3f96dd826a290147
15208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI/*
25208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
35208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
45208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	This program is free software; you can redistribute it and/or modify
55208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	it under the terms of the GNU General Public License as published by
65208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	the Free Software Foundation; either version 2 of the License, or
75208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	(at your option) any later version.
85208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
95208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	This program is distributed in the hope that it will be useful,
105208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	but WITHOUT ANY WARRANTY; without even the implied warranty of
115208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
125208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	GNU General Public License for more details.
135208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
145208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	You should have received a copy of the GNU General Public License
155208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	along with this program; if not, write to the Free Software
165208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
175208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI */
185208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI
193dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <errno.h>
200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <fcntl.h>
2104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI#include <netdb.h>
22aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt#include <stdarg.h>
23cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt#include <stdbool.h>
243dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdio.h>
253dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdlib.h>
260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <string.h>
270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <unistd.h>
280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#include <sys/socket.h>
290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/stat.h>
300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/types.h>
310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/wait.h>
3208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#include <arpa/inet.h>
333dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
345208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI#include <xtables.h>
3577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
3677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
37ef18e8147903885708d1c264904129af4fb636d6Jan Engelhardt#include <libiptc/libxtc.h>
383dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
395a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
405a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
415a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
425a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#define NPROTO	255
440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#ifndef PROC_SYS_MODPROBE
460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
470b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#endif
480b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
498e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salimstruct xtables_globals *xt_params;
508e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim/**
518e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim * xtables_set_params - set the global parameters used by xtables
528e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim * @xtp:	input xtables_globals structure
538e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim *
548e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim * The app is expected to pass a valid xtables_globals data-filled
558e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim * with proper values
568e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim * @xtp cannot be NULL
578e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim *
588e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim * Returns -1 on failure to set and 0 on success
598e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim */
608e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salimint xtables_set_params(struct xtables_globals *xtp)
618e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim{
628e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim	if (!xtp) {
638e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim		fprintf(stderr, "%s: Illegal global params\n",__func__);
648e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim		return -1;
658e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim	}
668e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim
678e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim	xt_params = xtp;
688e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim	return 0;
698e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim}
708e90ce66a99e5dc9b055a9fd14e8e9216f90233cJamal Hadi Salim
7184c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salimvoid xtables_free_opts(int reset_offset, struct option *original_opts)
7284c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim{
7384c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim	if (xt_params->opts != original_opts) {
7484c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim		if (original_opts)
7584c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim			free(xt_params->opts);
7684c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim		xt_params->opts = original_opts;
7784c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim		if (reset_offset)
7884c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim			xt_params->option_offset = 0;
7984c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim	}
8084c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim}
8184c3055bf08d0a8fe5db6e5f3f96dd826a290147Jamal Hadi Salim
82dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt/**
8377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * xtables_afinfo - protocol family dependent information
8477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @kmod:		kernel module basename (e.g. "ip_tables")
8577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @libprefix:		prefix of .so library name (e.g. "libipt_")
8677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @family:		nfproto family
8777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @ipproto:		used by setsockopt (e.g. IPPROTO_IP)
8877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @so_rev_match:	optname to check revision support of match
8977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt * @so_rev_target:	optname to check revision support of target
9077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt */
9177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstruct xtables_afinfo {
9277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	const char *kmod;
9377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	const char *libprefix;
9477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	uint8_t family;
9577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	uint8_t ipproto;
9677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	int so_rev_match;
9777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	int so_rev_target;
9877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
9977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
10077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv4 = {
10177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip_tables",
10277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libipt_",
10377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family	       = NFPROTO_IPV4,
10477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IP,
10577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
10677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
10777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
10877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
10977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo afinfo_ipv6 = {
11077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.kmod          = "ip6_tables",
11177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.libprefix     = "libip6t_",
11277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.family        = NFPROTO_IPV6,
11377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.ipproto       = IPPROTO_IPV6,
11477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
11577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
11677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt};
11777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
11877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtstatic const struct xtables_afinfo *afinfo;
11977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
12077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt/**
121dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt * Program will set this to its own name.
122dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt */
123dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardtconst char *xtables_program_name;
124dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt
12539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt/* Search path for Xtables .so files */
12639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtstatic const char *xtables_libdir;
1270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
129c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtconst char *xtables_modprobe_program;
1300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI/* Keeping track of external matches and targets: linked lists.  */
1320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
1330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
1340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
13539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtvoid xtables_init(void)
13639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt{
13739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("XTABLES_LIBDIR");
13839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL)
13939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
14039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("IPTABLES_LIB_DIR");
14139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL) {
14239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
14339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		        "use XTABLES_LIBDIR.\n");
14439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
14539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	}
14639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = XTABLES_LIBDIR;
14739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt}
14839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt
14977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardtvoid xtables_set_nfproto(uint8_t nfproto)
15077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt{
15177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	switch (nfproto) {
15277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV4:
15377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv4;
15477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
15577f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	case NFPROTO_IPV6:
15677f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		afinfo = &afinfo_ipv6;
15777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		break;
15877f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	default:
15977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
16077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		        __func__);
16177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	}
16277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt}
16377f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt
164630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt/**
165630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt * xtables_*alloc - wrappers that exit on failure
166630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt */
167630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_calloc(size_t count, size_t size)
1683dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
1693dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
1703dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1713dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
1723dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
1733dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
1743dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
1753dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1763dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
1773dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
1783dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
179630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_malloc(size_t size)
1803dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
1813dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
1823dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1833dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
1843dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
1853dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
1863dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
1873dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1883dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
1893dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
1900b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1910b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
1920b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
1930b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
1940b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
1950b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1960b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROCFILE_BUFSIZ	1024
1970b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
1980b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
1990b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
2000b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2010b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	ret = (char *) malloc(PROCFILE_BUFSIZ);
2020b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
2030b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		memset(ret, 0, PROCFILE_BUFSIZ);
2040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
2050b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case -1: goto fail;
2060b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
2070b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
2080b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (ret[strlen(ret)-1]=='\n')
2090b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			ret[strlen(ret)-1]=0;
2100b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		close(procfile);
2110b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return ret;
2120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
2130b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI fail:
2140b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
2150b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
2160b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
2170b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
2180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
219c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
2200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
2210b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
2220b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
2230b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
2240b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2250b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
2260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
2270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
2280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
2290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
2300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
2310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
2320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	switch (fork()) {
2340b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
2350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
2360b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
2370b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
2380b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
2390b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
2400b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
2410b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
2420b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
2430b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
2440b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
2450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
2470b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
2480b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
2490b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
2500b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2510b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
2520b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
2530b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
2540b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
2550b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
2560b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
2570b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
2580b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
2590b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
2600b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
261c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_load_ko(const char *modprobe, bool quiet)
2620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
263c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	static bool loaded = false;
2640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	static int ret = -1;
2650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (!loaded) {
26777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
2680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		loaded = (ret == 0);
2690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
2700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
2720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
2730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
2745f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt/**
2755f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * xtables_strtou{i,l} - string to number conversion
2765f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @s:	input string
2775f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @end:	like strtoul's "end" pointer
2785f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @value:	pointer for result
2795f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @min:	minimum accepted value
2805f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @max:	maximum accepted value
2815f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt *
2825f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
2835f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * "15a" is rejected.
2845f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * In either case, the value obtained is compared for min-max compliance.
2855f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Base is always 0, i.e. autodetect depending on @s.
286cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
2875f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Returns true/false whether number was accepted. On failure, *value has
2885f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * undefined contents.
289cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
2905f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoul(const char *s, char **end, unsigned long *value,
2915f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned long min, unsigned long max)
292cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
293cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
294cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
295cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
296cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
297cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	v = strtoul(s, &my_end, 0);
298cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
299cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
300cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
301cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
302cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
303cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
304cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
305cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
306cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
307cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
308cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
309cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
310cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
311cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
312cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
313cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
314cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
3155f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoui(const char *s, char **end, unsigned int *value,
3165f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned int min, unsigned int max)
317cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
318cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
319cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
320cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
3215f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	ret = xtables_strtoul(s, end, &v, min, max);
322cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
323cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
324cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
325cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
326cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
327aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtint xtables_service_to_port(const char *name, const char *proto)
32804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
32904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
33004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
33104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
33204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
33304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
33404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
33504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
33604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
337aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtu_int16_t xtables_parse_port(const char *port, const char *proto)
33804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
3397a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
34004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
3415f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
342aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
343213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
34404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
34504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	exit_error(PARAMETER_PROBLEM,
34604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
34704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
34804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
349aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardtvoid xtables_parse_interface(const char *arg, char *vianame,
350aae6be9edc99e58164a3592c510fe5488141c698Jan Engelhardt			     unsigned char *mask)
35104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
35204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	int vialen = strlen(arg);
35304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
35404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
35504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
35604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
35704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
35804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
35904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
36004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
36104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
36204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
36304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
36404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
36504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0, IFNAMSIZ);
36604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
36704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
36804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
36904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
37004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
37104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
37204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
37304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
37404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
37504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			if (vianame[i] == ':' ||
37604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '!' ||
37704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '*') {
378aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
379aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
380aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					" `%s' (No aliases, :, ! or *).\n",
381aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
38204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
38304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
38404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
38504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
38604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
38704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
388cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
38921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardtstatic void *load_extension(const char *search_path, const char *prefix,
39021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
39121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
39221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
39321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
39421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
39521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
39621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
39721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
39821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
39921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
40021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
40121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
4022c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, name);
40321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
40421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
40521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			/* Found library.  If it didn't register itself,
40621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			   maybe they specified target as match. */
40721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
4082338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
40921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
4102338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
4112338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
41221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
41321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
41421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
41521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
41621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
41721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
41821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
41921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/%s%s.so",
4202c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, prefix, name);
42121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
42221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
4232338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
42421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
4252338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
4262338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
42721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
42821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
42921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
43021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
43121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
43221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
43321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
43421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
43521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
43621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
43721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
43821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
439cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
44021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
4412338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_match *
4422338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_match(const char *name, enum xtables_tryload tryload,
4432338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		   struct xtables_rule_match **matches)
4440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
4450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
4460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
4470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
4490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
4500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
4510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
4520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
4530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
4540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
4560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
4570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
4580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
4600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
4610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
4620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
464630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt			clone = xtables_malloc(sizeof(struct xtables_match));
4650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
4660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
4670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
4680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
4690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
4710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
4720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
4730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
4762338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
47777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
47839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, false);
479170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
4802338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
4810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
4820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
4830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
4840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
4860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
4872338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
4880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
4890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
4900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
4910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4922338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
4930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
4940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
4950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
4970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
4990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
5000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
5010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
502630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
5030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
5050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
5062338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				(*i)->completed = true;
5070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
5080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
5092338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		newentry->completed = false;
5100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
5110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
5120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
5150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5172338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_target *
5182338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_target(const char *name, enum xtables_tryload tryload)
5190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
5210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
5230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
5240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
5250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
5260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
5270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
5280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
5290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
5310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
5320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
5330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
5362338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
53777f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt		ptr = load_extension(xtables_libdir, afinfo->libprefix,
53839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, true);
539170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
5402338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
5410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
5420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
5430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
5440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
5460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
5472338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
5480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
5490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
5500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
5510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
5530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
5540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
5550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
5570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
5590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
5600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
5620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_revision(const char *name, u_int8_t revision, int opt)
5650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
5670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
5680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
5690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
57077f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
5710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
572df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
573df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
574df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
575df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy				fprintf(stderr, "Could not determine whether "
576df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
577df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
578df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy					revision);
579df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
580df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
5810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
5820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
5830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
586c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	xtables_load_ko(xtables_modprobe_program, true);
5870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
5890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
5900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
59177f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
5920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
5930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
5940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
5950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
5970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
5980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
6010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
6020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
6030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
6040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
6050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
6080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
6090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_match_revision(const char *name, u_int8_t revision)
6130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
61477f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_match);
6150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_target_revision(const char *name, u_int8_t revision)
6180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
61977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	return compatible_revision(name, revision, afinfo->so_rev_target);
6200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
6230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match **i, *old;
6250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
626dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
627dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
628dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
629dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
630dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
6310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
6360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
637dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
6420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
6430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
644dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
64977f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
6500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
6510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6522338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
6530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
65423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
65523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
6560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
6570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
658dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
6590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
6600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
6630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_match_revision(old->name, old->revision)
6640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
6650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
66723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
6680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_match_revision(me->name, me->revision))
6690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
67123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
67223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
67323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
67423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
6770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
6780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
6810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
682dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
6830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
6870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
6880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
6890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
6900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
6920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
6930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
6960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *old;
6980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
699dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
700dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
701dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
702dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
703dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
7040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
7080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
7090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
710dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
7110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
7150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
7160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
717dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
7180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
72277f48c2f1ef21fa43aa68c25a1457db319ca2526Jan Engelhardt	if (me->family != afinfo->family && me->family != AF_UNSPEC)
7230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
7240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7252338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_target(me->name, XTF_DURING_LOAD);
7260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
7270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
7280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
72923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
73023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
7310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
7320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
733dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
7340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
7350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
7360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
7380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_target_revision(old->name, old->revision)
7390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
7400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
7410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
74223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
7430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_target_revision(me->name, me->revision))
7440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
7450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
74623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
74723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
74823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
74923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
7500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
7510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
7520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
7530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
7560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
757dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
7580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
7590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
7600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
7610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
7620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
7630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
7640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
7650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
7660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
767aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
768a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt/**
769a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * xtables_param_act - act on condition
770a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @status:	a constant from enum xtables_exittype
771a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
772a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONLY_ONCE: print error message that option may only be used once.
773a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name (e.g. "mark")
774a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2(...):	option in conflict (e.g. "--mark")
775a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3(...):	condition to match on (see extensions/ for examples)
776a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
777a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_NO_INVERT: option does not support inversion
778a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
779a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option in conflict
780a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		condition to match on
781a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
782a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_BAD_VALUE: bad value for option
783a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
784a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option with which the problem occured (e.g. "--mark")
785a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		string the user passed in (e.g. "99999999999999")
786a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
787a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
788a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
789a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
790a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * Displays an error message and exits the program.
791a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt */
792a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid xtables_param_act(unsigned int status, const char *p1, ...)
793aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
794aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
795aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
796aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
797aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
798aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
799aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
800aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
801a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONLY_ONCE:
802aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
803aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
804aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
805aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
806aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
807aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
808aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
809aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
810a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_NO_INVERT:
811aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
812aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
813aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
814aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
815aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
816aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
817aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
818a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_BAD_VALUE:
819aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
820aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
821aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
822aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
823aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
824aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
825a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONE_ACTION:
826aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
827aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
828aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
829aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
830aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
831aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
832aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
833aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(status, p1, args);
834aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
835aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
836aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
837aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
838aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
83908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
840e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
84108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
84208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
84308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
84408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
84508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
84608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
84708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
84808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
84908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
85008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
85108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
85208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
85308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
85408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
85508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
85608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
85708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
85808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
85908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
86008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
86108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
86208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
86308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
86408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
86508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
86608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
86708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
86808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
86908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
870e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
87108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
87208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
87308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
87408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
87508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
87608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
87708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
878e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ipaddr_to_numeric(addr);
87908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
88008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
881e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
88208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
88308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
88408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
88508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
88608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
88708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
88808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
88908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
89008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* we don't want to see "/32" */
89108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return "";
89208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
89308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
89408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
89508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
89608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
89708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
89808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%d", i);
89908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	else
90008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
901e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
90208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
90308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
90408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
90508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
906bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
907bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
908bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
909bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
910bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
911bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
912bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
913bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
914bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
915bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
916bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
917bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
918bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
919bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
920bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
921bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
922bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
923bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
924bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
925bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
9265f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
927bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
928bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
929bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
930bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
931bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
932bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
933bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
934bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
935bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
936bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
9375f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
938bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
939bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
940bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
941bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
942bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
943bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
944bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
9455f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
946bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
947bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
948bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
949bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
950bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
951bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
9521e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
953bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
954bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
955bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
956bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
9571e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in_addr *xtables_numeric_to_ipmask(const char *dotted)
958bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
959bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
960bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
961bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
962bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
963bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
964bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
965bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
966bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
967bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
968bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
969bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
970bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
971bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
972bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
973bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
974bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
975bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
976bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
977bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
978bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
979bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
980bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
981bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
982bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
983bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
984bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
985bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
986bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
987bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
988bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
989bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
990bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
991630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
992bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
993bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
994bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
995bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
996bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
997bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
998bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
999bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1000bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1001bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
1002bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
1003bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1004bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
1005bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
10061e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1007bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1008630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in_addr));
1009bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1010bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1011bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1012bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1013bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1014bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
1015bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1016bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1017bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1018bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1019bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
1020bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1021bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
1022bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1023bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1024bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1025bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1026bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
1027bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
1028bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1029bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
10301e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1031bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
1032bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
10335f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1034bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
1035bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1036bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1037bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1038bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1039bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1040bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1041bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
1042bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1043bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1044bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1045a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt/**
1046a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * xtables_ipparse_any - transform arbitrary name to in_addr
1047a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt *
1048a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * Possible inputs (pseudo regex):
1049a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1050a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1051a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt */
1052a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1053a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                         struct in_addr *maskp, unsigned int *naddrs)
1054bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1055bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1056bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
1057bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1058bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1059bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1060bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
1061bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1062bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1063bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
1064bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1065bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
1066bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1067bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1068bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1069bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1070bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
1071bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
1072bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1073bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1074bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1075bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1076bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
1077bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1078bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1079bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1080bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1081bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1082bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1083bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1084bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1085bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1086e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
108708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
108808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	/* 0000:0000:0000:0000:0000:000.000.000.000
108908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
109008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
109108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
109208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
109308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
109408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
109508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
109608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
109708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
109808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
109908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
110108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
110208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
110308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
110408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
110508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
110608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
110708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
110808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
110908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
111008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
111108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
111208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
111308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
111408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
111508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
111608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
111708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
111808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1119e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
112008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
112108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
112208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
112308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
112408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
112508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1126e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ip6addr_to_numeric(addr);
112708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
112808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
112908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic int ip6addr_prefix_length(const struct in6_addr *k)
113008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
113108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
113208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
113308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
113448607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
113548607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
113648607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
113748607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
113808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
113908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
114008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
114108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
114208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
114308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
114408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
114508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
114608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
114708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
114808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
114908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
115008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
115108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
115208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1153e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
115408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
115508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
115608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int l = ip6addr_prefix_length(addrp);
115708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
115808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
115908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
1160e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		strcat(buf, xtables_ip6addr_to_numeric(addrp));
116108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
116208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
116308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "/%d", l);
116408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
116508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1166bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
11671e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardtstruct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1168bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1169bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1170bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1171bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1172bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1173bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1174bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1175bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1176bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1177bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1178bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1179bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1180bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1181bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1182bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1183bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr *addr;
1184bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
1185bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo *res;
1186bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1187bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1188bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1189bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1190bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1191bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1192bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_protocol = IPPROTO_IPV6;
1193bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_next     = NULL;
1194bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1195bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1196bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1197bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1198bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1199bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1200bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1201bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1202bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (res->ai_family != AF_INET6 ||
1203bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1204bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1205bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1206bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1207bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1208bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1209bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1210bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* Get the first element of the address-chain */
1211630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_malloc(sizeof(struct in6_addr));
1212bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1213bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		       sizeof(struct in6_addr));
1214bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1215bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddr = 1;
1216bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1217bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1218bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1219bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1220bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1221bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1222bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1223bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1224bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1225bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1226bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1227bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1228bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1229bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1230bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1231bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1232bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1233bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1234bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
12351e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1236bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1237630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in6_addr));
1238bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1239bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1240bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1241bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1242bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1243bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1244bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1245bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1246bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1247bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1248bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1249bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1250bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1251bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1252bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1253bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1254bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1255bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1256bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1257bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1258bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
12591e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1260bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
12615f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1262bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
1263bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1264bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1265bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1266bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1267bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1268bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1269bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1270bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1271bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1272bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1273bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1274bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1275bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1276a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1277a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardt                          struct in6_addr *maskp, unsigned int *naddrs)
1278bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1279bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1280bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1281bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1282bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1283bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1284bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1285bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1286bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1287bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1288bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1289bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1290bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1291bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1292bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1293bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1294bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1295bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1296bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1297bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1298bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1299bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1300bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
13015a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1302bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1303bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1304bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1305bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1306bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1307bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1308bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1309bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1310bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1311a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1312a0baae85f8159f03d52535934aa9b3a375e0f1f3Jan Engelhardtvoid xtables_save_string(const char *value)
1313a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1314a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1315a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1316a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1317a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1318a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1319a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1320a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1321a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	length = strcspn(value, no_quote_chars);
1322a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1323a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1324a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1325a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
1326a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1327a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1328a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1329a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1330a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
1331a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar('"');
1332a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1333a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1334a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1335a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1336a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1337a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1338a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1339a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1340a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1341a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1342a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1343a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1344a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1345a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		printf("\" ");
1346a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1347a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
13480f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13490f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt/**
13500f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Check for option-intrapositional negation.
13510f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt * Do not use in new code.
13520f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt */
13530f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardtint xtables_check_inverse(const char option[], int *invert,
13540f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			  int *my_optind, int argc)
13550f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt{
13560f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	if (option && strcmp(option, "!") == 0) {
13570f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		fprintf(stderr, "Using intrapositioned negation "
13580f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		        "(`--option ! this`) is deprecated in favor of "
13590f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		        "extrapositioned (`! --option this`).\n");
13600f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13610f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		if (*invert)
13620f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			exit_error(PARAMETER_PROBLEM,
13630f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt				   "Multiple `!' flags not allowed");
13640f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		*invert = true;
13650f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		if (my_optind != NULL) {
13660f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			++*my_optind;
13670f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt			if (argc && *my_optind > argc)
13680f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt				exit_error(PARAMETER_PROBLEM,
13690f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt					   "no argument following `!'");
13700f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		}
13710f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt
13720f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		return true;
13730f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	}
13740f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt	return false;
13750f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt}
13761de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13771de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtconst struct xtables_pprot xtables_chain_protos[] = {
13781de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"tcp",       IPPROTO_TCP},
13791de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"sctp",      IPPROTO_SCTP},
13801de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udp",       IPPROTO_UDP},
13811de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"udplite",   IPPROTO_UDPLITE},
13821de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmp",      IPPROTO_ICMP},
13831de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"icmpv6",    IPPROTO_ICMPV6},
13841de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-icmp", IPPROTO_ICMPV6},
13851de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"esp",       IPPROTO_ESP},
13861de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ah",        IPPROTO_AH},
13871de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"ipv6-mh",   IPPROTO_MH},
13881de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"mh",        IPPROTO_MH},
13891de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{"all",       0},
13901de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	{NULL},
13911de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt};
13921de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13931de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtu_int16_t
13941de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardtxtables_parse_protocol(const char *s)
13951de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt{
13961de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	unsigned int proto;
13971de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
13981de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	if (!xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) {
13991de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		struct protoent *pent;
14001de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
14011de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		/* first deal with the special case of 'all' to prevent
14021de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * people from being able to redefine 'all' in nsswitch
14031de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * and/or provoke expensive [not working] ldap/nis/...
14041de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		 * lookups */
14051de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		if (!strcmp(s, "all"))
14061de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			return 0;
14071de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
14081de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		if ((pent = getprotobyname(s)))
14091de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			proto = pent->p_proto;
14101de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		else {
14111de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			unsigned int i;
14121de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
14131de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				if (strcmp(s, xtables_chain_protos[i].name) == 0) {
14141de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					proto = xtables_chain_protos[i].num;
14151de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					break;
14161de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				}
14171de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			}
14181de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt			if (i == ARRAY_SIZE(xtables_chain_protos))
14191de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt				exit_error(PARAMETER_PROBLEM,
14201de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					   "unknown protocol `%s' specified",
14211de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt					   s);
14221de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt		}
14231de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	}
14241de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt
14251de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt	return proto;
14261de7edffc9085c0f41c261dca995e28ae4126c29Jan Engelhardt}
1427