iptables-save.c revision 7e4db2f50133007f549f222468bde4f3adcf41ac
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Code to save the iptables state, in human readable-form. */
210a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte/* (C) 1999 by Paul 'Rusty' Russell <rusty@rustcorp.com.au> and
310a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
410a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte *
510a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte * This code is distributed under the terms of GNU GPL v2
610a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte *
7ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte */
8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <getopt.h>
9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <sys/errno.h>
10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h>
11ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <fcntl.h>
12ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <stdlib.h>
13ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <string.h>
14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <time.h>
15d8ac967249f78212e1fe5eb55e9a417ac1d737d6Harald Welte#include <netdb.h>
16b1f69befb5b35d0cbf607ed13a6e823a94cb79ffRusty Russell#include "libiptc/libiptc.h"
17b1f69befb5b35d0cbf607ed13a6e823a94cb79ffRusty Russell#include "iptables.h"
1833690a1aec0b6309ff90066ca56285b6e43013f2Jan Engelhardt#include "iptables-multi.h"
19e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
205a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
215a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
225a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
235a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
24dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardtstatic int show_binary = 0, show_counters = 0;
25a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
267bc3cb7eec4c4db5edc4b503a5dfab799e0bce62Gáspár Lajosstatic const struct option options[] = {
277bc3cb7eec4c4db5edc4b503a5dfab799e0bce62Gáspár Lajos	{.name = "binary",   .has_arg = false, .val = 'b'},
287bc3cb7eec4c4db5edc4b503a5dfab799e0bce62Gáspár Lajos	{.name = "counters", .has_arg = false, .val = 'c'},
297bc3cb7eec4c4db5edc4b503a5dfab799e0bce62Gáspár Lajos	{.name = "dump",     .has_arg = false, .val = 'd'},
307bc3cb7eec4c4db5edc4b503a5dfab799e0bce62Gáspár Lajos	{.name = "table",    .has_arg = true,  .val = 't'},
317bc3cb7eec4c4db5edc4b503a5dfab799e0bce62Gáspár Lajos	{NULL},
32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Debugging prototype. */
35a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int for_each_table(int (*func)(const char *tablename))
36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
375b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann	int ret = 1;
38ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	FILE *procfile = NULL;
39a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	char tablename[IPT_TABLE_MAXNAMELEN+1];
40a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
41ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	procfile = fopen("/proc/net/ip_tables_names", "r");
42a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!procfile)
4365334ad262ffe9e7ad82a3b9b42ec4b03cd515e1Victor Stinner		exit_error(OTHER_PROBLEM,
4465334ad262ffe9e7ad82a3b9b42ec4b03cd515e1Victor Stinner			   "Unable to open /proc/net/ip_tables_names: %s\n",
4565334ad262ffe9e7ad82a3b9b42ec4b03cd515e1Victor Stinner			   strerror(errno));
46a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
47a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	while (fgets(tablename, sizeof(tablename), procfile)) {
48a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		if (tablename[strlen(tablename) - 1] != '\n')
49a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			exit_error(OTHER_PROBLEM,
50a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell				   "Badly formed tablename `%s'\n",
51a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell				   tablename);
52a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		tablename[strlen(tablename) - 1] = '\0';
53a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		ret &= func(tablename);
54a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
56a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return ret;
57a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell}
585b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
60a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int do_output(const char *tablename)
61a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell{
62fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	struct iptc_handle *h;
63a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	const char *chain = NULL;
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
65a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!tablename)
66a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		return for_each_table(&do_output);
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
68a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	h = iptc_init(tablename);
69a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!h)
705b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann		exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
71a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			   iptc_strerror(errno));
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
73dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt	if (!show_binary) {
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		time_t now = time(NULL);
75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("# Generated by iptables-save v%s on %s",
77dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		       IPTABLES_VERSION, ctime(&now));
78ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		printf("*%s\n", tablename);
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
805b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann		/* Dump out chain names first,
819f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		 * thereby preventing dependency conflicts */
821c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		for (chain = iptc_first_chain(h);
83a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		     chain;
841c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		     chain = iptc_next_chain(h)) {
855b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(":%s ", chain);
87ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			if (iptc_builtin(chain, h)) {
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				struct ipt_counters count;
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("%s ",
901c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt				       iptc_get_policy(chain, &count, h));
91a28d495285ad7dd9f286d63958cf20d74eec6bcbMartin Josefsson				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			} else {
93d8e6563430ab692cf093a81b9b6ac997739d9504Harald Welte				printf("- [0:0]\n");
94e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
959f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		}
965b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
979f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte
981c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		for (chain = iptc_first_chain(h);
999f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		     chain;
1001c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		     chain = iptc_next_chain(h)) {
1019f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte			const struct ipt_entry *e;
102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
103ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			/* Dump out rules */
1041c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt			e = iptc_first_rule(chain, h);
105ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			while(e) {
1061c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt				print_rule(e, h, chain, show_counters);
1071c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt				e = iptc_next_rule(e, h);
108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		now = time(NULL);
112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("COMMIT\n");
113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("# Completed on %s", ctime(&now));
114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Binary, huh?  OK. */
116a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		exit_error(OTHER_PROBLEM, "Binary NYI\n");
117a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
118a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
1191c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	iptc_free(h);
120841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
121a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return 1;
122a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell}
123a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
124a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell/* Format:
125a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell * :Chain name POLICY packets bytes
126a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell * rule
127a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell */
1284e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#ifdef IPTABLES_MULTI
1294e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkerint
1304e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkeriptables_save_main(int argc, char *argv[])
1314e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#else
1324e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkerint
1334e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkermain(int argc, char *argv[])
1344e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#endif
135a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell{
136a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	const char *tablename = NULL;
137a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	int c;
138a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
139a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	program_name = "iptables-save";
140dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	program_version = IPTABLES_VERSION;
141a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
142dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	xtables_program_name = program_name;
143617d3d140f4739558dce2ef8ed01aef251cf5487Jamal Hadi Salim	iptables_globals.program_name = "iptables-save";
1447e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
1457e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (c < 0) {
1467e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
1477e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim				iptables_globals.program_name,
1487e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim				iptables_globals.program_version);
1497e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		exit(1);
1507e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	}
1513efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte#ifdef NO_SHARED_LIBS
1523efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte	init_extensions();
1533efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte#endif
1543efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte
155163ad7801e93e4d8d3308741d34bcc1ee695d87bMarc Boucher	while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
156a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		switch (c) {
157a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'b':
158dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt			show_binary = 1;
159a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
160a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
161a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'c':
162dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt			show_counters = 1;
163a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
164a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
165a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 't':
166a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			/* Select specific table. */
167a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			tablename = optarg;
168a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
169a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'd':
170ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			do_output(tablename);
171a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			exit(0);
172a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		}
173a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
174a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
175a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (optind < argc) {
176972af09e79618c5086e26ef6438bd38c45c4bb3fPavel Rusnak		fprintf(stderr, "Unknown arguments found on commandline\n");
177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
180a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return !do_output(tablename);
181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
182