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'},
31fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt	{.name = "modprobe", .has_arg = true,  .val = 'M'},
327bc3cb7eec4c4db5edc4b503a5dfab799e0bce62Gáspár Lajos	{NULL},
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Debugging prototype. */
36a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int for_each_table(int (*func)(const char *tablename))
37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
385b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann	int ret = 1;
39ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	FILE *procfile = NULL;
40a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	char tablename[IPT_TABLE_MAXNAMELEN+1];
41a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
42a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	procfile = fopen("/proc/net/ip_tables_names", "re");
43a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!procfile)
44fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt		return ret;
45a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
46a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	while (fgets(tablename, sizeof(tablename), procfile)) {
47a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		if (tablename[strlen(tablename) - 1] != '\n')
481829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(OTHER_PROBLEM,
49a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell				   "Badly formed tablename `%s'\n",
50a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell				   tablename);
51a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		tablename[strlen(tablename) - 1] = '\0';
52a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		ret &= func(tablename);
53a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
55f1afcc896e7f8be3a6419681fd8cdee1d600a3aaJan Engelhardt	fclose(procfile);
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);
69fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt	if (h == NULL) {
70fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt		xtables_load_ko(xtables_modprobe_program, false);
71fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt		h = iptc_init(tablename);
72fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt	}
73a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!h)
741829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n",
75a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			   iptc_strerror(errno));
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
77dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt	if (!show_binary) {
78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		time_t now = time(NULL);
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("# Generated by iptables-save v%s on %s",
81dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		       IPTABLES_VERSION, ctime(&now));
82ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		printf("*%s\n", tablename);
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
845b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann		/* Dump out chain names first,
859f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		 * thereby preventing dependency conflicts */
861c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		for (chain = iptc_first_chain(h);
87a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		     chain;
881c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		     chain = iptc_next_chain(h)) {
895b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(":%s ", chain);
91ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			if (iptc_builtin(chain, h)) {
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				struct ipt_counters count;
93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("%s ",
941c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt				       iptc_get_policy(chain, &count, h));
95a28d495285ad7dd9f286d63958cf20d74eec6bcbMartin Josefsson				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			} else {
97d8e6563430ab692cf093a81b9b6ac997739d9504Harald Welte				printf("- [0:0]\n");
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
999f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		}
1005b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
1019f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte
1021c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		for (chain = iptc_first_chain(h);
1039f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		     chain;
1041c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		     chain = iptc_next_chain(h)) {
1059f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte			const struct ipt_entry *e;
106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
107ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			/* Dump out rules */
1081c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt			e = iptc_first_rule(chain, h);
109ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			while(e) {
110bb9fe8059f40f0dde9c780498f5af42f5aa6a179Maciej Zenczykowski				print_rule4(e, h, chain, show_counters);
1111c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt				e = iptc_next_rule(e, h);
112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		now = time(NULL);
116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("COMMIT\n");
117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("# Completed on %s", ctime(&now));
118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Binary, huh?  OK. */
1201829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(OTHER_PROBLEM, "Binary NYI\n");
121a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
122a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
1231c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	iptc_free(h);
124841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
125a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return 1;
126a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell}
127a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
128a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell/* Format:
129a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell * :Chain name POLICY packets bytes
130a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell * rule
131a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell */
1324e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#ifdef IPTABLES_MULTI
1334e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkerint
1344e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkeriptables_save_main(int argc, char *argv[])
1354e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#else
1364e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkerint
1374e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkermain(int argc, char *argv[])
1384e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#endif
139a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell{
140a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	const char *tablename = NULL;
141a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	int c;
142a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
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	}
151b79ec69027fd8b65e7eccd78a445b6665e8ad53bJan Engelhardt#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
1529a9694fbf1796a6a5011b60b2a15c01fa3c61368Maciej Żenczykowski	init_extensions();
1535e8f947becc00a79e78b2a6cf0e25fd674c57ec4Maciej Zenczykowski	init_extensions4();
1543efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte#endif
1553efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte
156163ad7801e93e4d8d3308741d34bcc1ee695d87bMarc Boucher	while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
157a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		switch (c) {
158a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'b':
159dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt			show_binary = 1;
160a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
161a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
162a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'c':
163dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt			show_counters = 1;
164a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
165a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
166a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 't':
167a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			/* Select specific table. */
168a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			tablename = optarg;
169a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
170fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt		case 'M':
171fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt			xtables_modprobe_program = optarg;
172fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt			break;
173a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'd':
174ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			do_output(tablename);
175a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			exit(0);
176a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		}
177a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
178a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
179a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (optind < argc) {
180972af09e79618c5086e26ef6438bd38c45c4bb3fPavel Rusnak		fprintf(stderr, "Unknown arguments found on commandline\n");
181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
184a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return !do_output(tablename);
185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
186