Blame iptables/xshared.c

Packit 7b22a4
#include <config.h>
Packit 7b22a4
#include <ctype.h>
Packit 7b22a4
#include <getopt.h>
Packit 7b22a4
#include <errno.h>
Packit 7b22a4
#include <libgen.h>
Packit 7b22a4
#include <netdb.h>
Packit 7b22a4
#include <stdbool.h>
Packit 7b22a4
#include <stdint.h>
Packit 7b22a4
#include <stdio.h>
Packit 7b22a4
#include <stdlib.h>
Packit 7b22a4
#include <string.h>
Packit 7b22a4
#include <sys/file.h>
Packit 7b22a4
#include <sys/socket.h>
Packit 7b22a4
#include <sys/un.h>
Packit 7b22a4
#include <sys/time.h>
Packit 7b22a4
#include <unistd.h>
Packit 7b22a4
#include <fcntl.h>
Packit 7b22a4
#include <xtables.h>
Packit 7b22a4
#include <math.h>
Packit 7b22a4
#include "xshared.h"
Packit 7b22a4
Packit 7b22a4
/*
Packit 7b22a4
 * Print out any special helps. A user might like to be able to add a --help
Packit 7b22a4
 * to the commandline, and see expected results. So we call help for all
Packit 7b22a4
 * specified matches and targets.
Packit 7b22a4
 */
Packit 7b22a4
void print_extension_helps(const struct xtables_target *t,
Packit 7b22a4
    const struct xtables_rule_match *m)
Packit 7b22a4
{
Packit 7b22a4
	for (; t != NULL; t = t->next) {
Packit 7b22a4
		if (t->used) {
Packit 7b22a4
			printf("\n");
Packit 7b22a4
			if (t->help == NULL)
Packit 7b22a4
				printf("%s does not take any options\n",
Packit 7b22a4
				       t->name);
Packit 7b22a4
			else
Packit 7b22a4
				t->help();
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	for (; m != NULL; m = m->next) {
Packit 7b22a4
		printf("\n");
Packit 7b22a4
		if (m->match->help == NULL)
Packit 7b22a4
			printf("%s does not take any options\n",
Packit 7b22a4
			       m->match->name);
Packit 7b22a4
		else
Packit 7b22a4
			m->match->help();
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *
Packit 7b22a4
proto_to_name(uint8_t proto, int nolookup)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
Packit 7b22a4
	if (proto && !nolookup) {
Packit 7b22a4
		struct protoent *pent = getprotobynumber(proto);
Packit 7b22a4
		if (pent)
Packit 7b22a4
			return pent->p_name;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
Packit 7b22a4
		if (xtables_chain_protos[i].num == proto)
Packit 7b22a4
			return xtables_chain_protos[i].name;
Packit 7b22a4
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct xtables_match *
Packit 7b22a4
find_proto(const char *pname, enum xtables_tryload tryload,
Packit 7b22a4
	   int nolookup, struct xtables_rule_match **matches)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int proto;
Packit 7b22a4
Packit 7b22a4
	if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) {
Packit 7b22a4
		const char *protoname = proto_to_name(proto, nolookup);
Packit 7b22a4
Packit 7b22a4
		if (protoname)
Packit 7b22a4
			return xtables_find_match(protoname, tryload, matches);
Packit 7b22a4
	} else
Packit 7b22a4
		return xtables_find_match(pname, tryload, matches);
Packit 7b22a4
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/*
Packit 7b22a4
 * Some explanations (after four different bugs in 3 different releases): If
Packit 7b22a4
 * we encounter a parameter, that has not been parsed yet, it's not an option
Packit 7b22a4
 * of an explicitly loaded match or a target. However, we support implicit
Packit 7b22a4
 * loading of the protocol match extension. '-p tcp' means 'l4 proto 6' and at
Packit 7b22a4
 * the same time 'load tcp protocol match on demand if we specify --dport'.
Packit 7b22a4
 *
Packit 7b22a4
 * To make this work, we need to make sure:
Packit 7b22a4
 * - the parameter has not been parsed by a match (m above)
Packit 7b22a4
 * - a protocol has been specified
Packit 7b22a4
 * - the protocol extension has not been loaded yet, or is loaded and unused
Packit 7b22a4
 *   [think of ip6tables-restore!]
Packit 7b22a4
 * - the protocol extension can be successively loaded
Packit 7b22a4
 */
Packit 7b22a4
static bool should_load_proto(struct iptables_command_state *cs)
Packit 7b22a4
{
Packit 7b22a4
	if (cs->protocol == NULL)
Packit 7b22a4
		return false;
Packit 7b22a4
	if (find_proto(cs->protocol, XTF_DONT_LOAD,
Packit 7b22a4
	    cs->options & OPT_NUMERIC, NULL) == NULL)
Packit 7b22a4
		return true;
Packit 7b22a4
	return !cs->proto_used;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct xtables_match *load_proto(struct iptables_command_state *cs)
Packit 7b22a4
{
Packit 7b22a4
	if (!should_load_proto(cs))
Packit 7b22a4
		return NULL;
Packit 7b22a4
	return find_proto(cs->protocol, XTF_TRY_LOAD,
Packit 7b22a4
			  cs->options & OPT_NUMERIC, &cs->matches);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int command_default(struct iptables_command_state *cs,
Packit 7b22a4
		    struct xtables_globals *gl)
Packit 7b22a4
{
Packit 7b22a4
	struct xtables_rule_match *matchp;
Packit 7b22a4
	struct xtables_match *m;
Packit 7b22a4
Packit 7b22a4
	if (cs->target != NULL &&
Packit 7b22a4
	    (cs->target->parse != NULL || cs->target->x6_parse != NULL) &&
Packit 7b22a4
	    cs->c >= cs->target->option_offset &&
Packit 7b22a4
	    cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) {
Packit 7b22a4
		xtables_option_tpcall(cs->c, cs->argv, cs->invert,
Packit 7b22a4
				      cs->target, &cs->fw);
Packit 7b22a4
		return 0;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	for (matchp = cs->matches; matchp; matchp = matchp->next) {
Packit 7b22a4
		m = matchp->match;
Packit 7b22a4
Packit 7b22a4
		if (matchp->completed ||
Packit 7b22a4
		    (m->x6_parse == NULL && m->parse == NULL))
Packit 7b22a4
			continue;
Packit 7b22a4
		if (cs->c < matchp->match->option_offset ||
Packit 7b22a4
		    cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE)
Packit 7b22a4
			continue;
Packit 7b22a4
		xtables_option_mpcall(cs->c, cs->argv, cs->invert, m, &cs->fw);
Packit 7b22a4
		return 0;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	/* Try loading protocol */
Packit 7b22a4
	m = load_proto(cs);
Packit 7b22a4
	if (m != NULL) {
Packit 7b22a4
		size_t size;
Packit 7b22a4
Packit 7b22a4
		cs->proto_used = 1;
Packit 7b22a4
Packit 7b22a4
		size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
Packit 7b22a4
Packit 7b22a4
		m->m = xtables_calloc(1, size);
Packit 7b22a4
		m->m->u.match_size = size;
Packit 7b22a4
		strcpy(m->m->u.user.name, m->name);
Packit 7b22a4
		m->m->u.user.revision = m->revision;
Packit 7b22a4
		xs_init_match(m);
Packit 7b22a4
Packit 7b22a4
		if (m->x6_options != NULL)
Packit 7b22a4
			gl->opts = xtables_options_xfrm(gl->orig_opts,
Packit 7b22a4
							gl->opts,
Packit 7b22a4
							m->x6_options,
Packit 7b22a4
							&m->option_offset);
Packit 7b22a4
		else
Packit 7b22a4
			gl->opts = xtables_merge_options(gl->orig_opts,
Packit 7b22a4
							 gl->opts,
Packit 7b22a4
							 m->extra_opts,
Packit 7b22a4
							 &m->option_offset);
Packit 7b22a4
		if (gl->opts == NULL)
Packit 7b22a4
			xtables_error(OTHER_PROBLEM, "can't alloc memory!");
Packit 7b22a4
		optind--;
Packit 7b22a4
		/* Indicate to rerun getopt *immediately* */
Packit 7b22a4
 		return 1;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (cs->c == ':')
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "option \"%s\" "
Packit 7b22a4
		              "requires an argument", cs->argv[optind-1]);
Packit 7b22a4
	if (cs->c == '?')
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "unknown option "
Packit 7b22a4
			      "\"%s\"", cs->argv[optind-1]);
Packit 7b22a4
	xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static mainfunc_t subcmd_get(const char *cmd, const struct subcommand *cb)
Packit 7b22a4
{
Packit 7b22a4
	for (; cb->name != NULL; ++cb)
Packit 7b22a4
		if (strcmp(cb->name, cmd) == 0)
Packit 7b22a4
			return cb->main;
Packit 7b22a4
	return NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int subcmd_main(int argc, char **argv, const struct subcommand *cb)
Packit 7b22a4
{
Packit 7b22a4
	const char *cmd = basename(*argv);
Packit 7b22a4
	mainfunc_t f = subcmd_get(cmd, cb);
Packit 7b22a4
Packit 7b22a4
	if (f == NULL && argc > 1) {
Packit 7b22a4
		/*
Packit 7b22a4
		 * Unable to find a main method for our command name?
Packit 7b22a4
		 * Let's try again with the first argument!
Packit 7b22a4
		 */
Packit 7b22a4
		++argv;
Packit 7b22a4
		--argc;
Packit 7b22a4
		f = subcmd_get(*argv, cb);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	/* now we should have a valid function pointer */
Packit 7b22a4
	if (f != NULL)
Packit 7b22a4
		return f(argc, argv);
Packit 7b22a4
Packit 7b22a4
	fprintf(stderr, "ERROR: No valid subcommand given.\nValid subcommands:\n");
Packit 7b22a4
	for (; cb->name != NULL; ++cb)
Packit 7b22a4
		fprintf(stderr, " * %s\n", cb->name);
Packit 7b22a4
	exit(EXIT_FAILURE);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xs_init_target(struct xtables_target *target)
Packit 7b22a4
{
Packit 7b22a4
	if (target->udata_size != 0) {
Packit 7b22a4
		free(target->udata);
Packit 7b22a4
		target->udata = calloc(1, target->udata_size);
Packit 7b22a4
		if (target->udata == NULL)
Packit 7b22a4
			xtables_error(RESOURCE_PROBLEM, "malloc");
Packit 7b22a4
	}
Packit 7b22a4
	if (target->init != NULL)
Packit 7b22a4
		target->init(target->t);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xs_init_match(struct xtables_match *match)
Packit 7b22a4
{
Packit 7b22a4
	if (match->udata_size != 0) {
Packit 7b22a4
		/*
Packit 7b22a4
		 * As soon as a subsequent instance of the same match
Packit 7b22a4
		 * is used, e.g. "-m time -m time", the first instance
Packit 7b22a4
		 * is no longer reachable anyway, so we can free udata.
Packit 7b22a4
		 * Same goes for target.
Packit 7b22a4
		 */
Packit 7b22a4
		free(match->udata);
Packit 7b22a4
		match->udata = calloc(1, match->udata_size);
Packit 7b22a4
		if (match->udata == NULL)
Packit 7b22a4
			xtables_error(RESOURCE_PROBLEM, "malloc");
Packit 7b22a4
	}
Packit 7b22a4
	if (match->init != NULL)
Packit 7b22a4
		match->init(match->m);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int xtables_lock(int wait, struct timeval *wait_interval)
Packit 7b22a4
{
Packit 7b22a4
	struct timeval time_left, wait_time;
Packit 7b22a4
	int fd, i = 0;
Packit 7b22a4
Packit 7b22a4
	time_left.tv_sec = wait;
Packit 7b22a4
	time_left.tv_usec = 0;
Packit 7b22a4
Packit 7b22a4
	fd = open(XT_LOCK_NAME, O_CREAT, 0600);
Packit 7b22a4
	if (fd < 0) {
Packit 7b22a4
		fprintf(stderr, "Fatal: can't open lock file %s: %s\n",
Packit 7b22a4
			XT_LOCK_NAME, strerror(errno));
Packit 7b22a4
		return XT_LOCK_FAILED;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (wait == -1) {
Packit 7b22a4
		if (flock(fd, LOCK_EX) == 0)
Packit 7b22a4
			return fd;
Packit 7b22a4
Packit 7b22a4
		fprintf(stderr, "Can't lock %s: %s\n", XT_LOCK_NAME,
Packit 7b22a4
			strerror(errno));
Packit 7b22a4
		return XT_LOCK_BUSY;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	while (1) {
Packit 7b22a4
		if (flock(fd, LOCK_EX | LOCK_NB) == 0)
Packit 7b22a4
			return fd;
Packit 7b22a4
		else if (timercmp(&time_left, wait_interval, <))
Packit 7b22a4
			return XT_LOCK_BUSY;
Packit 7b22a4
Packit 7b22a4
		if (++i % 10 == 0) {
Packit 7b22a4
			fprintf(stderr, "Another app is currently holding the xtables lock; "
Packit 7b22a4
				"still %lds %ldus time ahead to have a chance to grab the lock...\n",
Packit 7b22a4
				time_left.tv_sec, time_left.tv_usec);
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
		wait_time = *wait_interval;
Packit 7b22a4
		select(0, NULL, NULL, NULL, &wait_time);
Packit 7b22a4
		timersub(&time_left, wait_interval, &time_left);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void xtables_unlock(int lock)
Packit 7b22a4
{
Packit 7b22a4
	if (lock >= 0)
Packit 7b22a4
		close(lock);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int xtables_lock_or_exit(int wait, struct timeval *wait_interval)
Packit 7b22a4
{
Packit 7b22a4
	int lock = xtables_lock(wait, wait_interval);
Packit 7b22a4
Packit 7b22a4
	if (lock == XT_LOCK_FAILED) {
Packit 7b22a4
		xtables_free_opts(1);
Packit 7b22a4
		exit(RESOURCE_PROBLEM);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (lock == XT_LOCK_BUSY) {
Packit 7b22a4
		fprintf(stderr, "Another app is currently holding the xtables lock. ");
Packit 7b22a4
		if (wait == 0)
Packit 7b22a4
			fprintf(stderr, "Perhaps you want to use the -w option?\n");
Packit 7b22a4
		else
Packit 7b22a4
			fprintf(stderr, "Stopped waiting after %ds.\n", wait);
Packit 7b22a4
		xtables_free_opts(1);
Packit 7b22a4
		exit(RESOURCE_PROBLEM);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return lock;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int parse_wait_time(int argc, char *argv[])
Packit 7b22a4
{
Packit 7b22a4
	int wait = -1;
Packit 7b22a4
Packit 7b22a4
	if (optarg) {
Packit 7b22a4
		if (sscanf(optarg, "%i", &wait) != 1)
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				"wait seconds not numeric");
Packit 7b22a4
	} else if (xs_has_arg(argc, argv))
Packit 7b22a4
		if (sscanf(argv[optind++], "%i", &wait) != 1)
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				"wait seconds not numeric");
Packit 7b22a4
Packit 7b22a4
	return wait;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval)
Packit 7b22a4
{
Packit 7b22a4
	const char *arg;
Packit 7b22a4
	unsigned int usec;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	if (optarg)
Packit 7b22a4
		arg = optarg;
Packit 7b22a4
	else if (xs_has_arg(argc, argv))
Packit 7b22a4
		arg = argv[optind++];
Packit 7b22a4
	else
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "wait interval value required");
Packit 7b22a4
Packit 7b22a4
	ret = sscanf(arg, "%u", &usec);
Packit 7b22a4
	if (ret == 1) {
Packit 7b22a4
		if (usec > 999999)
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				      "too long usec wait %u > 999999 usec",
Packit 7b22a4
				      usec);
Packit 7b22a4
Packit 7b22a4
		wait_interval->tv_sec = 0;
Packit 7b22a4
		wait_interval->tv_usec = usec;
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	xtables_error(PARAMETER_PROBLEM, "wait interval not numeric");
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int parse_counters(const char *string, struct xt_counters *ctr)
Packit 7b22a4
{
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	if (!string)
Packit 7b22a4
		return 0;
Packit 7b22a4
Packit 7b22a4
	ret = sscanf(string, "[%llu:%llu]",
Packit 7b22a4
		     (unsigned long long *)&ctr->pcnt,
Packit 7b22a4
		     (unsigned long long *)&ctr->bcnt);
Packit 7b22a4
Packit 7b22a4
	return ret == 2;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* Tokenize counters argument of typical iptables-restore format rule.
Packit 7b22a4
 *
Packit 7b22a4
 * If *bufferp contains counters, update *pcntp and *bcntp to point at them,
Packit 7b22a4
 * change bytes after counters in *bufferp to nul-bytes, update *bufferp to
Packit 7b22a4
 * point to after the counters and return true.
Packit 7b22a4
 * If *bufferp does not contain counters, return false.
Packit 7b22a4
 * If syntax is wrong in *bufferp, call xtables_error() and hence exit().
Packit 7b22a4
 * */
Packit 7b22a4
bool tokenize_rule_counters(char **bufferp, char **pcntp, char **bcntp, int line)
Packit 7b22a4
{
Packit 7b22a4
	char *ptr, *buffer = *bufferp, *pcnt, *bcnt;
Packit 7b22a4
Packit 7b22a4
	if (buffer[0] != '[')
Packit 7b22a4
		return false;
Packit 7b22a4
Packit 7b22a4
	/* we have counters in our input */
Packit 7b22a4
Packit 7b22a4
	ptr = strchr(buffer, ']');
Packit 7b22a4
	if (!ptr)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
Packit 7b22a4
Packit 7b22a4
	pcnt = strtok(buffer+1, ":");
Packit 7b22a4
	if (!pcnt)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line);
Packit 7b22a4
Packit 7b22a4
	bcnt = strtok(NULL, "]");
Packit 7b22a4
	if (!bcnt)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
Packit 7b22a4
Packit 7b22a4
	*pcntp = pcnt;
Packit 7b22a4
	*bcntp = bcnt;
Packit 7b22a4
	/* start command parsing after counter */
Packit 7b22a4
	*bufferp = ptr + 1;
Packit 7b22a4
Packit 7b22a4
	return true;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
inline bool xs_has_arg(int argc, char *argv[])
Packit 7b22a4
{
Packit 7b22a4
	return optind < argc &&
Packit 7b22a4
	       argv[optind][0] != '-' &&
Packit 7b22a4
	       argv[optind][0] != '!';
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* function adding one argument to store, updating argc
Packit 7b22a4
 * returns if argument added, does not return otherwise */
Packit 7b22a4
void add_argv(struct argv_store *store, const char *what, int quoted)
Packit 7b22a4
{
Packit 7b22a4
	DEBUGP("add_argv: %s\n", what);
Packit 7b22a4
Packit 7b22a4
	if (store->argc + 1 >= MAX_ARGC)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			      "Parser cannot handle more arguments\n");
Packit 7b22a4
	if (!what)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			      "Trying to store NULL argument\n");
Packit 7b22a4
Packit 7b22a4
	store->argv[store->argc] = strdup(what);
Packit 7b22a4
	store->argvattr[store->argc] = quoted;
Packit 7b22a4
	store->argv[++store->argc] = NULL;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void free_argv(struct argv_store *store)
Packit 7b22a4
{
Packit 7b22a4
	while (store->argc) {
Packit 7b22a4
		store->argc--;
Packit 7b22a4
		free(store->argv[store->argc]);
Packit 7b22a4
		store->argvattr[store->argc] = 0;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* Save parsed rule for comparison with next rule to perform action aggregation
Packit 7b22a4
 * on duplicate conditions.
Packit 7b22a4
 */
Packit 7b22a4
void save_argv(struct argv_store *dst, struct argv_store *src)
Packit 7b22a4
{
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	free_argv(dst);
Packit 7b22a4
	for (i = 0; i < src->argc; i++) {
Packit 7b22a4
		dst->argvattr[i] = src->argvattr[i];
Packit 7b22a4
		dst->argv[i] = src->argv[i];
Packit 7b22a4
		src->argv[i] = NULL;
Packit 7b22a4
	}
Packit 7b22a4
	dst->argc = src->argc;
Packit 7b22a4
	src->argc = 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct xt_param_buf {
Packit 7b22a4
	char	buffer[1024];
Packit 7b22a4
	int 	len;
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static void add_param(struct xt_param_buf *param, const char *curchar)
Packit 7b22a4
{
Packit 7b22a4
	param->buffer[param->len++] = *curchar;
Packit 7b22a4
	if (param->len >= sizeof(param->buffer))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			      "Parameter too long!");
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void add_param_to_argv(struct argv_store *store, char *parsestart, int line)
Packit 7b22a4
{
Packit 7b22a4
	int quote_open = 0, escaped = 0, quoted = 0;
Packit 7b22a4
	struct xt_param_buf param = {};
Packit 7b22a4
	char *curchar;
Packit 7b22a4
Packit 7b22a4
	/* After fighting with strtok enough, here's now
Packit 7b22a4
	 * a 'real' parser. According to Rusty I'm now no
Packit 7b22a4
	 * longer a real hacker, but I can live with that */
Packit 7b22a4
Packit 7b22a4
	for (curchar = parsestart; *curchar; curchar++) {
Packit 7b22a4
		if (quote_open) {
Packit 7b22a4
			if (escaped) {
Packit 7b22a4
				add_param(&param, curchar);
Packit 7b22a4
				escaped = 0;
Packit 7b22a4
				continue;
Packit 7b22a4
			} else if (*curchar == '\\') {
Packit 7b22a4
				escaped = 1;
Packit 7b22a4
				continue;
Packit 7b22a4
			} else if (*curchar == '"') {
Packit 7b22a4
				quote_open = 0;
Packit 7b22a4
				*curchar = '"';
Packit 7b22a4
			} else {
Packit 7b22a4
				add_param(&param, curchar);
Packit 7b22a4
				continue;
Packit 7b22a4
			}
Packit 7b22a4
		} else {
Packit 7b22a4
			if (*curchar == '"') {
Packit 7b22a4
				quote_open = 1;
Packit 7b22a4
				quoted = 1;
Packit 7b22a4
				continue;
Packit 7b22a4
			}
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
		switch (*curchar) {
Packit 7b22a4
		case '"':
Packit 7b22a4
			break;
Packit 7b22a4
		case ' ':
Packit 7b22a4
		case '\t':
Packit 7b22a4
		case '\n':
Packit 7b22a4
			if (!param.len) {
Packit 7b22a4
				/* two spaces? */
Packit 7b22a4
				continue;
Packit 7b22a4
			}
Packit 7b22a4
			break;
Packit 7b22a4
		default:
Packit 7b22a4
			/* regular character, copy to buffer */
Packit 7b22a4
			add_param(&param, curchar);
Packit 7b22a4
			continue;
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
		param.buffer[param.len] = '\0';
Packit 7b22a4
		add_argv(store, param.buffer, quoted);
Packit 7b22a4
		param.len = 0;
Packit 7b22a4
		quoted = 0;
Packit 7b22a4
	}
Packit 7b22a4
	if (param.len) {
Packit 7b22a4
		param.buffer[param.len] = '\0';
Packit 7b22a4
		add_argv(store, param.buffer, 0);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
#ifdef DEBUG
Packit 7b22a4
void debug_print_argv(struct argv_store *store)
Packit 7b22a4
{
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < store->argc; i++)
Packit 7b22a4
		fprintf(stderr, "argv[%d]: %s\n", i, store->argv[i]);
Packit 7b22a4
}
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
static const char *ipv4_addr_to_string(const struct in_addr *addr,
Packit 7b22a4
				       const struct in_addr *mask,
Packit 7b22a4
				       unsigned int format)
Packit 7b22a4
{
Packit 7b22a4
	static char buf[BUFSIZ];
Packit 7b22a4
Packit 7b22a4
	if (!mask->s_addr && !(format & FMT_NUMERIC))
Packit 7b22a4
		return "anywhere";
Packit 7b22a4
Packit 7b22a4
	if (format & FMT_NUMERIC)
Packit 7b22a4
		strncpy(buf, xtables_ipaddr_to_numeric(addr), BUFSIZ - 1);
Packit 7b22a4
	else
Packit 7b22a4
		strncpy(buf, xtables_ipaddr_to_anyname(addr), BUFSIZ - 1);
Packit 7b22a4
	buf[BUFSIZ - 1] = '\0';
Packit 7b22a4
Packit 7b22a4
	strncat(buf, xtables_ipmask_to_numeric(mask),
Packit 7b22a4
		BUFSIZ - strlen(buf) - 1);
Packit 7b22a4
Packit 7b22a4
	return buf;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format)
Packit 7b22a4
{
Packit 7b22a4
	fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
Packit 7b22a4
	printf(FMT("%-19s ", "%s "),
Packit 7b22a4
	       ipv4_addr_to_string(&fw->ip.src, &fw->ip.smsk, format));
Packit 7b22a4
Packit 7b22a4
	fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
Packit 7b22a4
	printf(FMT("%-19s ", "-> %s"),
Packit 7b22a4
	       ipv4_addr_to_string(&fw->ip.dst, &fw->ip.dmsk, format));
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const char *ipv6_addr_to_string(const struct in6_addr *addr,
Packit 7b22a4
				       const struct in6_addr *mask,
Packit 7b22a4
				       unsigned int format)
Packit 7b22a4
{
Packit 7b22a4
	static char buf[BUFSIZ];
Packit 7b22a4
Packit 7b22a4
	if (IN6_IS_ADDR_UNSPECIFIED(addr) && !(format & FMT_NUMERIC))
Packit 7b22a4
		return "anywhere";
Packit 7b22a4
Packit 7b22a4
	if (format & FMT_NUMERIC)
Packit 7b22a4
		strncpy(buf, xtables_ip6addr_to_numeric(addr), BUFSIZ - 1);
Packit 7b22a4
	else
Packit 7b22a4
		strncpy(buf, xtables_ip6addr_to_anyname(addr), BUFSIZ - 1);
Packit 7b22a4
	buf[BUFSIZ - 1] = '\0';
Packit 7b22a4
Packit 7b22a4
	strncat(buf, xtables_ip6mask_to_numeric(mask),
Packit 7b22a4
		BUFSIZ - strlen(buf) - 1);
Packit 7b22a4
Packit 7b22a4
	return buf;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format)
Packit 7b22a4
{
Packit 7b22a4
	fputc(fw6->ipv6.invflags & IP6T_INV_SRCIP ? '!' : ' ', stdout);
Packit 7b22a4
	printf(FMT("%-19s ", "%s "),
Packit 7b22a4
	       ipv6_addr_to_string(&fw6->ipv6.src,
Packit 7b22a4
				   &fw6->ipv6.smsk, format));
Packit 7b22a4
Packit 7b22a4
	fputc(fw6->ipv6.invflags & IP6T_INV_DSTIP ? '!' : ' ', stdout);
Packit 7b22a4
	printf(FMT("%-19s ", "-> %s"),
Packit 7b22a4
	       ipv6_addr_to_string(&fw6->ipv6.dst,
Packit 7b22a4
				   &fw6->ipv6.dmsk, format));
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* Luckily, IPT_INV_VIA_IN and IPT_INV_VIA_OUT
Packit 7b22a4
 * have the same values as IP6T_INV_VIA_IN and IP6T_INV_VIA_OUT
Packit 7b22a4
 * so this function serves for both iptables and ip6tables */
Packit 7b22a4
void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
Packit 7b22a4
		  unsigned int format)
Packit 7b22a4
{
Packit 7b22a4
	const char *anyname = format & FMT_NUMERIC ? "*" : "any";
Packit 7b22a4
	char iface[IFNAMSIZ + 2];
Packit 7b22a4
Packit 7b22a4
	if (!(format & FMT_VIA))
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	snprintf(iface, IFNAMSIZ + 2, "%s%s",
Packit 7b22a4
		 invflags & IPT_INV_VIA_IN ? "!" : "",
Packit 7b22a4
		 iniface[0] != '\0' ? iniface : anyname);
Packit 7b22a4
Packit 7b22a4
	printf(FMT(" %-6s ", "in %s "), iface);
Packit 7b22a4
Packit 7b22a4
	snprintf(iface, IFNAMSIZ + 2, "%s%s",
Packit 7b22a4
		 invflags & IPT_INV_VIA_OUT ? "!" : "",
Packit 7b22a4
		 outiface[0] != '\0' ? outiface : anyname);
Packit 7b22a4
Packit 7b22a4
	printf(FMT("%-6s ", "out %s "), iface);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void command_match(struct iptables_command_state *cs)
Packit 7b22a4
{
Packit 7b22a4
	struct option *opts = xt_params->opts;
Packit 7b22a4
	struct xtables_match *m;
Packit 7b22a4
	size_t size;
Packit 7b22a4
Packit 7b22a4
	if (cs->invert)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			   "unexpected ! flag before --match");
Packit 7b22a4
Packit 7b22a4
	m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches);
Packit 7b22a4
	size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
Packit 7b22a4
	m->m = xtables_calloc(1, size);
Packit 7b22a4
	m->m->u.match_size = size;
Packit 7b22a4
	if (m->real_name == NULL) {
Packit 7b22a4
		strcpy(m->m->u.user.name, m->name);
Packit 7b22a4
	} else {
Packit 7b22a4
		strcpy(m->m->u.user.name, m->real_name);
Packit 7b22a4
		if (!(m->ext_flags & XTABLES_EXT_ALIAS))
Packit 7b22a4
			fprintf(stderr, "Notice: the %s match is converted into %s match "
Packit 7b22a4
				"in rule listing and saving.\n", m->name, m->real_name);
Packit 7b22a4
	}
Packit 7b22a4
	m->m->u.user.revision = m->revision;
Packit 7b22a4
	xs_init_match(m);
Packit 7b22a4
	if (m == m->next)
Packit 7b22a4
		return;
Packit 7b22a4
	/* Merge options for non-cloned matches */
Packit 7b22a4
	if (m->x6_options != NULL)
Packit 7b22a4
		opts = xtables_options_xfrm(xt_params->orig_opts, opts,
Packit 7b22a4
					    m->x6_options, &m->option_offset);
Packit 7b22a4
	else if (m->extra_opts != NULL)
Packit 7b22a4
		opts = xtables_merge_options(xt_params->orig_opts, opts,
Packit 7b22a4
					     m->extra_opts, &m->option_offset);
Packit 7b22a4
	if (opts == NULL)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
Packit 7b22a4
	xt_params->opts = opts;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
const char *xt_parse_target(const char *targetname)
Packit 7b22a4
{
Packit 7b22a4
	const char *ptr;
Packit 7b22a4
Packit 7b22a4
	if (strlen(targetname) < 1)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			   "Invalid target name (too short)");
Packit 7b22a4
Packit 7b22a4
	if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			   "Invalid target name `%s' (%u chars max)",
Packit 7b22a4
			   targetname, XT_EXTENSION_MAXNAMELEN - 1);
Packit 7b22a4
Packit 7b22a4
	for (ptr = targetname; *ptr; ptr++)
Packit 7b22a4
		if (isspace(*ptr))
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				   "Invalid target name `%s'", targetname);
Packit 7b22a4
	return targetname;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void command_jump(struct iptables_command_state *cs, const char *jumpto)
Packit 7b22a4
{
Packit 7b22a4
	struct option *opts = xt_params->opts;
Packit 7b22a4
	size_t size;
Packit 7b22a4
Packit 7b22a4
	cs->jumpto = xt_parse_target(jumpto);
Packit 7b22a4
	/* TRY_LOAD (may be chain name) */
Packit 7b22a4
	cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
Packit 7b22a4
Packit 7b22a4
	if (cs->target == NULL)
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
Packit 7b22a4
Packit 7b22a4
	cs->target->t = xtables_calloc(1, size);
Packit 7b22a4
	cs->target->t->u.target_size = size;
Packit 7b22a4
	if (cs->target->real_name == NULL) {
Packit 7b22a4
		strcpy(cs->target->t->u.user.name, cs->jumpto);
Packit 7b22a4
	} else {
Packit 7b22a4
		/* Alias support for userspace side */
Packit 7b22a4
		strcpy(cs->target->t->u.user.name, cs->target->real_name);
Packit 7b22a4
		if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS))
Packit 7b22a4
			fprintf(stderr, "Notice: The %s target is converted into %s target "
Packit 7b22a4
				"in rule listing and saving.\n",
Packit 7b22a4
				cs->jumpto, cs->target->real_name);
Packit 7b22a4
	}
Packit 7b22a4
	cs->target->t->u.user.revision = cs->target->revision;
Packit 7b22a4
	xs_init_target(cs->target);
Packit 7b22a4
Packit 7b22a4
	if (cs->target->x6_options != NULL)
Packit 7b22a4
		opts = xtables_options_xfrm(xt_params->orig_opts, opts,
Packit 7b22a4
					    cs->target->x6_options,
Packit 7b22a4
					    &cs->target->option_offset);
Packit 7b22a4
	else
Packit 7b22a4
		opts = xtables_merge_options(xt_params->orig_opts, opts,
Packit 7b22a4
					     cs->target->extra_opts,
Packit 7b22a4
					     &cs->target->option_offset);
Packit 7b22a4
	if (opts == NULL)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
Packit 7b22a4
	xt_params->opts = opts;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
char cmd2char(int option)
Packit 7b22a4
{
Packit 7b22a4
	/* cmdflags index corresponds with position of bit in CMD_* values */
Packit 7b22a4
	static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
Packit 7b22a4
					 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	for (i = 0; option > 1; option >>= 1, i++)
Packit 7b22a4
		;
Packit 7b22a4
	if (i >= ARRAY_SIZE(cmdflags))
Packit 7b22a4
		xtables_error(OTHER_PROBLEM,
Packit 7b22a4
			      "cmd2char(): Invalid command number %u.\n",
Packit 7b22a4
			      1 << i);
Packit 7b22a4
	return cmdflags[i];
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
void add_command(unsigned int *cmd, const int newcmd,
Packit 7b22a4
		 const int othercmds, int invert)
Packit 7b22a4
{
Packit 7b22a4
	if (invert)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag");
Packit 7b22a4
	if (*cmd & (~othercmds))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
Packit 7b22a4
			   cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
Packit 7b22a4
	*cmd |= newcmd;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* Can't be zero. */
Packit 7b22a4
int parse_rulenumber(const char *rule)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int rulenum;
Packit 7b22a4
Packit 7b22a4
	if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			   "Invalid rule number `%s'", rule);
Packit 7b22a4
Packit 7b22a4
	return rulenum;
Packit 7b22a4
}