12f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó/* Code to save the ip6tables state, in human readable-form. */
22f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó/* Author:  Andras Kis-Szabo <kisza@sch.bme.hu>
32f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó * Original code: iptables-save
42f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó * Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
55b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann *          Harald Welte <laforge@gnumonks.org>
60c4188f446e7c0ed07076c69d1d7f336a92efc8bAndrás Kis-Szabó * This code is distributed under the terms of GNU GPL v2
72f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó */
82f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <getopt.h>
92f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <sys/errno.h>
102f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <stdio.h>
112f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <fcntl.h>
122f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <stdlib.h>
132f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <string.h>
142f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <time.h>
152f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <netdb.h>
162f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include <arpa/inet.h>
172f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include "libiptc/libip6tc.h"
182f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó#include "ip6tables.h"
1933690a1aec0b6309ff90066ca56285b6e43013f2Jan Engelhardt#include "ip6tables-multi.h"
202f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
215a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
225a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
235a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
245a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
25296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardtstatic int show_counters = 0;
262f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
277bc3cb7eec4c4db5edc4b503a5dfab799e0bce62Gáspár Lajosstatic const struct option options[] = {
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},
332f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó};
342f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
352f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
362f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó/* Debugging prototype. */
372f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabóstatic int for_each_table(int (*func)(const char *tablename))
382f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó{
395b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann	int ret = 1;
402f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	FILE *procfile = NULL;
4114da56743c6cdf25da35b7b5ca7a5d201771990dJan Engelhardt	char tablename[XT_TABLE_MAXNAMELEN+1];
422f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
43a239728ec064666025de2723997d87b176d57fd6Maciej Zenczykowski	procfile = fopen("/proc/net/ip6_tables_names", "re");
442f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	if (!procfile)
45fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt		return ret;
462f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
472f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	while (fgets(tablename, sizeof(tablename), procfile)) {
482f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		if (tablename[strlen(tablename) - 1] != '\n')
491829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(OTHER_PROBLEM,
502f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó				   "Badly formed tablename `%s'\n",
512f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó				   tablename);
522f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		tablename[strlen(tablename) - 1] = '\0';
532f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		ret &= func(tablename);
542f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	}
552f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
56f1afcc896e7f8be3a6419681fd8cdee1d600a3aaJan Engelhardt	fclose(procfile);
572f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	return ret;
582f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó}
595b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
602f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
612f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabóstatic int do_output(const char *tablename)
622f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó{
631639fe86579f86f5f6a954a9b0adde2e16ad1980Jan Engelhardt	struct xtc_handle *h;
642f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	const char *chain = NULL;
652f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
662f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	if (!tablename)
672f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		return for_each_table(&do_output);
682f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
692f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	h = ip6tc_init(tablename);
70fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt	if (h == NULL) {
71fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt		xtables_load_ko(xtables_modprobe_program, false);
72fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt		h = ip6tc_init(tablename);
73fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt	}
742f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	if (!h)
751829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n",
762f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó			   ip6tc_strerror(errno));
772f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
78296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	time_t now = time(NULL);
79296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt
80296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	printf("# Generated by ip6tables-save v%s on %s",
81296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	       IPTABLES_VERSION, ctime(&now));
82296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	printf("*%s\n", tablename);
83296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt
84296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	/* Dump out chain names first,
85296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	 * thereby preventing dependency conflicts */
86296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	for (chain = ip6tc_first_chain(h);
87296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	     chain;
88296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	     chain = ip6tc_next_chain(h)) {
89296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt
90296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt		printf(":%s ", chain);
91296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt		if (ip6tc_builtin(chain, h)) {
9214da56743c6cdf25da35b7b5ca7a5d201771990dJan Engelhardt			struct xt_counters count;
93296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt			printf("%s ",
94296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt			       ip6tc_get_policy(chain, &count, h));
95296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
96296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt		} else {
97296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt			printf("- [0:0]\n");
98885c6eb5ec8a186c77a4710808374dd612e82b20Harald Welte		}
99296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	}
100885c6eb5ec8a186c77a4710808374dd612e82b20Harald Welte
101296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	for (chain = ip6tc_first_chain(h);
102296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	     chain;
103296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	     chain = ip6tc_next_chain(h)) {
104296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt		const struct ip6t_entry *e;
10597fd91a58e7978338451471cfc2cd5ead3b22f26András Kis-Szabó
106296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt		/* Dump out rules */
107296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt		e = ip6tc_first_rule(chain, h);
108296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt		while(e) {
109296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt			print_rule6(e, h, chain, show_counters);
110296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt			e = ip6tc_next_rule(e, h);
1112f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		}
1122f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	}
1132f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
114296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	now = time(NULL);
115296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	printf("COMMIT\n");
116296dca39be1166c4b7c6367c1b97ee95aebddfc3Jan Engelhardt	printf("# Completed on %s", ctime(&now));
1171c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	ip6tc_free(h);
118841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
1192f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	return 1;
1202f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó}
1212f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
1222f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó/* Format:
1232f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó * :Chain name POLICY packets bytes
1242f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó * rule
1252f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó */
1264bc48331d2d1ef64ba452329f2c77137036f6437Hann-Huei Chiouint ip6tables_save_main(int argc, char *argv[])
1272f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó{
1282f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	const char *tablename = NULL;
1292f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	int c;
1302f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
131617d3d140f4739558dce2ef8ed01aef251cf5487Jamal Hadi Salim	ip6tables_globals.program_name = "ip6tables-save";
1327e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
1337e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	if (c < 0) {
1347e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
1357e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim				ip6tables_globals.program_name,
1367e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim				ip6tables_globals.program_version);
1377e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim		exit(1);
1387e4db2f50133007f549f222468bde4f3adcf41acJamal Hadi Salim	}
139b79ec69027fd8b65e7eccd78a445b6665e8ad53bJan Engelhardt#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
1409a9694fbf1796a6a5011b60b2a15c01fa3c61368Maciej Żenczykowski	init_extensions();
14149d8c5d564cad70c5c1bef2d5571e8e494454210Maciej Zenczykowski	init_extensions6();
1423efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte#endif
1433efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte
14497fd91a58e7978338451471cfc2cd5ead3b22f26András Kis-Szabó	while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
1452f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		switch (c) {
1462f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		case 'c':
147dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt			show_counters = 1;
1482f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó			break;
1492f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
1502f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		case 't':
1512f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó			/* Select specific table. */
1522f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó			tablename = optarg;
1532f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó			break;
154fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt		case 'M':
155fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt			xtables_modprobe_program = optarg;
156fbb5639c02218acfd84c4f25f134efecb564fee1Jan Engelhardt			break;
1572f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		case 'd':
1582f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó			do_output(tablename);
1592f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó			exit(0);
1602f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		}
1612f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	}
1622f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
1632f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	if (optind < argc) {
164972af09e79618c5086e26ef6438bd38c45c4bb3fPavel Rusnak		fprintf(stderr, "Unknown arguments found on commandline\n");
1652f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó		exit(1);
1662f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	}
1672f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó
1682f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó	return !do_output(tablename);
1692f52379841217e55201fbc93872be9a21fa5d443András Kis-Szabó}
170