Blame libxtables/xtables.c

Packit 7b22a4
/*
Packit 7b22a4
 * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
Packit 7b22a4
 *
Packit 7b22a4
 *	This program is free software; you can redistribute it and/or modify
Packit 7b22a4
 *	it under the terms of the GNU General Public License as published by
Packit 7b22a4
 *	the Free Software Foundation; either version 2 of the License, or
Packit 7b22a4
 *	(at your option) any later version.
Packit 7b22a4
 *
Packit 7b22a4
 *	This program is distributed in the hope that it will be useful,
Packit 7b22a4
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 7b22a4
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 7b22a4
 *	GNU General Public License for more details.
Packit 7b22a4
 *
Packit 7b22a4
 *	You should have received a copy of the GNU General Public License
Packit 7b22a4
 *	along with this program; if not, write to the Free Software
Packit 7b22a4
 *	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Packit 7b22a4
 */
Packit 7b22a4
#include "config.h"
Packit 7b22a4
#include <ctype.h>
Packit 7b22a4
#include <errno.h>
Packit 7b22a4
#include <fcntl.h>
Packit 7b22a4
#include <inttypes.h>
Packit 7b22a4
#include <netdb.h>
Packit 7b22a4
#include <spawn.h>
Packit 7b22a4
#include <stdarg.h>
Packit 7b22a4
#include <stdbool.h>
Packit 7b22a4
#include <stdio.h>
Packit 7b22a4
#include <stdlib.h>
Packit 7b22a4
#include <string.h>
Packit 7b22a4
#include <unistd.h>
Packit 7b22a4
#include <sys/socket.h>
Packit 7b22a4
#include <sys/stat.h>
Packit 7b22a4
#include <sys/statfs.h>
Packit 7b22a4
#include <sys/types.h>
Packit 7b22a4
#include <sys/utsname.h>
Packit 7b22a4
#include <sys/wait.h>
Packit 7b22a4
#include <arpa/inet.h>
Packit 7b22a4
#if defined(HAVE_LINUX_MAGIC_H)
Packit 7b22a4
#	include <linux/magic.h> /* for PROC_SUPER_MAGIC */
Packit 7b22a4
#elif defined(HAVE_LINUX_PROC_FS_H)
Packit 7b22a4
#	include <linux/proc_fs.h>	/* Linux 2.4 */
Packit 7b22a4
#else
Packit 7b22a4
#	define PROC_SUPER_MAGIC	0x9fa0
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
#include <xtables.h>
Packit 7b22a4
#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
Packit 7b22a4
#include <linux/netfilter_ipv4/ip_tables.h>
Packit 7b22a4
#include <linux/netfilter_ipv6/ip6_tables.h>
Packit 7b22a4
#include <libiptc/libxtc.h>
Packit 7b22a4
Packit 7b22a4
#ifndef NO_SHARED_LIBS
Packit 7b22a4
#include <dlfcn.h>
Packit 7b22a4
#endif
Packit 7b22a4
#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
Packit 7b22a4
#	define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
Packit 7b22a4
#	define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
Packit 7b22a4
#endif
Packit 7b22a4
#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
Packit 7b22a4
#	define IP6T_SO_GET_REVISION_MATCH	68
Packit 7b22a4
#	define IP6T_SO_GET_REVISION_TARGET	69
Packit 7b22a4
#endif
Packit 7b22a4
#include <getopt.h>
Packit 7b22a4
#include "iptables/internal.h"
Packit 7b22a4
#include "xshared.h"
Packit 7b22a4
Packit 7b22a4
#define NPROTO	255
Packit 7b22a4
Packit 7b22a4
#ifndef PROC_SYS_MODPROBE
Packit 7b22a4
#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
/* we need this for ip6?tables-restore.  ip6?tables-restore.c sets line to the
Packit 7b22a4
 * current line of the input file, in order  to give a more precise error
Packit 7b22a4
 * message.  ip6?tables itself doesn't need this, so it is initialized to the
Packit 7b22a4
 * magic number of -1 */
Packit 7b22a4
int line = -1;
Packit 7b22a4
Packit 7b22a4
void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
Packit 7b22a4
Packit 7b22a4
struct xtables_globals *xt_params = NULL;
Packit 7b22a4
Packit 7b22a4
void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
Packit 7b22a4
{
Packit 7b22a4
	va_list args;
Packit 7b22a4
Packit 7b22a4
	va_start(args, msg);
Packit 7b22a4
	fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
Packit 7b22a4
	vfprintf(stderr, msg, args);
Packit 7b22a4
	va_end(args);
Packit 7b22a4
	fprintf(stderr, "\n");
Packit 7b22a4
	exit(status);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_free_opts(int unused)
Packit 7b22a4
{
Packit 7b22a4
	if (xt_params->opts != xt_params->orig_opts) {
Packit 7b22a4
		free(xt_params->opts);
Packit 7b22a4
		xt_params->opts = NULL;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct option *xtables_merge_options(struct option *orig_opts,
Packit 7b22a4
				     struct option *oldopts,
Packit 7b22a4
				     const struct option *newopts,
Packit 7b22a4
				     unsigned int *option_offset)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
Packit 7b22a4
	struct option *merge, *mp;
Packit 7b22a4
Packit 7b22a4
	if (newopts == NULL)
Packit 7b22a4
		return oldopts;
Packit 7b22a4
Packit 7b22a4
	for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
Packit 7b22a4
	if (oldopts != NULL)
Packit 7b22a4
		for (num_old = 0; oldopts[num_old].name; num_old++) ;
Packit 7b22a4
	for (num_new = 0; newopts[num_new].name; num_new++) ;
Packit 7b22a4
Packit 7b22a4
	/*
Packit 7b22a4
	 * Since @oldopts also has @orig_opts already (and does so at the
Packit 7b22a4
	 * start), skip these entries.
Packit 7b22a4
	 */
Packit 7b22a4
	if (oldopts != NULL) {
Packit 7b22a4
		oldopts += num_oold;
Packit 7b22a4
		num_old -= num_oold;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
Packit 7b22a4
	if (merge == NULL)
Packit 7b22a4
		return NULL;
Packit 7b22a4
Packit 7b22a4
	/* Let the base options -[ADI...] have precedence over everything */
Packit 7b22a4
	memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
Packit 7b22a4
	mp = merge + num_oold;
Packit 7b22a4
Packit 7b22a4
	/* Second, the new options */
Packit 7b22a4
	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
Packit 7b22a4
	*option_offset = xt_params->option_offset;
Packit 7b22a4
	memcpy(mp, newopts, sizeof(*mp) * num_new);
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < num_new; ++i, ++mp)
Packit 7b22a4
		mp->val += *option_offset;
Packit 7b22a4
Packit 7b22a4
	/* Third, the old options */
Packit 7b22a4
	if (oldopts != NULL) {
Packit 7b22a4
		memcpy(mp, oldopts, sizeof(*mp) * num_old);
Packit 7b22a4
		mp += num_old;
Packit 7b22a4
	}
Packit 7b22a4
	xtables_free_opts(0);
Packit 7b22a4
Packit 7b22a4
	/* Clear trailing entry */
Packit 7b22a4
	memset(mp, 0, sizeof(*mp));
Packit 7b22a4
	return merge;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const struct xtables_afinfo afinfo_ipv4 = {
Packit 7b22a4
	.kmod          = "ip_tables",
Packit 7b22a4
	.proc_exists   = "/proc/net/ip_tables_names",
Packit 7b22a4
	.libprefix     = "libipt_",
Packit 7b22a4
	.family	       = NFPROTO_IPV4,
Packit 7b22a4
	.ipproto       = IPPROTO_IP,
Packit 7b22a4
	.so_rev_match  = IPT_SO_GET_REVISION_MATCH,
Packit 7b22a4
	.so_rev_target = IPT_SO_GET_REVISION_TARGET,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static const struct xtables_afinfo afinfo_ipv6 = {
Packit 7b22a4
	.kmod          = "ip6_tables",
Packit 7b22a4
	.proc_exists   = "/proc/net/ip6_tables_names",
Packit 7b22a4
	.libprefix     = "libip6t_",
Packit 7b22a4
	.family        = NFPROTO_IPV6,
Packit 7b22a4
	.ipproto       = IPPROTO_IPV6,
Packit 7b22a4
	.so_rev_match  = IP6T_SO_GET_REVISION_MATCH,
Packit 7b22a4
	.so_rev_target = IP6T_SO_GET_REVISION_TARGET,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
/* Dummy families for arptables-compat and ebtables-compat. Leave structure
Packit 7b22a4
 * fields that we don't use unset.
Packit 7b22a4
 */
Packit 7b22a4
static const struct xtables_afinfo afinfo_bridge = {
Packit 7b22a4
	.libprefix     = "libebt_",
Packit 7b22a4
	.family        = NFPROTO_BRIDGE,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static const struct xtables_afinfo afinfo_arp = {
Packit 7b22a4
	.libprefix     = "libarpt_",
Packit 7b22a4
	.family        = NFPROTO_ARP,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
const struct xtables_afinfo *afinfo;
Packit 7b22a4
Packit 7b22a4
/* Search path for Xtables .so files */
Packit 7b22a4
static const char *xtables_libdir;
Packit 7b22a4
Packit 7b22a4
/* the path to command to load kernel module */
Packit 7b22a4
const char *xtables_modprobe_program;
Packit 7b22a4
Packit 7b22a4
/* Keep track of matches/targets pending full registration: linked lists. */
Packit 7b22a4
struct xtables_match *xtables_pending_matches;
Packit 7b22a4
struct xtables_target *xtables_pending_targets;
Packit 7b22a4
Packit 7b22a4
/* Keep track of fully registered external matches/targets: linked lists. */
Packit 7b22a4
struct xtables_match *xtables_matches;
Packit 7b22a4
struct xtables_target *xtables_targets;
Packit 7b22a4
Packit 7b22a4
/* Fully register a match/target which was previously partially registered. */
Packit Service cc78cd
static bool xtables_fully_register_pending_match(struct xtables_match *me,
Packit Service cc78cd
						 struct xtables_match *prev);
Packit Service cc78cd
static bool xtables_fully_register_pending_target(struct xtables_target *me,
Packit Service cc78cd
						  struct xtables_target *prev);
Packit 7b22a4
Packit 7b22a4
void xtables_init(void)
Packit 7b22a4
{
Packit 7b22a4
	xtables_libdir = getenv("XTABLES_LIBDIR");
Packit 7b22a4
	if (xtables_libdir != NULL)
Packit 7b22a4
		return;
Packit 7b22a4
	xtables_libdir = getenv("IPTABLES_LIB_DIR");
Packit 7b22a4
	if (xtables_libdir != NULL) {
Packit 7b22a4
		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
Packit 7b22a4
		        "use XTABLES_LIBDIR.\n");
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	/*
Packit 7b22a4
	 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
Packit 7b22a4
	 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
Packit 7b22a4
	 * for these env vars are deprecated anyhow, and in light of the
Packit 7b22a4
	 * (shared) libxt_*.so files, makes less sense to have
Packit 7b22a4
	 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
Packit 7b22a4
	 */
Packit 7b22a4
	xtables_libdir = getenv("IP6TABLES_LIB_DIR");
Packit 7b22a4
	if (xtables_libdir != NULL) {
Packit 7b22a4
		fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
Packit 7b22a4
		        "use XTABLES_LIBDIR.\n");
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	xtables_libdir = XTABLES_LIBDIR;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_set_nfproto(uint8_t nfproto)
Packit 7b22a4
{
Packit 7b22a4
	switch (nfproto) {
Packit 7b22a4
	case NFPROTO_IPV4:
Packit 7b22a4
		afinfo = &afinfo_ipv4;
Packit 7b22a4
		break;
Packit 7b22a4
	case NFPROTO_IPV6:
Packit 7b22a4
		afinfo = &afinfo_ipv6;
Packit 7b22a4
		break;
Packit 7b22a4
	case NFPROTO_BRIDGE:
Packit 7b22a4
		afinfo = &afinfo_bridge;
Packit 7b22a4
		break;
Packit 7b22a4
	case NFPROTO_ARP:
Packit 7b22a4
		afinfo = &afinfo_arp;
Packit 7b22a4
		break;
Packit 7b22a4
	default:
Packit 7b22a4
		fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
Packit 7b22a4
		        __func__);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/**
Packit 7b22a4
 * xtables_set_params - set the global parameters used by xtables
Packit 7b22a4
 * @xtp:	input xtables_globals structure
Packit 7b22a4
 *
Packit 7b22a4
 * The app is expected to pass a valid xtables_globals data-filled
Packit 7b22a4
 * with proper values
Packit 7b22a4
 * @xtp cannot be NULL
Packit 7b22a4
 *
Packit 7b22a4
 * Returns -1 on failure to set and 0 on success
Packit 7b22a4
 */
Packit 7b22a4
int xtables_set_params(struct xtables_globals *xtp)
Packit 7b22a4
{
Packit 7b22a4
	if (!xtp) {
Packit 7b22a4
		fprintf(stderr, "%s: Illegal global params\n",__func__);
Packit 7b22a4
		return -1;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	xt_params = xtp;
Packit 7b22a4
Packit 7b22a4
	if (!xt_params->exit_err)
Packit 7b22a4
		xt_params->exit_err = basic_exit_err;
Packit 7b22a4
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
Packit 7b22a4
{
Packit 7b22a4
	xtables_init();
Packit 7b22a4
	xtables_set_nfproto(nfproto);
Packit 7b22a4
	return xtables_set_params(xtp);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/**
Packit 7b22a4
 * xtables_*alloc - wrappers that exit on failure
Packit 7b22a4
 */
Packit 7b22a4
void *xtables_calloc(size_t count, size_t size)
Packit 7b22a4
{
Packit 7b22a4
	void *p;
Packit 7b22a4
Packit 7b22a4
	if ((p = calloc(count, size)) == NULL) {
Packit 7b22a4
		perror("ip[6]tables: calloc failed");
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return p;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void *xtables_malloc(size_t size)
Packit 7b22a4
{
Packit 7b22a4
	void *p;
Packit 7b22a4
Packit 7b22a4
	if ((p = malloc(size)) == NULL) {
Packit 7b22a4
		perror("ip[6]tables: malloc failed");
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return p;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void *xtables_realloc(void *ptr, size_t size)
Packit 7b22a4
{
Packit 7b22a4
	void *p;
Packit 7b22a4
Packit 7b22a4
	if ((p = realloc(ptr, size)) == NULL) {
Packit 7b22a4
		perror("ip[6]tables: realloc failed");
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return p;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static char *get_modprobe(void)
Packit 7b22a4
{
Packit 7b22a4
	int procfile;
Packit 7b22a4
	char *ret;
Packit 7b22a4
	int count;
Packit 7b22a4
Packit 7b22a4
	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
Packit 7b22a4
	if (procfile < 0)
Packit 7b22a4
		return NULL;
Packit 7b22a4
	if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
Packit 7b22a4
		fprintf(stderr, "Could not set close on exec: %s\n",
Packit 7b22a4
			strerror(errno));
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	ret = malloc(PATH_MAX);
Packit 7b22a4
	if (ret) {
Packit 7b22a4
		count = read(procfile, ret, PATH_MAX);
Packit 7b22a4
		if (count > 0 && count < PATH_MAX)
Packit 7b22a4
		{
Packit 7b22a4
			if (ret[count - 1] == '\n')
Packit 7b22a4
				ret[count - 1] = '\0';
Packit 7b22a4
			else
Packit 7b22a4
				ret[count] = '\0';
Packit 7b22a4
			close(procfile);
Packit 7b22a4
			return ret;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	free(ret);
Packit 7b22a4
	close(procfile);
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
Packit 7b22a4
{
Packit 7b22a4
	char *buf = NULL;
Packit 7b22a4
	char *argv[4];
Packit 7b22a4
	int status;
Packit 7b22a4
	pid_t pid;
Packit 7b22a4
Packit 7b22a4
	/* If they don't explicitly set it, read out of kernel */
Packit 7b22a4
	if (!modprobe) {
Packit 7b22a4
		buf = get_modprobe();
Packit 7b22a4
		if (!buf)
Packit 7b22a4
			return -1;
Packit 7b22a4
		modprobe = buf;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	argv[0] = (char *)modprobe;
Packit 7b22a4
	argv[1] = (char *)modname;
Packit 7b22a4
	argv[2] = quiet ? "-q" : NULL;
Packit 7b22a4
	argv[3] = NULL;
Packit 7b22a4
Packit 7b22a4
	/*
Packit 7b22a4
	 * Need to flush the buffer, or the child may output it again
Packit 7b22a4
	 * when switching the program thru execv.
Packit 7b22a4
	 */
Packit 7b22a4
	fflush(stdout);
Packit 7b22a4
Packit 7b22a4
	if (posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL)) {
Packit 7b22a4
		free(buf);
Packit 7b22a4
		return -1;
Packit 7b22a4
	} else {
Packit 7b22a4
		waitpid(pid, &status, 0);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	free(buf);
Packit 7b22a4
	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
Packit 7b22a4
		return 0;
Packit 7b22a4
	return -1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* return true if a given file exists within procfs */
Packit 7b22a4
static bool proc_file_exists(const char *filename)
Packit 7b22a4
{
Packit 7b22a4
	struct stat s;
Packit 7b22a4
	struct statfs f;
Packit 7b22a4
Packit 7b22a4
	if (lstat(filename, &s))
Packit 7b22a4
		return false;
Packit 7b22a4
	if (!S_ISREG(s.st_mode))
Packit 7b22a4
		return false;
Packit 7b22a4
	if (statfs(filename, &f))
Packit 7b22a4
		return false;
Packit 7b22a4
	if (f.f_type != PROC_SUPER_MAGIC)
Packit 7b22a4
		return false;
Packit 7b22a4
	return true;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int xtables_load_ko(const char *modprobe, bool quiet)
Packit 7b22a4
{
Packit 7b22a4
	static bool loaded = false;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	if (loaded)
Packit 7b22a4
		return 0;
Packit 7b22a4
Packit 7b22a4
	if (proc_file_exists(afinfo->proc_exists)) {
Packit 7b22a4
		loaded = true;
Packit 7b22a4
		return 0;
Packit 7b22a4
	};
Packit 7b22a4
Packit 7b22a4
	ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
Packit 7b22a4
	if (ret == 0)
Packit 7b22a4
		loaded = true;
Packit 7b22a4
Packit 7b22a4
	return ret;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/**
Packit 7b22a4
 * xtables_strtou{i,l} - string to number conversion
Packit 7b22a4
 * @s:	input string
Packit 7b22a4
 * @end:	like strtoul's "end" pointer
Packit 7b22a4
 * @value:	pointer for result
Packit 7b22a4
 * @min:	minimum accepted value
Packit 7b22a4
 * @max:	maximum accepted value
Packit 7b22a4
 *
Packit 7b22a4
 * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
Packit 7b22a4
 * "15a" is rejected.
Packit 7b22a4
 * In either case, the value obtained is compared for min-max compliance.
Packit 7b22a4
 * Base is always 0, i.e. autodetect depending on @s.
Packit 7b22a4
 *
Packit 7b22a4
 * Returns true/false whether number was accepted. On failure, *value has
Packit 7b22a4
 * undefined contents.
Packit 7b22a4
 */
Packit 7b22a4
bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
Packit 7b22a4
                     uintmax_t min, uintmax_t max)
Packit 7b22a4
{
Packit 7b22a4
	uintmax_t v;
Packit 7b22a4
	const char *p;
Packit 7b22a4
	char *my_end;
Packit 7b22a4
Packit 7b22a4
	errno = 0;
Packit 7b22a4
	/* Since strtoul allows leading minus, we have to check for ourself. */
Packit 7b22a4
	for (p = s; isspace(*p); ++p)
Packit 7b22a4
		;
Packit 7b22a4
	if (*p == '-')
Packit 7b22a4
		return false;
Packit 7b22a4
	v = strtoumax(s, &my_end, 0);
Packit 7b22a4
	if (my_end == s)
Packit 7b22a4
		return false;
Packit 7b22a4
	if (end != NULL)
Packit 7b22a4
		*end = my_end;
Packit 7b22a4
Packit 7b22a4
	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
Packit 7b22a4
		if (value != NULL)
Packit 7b22a4
			*value = v;
Packit 7b22a4
		if (end == NULL)
Packit 7b22a4
			return *my_end == '\0';
Packit 7b22a4
		return true;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return false;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
bool xtables_strtoui(const char *s, char **end, unsigned int *value,
Packit 7b22a4
                     unsigned int min, unsigned int max)
Packit 7b22a4
{
Packit 7b22a4
	uintmax_t v;
Packit 7b22a4
	bool ret;
Packit 7b22a4
Packit 7b22a4
	ret = xtables_strtoul(s, end, &v, min, max);
Packit 7b22a4
	if (ret && value != NULL)
Packit 7b22a4
		*value = v;
Packit 7b22a4
	return ret;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int xtables_service_to_port(const char *name, const char *proto)
Packit 7b22a4
{
Packit 7b22a4
	struct servent *service;
Packit 7b22a4
Packit 7b22a4
	if ((service = getservbyname(name, proto)) != NULL)
Packit 7b22a4
		return ntohs((unsigned short) service->s_port);
Packit 7b22a4
Packit 7b22a4
	return -1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
uint16_t xtables_parse_port(const char *port, const char *proto)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int portnum;
Packit 7b22a4
Packit 7b22a4
	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
Packit 7b22a4
	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
Packit 7b22a4
		return portnum;
Packit 7b22a4
Packit 7b22a4
	xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
		   "invalid port/service `%s' specified", port);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_parse_interface(const char *arg, char *vianame,
Packit 7b22a4
			     unsigned char *mask)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int vialen = strlen(arg);
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
Packit 7b22a4
	memset(mask, 0, IFNAMSIZ);
Packit 7b22a4
	memset(vianame, 0, IFNAMSIZ);
Packit 7b22a4
Packit 7b22a4
	if (vialen + 1 > IFNAMSIZ)
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
			   "interface name `%s' must be shorter than IFNAMSIZ"
Packit 7b22a4
			   " (%i)", arg, IFNAMSIZ-1);
Packit 7b22a4
Packit 7b22a4
	strcpy(vianame, arg);
Packit 7b22a4
	if (vialen == 0)
Packit 7b22a4
		return;
Packit 7b22a4
	else if (vianame[vialen - 1] == '+') {
Packit 7b22a4
		memset(mask, 0xFF, vialen - 1);
Packit 7b22a4
		/* Don't remove `+' here! -HW */
Packit 7b22a4
	} else {
Packit 7b22a4
		/* Include nul-terminator in match */
Packit 7b22a4
		memset(mask, 0xFF, vialen + 1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	/* Display warning on invalid characters */
Packit 7b22a4
	for (i = 0; vianame[i]; i++) {
Packit 7b22a4
		if (vianame[i] == '/' || vianame[i] == ' ') {
Packit 7b22a4
			fprintf(stderr,	"Warning: weird character in interface"
Packit 7b22a4
				" `%s' ('/' and ' ' are not allowed by the kernel).\n",
Packit 7b22a4
				vianame);
Packit 7b22a4
			break;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
#ifndef NO_SHARED_LIBS
Packit 7b22a4
static void *load_extension(const char *search_path, const char *af_prefix,
Packit 7b22a4
    const char *name, bool is_target)
Packit 7b22a4
{
Packit 7b22a4
	const char *all_prefixes[] = {af_prefix, "libxt_", NULL};
Packit 7b22a4
	const char **prefix;
Packit 7b22a4
	const char *dir = search_path, *next;
Packit 7b22a4
	void *ptr = NULL;
Packit 7b22a4
	struct stat sb;
Packit 7b22a4
	char path[256];
Packit 7b22a4
Packit 7b22a4
	do {
Packit 7b22a4
		next = strchr(dir, ':');
Packit 7b22a4
		if (next == NULL)
Packit 7b22a4
			next = dir + strlen(dir);
Packit 7b22a4
Packit 7b22a4
		for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
Packit 7b22a4
			snprintf(path, sizeof(path), "%.*s/%s%s.so",
Packit 7b22a4
			         (unsigned int)(next - dir), dir,
Packit 7b22a4
			         *prefix, name);
Packit 7b22a4
Packit 7b22a4
			if (stat(path, &sb) != 0) {
Packit 7b22a4
				if (errno == ENOENT)
Packit 7b22a4
					continue;
Packit 7b22a4
				fprintf(stderr, "%s: %s\n", path,
Packit 7b22a4
					strerror(errno));
Packit 7b22a4
				return NULL;
Packit 7b22a4
			}
Packit 7b22a4
			if (dlopen(path, RTLD_NOW) == NULL) {
Packit 7b22a4
				fprintf(stderr, "%s: %s\n", path, dlerror());
Packit 7b22a4
				break;
Packit 7b22a4
			}
Packit 7b22a4
Packit 7b22a4
			if (is_target)
Packit 7b22a4
				ptr = xtables_find_target(name, XTF_DONT_LOAD);
Packit 7b22a4
			else
Packit 7b22a4
				ptr = xtables_find_match(name,
Packit 7b22a4
				      XTF_DONT_LOAD, NULL);
Packit 7b22a4
Packit 7b22a4
			if (ptr != NULL)
Packit 7b22a4
				return ptr;
Packit 7b22a4
Packit 7b22a4
			errno = ENOENT;
Packit 7b22a4
			return NULL;
Packit 7b22a4
		}
Packit 7b22a4
		dir = next + 1;
Packit 7b22a4
	} while (*next != '\0');
Packit 7b22a4
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
static bool extension_cmp(const char *name1, const char *name2, uint32_t family)
Packit 7b22a4
{
Packit 7b22a4
	if (strcmp(name1, name2) == 0 &&
Packit 7b22a4
	    (family == afinfo->family ||
Packit 7b22a4
	     family == NFPROTO_UNSPEC))
Packit 7b22a4
		return true;
Packit 7b22a4
Packit 7b22a4
	return false;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct xtables_match *
Packit 7b22a4
xtables_find_match(const char *name, enum xtables_tryload tryload,
Packit 7b22a4
		   struct xtables_rule_match **matches)
Packit 7b22a4
{
Packit Service cc78cd
	struct xtables_match *prev = NULL;
Packit 7b22a4
	struct xtables_match **dptr;
Packit 7b22a4
	struct xtables_match *ptr;
Packit 7b22a4
	const char *icmp6 = "icmp6";
Packit 7b22a4
Packit 7b22a4
	if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			   "Invalid match name \"%s\" (%u chars max)",
Packit 7b22a4
			   name, XT_EXTENSION_MAXNAMELEN - 1);
Packit 7b22a4
Packit 7b22a4
	/* This is ugly as hell. Nonetheless, there is no way of changing
Packit 7b22a4
	 * this without hurting backwards compatibility */
Packit 7b22a4
	if ( (strcmp(name,"icmpv6") == 0) ||
Packit 7b22a4
	     (strcmp(name,"ipv6-icmp") == 0) ||
Packit 7b22a4
	     (strcmp(name,"icmp6") == 0) )
Packit 7b22a4
		name = icmp6;
Packit 7b22a4
Packit 7b22a4
	/* Trigger delayed initialization */
Packit 7b22a4
	for (dptr = &xtables_pending_matches; *dptr; ) {
Packit 7b22a4
		if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
Packit 7b22a4
			ptr = *dptr;
Packit 7b22a4
			*dptr = (*dptr)->next;
Packit Service cc78cd
			if (xtables_fully_register_pending_match(ptr, prev)) {
Packit Service cc78cd
				prev = ptr;
Packit 7b22a4
				continue;
Packit Service cc78cd
			} else if (prev) {
Packit Service cc78cd
				continue;
Packit Service cc78cd
			}
Packit 7b22a4
			*dptr = ptr;
Packit 7b22a4
		}
Packit 7b22a4
		dptr = &((*dptr)->next);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
Packit 7b22a4
		if (extension_cmp(name, ptr->name, ptr->family)) {
Packit 7b22a4
			struct xtables_match *clone;
Packit 7b22a4
Packit 7b22a4
			/* First match of this type: */
Packit 7b22a4
			if (ptr->m == NULL)
Packit 7b22a4
				break;
Packit 7b22a4
Packit 7b22a4
			/* Second and subsequent clones */
Packit 7b22a4
			clone = xtables_malloc(sizeof(struct xtables_match));
Packit 7b22a4
			memcpy(clone, ptr, sizeof(struct xtables_match));
Packit 7b22a4
			clone->udata = NULL;
Packit 7b22a4
			clone->mflags = 0;
Packit 7b22a4
			/* This is a clone: */
Packit 7b22a4
			clone->next = clone;
Packit 7b22a4
Packit 7b22a4
			ptr = clone;
Packit 7b22a4
			break;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
#ifndef NO_SHARED_LIBS
Packit 7b22a4
	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
Packit 7b22a4
		ptr = load_extension(xtables_libdir, afinfo->libprefix,
Packit 7b22a4
		      name, false);
Packit 7b22a4
Packit 7b22a4
		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
Packit 7b22a4
			xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
				   "Couldn't load match `%s':%s\n",
Packit 7b22a4
				   name, strerror(errno));
Packit 7b22a4
	}
Packit 7b22a4
#else
Packit 7b22a4
	if (ptr && !ptr->loaded) {
Packit 7b22a4
		if (tryload != XTF_DONT_LOAD)
Packit 7b22a4
			ptr->loaded = 1;
Packit 7b22a4
		else
Packit 7b22a4
			ptr = NULL;
Packit 7b22a4
	}
Packit 7b22a4
	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
			   "Couldn't find match `%s'\n", name);
Packit 7b22a4
	}
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
	if (ptr && matches) {
Packit 7b22a4
		struct xtables_rule_match **i;
Packit 7b22a4
		struct xtables_rule_match *newentry;
Packit 7b22a4
Packit 7b22a4
		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
Packit 7b22a4
Packit 7b22a4
		for (i = matches; *i; i = &(*i)->next) {
Packit 7b22a4
			if (extension_cmp(name, (*i)->match->name,
Packit 7b22a4
					  (*i)->match->family))
Packit 7b22a4
				(*i)->completed = true;
Packit 7b22a4
		}
Packit 7b22a4
		newentry->match = ptr;
Packit 7b22a4
		newentry->completed = false;
Packit 7b22a4
		newentry->next = NULL;
Packit 7b22a4
		*i = newentry;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return ptr;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct xtables_match *
Packit 7b22a4
xtables_find_match_revision(const char *name, enum xtables_tryload tryload,
Packit 7b22a4
			    struct xtables_match *match, int revision)
Packit 7b22a4
{
Packit 7b22a4
	if (!match) {
Packit 7b22a4
		match = xtables_find_match(name, tryload, NULL);
Packit 7b22a4
		if (!match)
Packit 7b22a4
			return NULL;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	while (1) {
Packit 7b22a4
		if (match->revision == revision)
Packit 7b22a4
			return match;
Packit 7b22a4
		match = match->next;
Packit 7b22a4
		if (!match)
Packit 7b22a4
			return NULL;
Packit 7b22a4
		if (!extension_cmp(name, match->name, match->family))
Packit 7b22a4
			return NULL;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct xtables_target *
Packit 7b22a4
xtables_find_target(const char *name, enum xtables_tryload tryload)
Packit 7b22a4
{
Packit Service cc78cd
	struct xtables_target *prev = NULL;
Packit 7b22a4
	struct xtables_target **dptr;
Packit 7b22a4
	struct xtables_target *ptr;
Packit 7b22a4
Packit 7b22a4
	/* Standard target? */
Packit 7b22a4
	if (strcmp(name, "") == 0
Packit 7b22a4
	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
Packit 7b22a4
	    || strcmp(name, XTC_LABEL_DROP) == 0
Packit 7b22a4
	    || strcmp(name, XTC_LABEL_QUEUE) == 0
Packit 7b22a4
	    || strcmp(name, XTC_LABEL_RETURN) == 0)
Packit 7b22a4
		name = "standard";
Packit 7b22a4
Packit 7b22a4
	/* Trigger delayed initialization */
Packit 7b22a4
	for (dptr = &xtables_pending_targets; *dptr; ) {
Packit 7b22a4
		if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
Packit 7b22a4
			ptr = *dptr;
Packit 7b22a4
			*dptr = (*dptr)->next;
Packit Service cc78cd
			if (xtables_fully_register_pending_target(ptr, prev)) {
Packit Service cc78cd
				prev = ptr;
Packit 7b22a4
				continue;
Packit Service cc78cd
			} else if (prev) {
Packit Service cc78cd
				continue;
Packit Service cc78cd
			}
Packit 7b22a4
			*dptr = ptr;
Packit 7b22a4
		}
Packit 7b22a4
		dptr = &((*dptr)->next);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
Packit 7b22a4
		if (extension_cmp(name, ptr->name, ptr->family)) {
Packit 7b22a4
			struct xtables_target *clone;
Packit 7b22a4
Packit 7b22a4
			/* First target of this type: */
Packit 7b22a4
			if (ptr->t == NULL)
Packit 7b22a4
				break;
Packit 7b22a4
Packit 7b22a4
			/* Second and subsequent clones */
Packit 7b22a4
			clone = xtables_malloc(sizeof(struct xtables_target));
Packit 7b22a4
			memcpy(clone, ptr, sizeof(struct xtables_target));
Packit 7b22a4
			clone->udata = NULL;
Packit 7b22a4
			clone->tflags = 0;
Packit 7b22a4
			/* This is a clone: */
Packit 7b22a4
			clone->next = clone;
Packit 7b22a4
Packit 7b22a4
			ptr = clone;
Packit 7b22a4
			break;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
#ifndef NO_SHARED_LIBS
Packit 7b22a4
	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
Packit 7b22a4
		ptr = load_extension(xtables_libdir, afinfo->libprefix,
Packit 7b22a4
		      name, true);
Packit 7b22a4
Packit 7b22a4
		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
Packit 7b22a4
			xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
				   "Couldn't load target `%s':%s\n",
Packit 7b22a4
				   name, strerror(errno));
Packit 7b22a4
	}
Packit 7b22a4
#else
Packit 7b22a4
	if (ptr && !ptr->loaded) {
Packit 7b22a4
		if (tryload != XTF_DONT_LOAD)
Packit 7b22a4
			ptr->loaded = 1;
Packit 7b22a4
		else
Packit 7b22a4
			ptr = NULL;
Packit 7b22a4
	}
Packit 7b22a4
	if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
			   "Couldn't find target `%s'\n", name);
Packit 7b22a4
	}
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
	if (ptr)
Packit 7b22a4
		ptr->used = 1;
Packit 7b22a4
Packit 7b22a4
	return ptr;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct xtables_target *
Packit 7b22a4
xtables_find_target_revision(const char *name, enum xtables_tryload tryload,
Packit 7b22a4
			     struct xtables_target *target, int revision)
Packit 7b22a4
{
Packit 7b22a4
	if (!target) {
Packit 7b22a4
		target = xtables_find_target(name, tryload);
Packit 7b22a4
		if (!target)
Packit 7b22a4
			return NULL;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	while (1) {
Packit 7b22a4
		if (target->revision == revision)
Packit 7b22a4
			return target;
Packit 7b22a4
		target = target->next;
Packit 7b22a4
		if (!target)
Packit 7b22a4
			return NULL;
Packit 7b22a4
		if (!extension_cmp(name, target->name, target->family))
Packit 7b22a4
			return NULL;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_get_revision rev;
Packit 7b22a4
	socklen_t s = sizeof(rev);
Packit 7b22a4
	int max_rev, sockfd;
Packit 7b22a4
Packit 7b22a4
	sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
Packit 7b22a4
	if (sockfd < 0) {
Packit 7b22a4
		if (errno == EPERM) {
Packit 7b22a4
			/* revision 0 is always supported. */
Packit 7b22a4
			if (revision != 0)
Packit 7b22a4
				fprintf(stderr, "%s: Could not determine whether "
Packit 7b22a4
						"revision %u is supported, "
Packit 7b22a4
						"assuming it is.\n",
Packit 7b22a4
					name, revision);
Packit 7b22a4
			return 1;
Packit 7b22a4
		}
Packit 7b22a4
		fprintf(stderr, "Could not open socket to kernel: %s\n",
Packit 7b22a4
			strerror(errno));
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
Packit 7b22a4
		fprintf(stderr, "Could not set close on exec: %s\n",
Packit 7b22a4
			strerror(errno));
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	xtables_load_ko(xtables_modprobe_program, true);
Packit 7b22a4
Packit Service d1e015
	strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
Packit Service d1e015
	rev.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
Packit 7b22a4
	rev.revision = revision;
Packit 7b22a4
Packit 7b22a4
	max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
Packit 7b22a4
	if (max_rev < 0) {
Packit 7b22a4
		/* Definitely don't support this? */
Packit 7b22a4
		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
Packit 7b22a4
			close(sockfd);
Packit 7b22a4
			return 0;
Packit 7b22a4
		} else if (errno == ENOPROTOOPT) {
Packit 7b22a4
			close(sockfd);
Packit 7b22a4
			/* Assume only revision 0 support (old kernel) */
Packit 7b22a4
			return (revision == 0);
Packit 7b22a4
		} else {
Packit 7b22a4
			fprintf(stderr, "getsockopt failed strangely: %s\n",
Packit 7b22a4
				strerror(errno));
Packit 7b22a4
			exit(1);
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	close(sockfd);
Packit 7b22a4
	return 1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
Packit 7b22a4
static int compatible_match_revision(const char *name, uint8_t revision)
Packit 7b22a4
{
Packit 7b22a4
	return xt_params->compat_rev(name, revision, afinfo->so_rev_match);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int compatible_target_revision(const char *name, uint8_t revision)
Packit 7b22a4
{
Packit 7b22a4
	return xt_params->compat_rev(name, revision, afinfo->so_rev_target);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void xtables_check_options(const char *name, const struct option *opt)
Packit 7b22a4
{
Packit 7b22a4
	for (; opt->name != NULL; ++opt)
Packit 7b22a4
		if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
Packit 7b22a4
			fprintf(stderr, "%s: Extension %s uses invalid "
Packit 7b22a4
			        "option value %d\n",xt_params->program_name,
Packit 7b22a4
			        name, opt->val);
Packit 7b22a4
			exit(1);
Packit 7b22a4
		}
Packit 7b22a4
}
Packit 7b22a4
Packit Service a0f631
static int xtables_match_prefer(const struct xtables_match *a,
Packit Service a0f631
				const struct xtables_match *b);
Packit Service a0f631
Packit 7b22a4
void xtables_register_match(struct xtables_match *me)
Packit 7b22a4
{
Packit Service a0f631
	struct xtables_match **pos;
Packit Service a0f631
	bool seen_myself = false;
Packit Service a0f631
Packit 7b22a4
	if (me->next) {
Packit 7b22a4
		fprintf(stderr, "%s: match \"%s\" already registered\n",
Packit 7b22a4
			xt_params->program_name, me->name);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->version == NULL) {
Packit 7b22a4
		fprintf(stderr, "%s: match %s<%u> is missing a version\n",
Packit 7b22a4
		        xt_params->program_name, me->name, me->revision);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->size != XT_ALIGN(me->size)) {
Packit 7b22a4
		fprintf(stderr, "%s: match \"%s\" has invalid size %u.\n",
Packit 7b22a4
		        xt_params->program_name, me->name,
Packit 7b22a4
		        (unsigned int)me->size);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (strcmp(me->version, XTABLES_VERSION) != 0) {
Packit 7b22a4
		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
Packit 7b22a4
		        "but \"%s\" is required.\n",
Packit 7b22a4
			xt_params->program_name, me->name,
Packit 7b22a4
			me->version, XTABLES_VERSION);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
Packit 7b22a4
		fprintf(stderr, "%s: match `%s' has invalid name\n",
Packit 7b22a4
			xt_params->program_name, me->name);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
Packit 7b22a4
		fprintf(stderr, "%s: match `%s' has invalid real name\n",
Packit 7b22a4
			xt_params->program_name, me->real_name);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->family >= NPROTO) {
Packit 7b22a4
		fprintf(stderr,
Packit 7b22a4
			"%s: BUG: match %s has invalid protocol family\n",
Packit 7b22a4
			xt_params->program_name, me->name);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->x6_options != NULL)
Packit 7b22a4
		xtables_option_metavalidate(me->name, me->x6_options);
Packit 7b22a4
	if (me->extra_opts != NULL)
Packit 7b22a4
		xtables_check_options(me->name, me->extra_opts);
Packit 7b22a4
Packit Service a0f631
	/* order into linked list of matches pending full registration */
Packit Service a0f631
	for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
Packit Service a0f631
		/* group by name and family */
Packit Service a0f631
		if (strcmp(me->name, (*pos)->name) ||
Packit Service a0f631
		    me->family != (*pos)->family) {
Packit Service a0f631
			if (seen_myself)
Packit Service a0f631
				break; /* end of own group, append to it */
Packit Service a0f631
			continue;
Packit Service a0f631
		}
Packit Service a0f631
		/* found own group */
Packit Service a0f631
		seen_myself = true;
Packit Service a0f631
		if (xtables_match_prefer(me, *pos) >= 0)
Packit Service a0f631
			break; /* put preferred items first in group */
Packit Service a0f631
	}
Packit Service a0f631
	/* if own group was not found, prepend item */
Packit Service a0f631
	if (!*pos && !seen_myself)
Packit Service a0f631
		pos = &xtables_pending_matches;
Packit Service a0f631
Packit Service a0f631
	me->next = *pos;
Packit Service a0f631
	*pos = me;
Packit Service a0f631
#ifdef DEBUG
Packit Service a0f631
	printf("%s: inserted match %s (family %d, revision %d):\n",
Packit Service a0f631
			__func__, me->name, me->family, me->revision);
Packit Service a0f631
	for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
Packit Service a0f631
		printf("%s:\tmatch %s (family %d, revision %d)\n", __func__,
Packit Service a0f631
		       (*pos)->name, (*pos)->family, (*pos)->revision);
Packit Service a0f631
	}
Packit Service a0f631
#endif
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/**
Packit 7b22a4
 * Compare two actions for their preference
Packit 7b22a4
 * @a:	one action
Packit 7b22a4
 * @b: 	another
Packit 7b22a4
 *
Packit 7b22a4
 * Like strcmp, returns a negative number if @a is less preferred than @b,
Packit 7b22a4
 * positive number if @a is more preferred than @b, or zero if equally
Packit 7b22a4
 * preferred.
Packit 7b22a4
 */
Packit 7b22a4
static int
Packit 7b22a4
xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam,
Packit 7b22a4
		  bool b_alias, unsigned int b_rev, unsigned int b_fam)
Packit 7b22a4
{
Packit 7b22a4
	/*
Packit 7b22a4
	 * Alias ranks higher than no alias.
Packit 7b22a4
	 * (We want the new action to be used whenever possible.)
Packit 7b22a4
	 */
Packit 7b22a4
	if (!a_alias && b_alias)
Packit 7b22a4
		return -1;
Packit 7b22a4
	if (a_alias && !b_alias)
Packit 7b22a4
		return 1;
Packit 7b22a4
Packit 7b22a4
	/* Higher revision ranks higher. */
Packit 7b22a4
	if (a_rev < b_rev)
Packit 7b22a4
		return -1;
Packit 7b22a4
	if (a_rev > b_rev)
Packit 7b22a4
		return 1;
Packit 7b22a4
Packit 7b22a4
	/* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */
Packit 7b22a4
	if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC)
Packit 7b22a4
		return -1;
Packit 7b22a4
	if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC)
Packit 7b22a4
		return 1;
Packit 7b22a4
Packit 7b22a4
	/* Must be the same thing. */
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int xtables_match_prefer(const struct xtables_match *a,
Packit 7b22a4
				const struct xtables_match *b)
Packit 7b22a4
{
Packit 7b22a4
	return xtables_mt_prefer(a->real_name != NULL,
Packit 7b22a4
				 a->revision, a->family,
Packit 7b22a4
				 b->real_name != NULL,
Packit 7b22a4
				 b->revision, b->family);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int xtables_target_prefer(const struct xtables_target *a,
Packit 7b22a4
				 const struct xtables_target *b)
Packit 7b22a4
{
Packit 7b22a4
	/*
Packit 7b22a4
	 * Note that if x->real_name==NULL, it will be set to x->name in
Packit 7b22a4
	 * xtables_register_*; the direct pointer comparison here is therefore
Packit 7b22a4
	 * legitimate to detect an alias.
Packit 7b22a4
	 */
Packit 7b22a4
	return xtables_mt_prefer(a->real_name != NULL,
Packit 7b22a4
				 a->revision, a->family,
Packit 7b22a4
				 b->real_name != NULL,
Packit 7b22a4
				 b->revision, b->family);
Packit 7b22a4
}
Packit 7b22a4
Packit Service cc78cd
static bool xtables_fully_register_pending_match(struct xtables_match *me,
Packit Service cc78cd
						 struct xtables_match *prev)
Packit 7b22a4
{
Packit Service cc78cd
	struct xtables_match **i;
Packit 7b22a4
	const char *rn;
Packit 7b22a4
Packit 7b22a4
	/* See if new match can be used. */
Packit 7b22a4
	rn = (me->real_name != NULL) ? me->real_name : me->name;
Packit 7b22a4
	if (!compatible_match_revision(rn, me->revision))
Packit 7b22a4
		return false;
Packit 7b22a4
Packit Service cc78cd
	if (!prev) {
Packit 7b22a4
		/* Append to list. */
Packit 7b22a4
		for (i = &xtables_matches; *i; i = &(*i)->next);
Packit Service cc78cd
	} else {
Packit 7b22a4
		/* Append it */
Packit Service cc78cd
		i = &prev->next;
Packit Service cc78cd
		prev = prev->next;
Packit 7b22a4
	}
Packit 7b22a4
Packit Service cc78cd
	me->next = prev;
Packit 7b22a4
	*i = me;
Packit 7b22a4
Packit 7b22a4
	me->m = NULL;
Packit 7b22a4
	me->mflags = 0;
Packit 7b22a4
Packit 7b22a4
	return true;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_register_matches(struct xtables_match *match, unsigned int n)
Packit 7b22a4
{
Packit Service 720881
	int i;
Packit Service 720881
Packit Service 720881
	for (i = 0; i < n; i++)
Packit Service 720881
		xtables_register_match(&match[i]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_register_target(struct xtables_target *me)
Packit 7b22a4
{
Packit Service a0f631
	struct xtables_target **pos;
Packit Service a0f631
	bool seen_myself = false;
Packit Service a0f631
Packit 7b22a4
	if (me->next) {
Packit 7b22a4
		fprintf(stderr, "%s: target \"%s\" already registered\n",
Packit 7b22a4
			xt_params->program_name, me->name);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->version == NULL) {
Packit 7b22a4
		fprintf(stderr, "%s: target %s<%u> is missing a version\n",
Packit 7b22a4
		        xt_params->program_name, me->name, me->revision);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->size != XT_ALIGN(me->size)) {
Packit 7b22a4
		fprintf(stderr, "%s: target \"%s\" has invalid size %u.\n",
Packit 7b22a4
		        xt_params->program_name, me->name,
Packit 7b22a4
		        (unsigned int)me->size);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (strcmp(me->version, XTABLES_VERSION) != 0) {
Packit 7b22a4
		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
Packit 7b22a4
		        "but \"%s\" is required.\n",
Packit 7b22a4
			xt_params->program_name, me->name,
Packit 7b22a4
			me->version, XTABLES_VERSION);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
Packit 7b22a4
		fprintf(stderr, "%s: target `%s' has invalid name\n",
Packit 7b22a4
			xt_params->program_name, me->name);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
Packit 7b22a4
		fprintf(stderr, "%s: target `%s' has invalid real name\n",
Packit 7b22a4
			xt_params->program_name, me->real_name);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->family >= NPROTO) {
Packit 7b22a4
		fprintf(stderr,
Packit 7b22a4
			"%s: BUG: target %s has invalid protocol family\n",
Packit 7b22a4
			xt_params->program_name, me->name);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (me->x6_options != NULL)
Packit 7b22a4
		xtables_option_metavalidate(me->name, me->x6_options);
Packit 7b22a4
	if (me->extra_opts != NULL)
Packit 7b22a4
		xtables_check_options(me->name, me->extra_opts);
Packit 7b22a4
Packit 7b22a4
	/* ignore not interested target */
Packit 7b22a4
	if (me->family != afinfo->family && me->family != AF_UNSPEC)
Packit 7b22a4
		return;
Packit 7b22a4
Packit Service a0f631
	/* order into linked list of targets pending full registration */
Packit Service a0f631
	for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
Packit Service a0f631
		/* group by name */
Packit Service a0f631
		if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) {
Packit Service a0f631
			if (seen_myself)
Packit Service a0f631
				break; /* end of own group, append to it */
Packit Service a0f631
			continue;
Packit Service a0f631
		}
Packit Service a0f631
		/* found own group */
Packit Service a0f631
		seen_myself = true;
Packit Service a0f631
		if (xtables_target_prefer(me, *pos) >= 0)
Packit Service a0f631
			break; /* put preferred items first in group */
Packit Service a0f631
	}
Packit Service a0f631
	/* if own group was not found, prepend item */
Packit Service a0f631
	if (!*pos && !seen_myself)
Packit Service a0f631
		pos = &xtables_pending_targets;
Packit Service a0f631
Packit Service a0f631
	me->next = *pos;
Packit Service a0f631
	*pos = me;
Packit Service a0f631
#ifdef DEBUG
Packit Service a0f631
	printf("%s: inserted target %s (family %d, revision %d):\n",
Packit Service a0f631
			__func__, me->name, me->family, me->revision);
Packit Service a0f631
	for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
Packit Service a0f631
		printf("%s:\ttarget %s (family %d, revision %d)\n", __func__,
Packit Service a0f631
		       (*pos)->name, (*pos)->family, (*pos)->revision);
Packit Service a0f631
	}
Packit Service a0f631
#endif
Packit 7b22a4
}
Packit 7b22a4
Packit Service cc78cd
static bool xtables_fully_register_pending_target(struct xtables_target *me,
Packit Service cc78cd
						  struct xtables_target *prev)
Packit 7b22a4
{
Packit Service cc78cd
	struct xtables_target **i;
Packit 7b22a4
	const char *rn;
Packit 7b22a4
Packit 7b22a4
	if (strcmp(me->name, "standard") != 0) {
Packit 7b22a4
		/* See if new target can be used. */
Packit 7b22a4
		rn = (me->real_name != NULL) ? me->real_name : me->name;
Packit 7b22a4
		if (!compatible_target_revision(rn, me->revision))
Packit 7b22a4
			return false;
Packit 7b22a4
	}
Packit 7b22a4
Packit Service cc78cd
	if (!prev) {
Packit 7b22a4
		/* Prepend to list. */
Packit 7b22a4
		i = &xtables_targets;
Packit Service cc78cd
		prev = xtables_targets;
Packit Service cc78cd
	} else {
Packit 7b22a4
		/* Append it */
Packit Service cc78cd
		i = &prev->next;
Packit Service cc78cd
		prev = prev->next;
Packit 7b22a4
	}
Packit 7b22a4
Packit Service cc78cd
	me->next = prev;
Packit 7b22a4
	*i = me;
Packit 7b22a4
Packit 7b22a4
	me->t = NULL;
Packit 7b22a4
	me->tflags = 0;
Packit 7b22a4
Packit 7b22a4
	return true;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_register_targets(struct xtables_target *target, unsigned int n)
Packit 7b22a4
{
Packit Service 720881
	int i;
Packit Service 720881
Packit Service 720881
	for (i = 0; i < n; i++)
Packit Service 720881
		xtables_register_target(&target[i]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* receives a list of xtables_rule_match, release them */
Packit 7b22a4
void xtables_rule_matches_free(struct xtables_rule_match **matches)
Packit 7b22a4
{
Packit 7b22a4
	struct xtables_rule_match *matchp, *tmp;
Packit 7b22a4
Packit 7b22a4
	for (matchp = *matches; matchp;) {
Packit 7b22a4
		tmp = matchp->next;
Packit 7b22a4
		if (matchp->match->m) {
Packit 7b22a4
			free(matchp->match->m);
Packit 7b22a4
			matchp->match->m = NULL;
Packit 7b22a4
		}
Packit 7b22a4
		if (matchp->match == matchp->match->next) {
Packit 7b22a4
			free(matchp->match);
Packit 7b22a4
			matchp->match = NULL;
Packit 7b22a4
		}
Packit 7b22a4
		free(matchp);
Packit 7b22a4
		matchp = tmp;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	*matches = NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/**
Packit 7b22a4
 * xtables_param_act - act on condition
Packit 7b22a4
 * @status:	a constant from enum xtables_exittype
Packit 7b22a4
 *
Packit 7b22a4
 * %XTF_ONLY_ONCE: print error message that option may only be used once.
Packit 7b22a4
 * @p1:		module name (e.g. "mark")
Packit 7b22a4
 * @p2(...):	option in conflict (e.g. "--mark")
Packit 7b22a4
 * @p3(...):	condition to match on (see extensions/ for examples)
Packit 7b22a4
 *
Packit 7b22a4
 * %XTF_NO_INVERT: option does not support inversion
Packit 7b22a4
 * @p1:		module name
Packit 7b22a4
 * @p2:		option in conflict
Packit 7b22a4
 * @p3:		condition to match on
Packit 7b22a4
 *
Packit 7b22a4
 * %XTF_BAD_VALUE: bad value for option
Packit 7b22a4
 * @p1:		module name
Packit 7b22a4
 * @p2:		option with which the problem occurred (e.g. "--mark")
Packit 7b22a4
 * @p3:		string the user passed in (e.g. "99999999999999")
Packit 7b22a4
 *
Packit 7b22a4
 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
Packit 7b22a4
 * @p1:		module name
Packit 7b22a4
 *
Packit 7b22a4
 * Displays an error message and exits the program.
Packit 7b22a4
 */
Packit 7b22a4
void xtables_param_act(unsigned int status, const char *p1, ...)
Packit 7b22a4
{
Packit 7b22a4
	const char *p2, *p3;
Packit 7b22a4
	va_list args;
Packit 7b22a4
	bool b;
Packit 7b22a4
Packit 7b22a4
	va_start(args, p1);
Packit 7b22a4
Packit 7b22a4
	switch (status) {
Packit 7b22a4
	case XTF_ONLY_ONCE:
Packit 7b22a4
		p2 = va_arg(args, const char *);
Packit 7b22a4
		b  = va_arg(args, unsigned int);
Packit 7b22a4
		if (!b) {
Packit 7b22a4
			va_end(args);
Packit 7b22a4
			return;
Packit 7b22a4
		}
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
		           "%s: \"%s\" option may only be specified once",
Packit 7b22a4
		           p1, p2);
Packit 7b22a4
		break;
Packit 7b22a4
	case XTF_NO_INVERT:
Packit 7b22a4
		p2 = va_arg(args, const char *);
Packit 7b22a4
		b  = va_arg(args, unsigned int);
Packit 7b22a4
		if (!b) {
Packit 7b22a4
			va_end(args);
Packit 7b22a4
			return;
Packit 7b22a4
		}
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
		           "%s: \"%s\" option cannot be inverted", p1, p2);
Packit 7b22a4
		break;
Packit 7b22a4
	case XTF_BAD_VALUE:
Packit 7b22a4
		p2 = va_arg(args, const char *);
Packit 7b22a4
		p3 = va_arg(args, const char *);
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
		           "%s: Bad value for \"%s\" option: \"%s\"",
Packit 7b22a4
		           p1, p2, p3);
Packit 7b22a4
		break;
Packit 7b22a4
	case XTF_ONE_ACTION:
Packit 7b22a4
		b = va_arg(args, unsigned int);
Packit 7b22a4
		if (!b) {
Packit 7b22a4
			va_end(args);
Packit 7b22a4
			return;
Packit 7b22a4
		}
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
		           "%s: At most one action is possible", p1);
Packit 7b22a4
		break;
Packit 7b22a4
	default:
Packit 7b22a4
		xt_params->exit_err(status, p1, args);
Packit 7b22a4
		break;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	va_end(args);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
Packit 7b22a4
{
Packit 7b22a4
	static char buf[20];
Packit 7b22a4
	const unsigned char *bytep = (const void *)&addrp->s_addr;
Packit 7b22a4
Packit 7b22a4
	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
Packit 7b22a4
	return buf;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const char *ipaddr_to_host(const struct in_addr *addr)
Packit 7b22a4
{
Packit 7b22a4
	static char hostname[NI_MAXHOST];
Packit 7b22a4
	struct sockaddr_in saddr = {
Packit 7b22a4
		.sin_family = AF_INET,
Packit 7b22a4
		.sin_addr = *addr,
Packit 7b22a4
	};
Packit 7b22a4
	int err;
Packit 7b22a4
Packit 7b22a4
Packit 7b22a4
	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in),
Packit 7b22a4
		       hostname, sizeof(hostname) - 1, NULL, 0, 0);
Packit 7b22a4
	if (err != 0)
Packit 7b22a4
		return NULL;
Packit 7b22a4
Packit 7b22a4
	return hostname;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const char *ipaddr_to_network(const struct in_addr *addr)
Packit 7b22a4
{
Packit 7b22a4
	struct netent *net;
Packit 7b22a4
Packit 7b22a4
	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
Packit 7b22a4
		return net->n_name;
Packit 7b22a4
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
Packit 7b22a4
{
Packit 7b22a4
	const char *name;
Packit 7b22a4
Packit 7b22a4
	if ((name = ipaddr_to_host(addr)) != NULL ||
Packit 7b22a4
	    (name = ipaddr_to_network(addr)) != NULL)
Packit 7b22a4
		return name;
Packit 7b22a4
Packit 7b22a4
	return xtables_ipaddr_to_numeric(addr);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int xtables_ipmask_to_cidr(const struct in_addr *mask)
Packit 7b22a4
{
Packit 7b22a4
	uint32_t maskaddr, bits;
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	maskaddr = ntohl(mask->s_addr);
Packit 7b22a4
	/* shortcut for /32 networks */
Packit 7b22a4
	if (maskaddr == 0xFFFFFFFFL)
Packit 7b22a4
		return 32;
Packit 7b22a4
Packit 7b22a4
	i = 32;
Packit 7b22a4
	bits = 0xFFFFFFFEL;
Packit 7b22a4
	while (--i >= 0 && maskaddr != bits)
Packit 7b22a4
		bits <<= 1;
Packit 7b22a4
	if (i >= 0)
Packit 7b22a4
		return i;
Packit 7b22a4
Packit 7b22a4
	/* this mask cannot be converted to CIDR notation */
Packit 7b22a4
	return -1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
Packit 7b22a4
{
Packit 7b22a4
	static char buf[20];
Packit 7b22a4
	uint32_t cidr;
Packit 7b22a4
Packit 7b22a4
	cidr = xtables_ipmask_to_cidr(mask);
Packit 7b22a4
	if (cidr == (unsigned int)-1) {
Packit 7b22a4
		/* mask was not a decent combination of 1's and 0's */
Packit 7b22a4
		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
Packit 7b22a4
		return buf;
Packit 7b22a4
	} else if (cidr == 32) {
Packit 7b22a4
		/* we don't want to see "/32" */
Packit 7b22a4
		return "";
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	sprintf(buf, "/%d", cidr);
Packit 7b22a4
	return buf;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
Packit 7b22a4
{
Packit 7b22a4
	static struct in_addr addr;
Packit 7b22a4
	unsigned char *addrp;
Packit 7b22a4
	unsigned int onebyte;
Packit 7b22a4
	char buf[20], *p, *q;
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	/* copy dotted string, because we need to modify it */
Packit 7b22a4
	strncpy(buf, dotted, sizeof(buf) - 1);
Packit 7b22a4
	buf[sizeof(buf) - 1] = '\0';
Packit 7b22a4
	addrp = (void *)&addr.s_addr;
Packit 7b22a4
Packit 7b22a4
	p = buf;
Packit 7b22a4
	for (i = 0; i < 3; ++i) {
Packit 7b22a4
		if ((q = strchr(p, '.')) == NULL) {
Packit 7b22a4
			if (is_mask)
Packit 7b22a4
				return NULL;
Packit 7b22a4
Packit 7b22a4
			/* autocomplete, this is a network address */
Packit 7b22a4
			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
Packit 7b22a4
				return NULL;
Packit 7b22a4
Packit 7b22a4
			addrp[i] = onebyte;
Packit 7b22a4
			while (i < 3)
Packit 7b22a4
				addrp[++i] = 0;
Packit 7b22a4
Packit 7b22a4
			return &addr;
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
		*q = '\0';
Packit 7b22a4
		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
Packit 7b22a4
			return NULL;
Packit 7b22a4
Packit 7b22a4
		addrp[i] = onebyte;
Packit 7b22a4
		p = q + 1;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	/* we have checked 3 bytes, now we check the last one */
Packit 7b22a4
	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
Packit 7b22a4
		return NULL;
Packit 7b22a4
Packit 7b22a4
	addrp[3] = onebyte;
Packit 7b22a4
	return &addr;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
Packit 7b22a4
{
Packit 7b22a4
	return __numeric_to_ipaddr(dotted, false);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
Packit 7b22a4
{
Packit 7b22a4
	return __numeric_to_ipaddr(dotted, true);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in_addr *network_to_ipaddr(const char *name)
Packit 7b22a4
{
Packit 7b22a4
	static struct in_addr addr;
Packit 7b22a4
	struct netent *net;
Packit 7b22a4
Packit 7b22a4
	if ((net = getnetbyname(name)) != NULL) {
Packit 7b22a4
		if (net->n_addrtype != AF_INET)
Packit 7b22a4
			return NULL;
Packit 7b22a4
		addr.s_addr = htonl(net->n_net);
Packit 7b22a4
		return &addr;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
Packit 7b22a4
{
Packit 7b22a4
	struct in_addr *addr;
Packit 7b22a4
	struct addrinfo hints;
Packit 7b22a4
	struct addrinfo *res, *p;
Packit 7b22a4
	int err;
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
Packit 7b22a4
	memset(&hints, 0, sizeof(hints));
Packit 7b22a4
	hints.ai_family   = AF_INET;
Packit 7b22a4
	hints.ai_socktype = SOCK_RAW;
Packit 7b22a4
Packit 7b22a4
	*naddr = 0;
Packit 7b22a4
	err = getaddrinfo(name, NULL, &hints, &res;;
Packit 7b22a4
	if (err != 0)
Packit 7b22a4
		return NULL;
Packit 7b22a4
	for (p = res; p != NULL; p = p->ai_next)
Packit 7b22a4
		++*naddr;
Packit 7b22a4
	addr = xtables_calloc(*naddr, sizeof(struct in_addr));
Packit 7b22a4
	for (i = 0, p = res; p != NULL; p = p->ai_next)
Packit 7b22a4
		memcpy(&addr[i++],
Packit 7b22a4
		       &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
Packit 7b22a4
		       sizeof(struct in_addr));
Packit 7b22a4
	freeaddrinfo(res);
Packit 7b22a4
	return addr;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in_addr *
Packit 7b22a4
ipparse_hostnetwork(const char *name, unsigned int *naddrs)
Packit 7b22a4
{
Packit 7b22a4
	struct in_addr *addrptmp, *addrp;
Packit 7b22a4
Packit 7b22a4
	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
Packit 7b22a4
	    (addrptmp = network_to_ipaddr(name)) != NULL) {
Packit 7b22a4
		addrp = xtables_malloc(sizeof(struct in_addr));
Packit 7b22a4
		memcpy(addrp, addrptmp, sizeof(*addrp));
Packit 7b22a4
		*naddrs = 1;
Packit 7b22a4
		return addrp;
Packit 7b22a4
	}
Packit 7b22a4
	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
Packit 7b22a4
		return addrptmp;
Packit 7b22a4
Packit 7b22a4
	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in_addr *parse_ipmask(const char *mask)
Packit 7b22a4
{
Packit 7b22a4
	static struct in_addr maskaddr;
Packit 7b22a4
	struct in_addr *addrp;
Packit 7b22a4
	unsigned int bits;
Packit 7b22a4
Packit 7b22a4
	if (mask == NULL) {
Packit 7b22a4
		/* no mask at all defaults to 32 bits */
Packit 7b22a4
		maskaddr.s_addr = 0xFFFFFFFF;
Packit 7b22a4
		return &maskaddr;
Packit 7b22a4
	}
Packit 7b22a4
	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
Packit 7b22a4
		/* dotted_to_addr already returns a network byte order addr */
Packit 7b22a4
		return addrp;
Packit 7b22a4
	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
			   "invalid mask `%s' specified", mask);
Packit 7b22a4
	if (bits != 0) {
Packit 7b22a4
		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
Packit 7b22a4
		return &maskaddr;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	maskaddr.s_addr = 0U;
Packit 7b22a4
	return &maskaddr;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
Packit 7b22a4
                              struct in_addr **maskpp, unsigned int *naddrs)
Packit 7b22a4
{
Packit 7b22a4
	struct in_addr *addrp;
Packit 7b22a4
	char buf[256], *p, *next;
Packit 7b22a4
	unsigned int len, i, j, n, count = 1;
Packit 7b22a4
	const char *loop = name;
Packit 7b22a4
Packit 7b22a4
	while ((loop = strchr(loop, ',')) != NULL) {
Packit 7b22a4
		++count;
Packit 7b22a4
		++loop; /* skip ',' */
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	*addrpp = xtables_malloc(sizeof(struct in_addr) * count);
Packit 7b22a4
	*maskpp = xtables_malloc(sizeof(struct in_addr) * count);
Packit 7b22a4
Packit 7b22a4
	loop = name;
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < count; ++i) {
Packit 7b22a4
		while (isspace(*loop))
Packit 7b22a4
			++loop;
Packit 7b22a4
		next = strchr(loop, ',');
Packit 7b22a4
		if (next != NULL)
Packit 7b22a4
			len = next - loop;
Packit 7b22a4
		else
Packit 7b22a4
			len = strlen(loop);
Packit 7b22a4
		if (len > sizeof(buf) - 1)
Packit 7b22a4
			xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
				"Hostname too long");
Packit 7b22a4
Packit 7b22a4
		strncpy(buf, loop, len);
Packit 7b22a4
		buf[len] = '\0';
Packit 7b22a4
		if ((p = strrchr(buf, '/')) != NULL) {
Packit 7b22a4
			*p = '\0';
Packit 7b22a4
			addrp = parse_ipmask(p + 1);
Packit 7b22a4
		} else {
Packit 7b22a4
			addrp = parse_ipmask(NULL);
Packit 7b22a4
		}
Packit 7b22a4
		memcpy(*maskpp + i, addrp, sizeof(*addrp));
Packit 7b22a4
Packit 7b22a4
		/* if a null mask is given, the name is ignored, like in "any/0" */
Packit 7b22a4
		if ((*maskpp + i)->s_addr == 0)
Packit 7b22a4
			/*
Packit 7b22a4
			 * A bit pointless to process multiple addresses
Packit 7b22a4
			 * in this case...
Packit 7b22a4
			 */
Packit 7b22a4
			strcpy(buf, "0.0.0.0");
Packit 7b22a4
Packit 7b22a4
		addrp = ipparse_hostnetwork(buf, &n);
Packit 7b22a4
		if (n > 1) {
Packit 7b22a4
			count += n - 1;
Packit 7b22a4
			*addrpp = xtables_realloc(*addrpp,
Packit 7b22a4
			          sizeof(struct in_addr) * count);
Packit 7b22a4
			*maskpp = xtables_realloc(*maskpp,
Packit 7b22a4
			          sizeof(struct in_addr) * count);
Packit 7b22a4
			for (j = 0; j < n; ++j)
Packit 7b22a4
				/* for each new addr */
Packit 7b22a4
				memcpy(*addrpp + i + j, addrp + j,
Packit 7b22a4
				       sizeof(*addrp));
Packit 7b22a4
			for (j = 1; j < n; ++j)
Packit 7b22a4
				/* for each new mask */
Packit 7b22a4
				memcpy(*maskpp + i + j, *maskpp + i,
Packit 7b22a4
				       sizeof(*addrp));
Packit 7b22a4
			i += n - 1;
Packit 7b22a4
		} else {
Packit 7b22a4
			memcpy(*addrpp + i, addrp, sizeof(*addrp));
Packit 7b22a4
		}
Packit 7b22a4
		/* free what ipparse_hostnetwork had allocated: */
Packit 7b22a4
		free(addrp);
Packit 7b22a4
		if (next == NULL)
Packit 7b22a4
			break;
Packit 7b22a4
		loop = next + 1;
Packit 7b22a4
	}
Packit 7b22a4
	*naddrs = count;
Packit 7b22a4
	for (i = 0; i < count; ++i)
Packit 7b22a4
		(*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
Packit 7b22a4
/**
Packit 7b22a4
 * xtables_ipparse_any - transform arbitrary name to in_addr
Packit 7b22a4
 *
Packit 7b22a4
 * Possible inputs (pseudo regex):
Packit 7b22a4
 * 	m{^($hostname|$networkname|$ipaddr)(/$mask)?}
Packit 7b22a4
 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
Packit 7b22a4
 */
Packit 7b22a4
void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
Packit 7b22a4
                         struct in_addr *maskp, unsigned int *naddrs)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int i, j, k, n;
Packit 7b22a4
	struct in_addr *addrp;
Packit 7b22a4
	char buf[256], *p;
Packit 7b22a4
Packit 7b22a4
	strncpy(buf, name, sizeof(buf) - 1);
Packit 7b22a4
	buf[sizeof(buf) - 1] = '\0';
Packit 7b22a4
	if ((p = strrchr(buf, '/')) != NULL) {
Packit 7b22a4
		*p = '\0';
Packit 7b22a4
		addrp = parse_ipmask(p + 1);
Packit 7b22a4
	} else {
Packit 7b22a4
		addrp = parse_ipmask(NULL);
Packit 7b22a4
	}
Packit 7b22a4
	memcpy(maskp, addrp, sizeof(*maskp));
Packit 7b22a4
Packit 7b22a4
	/* if a null mask is given, the name is ignored, like in "any/0" */
Packit 7b22a4
	if (maskp->s_addr == 0U)
Packit 7b22a4
		strcpy(buf, "0.0.0.0");
Packit 7b22a4
Packit 7b22a4
	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
Packit 7b22a4
	n = *naddrs;
Packit 7b22a4
	for (i = 0, j = 0; i < n; ++i) {
Packit 7b22a4
		addrp[j++].s_addr &= maskp->s_addr;
Packit 7b22a4
		for (k = 0; k < j - 1; ++k)
Packit 7b22a4
			if (addrp[k].s_addr == addrp[j-1].s_addr) {
Packit 7b22a4
				/*
Packit 7b22a4
				 * Nuke the dup by copying an address from the
Packit 7b22a4
				 * tail here, and check the current position
Packit 7b22a4
				 * again (--j).
Packit 7b22a4
				 */
Packit 7b22a4
				memcpy(&addrp[--j], &addrp[--*naddrs],
Packit 7b22a4
				       sizeof(struct in_addr));
Packit 7b22a4
				break;
Packit 7b22a4
			}
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
Packit 7b22a4
{
Packit 7b22a4
	/* 0000:0000:0000:0000:0000:0000:000.000.000.000
Packit 7b22a4
	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
Packit 7b22a4
	static char buf[50+1];
Packit 7b22a4
	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const char *ip6addr_to_host(const struct in6_addr *addr)
Packit 7b22a4
{
Packit 7b22a4
	static char hostname[NI_MAXHOST];
Packit 7b22a4
	struct sockaddr_in6 saddr;
Packit 7b22a4
	int err;
Packit 7b22a4
Packit 7b22a4
	memset(&saddr, 0, sizeof(struct sockaddr_in6));
Packit 7b22a4
	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
Packit 7b22a4
	saddr.sin6_family = AF_INET6;
Packit 7b22a4
Packit 7b22a4
	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
Packit 7b22a4
			hostname, sizeof(hostname) - 1, NULL, 0, 0);
Packit 7b22a4
	if (err != 0)
Packit 7b22a4
		return NULL;
Packit 7b22a4
Packit 7b22a4
	return hostname;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
Packit 7b22a4
{
Packit 7b22a4
	const char *name;
Packit 7b22a4
Packit 7b22a4
	if ((name = ip6addr_to_host(addr)) != NULL)
Packit 7b22a4
		return name;
Packit 7b22a4
Packit 7b22a4
	return xtables_ip6addr_to_numeric(addr);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int xtables_ip6mask_to_cidr(const struct in6_addr *k)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int bits = 0;
Packit 7b22a4
	uint32_t a, b, c, d;
Packit 7b22a4
Packit 7b22a4
	a = ntohl(k->s6_addr32[0]);
Packit 7b22a4
	b = ntohl(k->s6_addr32[1]);
Packit 7b22a4
	c = ntohl(k->s6_addr32[2]);
Packit 7b22a4
	d = ntohl(k->s6_addr32[3]);
Packit 7b22a4
	while (a & 0x80000000U) {
Packit 7b22a4
		++bits;
Packit 7b22a4
		a <<= 1;
Packit 7b22a4
		a  |= (b >> 31) & 1;
Packit 7b22a4
		b <<= 1;
Packit 7b22a4
		b  |= (c >> 31) & 1;
Packit 7b22a4
		c <<= 1;
Packit 7b22a4
		c  |= (d >> 31) & 1;
Packit 7b22a4
		d <<= 1;
Packit 7b22a4
	}
Packit 7b22a4
	if (a != 0 || b != 0 || c != 0 || d != 0)
Packit 7b22a4
		return -1;
Packit 7b22a4
	return bits;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
Packit 7b22a4
{
Packit 7b22a4
	static char buf[50+2];
Packit 7b22a4
	int l = xtables_ip6mask_to_cidr(addrp);
Packit 7b22a4
Packit 7b22a4
	if (l == -1) {
Packit 7b22a4
		strcpy(buf, "/");
Packit 7b22a4
		strcat(buf, xtables_ip6addr_to_numeric(addrp));
Packit 7b22a4
		return buf;
Packit 7b22a4
	}
Packit 7b22a4
	/* we don't want to see "/128" */
Packit 7b22a4
	if (l == 128)
Packit 7b22a4
		return "";
Packit 7b22a4
	else
Packit 7b22a4
		sprintf(buf, "/%d", l);
Packit 7b22a4
	return buf;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
Packit 7b22a4
{
Packit 7b22a4
	static struct in6_addr ap;
Packit 7b22a4
	int err;
Packit 7b22a4
Packit 7b22a4
	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
Packit 7b22a4
		return ≈
Packit 7b22a4
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in6_addr *
Packit 7b22a4
host_to_ip6addr(const char *name, unsigned int *naddr)
Packit 7b22a4
{
Packit 7b22a4
	struct in6_addr *addr;
Packit 7b22a4
	struct addrinfo hints;
Packit 7b22a4
	struct addrinfo *res, *p;
Packit 7b22a4
	int err;
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
Packit 7b22a4
	memset(&hints, 0, sizeof(hints));
Packit 7b22a4
	hints.ai_family   = AF_INET6;
Packit 7b22a4
	hints.ai_socktype = SOCK_RAW;
Packit 7b22a4
Packit 7b22a4
	*naddr = 0;
Packit 7b22a4
	err = getaddrinfo(name, NULL, &hints, &res;;
Packit 7b22a4
	if (err != 0)
Packit 7b22a4
		return NULL;
Packit 7b22a4
	/* Find length of address chain */
Packit 7b22a4
	for (p = res; p != NULL; p = p->ai_next)
Packit 7b22a4
		++*naddr;
Packit 7b22a4
	/* Copy each element of the address chain */
Packit 7b22a4
	addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
Packit 7b22a4
	for (i = 0, p = res; p != NULL; p = p->ai_next)
Packit 7b22a4
		memcpy(&addr[i++],
Packit 7b22a4
		       &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
Packit 7b22a4
		       sizeof(struct in6_addr));
Packit 7b22a4
	freeaddrinfo(res);
Packit 7b22a4
	return addr;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in6_addr *network_to_ip6addr(const char *name)
Packit 7b22a4
{
Packit 7b22a4
	/*	abort();*/
Packit 7b22a4
	/* TODO: not implemented yet, but the exception breaks the
Packit 7b22a4
	 *       name resolvation */
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in6_addr *
Packit 7b22a4
ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
Packit 7b22a4
{
Packit 7b22a4
	struct in6_addr *addrp, *addrptmp;
Packit 7b22a4
Packit 7b22a4
	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
Packit 7b22a4
	    (addrptmp = network_to_ip6addr(name)) != NULL) {
Packit 7b22a4
		addrp = xtables_malloc(sizeof(struct in6_addr));
Packit 7b22a4
		memcpy(addrp, addrptmp, sizeof(*addrp));
Packit 7b22a4
		*naddrs = 1;
Packit 7b22a4
		return addrp;
Packit 7b22a4
	}
Packit 7b22a4
	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
Packit 7b22a4
		return addrp;
Packit 7b22a4
Packit 7b22a4
	xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct in6_addr *parse_ip6mask(char *mask)
Packit 7b22a4
{
Packit 7b22a4
	static struct in6_addr maskaddr;
Packit 7b22a4
	struct in6_addr *addrp;
Packit 7b22a4
	unsigned int bits;
Packit 7b22a4
Packit 7b22a4
	if (mask == NULL) {
Packit 7b22a4
		/* no mask at all defaults to 128 bits */
Packit 7b22a4
		memset(&maskaddr, 0xff, sizeof maskaddr);
Packit 7b22a4
		return &maskaddr;
Packit 7b22a4
	}
Packit 7b22a4
	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
Packit 7b22a4
		return addrp;
Packit 7b22a4
	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
			   "invalid mask `%s' specified", mask);
Packit 7b22a4
	if (bits != 0) {
Packit 7b22a4
		char *p = (void *)&maskaddr;
Packit 7b22a4
		memset(p, 0xff, bits / 8);
Packit 7b22a4
		memset(p + ((bits + 7) / 8), 0, (128 - bits) / 8);
Packit 7b22a4
		if (bits < 128)
Packit 7b22a4
			p[bits/8] = 0xff << (8 - (bits & 7));
Packit 7b22a4
		return &maskaddr;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	memset(&maskaddr, 0, sizeof(maskaddr));
Packit 7b22a4
	return &maskaddr;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void
Packit 7b22a4
xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
Packit 7b22a4
		      struct in6_addr **maskpp, unsigned int *naddrs)
Packit 7b22a4
{
Packit 7b22a4
	static const struct in6_addr zero_addr;
Packit 7b22a4
	struct in6_addr *addrp;
Packit 7b22a4
	char buf[256], *p, *next;
Packit 7b22a4
	unsigned int len, i, j, n, count = 1;
Packit 7b22a4
	const char *loop = name;
Packit 7b22a4
Packit 7b22a4
	while ((loop = strchr(loop, ',')) != NULL) {
Packit 7b22a4
		++count;
Packit 7b22a4
		++loop; /* skip ',' */
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	*addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
Packit 7b22a4
	*maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
Packit 7b22a4
Packit 7b22a4
	loop = name;
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < count /*NB: count can grow*/; ++i) {
Packit 7b22a4
		while (isspace(*loop))
Packit 7b22a4
			++loop;
Packit 7b22a4
		next = strchr(loop, ',');
Packit 7b22a4
		if (next != NULL)
Packit 7b22a4
			len = next - loop;
Packit 7b22a4
		else
Packit 7b22a4
			len = strlen(loop);
Packit 7b22a4
		if (len > sizeof(buf) - 1)
Packit 7b22a4
			xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
				"Hostname too long");
Packit 7b22a4
Packit 7b22a4
		strncpy(buf, loop, len);
Packit 7b22a4
		buf[len] = '\0';
Packit 7b22a4
		if ((p = strrchr(buf, '/')) != NULL) {
Packit 7b22a4
			*p = '\0';
Packit 7b22a4
			addrp = parse_ip6mask(p + 1);
Packit 7b22a4
		} else {
Packit 7b22a4
			addrp = parse_ip6mask(NULL);
Packit 7b22a4
		}
Packit 7b22a4
		memcpy(*maskpp + i, addrp, sizeof(*addrp));
Packit 7b22a4
Packit 7b22a4
		/* if a null mask is given, the name is ignored, like in "any/0" */
Packit 7b22a4
		if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
Packit 7b22a4
			strcpy(buf, "::");
Packit 7b22a4
Packit 7b22a4
		addrp = ip6parse_hostnetwork(buf, &n);
Packit 7b22a4
		if (n > 1) {
Packit 7b22a4
			count += n - 1;
Packit 7b22a4
			*addrpp = xtables_realloc(*addrpp,
Packit 7b22a4
			          sizeof(struct in6_addr) * count);
Packit 7b22a4
			*maskpp = xtables_realloc(*maskpp,
Packit 7b22a4
			          sizeof(struct in6_addr) * count);
Packit 7b22a4
			for (j = 0; j < n; ++j)
Packit 7b22a4
				/* for each new addr */
Packit 7b22a4
				memcpy(*addrpp + i + j, addrp + j,
Packit 7b22a4
				       sizeof(*addrp));
Packit 7b22a4
			for (j = 1; j < n; ++j)
Packit 7b22a4
				/* for each new mask */
Packit 7b22a4
				memcpy(*maskpp + i + j, *maskpp + i,
Packit 7b22a4
				       sizeof(*addrp));
Packit 7b22a4
			i += n - 1;
Packit 7b22a4
		} else {
Packit 7b22a4
			memcpy(*addrpp + i, addrp, sizeof(*addrp));
Packit 7b22a4
		}
Packit 7b22a4
		/* free what ip6parse_hostnetwork had allocated: */
Packit 7b22a4
		free(addrp);
Packit 7b22a4
		if (next == NULL)
Packit 7b22a4
			break;
Packit 7b22a4
		loop = next + 1;
Packit 7b22a4
	}
Packit 7b22a4
	*naddrs = count;
Packit 7b22a4
	for (i = 0; i < count; ++i)
Packit 7b22a4
		for (j = 0; j < 4; ++j)
Packit 7b22a4
			(*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
Packit 7b22a4
                          struct in6_addr *maskp, unsigned int *naddrs)
Packit 7b22a4
{
Packit 7b22a4
	static const struct in6_addr zero_addr;
Packit 7b22a4
	struct in6_addr *addrp;
Packit 7b22a4
	unsigned int i, j, k, n;
Packit 7b22a4
	char buf[256], *p;
Packit 7b22a4
Packit 7b22a4
	strncpy(buf, name, sizeof(buf) - 1);
Packit 7b22a4
	buf[sizeof(buf)-1] = '\0';
Packit 7b22a4
	if ((p = strrchr(buf, '/')) != NULL) {
Packit 7b22a4
		*p = '\0';
Packit 7b22a4
		addrp = parse_ip6mask(p + 1);
Packit 7b22a4
	} else {
Packit 7b22a4
		addrp = parse_ip6mask(NULL);
Packit 7b22a4
	}
Packit 7b22a4
	memcpy(maskp, addrp, sizeof(*maskp));
Packit 7b22a4
Packit 7b22a4
	/* if a null mask is given, the name is ignored, like in "any/0" */
Packit 7b22a4
	if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
Packit 7b22a4
		strcpy(buf, "::");
Packit 7b22a4
Packit 7b22a4
	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
Packit 7b22a4
	n = *naddrs;
Packit 7b22a4
	for (i = 0, j = 0; i < n; ++i) {
Packit 7b22a4
		for (k = 0; k < 4; ++k)
Packit 7b22a4
			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
Packit 7b22a4
		++j;
Packit 7b22a4
		for (k = 0; k < j - 1; ++k)
Packit 7b22a4
			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
Packit 7b22a4
				/*
Packit 7b22a4
				 * Nuke the dup by copying an address from the
Packit 7b22a4
				 * tail here, and check the current position
Packit 7b22a4
				 * again (--j).
Packit 7b22a4
				 */
Packit 7b22a4
				memcpy(&addrp[--j], &addrp[--*naddrs],
Packit 7b22a4
				       sizeof(struct in_addr));
Packit 7b22a4
				break;
Packit 7b22a4
			}
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_save_string(const char *value)
Packit 7b22a4
{
Packit 7b22a4
	static const char no_quote_chars[] = "_-0123456789"
Packit 7b22a4
		"abcdefghijklmnopqrstuvwxyz"
Packit 7b22a4
		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Packit 7b22a4
	static const char escape_chars[] = "\"\\'";
Packit 7b22a4
	size_t length;
Packit 7b22a4
	const char *p;
Packit 7b22a4
Packit 7b22a4
	length = strspn(value, no_quote_chars);
Packit 7b22a4
	if (length > 0 && value[length] == 0) {
Packit 7b22a4
		/* no quoting required */
Packit 7b22a4
		putchar(' ');
Packit 7b22a4
		fputs(value, stdout);
Packit 7b22a4
	} else {
Packit 7b22a4
		/* there is at least one dangerous character in the
Packit 7b22a4
		   value, which we have to quote.  Write double quotes
Packit 7b22a4
		   around the value and escape special characters with
Packit 7b22a4
		   a backslash */
Packit 7b22a4
		printf(" \"");
Packit 7b22a4
Packit 7b22a4
		for (p = strpbrk(value, escape_chars); p != NULL;
Packit 7b22a4
		     p = strpbrk(value, escape_chars)) {
Packit 7b22a4
			if (p > value)
Packit 7b22a4
				fwrite(value, 1, p - value, stdout);
Packit 7b22a4
			putchar('\\');
Packit 7b22a4
			putchar(*p);
Packit 7b22a4
			value = p + 1;
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
		/* print the rest and finish the double quoted
Packit 7b22a4
		   string */
Packit 7b22a4
		fputs(value, stdout);
Packit 7b22a4
		putchar('\"');
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const struct xtables_pprot xtables_chain_protos[] = {
Packit 7b22a4
	{"tcp",       IPPROTO_TCP},
Packit 7b22a4
	{"sctp",      IPPROTO_SCTP},
Packit 7b22a4
	{"udp",       IPPROTO_UDP},
Packit 7b22a4
	{"udplite",   IPPROTO_UDPLITE},
Packit 7b22a4
	{"icmp",      IPPROTO_ICMP},
Packit 7b22a4
	{"icmpv6",    IPPROTO_ICMPV6},
Packit 7b22a4
	{"ipv6-icmp", IPPROTO_ICMPV6},
Packit 7b22a4
	{"esp",       IPPROTO_ESP},
Packit 7b22a4
	{"ah",        IPPROTO_AH},
Packit 7b22a4
	{"ipv6-mh",   IPPROTO_MH},
Packit 7b22a4
	{"mh",        IPPROTO_MH},
Packit 7b22a4
	{"all",       0},
Packit 7b22a4
	{NULL},
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
uint16_t
Packit 7b22a4
xtables_parse_protocol(const char *s)
Packit 7b22a4
{
Packit 7b22a4
	const struct protoent *pent;
Packit 7b22a4
	unsigned int proto, i;
Packit 7b22a4
Packit 7b22a4
	if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
Packit 7b22a4
		return proto;
Packit 7b22a4
Packit 7b22a4
	/* first deal with the special case of 'all' to prevent
Packit 7b22a4
	 * people from being able to redefine 'all' in nsswitch
Packit 7b22a4
	 * and/or provoke expensive [not working] ldap/nis/...
Packit 7b22a4
	 * lookups */
Packit 7b22a4
	if (strcmp(s, "all") == 0)
Packit 7b22a4
		return 0;
Packit 7b22a4
Packit 7b22a4
	pent = getprotobyname(s);
Packit 7b22a4
	if (pent != NULL)
Packit 7b22a4
		return pent->p_proto;
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
Packit 7b22a4
		if (xtables_chain_protos[i].name == NULL)
Packit 7b22a4
			continue;
Packit 7b22a4
		if (strcmp(s, xtables_chain_protos[i].name) == 0)
Packit 7b22a4
			return xtables_chain_protos[i].num;
Packit 7b22a4
	}
Packit 7b22a4
	xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
		"unknown protocol \"%s\" specified", s);
Packit 7b22a4
	return -1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_print_num(uint64_t number, unsigned int format)
Packit 7b22a4
{
Packit 7b22a4
	if (!(format & FMT_KILOMEGAGIGA)) {
Packit 7b22a4
		printf(FMT("%8llu ","%llu "), (unsigned long long)number);
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	if (number <= 99999) {
Packit 7b22a4
		printf(FMT("%5llu ","%llu "), (unsigned long long)number);
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	number = (number + 500) / 1000;
Packit 7b22a4
	if (number <= 9999) {
Packit 7b22a4
		printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	number = (number + 500) / 1000;
Packit 7b22a4
	if (number <= 9999) {
Packit 7b22a4
		printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	number = (number + 500) / 1000;
Packit 7b22a4
	if (number <= 9999) {
Packit 7b22a4
		printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	number = (number + 500) / 1000;
Packit 7b22a4
	printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_print_mac(const unsigned char *macaddress)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
Packit 7b22a4
	printf("%02x", macaddress[0]);
Packit 7b22a4
	for (i = 1; i < 6; ++i)
Packit 7b22a4
		printf(":%02x", macaddress[i]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
Packit 7b22a4
{
Packit 7b22a4
	static const char hlpmsk[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
Packit 7b22a4
Packit 7b22a4
	xtables_print_mac(mac);
Packit 7b22a4
Packit 7b22a4
	if (memcmp(mask, hlpmsk, 6) == 0)
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	printf("/");
Packit 7b22a4
	xtables_print_mac(mask);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_parse_val_mask(struct xt_option_call *cb,
Packit 7b22a4
			    unsigned int *val, unsigned int *mask,
Packit 7b22a4
			    const struct xtables_lmap *lmap)
Packit 7b22a4
{
Packit 7b22a4
	char *end;
Packit 7b22a4
Packit 7b22a4
	*mask = ~0U;
Packit 7b22a4
Packit 7b22a4
	if (!xtables_strtoui(cb->arg, &end, val, 0, UINT32_MAX)) {
Packit 7b22a4
		if (lmap)
Packit 7b22a4
			goto name2val;
Packit 7b22a4
		else
Packit 7b22a4
			goto bad_val;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (*end == '\0')
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	if (*end != '/') {
Packit 7b22a4
		if (lmap)
Packit 7b22a4
			goto name2val;
Packit 7b22a4
		else
Packit 7b22a4
			goto garbage;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (!xtables_strtoui(end + 1, &end, mask, 0, UINT32_MAX))
Packit 7b22a4
		goto bad_val;
Packit 7b22a4
Packit 7b22a4
	if (*end == '\0')
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
garbage:
Packit 7b22a4
	xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
			"%s: trailing garbage after value "
Packit 7b22a4
			"for option \"--%s\".\n",
Packit 7b22a4
			cb->ext_name, cb->entry->name);
Packit 7b22a4
Packit 7b22a4
bad_val:
Packit 7b22a4
	xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
			"%s: bad integer value for option \"--%s\", "
Packit 7b22a4
			"or out of range.\n",
Packit 7b22a4
			cb->ext_name, cb->entry->name);
Packit 7b22a4
Packit 7b22a4
name2val:
Packit 7b22a4
	*val = xtables_lmap_name2id(lmap, cb->arg);
Packit 7b22a4
	if ((int)*val == -1)
Packit 7b22a4
		xt_params->exit_err(PARAMETER_PROBLEM,
Packit 7b22a4
			"%s: could not map name %s to an integer value "
Packit 7b22a4
			"for option \"--%s\".\n",
Packit 7b22a4
			cb->ext_name, cb->arg, cb->entry->name);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_print_val_mask(unsigned int val, unsigned int mask,
Packit 7b22a4
			    const struct xtables_lmap *lmap)
Packit 7b22a4
{
Packit 7b22a4
	if (mask != ~0U) {
Packit 7b22a4
		printf(" 0x%x/0x%x", val, mask);
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (lmap) {
Packit 7b22a4
		const char *name = xtables_lmap_id2name(lmap, val);
Packit 7b22a4
Packit 7b22a4
		if (name) {
Packit 7b22a4
			printf(" %s", name);
Packit 7b22a4
			return;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	printf(" 0x%x", val);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int kernel_version;
Packit 7b22a4
Packit 7b22a4
void get_kernel_version(void)
Packit 7b22a4
{
Packit 7b22a4
	static struct utsname uts;
Packit 7b22a4
	int x = 0, y = 0, z = 0;
Packit 7b22a4
Packit 7b22a4
	if (uname(&uts) == -1) {
Packit 7b22a4
		fprintf(stderr, "Unable to retrieve kernel version.\n");
Packit 7b22a4
		xtables_free_opts(1);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
Packit 7b22a4
	kernel_version = LINUX_VERSION(x, y, z);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
#include <linux/netfilter/nf_tables.h>
Packit 7b22a4
Packit 7b22a4
struct xt_xlate {
Packit 7b22a4
	struct {
Packit 7b22a4
		char	*data;
Packit 7b22a4
		int	size;
Packit 7b22a4
		int	rem;
Packit 7b22a4
		int	off;
Packit 7b22a4
	} buf;
Packit 7b22a4
	char comment[NFT_USERDATA_MAXLEN];
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
struct xt_xlate *xt_xlate_alloc(int size)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_xlate *xl;
Packit 7b22a4
Packit 7b22a4
	xl = malloc(sizeof(struct xt_xlate));
Packit 7b22a4
	if (xl == NULL)
Packit 7b22a4
		xtables_error(RESOURCE_PROBLEM, "OOM");
Packit 7b22a4
Packit 7b22a4
	xl->buf.data = malloc(size);
Packit 7b22a4
	if (xl->buf.data == NULL)
Packit 7b22a4
		xtables_error(RESOURCE_PROBLEM, "OOM");
Packit 7b22a4
Packit 7b22a4
	xl->buf.data[0] = '\0';
Packit 7b22a4
	xl->buf.size = size;
Packit 7b22a4
	xl->buf.rem = size;
Packit 7b22a4
	xl->buf.off = 0;
Packit 7b22a4
	xl->comment[0] = '\0';
Packit 7b22a4
Packit 7b22a4
	return xl;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xt_xlate_free(struct xt_xlate *xl)
Packit 7b22a4
{
Packit 7b22a4
	free(xl->buf.data);
Packit 7b22a4
	free(xl);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...)
Packit 7b22a4
{
Packit 7b22a4
	va_list ap;
Packit 7b22a4
	int len;
Packit 7b22a4
Packit 7b22a4
	va_start(ap, fmt);
Packit 7b22a4
	len = vsnprintf(xl->buf.data + xl->buf.off, xl->buf.rem, fmt, ap);
Packit 7b22a4
	if (len < 0 || len >= xl->buf.rem)
Packit 7b22a4
		xtables_error(RESOURCE_PROBLEM, "OOM");
Packit 7b22a4
Packit 7b22a4
	va_end(ap);
Packit 7b22a4
	xl->buf.rem -= len;
Packit 7b22a4
	xl->buf.off += len;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
Packit 7b22a4
{
Packit 7b22a4
	strncpy(xl->comment, comment, NFT_USERDATA_MAXLEN - 1);
Packit 7b22a4
	xl->comment[NFT_USERDATA_MAXLEN - 1] = '\0';
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xt_xlate_get_comment(struct xt_xlate *xl)
Packit 7b22a4
{
Packit 7b22a4
	return xl->comment[0] ? xl->comment : NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xt_xlate_get(struct xt_xlate *xl)
Packit 7b22a4
{
Packit 7b22a4
	return xl->buf.data;
Packit 7b22a4
}