Blame libxtables/xtables.c

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