xtables.c revision e55cc4aaa6e35448c14370e5261c3387d26b257d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	This program is free software; you can redistribute it and/or modify
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *	it under the terms of the GNU General Public License as published by
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	the Free Software Foundation; either version 2 of the License, or
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *	(at your option) any later version.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	This program is distributed in the hope that it will be useful,
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	but WITHOUT ANY WARRANTY; without even the implied warranty of
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *	GNU General Public License for more details.
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
145e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) *	You should have received a copy of the GNU General Public License
155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) *	along with this program; if not, write to the Free Software
167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netdb.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdarg.h>
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdbool.h>
247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <stdio.h>
257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <stdlib.h>
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <string.h>
277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <unistd.h>
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <sys/socket.h>
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/wait.h>
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <arpa/inet.h>
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <xtables.h>
357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <linux/netfilter_ipv4/ip_tables.h>
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/netfilter_ipv6/ip6_tables.h>
387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <libiptc/libxtc.h>
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NO_SHARED_LIBS
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dlfcn.h>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#	define IP6T_SO_GET_REVISION_MATCH	68
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#	define IP6T_SO_GET_REVISION_TARGET	69
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <getopt.h>
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NPROTO	255
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef PROC_SYS_MODPROBE
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct xtables_globals *xt_params = NULL;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	va_list args;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	va_start(args, msg);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	vfprintf(stderr, msg, args);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	va_end(args);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fprintf(stderr, "\n");
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	exit(status);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void xtables_free_opts(int reset_offset)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (xt_params->opts != xt_params->orig_opts) {
80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)		free(xt_params->opts);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		xt_params->opts = xt_params->orig_opts;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (reset_offset)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			xt_params->option_offset = 0;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct option *xtables_merge_options(struct option *oldopts,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				     const struct option *newopts,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				     unsigned int *option_offset)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int num_old, num_new, i;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct option *merge;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (newopts == NULL)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		return oldopts;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (num_old = 0; oldopts[num_old].name; num_old++) ;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (num_new = 0; newopts[num_new].name; num_new++) ;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xt_params->option_offset += 256;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	*option_offset = xt_params->option_offset;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (merge == NULL)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		return NULL;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	memcpy(merge, oldopts, num_old * sizeof(struct option));
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xtables_free_opts(0);	/* Release any old options merged  */
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < num_new; i++) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		merge[num_old + i] = newopts[i];
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		merge[num_old + i].val += *option_offset;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	memset(merge + num_old + num_new, 0, sizeof(struct option));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)	return merge;
1157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void xtables_set_revision(char *name, u_int8_t revision)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	/* Old kernel sources don't have ".revision" field,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	*            but we stole a byte from name. */
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	name[XT_FUNCTION_MAXNAMELEN - 2] = '\0';
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	name[XT_FUNCTION_MAXNAMELEN - 1] = revision;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * xtables_afinfo - protocol family dependent information
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @kmod:		kernel module basename (e.g. "ip_tables")
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @libprefix:		prefix of .so library name (e.g. "libipt_")
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @family:		nfproto family
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @ipproto:		used by setsockopt (e.g. IPPROTO_IP)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @so_rev_match:	optname to check revision support of match
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @so_rev_target:	optname to check revision support of target
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)struct xtables_afinfo {
1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	const char *kmod;
1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	const char *libprefix;
1377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	uint8_t family;
1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	uint8_t ipproto;
1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	int so_rev_match;
1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	int so_rev_target;
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)};
1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static const struct xtables_afinfo afinfo_ipv4 = {
1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.kmod          = "ip_tables",
1457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.libprefix     = "libipt_",
1467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.family	       = NFPROTO_IPV4,
1477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.ipproto       = IPPROTO_IP,
1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)};
1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static const struct xtables_afinfo afinfo_ipv6 = {
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.kmod          = "ip6_tables",
1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.libprefix     = "libip6t_",
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.family        = NFPROTO_IPV6,
1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.ipproto       = IPPROTO_IPV6,
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)};
1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static const struct xtables_afinfo *afinfo;
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)/* Search path for Xtables .so files */
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static const char *xtables_libdir;
1657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)/* the path to command to load kernel module */
1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const char *xtables_modprobe_program;
1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)/* Keeping track of external matches and targets: linked lists.  */
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)struct xtables_match *xtables_matches;
1717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)struct xtables_target *xtables_targets;
1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void xtables_init(void)
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles){
1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	xtables_libdir = getenv("XTABLES_LIBDIR");
1767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	if (xtables_libdir != NULL)
1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		return;
1787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	xtables_libdir = getenv("IPTABLES_LIB_DIR");
1797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	if (xtables_libdir != NULL) {
1807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
1817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		        "use XTABLES_LIBDIR.\n");
1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		return;
1837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	}
1847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	/*
1857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
1867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * for these env vars are deprecated anyhow, and in light of the
1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * (shared) libxt_*.so files, makes less sense to have
1897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 */
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (xtables_libdir != NULL) {
1937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		        "use XTABLES_LIBDIR.\n");
1957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		return;
1967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	}
1977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	xtables_libdir = XTABLES_LIBDIR;
1987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void xtables_set_nfproto(uint8_t nfproto)
2017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles){
2027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	switch (nfproto) {
2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	case NFPROTO_IPV4:
2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		afinfo = &afinfo_ipv4;
2057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		break;
2067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	case NFPROTO_IPV6:
2077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		afinfo = &afinfo_ipv6;
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		break;
2097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	default:
2107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		        __func__);
2127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	}
2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)/**
2167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * xtables_set_params - set the global parameters used by xtables
2177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * @xtp:	input xtables_globals structure
2187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) *
2197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * The app is expected to pass a valid xtables_globals data-filled
2207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * with proper values
2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * @xtp cannot be NULL
2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) *
2237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * Returns -1 on failure to set and 0 on success
2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) */
2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int xtables_set_params(struct xtables_globals *xtp)
2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles){
2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	if (!xtp) {
2287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		fprintf(stderr, "%s: Illegal global params\n",__func__);
2297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		return -1;
2307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	}
2317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	xt_params = xtp;
2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	if (!xt_params->exit_err)
2357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		xt_params->exit_err = basic_exit_err;
2367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	return 0;
2387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
2417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles){
2427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	xtables_init();
2437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	xtables_set_nfproto(nfproto);
2447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	return xtables_set_params(xtp);
2457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)/**
2487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * xtables_*alloc - wrappers that exit on failure
2497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) */
2507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void *xtables_calloc(size_t count, size_t size)
2517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles){
2527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	void *p;
2537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	if ((p = calloc(count, size)) == NULL) {
2557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		perror("ip[6]tables: calloc failed");
2567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		exit(1);
2577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	}
2587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	return p;
2607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void *xtables_malloc(size_t size)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	void *p;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if ((p = malloc(size)) == NULL) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		perror("ip[6]tables: malloc failed");
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		exit(1);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return p;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char *get_modprobe(void)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int procfile;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *ret;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PROCFILE_BUFSIZ	1024
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (procfile < 0)
2821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		return NULL;
2831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	ret = (char *) malloc(PROCFILE_BUFSIZ);
2851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	if (ret) {
2861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		memset(ret, 0, PROCFILE_BUFSIZ);
2871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
2881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		case -1: goto fail;
2891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
2901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (ret[strlen(ret)-1]=='\n')
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ret[strlen(ret)-1]=0;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		close(procfile);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return ret;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fail:
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	free(ret);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	close(procfile);
299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)	return NULL;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *buf = NULL;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *argv[4];
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int status;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* If they don't explicitly set it, read out of kernel */
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!modprobe) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		buf = get_modprobe();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (!buf)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return -1;
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		modprobe = buf;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Need to flush the buffer, or the child may output it again
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * when switching the program thru execv.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fflush(stdout);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (fork()) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case 0:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		argv[0] = (char *)modprobe;
325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)		argv[1] = (char *)modname;
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		if (quiet) {
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			argv[2] = "-q";
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			argv[3] = NULL;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		} else {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			argv[2] = NULL;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			argv[3] = NULL;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		execv(argv[0], argv);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		/* not usually reached */
3361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		exit(1);
3371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	case -1:
3381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		return -1;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default: /* parent */
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		wait(&status);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	free(buf);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return -1;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int xtables_load_ko(const char *modprobe, bool quiet)
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	static bool loaded = false;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	static int ret = -1;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!loaded) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		loaded = (ret == 0);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return ret;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * xtables_strtou{i,l} - string to number conversion
3651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * @s:	input string
3661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * @end:	like strtoul's "end" pointer
3671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * @value:	pointer for result
3681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * @min:	minimum accepted value
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @max:	maximum accepted value
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "15a" is rejected.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * In either case, the value obtained is compared for min-max compliance.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Base is always 0, i.e. autodetect depending on @s.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns true/false whether number was accepted. On failure, *value has
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * undefined contents.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool xtables_strtoul(const char *s, char **end, unsigned long *value,
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     unsigned long min, unsigned long max)
381868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned long v;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *my_end;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	errno = 0;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	v = strtoul(s, &my_end, 0);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (my_end == s)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return false;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (end != NULL)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		*end = my_end;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (value != NULL)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			*value = v;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (end == NULL)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return *my_end == '\0';
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return true;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return false;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool xtables_strtoui(const char *s, char **end, unsigned int *value,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     unsigned int min, unsigned int max)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned long v;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	bool ret;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ret = xtables_strtoul(s, end, &v, min, max);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (value != NULL)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		*value = v;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return ret;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int xtables_service_to_port(const char *name, const char *proto)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct servent *service;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if ((service = getservbyname(name, proto)) != NULL)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return ntohs((unsigned short) service->s_port);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return -1;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)u_int16_t xtables_parse_port(const char *port, const char *proto)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int portnum;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return portnum;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xt_params->exit_err(PARAMETER_PROBLEM,
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		   "invalid port/service `%s' specified", port);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void xtables_parse_interface(const char *arg, char *vianame,
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			     unsigned char *mask)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
441	int vialen = strlen(arg);
442	unsigned int i;
443
444	memset(mask, 0, IFNAMSIZ);
445	memset(vianame, 0, IFNAMSIZ);
446
447	if (vialen + 1 > IFNAMSIZ)
448		xt_params->exit_err(PARAMETER_PROBLEM,
449			   "interface name `%s' must be shorter than IFNAMSIZ"
450			   " (%i)", arg, IFNAMSIZ-1);
451
452	strcpy(vianame, arg);
453	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
454		memset(mask, 0, IFNAMSIZ);
455	else if (vianame[vialen - 1] == '+') {
456		memset(mask, 0xFF, vialen - 1);
457		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
458		/* Don't remove `+' here! -HW */
459	} else {
460		/* Include nul-terminator in match */
461		memset(mask, 0xFF, vialen + 1);
462		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
463		for (i = 0; vianame[i]; i++) {
464			if (vianame[i] == ':' ||
465			    vianame[i] == '!' ||
466			    vianame[i] == '*') {
467				fprintf(stderr,
468					"Warning: weird character in interface"
469					" `%s' (No aliases, :, ! or *).\n",
470					vianame);
471				break;
472			}
473		}
474	}
475}
476
477#ifndef NO_SHARED_LIBS
478static void *load_extension(const char *search_path, const char *prefix,
479    const char *name, bool is_target)
480{
481	const char *dir = search_path, *next;
482	void *ptr = NULL;
483	struct stat sb;
484	char path[256];
485
486	do {
487		next = strchr(dir, ':');
488		if (next == NULL)
489			next = dir + strlen(dir);
490		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
491		         (unsigned int)(next - dir), dir, name);
492
493		if (dlopen(path, RTLD_NOW) != NULL) {
494			/* Found library.  If it didn't register itself,
495			   maybe they specified target as match. */
496			if (is_target)
497				ptr = xtables_find_target(name, XTF_DONT_LOAD);
498			else
499				ptr = xtables_find_match(name,
500				      XTF_DONT_LOAD, NULL);
501		} else if (stat(path, &sb) == 0) {
502			fprintf(stderr, "%s: %s\n", path, dlerror());
503		}
504
505		if (ptr != NULL)
506			return ptr;
507
508		snprintf(path, sizeof(path), "%.*s/%s%s.so",
509		         (unsigned int)(next - dir), dir, prefix, name);
510		if (dlopen(path, RTLD_NOW) != NULL) {
511			if (is_target)
512				ptr = xtables_find_target(name, XTF_DONT_LOAD);
513			else
514				ptr = xtables_find_match(name,
515				      XTF_DONT_LOAD, NULL);
516		} else if (stat(path, &sb) == 0) {
517			fprintf(stderr, "%s: %s\n", path, dlerror());
518		}
519
520		if (ptr != NULL)
521			return ptr;
522
523		dir = next + 1;
524	} while (*next != '\0');
525
526	return NULL;
527}
528#endif
529
530struct xtables_match *
531xtables_find_match(const char *name, enum xtables_tryload tryload,
532		   struct xtables_rule_match **matches)
533{
534	struct xtables_match *ptr;
535	const char *icmp6 = "icmp6";
536
537	/* This is ugly as hell. Nonetheless, there is no way of changing
538	 * this without hurting backwards compatibility */
539	if ( (strcmp(name,"icmpv6") == 0) ||
540	     (strcmp(name,"ipv6-icmp") == 0) ||
541	     (strcmp(name,"icmp6") == 0) )
542		name = icmp6;
543
544	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
545		if (strcmp(name, ptr->name) == 0) {
546			struct xtables_match *clone;
547
548			/* First match of this type: */
549			if (ptr->m == NULL)
550				break;
551
552			/* Second and subsequent clones */
553			clone = xtables_malloc(sizeof(struct xtables_match));
554			memcpy(clone, ptr, sizeof(struct xtables_match));
555			clone->mflags = 0;
556			/* This is a clone: */
557			clone->next = clone;
558
559			ptr = clone;
560			break;
561		}
562	}
563
564#ifndef NO_SHARED_LIBS
565	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
566		ptr = load_extension(xtables_libdir, afinfo->libprefix,
567		      name, false);
568
569		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
570			xt_params->exit_err(PARAMETER_PROBLEM,
571				   "Couldn't load match `%s':%s\n",
572				   name, dlerror());
573	}
574#else
575	if (ptr && !ptr->loaded) {
576		if (tryload != XTF_DONT_LOAD)
577			ptr->loaded = 1;
578		else
579			ptr = NULL;
580	}
581	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
582		xt_params->exit_err(PARAMETER_PROBLEM,
583			   "Couldn't find match `%s'\n", name);
584	}
585#endif
586
587	if (ptr && matches) {
588		struct xtables_rule_match **i;
589		struct xtables_rule_match *newentry;
590
591		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
592
593		for (i = matches; *i; i = &(*i)->next) {
594			if (strcmp(name, (*i)->match->name) == 0)
595				(*i)->completed = true;
596		}
597		newentry->match = ptr;
598		newentry->completed = false;
599		newentry->next = NULL;
600		*i = newentry;
601	}
602
603	return ptr;
604}
605
606struct xtables_target *
607xtables_find_target(const char *name, enum xtables_tryload tryload)
608{
609	struct xtables_target *ptr;
610
611	/* Standard target? */
612	if (strcmp(name, "") == 0
613	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
614	    || strcmp(name, XTC_LABEL_DROP) == 0
615	    || strcmp(name, XTC_LABEL_QUEUE) == 0
616	    || strcmp(name, XTC_LABEL_RETURN) == 0)
617		name = "standard";
618
619	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
620		if (strcmp(name, ptr->name) == 0)
621			break;
622	}
623
624#ifndef NO_SHARED_LIBS
625	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
626		ptr = load_extension(xtables_libdir, afinfo->libprefix,
627		      name, true);
628
629		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
630			xt_params->exit_err(PARAMETER_PROBLEM,
631				   "Couldn't load target `%s':%s\n",
632				   name, dlerror());
633	}
634#else
635	if (ptr && !ptr->loaded) {
636		if (tryload != XTF_DONT_LOAD)
637			ptr->loaded = 1;
638		else
639			ptr = NULL;
640	}
641	if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
642		xt_params->exit_err(PARAMETER_PROBLEM,
643			   "Couldn't find target `%s'\n", name);
644	}
645#endif
646
647	if (ptr)
648		ptr->used = 1;
649
650	return ptr;
651}
652
653static int compatible_revision(const char *name, u_int8_t revision, int opt)
654{
655	struct xt_get_revision rev;
656	socklen_t s = sizeof(rev);
657	int max_rev, sockfd;
658
659	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
660	if (sockfd < 0) {
661		if (errno == EPERM) {
662			/* revision 0 is always supported. */
663			if (revision != 0)
664				fprintf(stderr, "Could not determine whether "
665						"revision %u is supported, "
666						"assuming it is.\n",
667					revision);
668			return 1;
669		}
670		fprintf(stderr, "Could not open socket to kernel: %s\n",
671			strerror(errno));
672		exit(1);
673	}
674
675	xtables_load_ko(xtables_modprobe_program, true);
676
677	strcpy(rev.name, name);
678	rev.revision = revision;
679
680	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
681	if (max_rev < 0) {
682		/* Definitely don't support this? */
683		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
684			close(sockfd);
685			return 0;
686		} else if (errno == ENOPROTOOPT) {
687			close(sockfd);
688			/* Assume only revision 0 support (old kernel) */
689			return (revision == 0);
690		} else {
691			fprintf(stderr, "getsockopt failed strangely: %s\n",
692				strerror(errno));
693			exit(1);
694		}
695	}
696	close(sockfd);
697	return 1;
698}
699
700
701static int compatible_match_revision(const char *name, u_int8_t revision)
702{
703	return compatible_revision(name, revision, afinfo->so_rev_match);
704}
705
706static int compatible_target_revision(const char *name, u_int8_t revision)
707{
708	return compatible_revision(name, revision, afinfo->so_rev_target);
709}
710
711void xtables_register_match(struct xtables_match *me)
712{
713	struct xtables_match **i, *old;
714
715	if (strcmp(me->version, XTABLES_VERSION) != 0) {
716		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
717		        "but \"%s\" is required.\n",
718			xt_params->program_name, me->name,
719			me->version, XTABLES_VERSION);
720		exit(1);
721	}
722
723	/* Revision field stole a char from name. */
724	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
725		fprintf(stderr, "%s: target `%s' has invalid name\n",
726			xt_params->program_name, me->name);
727		exit(1);
728	}
729
730	if (me->family >= NPROTO) {
731		fprintf(stderr,
732			"%s: BUG: match %s has invalid protocol family\n",
733			xt_params->program_name, me->name);
734		exit(1);
735	}
736
737	/* ignore not interested match */
738	if (me->family != afinfo->family && me->family != AF_UNSPEC)
739		return;
740
741	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
742	if (old) {
743		if (old->revision == me->revision &&
744		    old->family == me->family) {
745			fprintf(stderr,
746				"%s: match `%s' already registered.\n",
747				xt_params->program_name, me->name);
748			exit(1);
749		}
750
751		/* Now we have two (or more) options, check compatibility. */
752		if (compatible_match_revision(old->name, old->revision)
753		    && old->revision > me->revision)
754			return;
755
756		/* See if new match can be used. */
757		if (!compatible_match_revision(me->name, me->revision))
758			return;
759
760		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
761		if (old->revision == me->revision && me->family == AF_UNSPEC)
762			return;
763
764		/* Delete old one. */
765		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
766		*i = old->next;
767	}
768
769	if (me->size != XT_ALIGN(me->size)) {
770		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
771		        xt_params->program_name, me->name,
772		        (unsigned int)me->size);
773		exit(1);
774	}
775
776	/* Append to list. */
777	for (i = &xtables_matches; *i; i = &(*i)->next);
778	me->next = NULL;
779	*i = me;
780
781	me->m = NULL;
782	me->mflags = 0;
783}
784
785void xtables_register_target(struct xtables_target *me)
786{
787	struct xtables_target *old;
788
789	if (strcmp(me->version, XTABLES_VERSION) != 0) {
790		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
791		        "but \"%s\" is required.\n",
792			xt_params->program_name, me->name,
793			me->version, XTABLES_VERSION);
794		exit(1);
795	}
796
797	/* Revision field stole a char from name. */
798	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
799		fprintf(stderr, "%s: target `%s' has invalid name\n",
800			xt_params->program_name, me->name);
801		exit(1);
802	}
803
804	if (me->family >= NPROTO) {
805		fprintf(stderr,
806			"%s: BUG: target %s has invalid protocol family\n",
807			xt_params->program_name, me->name);
808		exit(1);
809	}
810
811	/* ignore not interested target */
812	if (me->family != afinfo->family && me->family != AF_UNSPEC)
813		return;
814
815	old = xtables_find_target(me->name, XTF_DURING_LOAD);
816	if (old) {
817		struct xtables_target **i;
818
819		if (old->revision == me->revision &&
820		    old->family == me->family) {
821			fprintf(stderr,
822				"%s: target `%s' already registered.\n",
823				xt_params->program_name, me->name);
824			exit(1);
825		}
826
827		/* Now we have two (or more) options, check compatibility. */
828		if (compatible_target_revision(old->name, old->revision)
829		    && old->revision > me->revision)
830			return;
831
832		/* See if new target can be used. */
833		if (!compatible_target_revision(me->name, me->revision))
834			return;
835
836		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
837		if (old->revision == me->revision && me->family == AF_UNSPEC)
838			return;
839
840		/* Delete old one. */
841		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
842		*i = old->next;
843	}
844
845	if (me->size != XT_ALIGN(me->size)) {
846		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
847		        xt_params->program_name, me->name,
848		        (unsigned int)me->size);
849		exit(1);
850	}
851
852	/* Prepend to list. */
853	me->next = xtables_targets;
854	xtables_targets = me;
855	me->t = NULL;
856	me->tflags = 0;
857}
858
859/**
860 * xtables_param_act - act on condition
861 * @status:	a constant from enum xtables_exittype
862 *
863 * %XTF_ONLY_ONCE: print error message that option may only be used once.
864 * @p1:		module name (e.g. "mark")
865 * @p2(...):	option in conflict (e.g. "--mark")
866 * @p3(...):	condition to match on (see extensions/ for examples)
867 *
868 * %XTF_NO_INVERT: option does not support inversion
869 * @p1:		module name
870 * @p2:		option in conflict
871 * @p3:		condition to match on
872 *
873 * %XTF_BAD_VALUE: bad value for option
874 * @p1:		module name
875 * @p2:		option with which the problem occured (e.g. "--mark")
876 * @p3:		string the user passed in (e.g. "99999999999999")
877 *
878 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
879 * @p1:		module name
880 *
881 * Displays an error message and exits the program.
882 */
883void xtables_param_act(unsigned int status, const char *p1, ...)
884{
885	const char *p2, *p3;
886	va_list args;
887	bool b;
888
889	va_start(args, p1);
890
891	switch (status) {
892	case XTF_ONLY_ONCE:
893		p2 = va_arg(args, const char *);
894		b  = va_arg(args, unsigned int);
895		if (!b)
896			return;
897		xt_params->exit_err(PARAMETER_PROBLEM,
898		           "%s: \"%s\" option may only be specified once",
899		           p1, p2);
900		break;
901	case XTF_NO_INVERT:
902		p2 = va_arg(args, const char *);
903		b  = va_arg(args, unsigned int);
904		if (!b)
905			return;
906		xt_params->exit_err(PARAMETER_PROBLEM,
907		           "%s: \"%s\" option cannot be inverted", p1, p2);
908		break;
909	case XTF_BAD_VALUE:
910		p2 = va_arg(args, const char *);
911		p3 = va_arg(args, const char *);
912		xt_params->exit_err(PARAMETER_PROBLEM,
913		           "%s: Bad value for \"%s\" option: \"%s\"",
914		           p1, p2, p3);
915		break;
916	case XTF_ONE_ACTION:
917		b = va_arg(args, unsigned int);
918		if (!b)
919			return;
920		xt_params->exit_err(PARAMETER_PROBLEM,
921		           "%s: At most one action is possible", p1);
922		break;
923	default:
924		xt_params->exit_err(status, p1, args);
925		break;
926	}
927
928	va_end(args);
929}
930
931const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
932{
933	static char buf[20];
934	const unsigned char *bytep = (const void *)&addrp->s_addr;
935
936	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
937	return buf;
938}
939
940static const char *ipaddr_to_host(const struct in_addr *addr)
941{
942	struct hostent *host;
943
944	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
945	if (host == NULL)
946		return NULL;
947
948	return host->h_name;
949}
950
951static const char *ipaddr_to_network(const struct in_addr *addr)
952{
953	struct netent *net;
954
955	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
956		return net->n_name;
957
958	return NULL;
959}
960
961const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
962{
963	const char *name;
964
965	if ((name = ipaddr_to_host(addr)) != NULL ||
966	    (name = ipaddr_to_network(addr)) != NULL)
967		return name;
968
969	return xtables_ipaddr_to_numeric(addr);
970}
971
972const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
973{
974	static char buf[20];
975	uint32_t maskaddr, bits;
976	int i;
977
978	maskaddr = ntohl(mask->s_addr);
979
980	if (maskaddr == 0xFFFFFFFFL)
981		/* we don't want to see "/32" */
982		return "";
983
984	i = 32;
985	bits = 0xFFFFFFFEL;
986	while (--i >= 0 && maskaddr != bits)
987		bits <<= 1;
988	if (i >= 0)
989		sprintf(buf, "/%d", i);
990	else
991		/* mask was not a decent combination of 1's and 0's */
992		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
993
994	return buf;
995}
996
997static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
998{
999	static struct in_addr addr;
1000	unsigned char *addrp;
1001	unsigned int onebyte;
1002	char buf[20], *p, *q;
1003	int i;
1004
1005	/* copy dotted string, because we need to modify it */
1006	strncpy(buf, dotted, sizeof(buf) - 1);
1007	buf[sizeof(buf) - 1] = '\0';
1008	addrp = (void *)&addr.s_addr;
1009
1010	p = buf;
1011	for (i = 0; i < 3; ++i) {
1012		if ((q = strchr(p, '.')) == NULL) {
1013			if (is_mask)
1014				return NULL;
1015
1016			/* autocomplete, this is a network address */
1017			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1018				return NULL;
1019
1020			addrp[i] = onebyte;
1021			while (i < 3)
1022				addrp[++i] = 0;
1023
1024			return &addr;
1025		}
1026
1027		*q = '\0';
1028		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1029			return NULL;
1030
1031		addrp[i] = onebyte;
1032		p = q + 1;
1033	}
1034
1035	/* we have checked 3 bytes, now we check the last one */
1036	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1037		return NULL;
1038
1039	addrp[3] = onebyte;
1040	return &addr;
1041}
1042
1043struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1044{
1045	return __numeric_to_ipaddr(dotted, false);
1046}
1047
1048struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1049{
1050	return __numeric_to_ipaddr(dotted, true);
1051}
1052
1053static struct in_addr *network_to_ipaddr(const char *name)
1054{
1055	static struct in_addr addr;
1056	struct netent *net;
1057
1058	if ((net = getnetbyname(name)) != NULL) {
1059		if (net->n_addrtype != AF_INET)
1060			return NULL;
1061		addr.s_addr = htonl(net->n_net);
1062		return &addr;
1063	}
1064
1065	return NULL;
1066}
1067
1068static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1069{
1070	struct hostent *host;
1071	struct in_addr *addr;
1072	unsigned int i;
1073
1074	*naddr = 0;
1075	if ((host = gethostbyname(name)) != NULL) {
1076		if (host->h_addrtype != AF_INET ||
1077		    host->h_length != sizeof(struct in_addr))
1078			return NULL;
1079
1080		while (host->h_addr_list[*naddr] != NULL)
1081			++*naddr;
1082		addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
1083		for (i = 0; i < *naddr; i++)
1084			memcpy(&addr[i], host->h_addr_list[i],
1085			       sizeof(struct in_addr));
1086		return addr;
1087	}
1088
1089	return NULL;
1090}
1091
1092static struct in_addr *
1093ipparse_hostnetwork(const char *name, unsigned int *naddrs)
1094{
1095	struct in_addr *addrptmp, *addrp;
1096
1097	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1098	    (addrptmp = network_to_ipaddr(name)) != NULL) {
1099		addrp = xtables_malloc(sizeof(struct in_addr));
1100		memcpy(addrp, addrptmp, sizeof(*addrp));
1101		*naddrs = 1;
1102		return addrp;
1103	}
1104	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1105		return addrptmp;
1106
1107	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1108}
1109
1110static struct in_addr *parse_ipmask(const char *mask)
1111{
1112	static struct in_addr maskaddr;
1113	struct in_addr *addrp;
1114	unsigned int bits;
1115
1116	if (mask == NULL) {
1117		/* no mask at all defaults to 32 bits */
1118		maskaddr.s_addr = 0xFFFFFFFF;
1119		return &maskaddr;
1120	}
1121	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1122		/* dotted_to_addr already returns a network byte order addr */
1123		return addrp;
1124	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1125		xt_params->exit_err(PARAMETER_PROBLEM,
1126			   "invalid mask `%s' specified", mask);
1127	if (bits != 0) {
1128		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1129		return &maskaddr;
1130	}
1131
1132	maskaddr.s_addr = 0U;
1133	return &maskaddr;
1134}
1135
1136/**
1137 * xtables_ipparse_any - transform arbitrary name to in_addr
1138 *
1139 * Possible inputs (pseudo regex):
1140 * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1141 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1142 */
1143void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1144                         struct in_addr *maskp, unsigned int *naddrs)
1145{
1146	unsigned int i, j, k, n;
1147	struct in_addr *addrp;
1148	char buf[256], *p;
1149
1150	strncpy(buf, name, sizeof(buf) - 1);
1151	buf[sizeof(buf) - 1] = '\0';
1152	if ((p = strrchr(buf, '/')) != NULL) {
1153		*p = '\0';
1154		addrp = parse_ipmask(p + 1);
1155	} else {
1156		addrp = parse_ipmask(NULL);
1157	}
1158	memcpy(maskp, addrp, sizeof(*maskp));
1159
1160	/* if a null mask is given, the name is ignored, like in "any/0" */
1161	if (maskp->s_addr == 0U)
1162		strcpy(buf, "0.0.0.0");
1163
1164	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1165	n = *naddrs;
1166	for (i = 0, j = 0; i < n; ++i) {
1167		addrp[j++].s_addr &= maskp->s_addr;
1168		for (k = 0; k < j - 1; ++k)
1169			if (addrp[k].s_addr == addrp[j-1].s_addr) {
1170				--*naddrs;
1171				--j;
1172				break;
1173			}
1174	}
1175}
1176
1177const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1178{
1179	/* 0000:0000:0000:0000:0000:000.000.000.000
1180	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
1181	static char buf[50+1];
1182	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1183}
1184
1185static const char *ip6addr_to_host(const struct in6_addr *addr)
1186{
1187	static char hostname[NI_MAXHOST];
1188	struct sockaddr_in6 saddr;
1189	int err;
1190
1191	memset(&saddr, 0, sizeof(struct sockaddr_in6));
1192	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1193	saddr.sin6_family = AF_INET6;
1194
1195	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1196	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
1197	if (err != 0) {
1198#ifdef DEBUG
1199		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
1200#endif
1201		return NULL;
1202	}
1203
1204#ifdef DEBUG
1205	fprintf (stderr, "\naddr2host: %s\n", hostname);
1206#endif
1207	return hostname;
1208}
1209
1210const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1211{
1212	const char *name;
1213
1214	if ((name = ip6addr_to_host(addr)) != NULL)
1215		return name;
1216
1217	return xtables_ip6addr_to_numeric(addr);
1218}
1219
1220static int ip6addr_prefix_length(const struct in6_addr *k)
1221{
1222	unsigned int bits = 0;
1223	uint32_t a, b, c, d;
1224
1225	a = ntohl(k->s6_addr32[0]);
1226	b = ntohl(k->s6_addr32[1]);
1227	c = ntohl(k->s6_addr32[2]);
1228	d = ntohl(k->s6_addr32[3]);
1229	while (a & 0x80000000U) {
1230		++bits;
1231		a <<= 1;
1232		a  |= (b >> 31) & 1;
1233		b <<= 1;
1234		b  |= (c >> 31) & 1;
1235		c <<= 1;
1236		c  |= (d >> 31) & 1;
1237		d <<= 1;
1238	}
1239	if (a != 0 || b != 0 || c != 0 || d != 0)
1240		return -1;
1241	return bits;
1242}
1243
1244const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1245{
1246	static char buf[50+2];
1247	int l = ip6addr_prefix_length(addrp);
1248
1249	if (l == -1) {
1250		strcpy(buf, "/");
1251		strcat(buf, xtables_ip6addr_to_numeric(addrp));
1252		return buf;
1253	}
1254	sprintf(buf, "/%d", l);
1255	return buf;
1256}
1257
1258struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1259{
1260	static struct in6_addr ap;
1261	int err;
1262
1263	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1264		return &ap;
1265#ifdef DEBUG
1266	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1267#endif
1268	return NULL;
1269}
1270
1271static struct in6_addr *
1272host_to_ip6addr(const char *name, unsigned int *naddr)
1273{
1274	static struct in6_addr *addr;
1275	struct addrinfo hints;
1276	struct addrinfo *res;
1277	int err;
1278
1279	memset(&hints, 0, sizeof(hints));
1280	hints.ai_flags    = AI_CANONNAME;
1281	hints.ai_family   = AF_INET6;
1282	hints.ai_socktype = SOCK_RAW;
1283	hints.ai_protocol = IPPROTO_IPV6;
1284	hints.ai_next     = NULL;
1285
1286	*naddr = 0;
1287	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1288#ifdef DEBUG
1289		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1290#endif
1291		return NULL;
1292	} else {
1293		if (res->ai_family != AF_INET6 ||
1294		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1295			return NULL;
1296
1297#ifdef DEBUG
1298		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1299		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1300#endif
1301		/* Get the first element of the address-chain */
1302		addr = xtables_malloc(sizeof(struct in6_addr));
1303		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1304		       sizeof(struct in6_addr));
1305		freeaddrinfo(res);
1306		*naddr = 1;
1307		return addr;
1308	}
1309
1310	return NULL;
1311}
1312
1313static struct in6_addr *network_to_ip6addr(const char *name)
1314{
1315	/*	abort();*/
1316	/* TODO: not implemented yet, but the exception breaks the
1317	 *       name resolvation */
1318	return NULL;
1319}
1320
1321static struct in6_addr *
1322ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1323{
1324	struct in6_addr *addrp, *addrptmp;
1325
1326	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1327	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1328		addrp = xtables_malloc(sizeof(struct in6_addr));
1329		memcpy(addrp, addrptmp, sizeof(*addrp));
1330		*naddrs = 1;
1331		return addrp;
1332	}
1333	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1334		return addrp;
1335
1336	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1337}
1338
1339static struct in6_addr *parse_ip6mask(char *mask)
1340{
1341	static struct in6_addr maskaddr;
1342	struct in6_addr *addrp;
1343	unsigned int bits;
1344
1345	if (mask == NULL) {
1346		/* no mask at all defaults to 128 bits */
1347		memset(&maskaddr, 0xff, sizeof maskaddr);
1348		return &maskaddr;
1349	}
1350	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1351		return addrp;
1352	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1353		xt_params->exit_err(PARAMETER_PROBLEM,
1354			   "invalid mask `%s' specified", mask);
1355	if (bits != 0) {
1356		char *p = (void *)&maskaddr;
1357		memset(p, 0xff, bits / 8);
1358		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1359		p[bits/8] = 0xff << (8 - (bits & 7));
1360		return &maskaddr;
1361	}
1362
1363	memset(&maskaddr, 0, sizeof(maskaddr));
1364	return &maskaddr;
1365}
1366
1367void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1368                          struct in6_addr *maskp, unsigned int *naddrs)
1369{
1370	static const struct in6_addr zero_addr;
1371	struct in6_addr *addrp;
1372	unsigned int i, j, k, n;
1373	char buf[256], *p;
1374
1375	strncpy(buf, name, sizeof(buf) - 1);
1376	buf[sizeof(buf)-1] = '\0';
1377	if ((p = strrchr(buf, '/')) != NULL) {
1378		*p = '\0';
1379		addrp = parse_ip6mask(p + 1);
1380	} else {
1381		addrp = parse_ip6mask(NULL);
1382	}
1383	memcpy(maskp, addrp, sizeof(*maskp));
1384
1385	/* if a null mask is given, the name is ignored, like in "any/0" */
1386	if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
1387		strcpy(buf, "::");
1388
1389	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1390	n = *naddrs;
1391	for (i = 0, j = 0; i < n; ++i) {
1392		for (k = 0; k < 4; ++k)
1393			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1394		++j;
1395		for (k = 0; k < j - 1; ++k)
1396			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1397				--*naddrs;
1398				--j;
1399				break;
1400			}
1401	}
1402}
1403
1404void xtables_save_string(const char *value)
1405{
1406	static const char no_quote_chars[] = "_-0123456789"
1407		"abcdefghijklmnopqrstuvwxyz"
1408		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1409	static const char escape_chars[] = "\"\\'";
1410	size_t length;
1411	const char *p;
1412
1413	length = strcspn(value, no_quote_chars);
1414	if (length > 0 && value[length] == 0) {
1415		/* no quoting required */
1416		fputs(value, stdout);
1417		putchar(' ');
1418	} else {
1419		/* there is at least one dangerous character in the
1420		   value, which we have to quote.  Write double quotes
1421		   around the value and escape special characters with
1422		   a backslash */
1423		putchar('"');
1424
1425		for (p = strpbrk(value, escape_chars); p != NULL;
1426		     p = strpbrk(value, escape_chars)) {
1427			if (p > value)
1428				fwrite(value, 1, p - value, stdout);
1429			putchar('\\');
1430			putchar(*p);
1431			value = p + 1;
1432		}
1433
1434		/* print the rest and finish the double quoted
1435		   string */
1436		fputs(value, stdout);
1437		printf("\" ");
1438	}
1439}
1440
1441/**
1442 * Check for option-intrapositional negation.
1443 * Do not use in new code.
1444 */
1445int xtables_check_inverse(const char option[], int *invert,
1446			  int *my_optind, int argc)
1447{
1448	if (option && strcmp(option, "!") == 0) {
1449		fprintf(stderr, "Using intrapositioned negation "
1450		        "(`--option ! this`) is deprecated in favor of "
1451		        "extrapositioned (`! --option this`).\n");
1452
1453		if (*invert)
1454			xt_params->exit_err(PARAMETER_PROBLEM,
1455				   "Multiple `!' flags not allowed");
1456		*invert = true;
1457		if (my_optind != NULL) {
1458			++*my_optind;
1459			if (argc && *my_optind > argc)
1460				xt_params->exit_err(PARAMETER_PROBLEM,
1461					   "no argument following `!'");
1462		}
1463
1464		return true;
1465	}
1466	return false;
1467}
1468
1469const struct xtables_pprot xtables_chain_protos[] = {
1470	{"tcp",       IPPROTO_TCP},
1471	{"sctp",      IPPROTO_SCTP},
1472	{"udp",       IPPROTO_UDP},
1473	{"udplite",   IPPROTO_UDPLITE},
1474	{"icmp",      IPPROTO_ICMP},
1475	{"icmpv6",    IPPROTO_ICMPV6},
1476	{"ipv6-icmp", IPPROTO_ICMPV6},
1477	{"esp",       IPPROTO_ESP},
1478	{"ah",        IPPROTO_AH},
1479	{"ipv6-mh",   IPPROTO_MH},
1480	{"mh",        IPPROTO_MH},
1481	{"all",       0},
1482	{NULL},
1483};
1484
1485u_int16_t
1486xtables_parse_protocol(const char *s)
1487{
1488	unsigned int proto;
1489
1490	if (!xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) {
1491		struct protoent *pent;
1492
1493		/* first deal with the special case of 'all' to prevent
1494		 * people from being able to redefine 'all' in nsswitch
1495		 * and/or provoke expensive [not working] ldap/nis/...
1496		 * lookups */
1497		if (!strcmp(s, "all"))
1498			return 0;
1499
1500		if ((pent = getprotobyname(s)))
1501			proto = pent->p_proto;
1502		else {
1503			unsigned int i;
1504			for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
1505				if (xtables_chain_protos[i].name == NULL)
1506					continue;
1507
1508				if (strcmp(s, xtables_chain_protos[i].name) == 0) {
1509					proto = xtables_chain_protos[i].num;
1510					break;
1511				}
1512			}
1513			if (i == ARRAY_SIZE(xtables_chain_protos))
1514				xt_params->exit_err(PARAMETER_PROBLEM,
1515					   "unknown protocol `%s' specified",
1516					   s);
1517		}
1518	}
1519
1520	return proto;
1521}
1522