Blame bootstrap_ver/iptables/ip6tables-restore.c

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