Blame iptables/iptables-restore.c

Packit 7b22a4
/* Code to restore the iptables state, from file by iptables-save.
Packit 7b22a4
 * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
Packit 7b22a4
 * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
Packit 7b22a4
 *
Packit 7b22a4
 * This code is distributed under the terms of GNU GPL v2
Packit 7b22a4
 */
Packit 7b22a4
#include "config.h"
Packit 7b22a4
#include <getopt.h>
Packit 7b22a4
#include <errno.h>
Packit 7b22a4
#include <stdbool.h>
Packit 7b22a4
#include <string.h>
Packit 7b22a4
#include <stdio.h>
Packit 7b22a4
#include <stdlib.h>
Packit 7b22a4
#include "iptables.h"
Packit 7b22a4
#include "ip6tables.h"
Packit 7b22a4
#include "xshared.h"
Packit 7b22a4
#include "xtables.h"
Packit 7b22a4
#include "libiptc/libiptc.h"
Packit 7b22a4
#include "libiptc/libip6tc.h"
Packit 7b22a4
#include "iptables-multi.h"
Packit 7b22a4
#include "ip6tables-multi.h"
Packit 7b22a4
Packit 7b22a4
static int counters, verbose, noflush, wait;
Packit 7b22a4
Packit 7b22a4
static struct timeval wait_interval = {
Packit 7b22a4
	.tv_sec	= 1,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
/* Keeping track of external matches and targets.  */
Packit 7b22a4
static const struct option options[] = {
Packit 7b22a4
	{.name = "counters",      .has_arg = 0, .val = 'c'},
Packit 7b22a4
	{.name = "verbose",       .has_arg = 0, .val = 'v'},
Packit 7b22a4
	{.name = "version",       .has_arg = 0, .val = 'V'},
Packit 7b22a4
	{.name = "test",          .has_arg = 0, .val = 't'},
Packit 7b22a4
	{.name = "help",          .has_arg = 0, .val = 'h'},
Packit 7b22a4
	{.name = "noflush",       .has_arg = 0, .val = 'n'},
Packit 7b22a4
	{.name = "modprobe",      .has_arg = 1, .val = 'M'},
Packit 7b22a4
	{.name = "table",         .has_arg = 1, .val = 'T'},
Packit 7b22a4
	{.name = "wait",          .has_arg = 2, .val = 'w'},
Packit 7b22a4
	{.name = "wait-interval", .has_arg = 2, .val = 'W'},
Packit 7b22a4
	{NULL},
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static void print_usage(const char *name, const char *version)
Packit 7b22a4
{
Packit 7b22a4
	fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command] [file]\n"
Packit 7b22a4
			"	   [ --counters ]\n"
Packit 7b22a4
			"	   [ --verbose ]\n"
Packit 7b22a4
			"	   [ --version]\n"
Packit 7b22a4
			"	   [ --test ]\n"
Packit 7b22a4
			"	   [ --help ]\n"
Packit 7b22a4
			"	   [ --noflush ]\n"
Packit 7b22a4
			"	   [ --wait=<seconds>\n"
Packit 7b22a4
			"	   [ --wait-interval=<usecs>\n"
Packit 7b22a4
			"	   [ --table= ]\n"
Packit 7b22a4
			"	   [ --modprobe=<command> ]\n", name);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct iptables_restore_cb {
Packit 7b22a4
	const struct xtc_ops *ops;
Packit 7b22a4
Packit 7b22a4
	int (*for_each_chain)(int (*fn)(const xt_chainlabel,
Packit 7b22a4
					int, struct xtc_handle *),
Packit 7b22a4
			      int verbose, int builtinstoo,
Packit 7b22a4
			      struct xtc_handle *handle);
Packit 7b22a4
	int (*flush_entries)(const xt_chainlabel, int, struct xtc_handle *);
Packit 7b22a4
	int (*delete_chain)(const xt_chainlabel, int, struct xtc_handle *);
Packit 7b22a4
	int (*do_command)(int argc, char *argv[], char **table,
Packit 7b22a4
			  struct xtc_handle **handle, bool restore);
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static struct xtc_handle *
Packit 7b22a4
create_handle(const struct iptables_restore_cb *cb, const char *tablename)
Packit 7b22a4
{
Packit 7b22a4
	struct xtc_handle *handle;
Packit 7b22a4
Packit 7b22a4
	handle = cb->ops->init(tablename);
Packit 7b22a4
Packit 7b22a4
	if (!handle) {
Packit 7b22a4
		/* try to insmod the module if iptc_init failed */
Packit 7b22a4
		xtables_load_ko(xtables_modprobe_program, false);
Packit 7b22a4
		handle = cb->ops->init(tablename);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (!handle)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
Packit 7b22a4
			"table '%s'\n", xt_params->program_name, tablename);
Packit 7b22a4
Packit 7b22a4
	return handle;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int
Packit 7b22a4
ip46tables_restore_main(const struct iptables_restore_cb *cb,
Packit 7b22a4
			int argc, char *argv[])
Packit 7b22a4
{
Packit 7b22a4
	struct xtc_handle *handle = NULL;
Packit 7b22a4
	struct argv_store av_store = {};
Packit 7b22a4
	char buffer[10240];
Packit 7b22a4
	int c, lock;
Packit 7b22a4
	char curtable[XT_TABLE_MAXNAMELEN + 1] = {};
Packit 7b22a4
	FILE *in;
Packit 7b22a4
	int in_table = 0, testing = 0;
Packit 7b22a4
	const char *tablename = NULL;
Packit 7b22a4
Packit 7b22a4
	line = 0;
Packit 7b22a4
	lock = XT_LOCK_NOT_ACQUIRED;
Packit 7b22a4
Packit 7b22a4
	while ((c = getopt_long(argc, argv, "bcvVthnwWM:T:", options, NULL)) != -1) {
Packit 7b22a4
		switch (c) {
Packit 7b22a4
			case 'b':
Packit 7b22a4
				fprintf(stderr, "-b/--binary option is not implemented\n");
Packit 7b22a4
				break;
Packit 7b22a4
			case 'c':
Packit 7b22a4
				counters = 1;
Packit 7b22a4
				break;
Packit 7b22a4
			case 'v':
Packit 7b22a4
				verbose = 1;
Packit 7b22a4
				break;
Packit 7b22a4
			case 'V':
Packit 7b22a4
				printf("%s v%s (legacy)\n",
Packit 7b22a4
				       xt_params->program_name,
Packit 7b22a4
				       xt_params->program_version);
Packit 7b22a4
				exit(0);
Packit 7b22a4
			case 't':
Packit 7b22a4
				testing = 1;
Packit 7b22a4
				break;
Packit 7b22a4
			case 'h':
Packit 7b22a4
				print_usage(xt_params->program_name,
Packit 7b22a4
					    PACKAGE_VERSION);
Packit 7b22a4
				exit(0);
Packit 7b22a4
			case 'n':
Packit 7b22a4
				noflush = 1;
Packit 7b22a4
				break;
Packit 7b22a4
			case 'w':
Packit 7b22a4
				wait = parse_wait_time(argc, argv);
Packit 7b22a4
				break;
Packit 7b22a4
			case 'W':
Packit 7b22a4
				parse_wait_interval(argc, argv, &wait_interval);
Packit 7b22a4
				break;
Packit 7b22a4
			case 'M':
Packit 7b22a4
				xtables_modprobe_program = optarg;
Packit 7b22a4
				break;
Packit 7b22a4
			case 'T':
Packit 7b22a4
				tablename = optarg;
Packit 7b22a4
				break;
Packit 7b22a4
			default:
Packit 7b22a4
				fprintf(stderr,
Packit 7b22a4
					"Try `%s -h' for more information.\n",
Packit 7b22a4
					xt_params->program_name);
Packit 7b22a4
				exit(1);
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (optind == argc - 1) {
Packit 7b22a4
		in = fopen(argv[optind], "re");
Packit 7b22a4
		if (!in) {
Packit 7b22a4
			fprintf(stderr, "Can't open %s: %s\n", argv[optind],
Packit 7b22a4
				strerror(errno));
Packit 7b22a4
			exit(1);
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	else if (optind < argc) {
Packit 7b22a4
		fprintf(stderr, "Unknown arguments found on commandline\n");
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
	else in = stdin;
Packit 7b22a4
Packit 7b22a4
	if (!wait_interval.tv_sec && !wait) {
Packit 7b22a4
		fprintf(stderr, "Option --wait-interval requires option --wait\n");
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	/* Grab standard input. */
Packit 7b22a4
	while (fgets(buffer, sizeof(buffer), in)) {
Packit 7b22a4
		int ret = 0;
Packit 7b22a4
Packit 7b22a4
		line++;
Packit 7b22a4
		if (buffer[0] == '\n')
Packit 7b22a4
			continue;
Packit 7b22a4
		else if (buffer[0] == '#') {
Packit 7b22a4
			if (verbose)
Packit 7b22a4
				fputs(buffer, stdout);
Packit 7b22a4
			continue;
Packit 7b22a4
		} else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
Packit 7b22a4
			if (!testing) {
Packit 7b22a4
				DEBUGP("Calling commit\n");
Packit 7b22a4
				ret = cb->ops->commit(handle);
Packit 7b22a4
				cb->ops->free(handle);
Packit 7b22a4
				handle = NULL;
Packit 7b22a4
			} else {
Packit 7b22a4
				DEBUGP("Not calling commit, testing\n");
Packit 7b22a4
				ret = 1;
Packit 7b22a4
			}
Packit 7b22a4
Packit 7b22a4
			/* Done with the current table, release the lock. */
Packit 7b22a4
			if (lock >= 0) {
Packit 7b22a4
				xtables_unlock(lock);
Packit 7b22a4
				lock = XT_LOCK_NOT_ACQUIRED;
Packit 7b22a4
			}
Packit 7b22a4
Packit 7b22a4
			in_table = 0;
Packit 7b22a4
		} else if ((buffer[0] == '*') && (!in_table)) {
Packit 7b22a4
			/* Acquire a lock before we create a new table handle */
Packit 7b22a4
			lock = xtables_lock_or_exit(wait, &wait_interval);
Packit 7b22a4
Packit 7b22a4
			/* New table */
Packit 7b22a4
			char *table;
Packit 7b22a4
Packit 7b22a4
			table = strtok(buffer+1, " \t\n");
Packit 7b22a4
			DEBUGP("line %u, table '%s'\n", line, table);
Packit 7b22a4
			if (!table)
Packit 7b22a4
				xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
					"%s: line %u table name invalid\n",
Packit 7b22a4
					xt_params->program_name, line);
Packit 7b22a4
Packit 7b22a4
			strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
Packit 7b22a4
			curtable[XT_TABLE_MAXNAMELEN] = '\0';
Packit 7b22a4
Packit 7b22a4
			if (tablename && strcmp(tablename, table) != 0) {
Packit 7b22a4
				if (lock >= 0) {
Packit 7b22a4
					xtables_unlock(lock);
Packit 7b22a4
					lock = XT_LOCK_NOT_ACQUIRED;
Packit 7b22a4
				}
Packit 7b22a4
				continue;
Packit 7b22a4
			}
Packit 7b22a4
			if (handle)
Packit 7b22a4
				cb->ops->free(handle);
Packit 7b22a4
Packit 7b22a4
			handle = create_handle(cb, table);
Packit 7b22a4
			if (noflush == 0) {
Packit 7b22a4
				DEBUGP("Cleaning all chains of table '%s'\n",
Packit 7b22a4
					table);
Packit 7b22a4
				cb->for_each_chain(cb->flush_entries, verbose, 1,
Packit 7b22a4
						handle);
Packit 7b22a4
Packit 7b22a4
				DEBUGP("Deleting all user-defined chains "
Packit 7b22a4
				       "of table '%s'\n", table);
Packit 7b22a4
				cb->for_each_chain(cb->delete_chain, verbose, 0,
Packit 7b22a4
						handle);
Packit 7b22a4
			}
Packit 7b22a4
Packit 7b22a4
			ret = 1;
Packit 7b22a4
			in_table = 1;
Packit 7b22a4
Packit 7b22a4
		} else if ((buffer[0] == ':') && (in_table)) {
Packit 7b22a4
			/* New chain. */
Packit 7b22a4
			char *policy, *chain;
Packit 7b22a4
Packit 7b22a4
			chain = strtok(buffer+1, " \t\n");
Packit 7b22a4
			DEBUGP("line %u, chain '%s'\n", line, chain);
Packit 7b22a4
			if (!chain)
Packit 7b22a4
				xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
					   "%s: line %u chain name invalid\n",
Packit 7b22a4
					   xt_params->program_name, line);
Packit 7b22a4
Packit 7b22a4
			if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
Packit 7b22a4
				xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
					   "Invalid chain name `%s' "
Packit 7b22a4
					   "(%u chars max)",
Packit 7b22a4
					   chain, XT_EXTENSION_MAXNAMELEN - 1);
Packit 7b22a4
Packit 7b22a4
			if (cb->ops->builtin(chain, handle) <= 0) {
Packit 7b22a4
				if (noflush && cb->ops->is_chain(chain, handle)) {
Packit 7b22a4
					DEBUGP("Flushing existing user defined chain '%s'\n", chain);
Packit 7b22a4
					if (!cb->ops->flush_entries(chain, handle))
Packit 7b22a4
						xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
							   "error flushing chain "
Packit 7b22a4
							   "'%s':%s\n", chain,
Packit 7b22a4
							   strerror(errno));
Packit 7b22a4
				} else {
Packit 7b22a4
					DEBUGP("Creating new chain '%s'\n", chain);
Packit 7b22a4
					if (!cb->ops->create_chain(chain, handle))
Packit 7b22a4
						xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
							   "error creating chain "
Packit 7b22a4
							   "'%s':%s\n", chain,
Packit 7b22a4
							   strerror(errno));
Packit 7b22a4
				}
Packit 7b22a4
			}
Packit 7b22a4
Packit 7b22a4
			policy = strtok(NULL, " \t\n");
Packit 7b22a4
			DEBUGP("line %u, policy '%s'\n", line, policy);
Packit 7b22a4
			if (!policy)
Packit 7b22a4
				xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
					   "%s: line %u policy invalid\n",
Packit 7b22a4
					   xt_params->program_name, line);
Packit 7b22a4
Packit 7b22a4
			if (strcmp(policy, "-") != 0) {
Packit 7b22a4
				struct xt_counters count = {};
Packit 7b22a4
Packit 7b22a4
				if (counters) {
Packit 7b22a4
					char *ctrs;
Packit 7b22a4
					ctrs = strtok(NULL, " \t\n");
Packit 7b22a4
Packit 7b22a4
					if (!ctrs || !parse_counters(ctrs, &count))
Packit 7b22a4
						xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
							  "invalid policy counters "
Packit 7b22a4
							  "for chain '%s'\n", chain);
Packit 7b22a4
				}
Packit 7b22a4
Packit 7b22a4
				DEBUGP("Setting policy of chain %s to %s\n",
Packit 7b22a4
					chain, policy);
Packit 7b22a4
Packit 7b22a4
				if (!cb->ops->set_policy(chain, policy, &count,
Packit 7b22a4
						     handle))
Packit 7b22a4
					xtables_error(OTHER_PROBLEM,
Packit 7b22a4
						"Can't set policy `%s'"
Packit 7b22a4
						" on `%s' line %u: %s\n",
Packit 7b22a4
						policy, chain, line,
Packit 7b22a4
						cb->ops->strerror(errno));
Packit 7b22a4
			}
Packit 7b22a4
Packit 7b22a4
			ret = 1;
Packit 7b22a4
Packit 7b22a4
		} else if (in_table) {
Packit 7b22a4
			char *pcnt = NULL;
Packit 7b22a4
			char *bcnt = NULL;
Packit 7b22a4
			char *parsestart = buffer;
Packit 7b22a4
Packit 7b22a4
			add_argv(&av_store, argv[0], 0);
Packit 7b22a4
			add_argv(&av_store, "-t", 0);
Packit 7b22a4
			add_argv(&av_store, curtable, 0);
Packit 7b22a4
Packit 7b22a4
			tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
Packit 7b22a4
			if (counters && pcnt && bcnt) {
Packit 7b22a4
				add_argv(&av_store, "--set-counters", 0);
Packit 7b22a4
				add_argv(&av_store, pcnt, 0);
Packit 7b22a4
				add_argv(&av_store, bcnt, 0);
Packit 7b22a4
			}
Packit 7b22a4
Packit 7b22a4
			add_param_to_argv(&av_store, parsestart, line);
Packit 7b22a4
Packit 7b22a4
			DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
Packit 7b22a4
				av_store.argc, curtable);
Packit 7b22a4
			debug_print_argv(&av_store);
Packit 7b22a4
Packit 7b22a4
			ret = cb->do_command(av_store.argc, av_store.argv,
Packit 7b22a4
					 &av_store.argv[2], &handle, true);
Packit 7b22a4
Packit 7b22a4
			free_argv(&av_store);
Packit 7b22a4
			fflush(stdout);
Packit 7b22a4
		}
Packit 7b22a4
		if (tablename && strcmp(tablename, curtable) != 0)
Packit 7b22a4
			continue;
Packit 7b22a4
		if (!ret) {
Packit 7b22a4
			fprintf(stderr, "%s: line %u failed\n",
Packit 7b22a4
					xt_params->program_name, line);
Packit 7b22a4
			exit(1);
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	if (in_table) {
Packit 7b22a4
		fprintf(stderr, "%s: COMMIT expected at line %u\n",
Packit 7b22a4
				xt_params->program_name, line + 1);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	fclose(in);
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
Packit 7b22a4
#if defined ENABLE_IPV4
Packit 7b22a4
static const struct iptables_restore_cb ipt_restore_cb = {
Packit 7b22a4
	.ops		= &iptc_ops,
Packit 7b22a4
	.for_each_chain	= for_each_chain4,
Packit 7b22a4
	.flush_entries	= flush_entries4,
Packit 7b22a4
	.delete_chain	= delete_chain4,
Packit 7b22a4
	.do_command	= do_command4,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
int
Packit 7b22a4
iptables_restore_main(int argc, char *argv[])
Packit 7b22a4
{
Packit 7b22a4
	int c;
Packit 7b22a4
Packit 7b22a4
	iptables_globals.program_name = "iptables-restore";
Packit 7b22a4
	c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
Packit 7b22a4
	if (c < 0) {
Packit 7b22a4
		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
Packit 7b22a4
				iptables_globals.program_name,
Packit 7b22a4
				iptables_globals.program_version);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
Packit 7b22a4
	init_extensions();
Packit 7b22a4
	init_extensions4();
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
	return ip46tables_restore_main(&ipt_restore_cb, argc, argv);
Packit 7b22a4
}
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
#if defined ENABLE_IPV6
Packit 7b22a4
static const struct iptables_restore_cb ip6t_restore_cb = {
Packit 7b22a4
	.ops		= &ip6tc_ops,
Packit 7b22a4
	.for_each_chain	= for_each_chain6,
Packit 7b22a4
	.flush_entries	= flush_entries6,
Packit 7b22a4
	.delete_chain	= delete_chain6,
Packit 7b22a4
	.do_command	= do_command6,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
int
Packit 7b22a4
ip6tables_restore_main(int argc, char *argv[])
Packit 7b22a4
{
Packit 7b22a4
	int c;
Packit 7b22a4
Packit 7b22a4
	ip6tables_globals.program_name = "ip6tables-restore";
Packit 7b22a4
	c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
Packit 7b22a4
	if (c < 0) {
Packit 7b22a4
		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
Packit 7b22a4
				ip6tables_globals.program_name,
Packit 7b22a4
				ip6tables_globals.program_version);
Packit 7b22a4
		exit(1);
Packit 7b22a4
	}
Packit 7b22a4
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
Packit 7b22a4
	init_extensions();
Packit 7b22a4
	init_extensions6();
Packit 7b22a4
#endif
Packit 7b22a4
Packit 7b22a4
	return ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
Packit 7b22a4
}
Packit 7b22a4
#endif