1/* Code to save the ip6tables state, in human readable-form. */
2/* Author:  Andras Kis-Szabo <kisza@sch.bme.hu>
3 * Original code: iptables-save
4 * Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
5 *          Harald Welte <laforge@gnumonks.org>
6 * This code is distributed under the terms of GNU GPL v2
7 */
8#include <getopt.h>
9#include <sys/errno.h>
10#include <stdio.h>
11#include <fcntl.h>
12#include <stdlib.h>
13#include <string.h>
14#include <time.h>
15#include <netdb.h>
16#include <arpa/inet.h>
17#include "libiptc/libip6tc.h"
18#include "ip6tables.h"
19#include "ip6tables-multi.h"
20
21#ifndef NO_SHARED_LIBS
22#include <dlfcn.h>
23#endif
24
25static int show_binary = 0, show_counters = 0;
26
27static const struct option options[] = {
28	{.name = "binary",   .has_arg = false, .val = 'b'},
29	{.name = "counters", .has_arg = false, .val = 'c'},
30	{.name = "dump",     .has_arg = false, .val = 'd'},
31	{.name = "table",    .has_arg = true,  .val = 't'},
32	{.name = "modprobe", .has_arg = true,  .val = 'M'},
33	{NULL},
34};
35
36
37/* Debugging prototype. */
38static int for_each_table(int (*func)(const char *tablename))
39{
40	int ret = 1;
41	FILE *procfile = NULL;
42	char tablename[IP6T_TABLE_MAXNAMELEN+1];
43
44	procfile = fopen("/proc/net/ip6_tables_names", "re");
45	if (!procfile)
46		return ret;
47
48	while (fgets(tablename, sizeof(tablename), procfile)) {
49		if (tablename[strlen(tablename) - 1] != '\n')
50			xtables_error(OTHER_PROBLEM,
51				   "Badly formed tablename `%s'\n",
52				   tablename);
53		tablename[strlen(tablename) - 1] = '\0';
54		ret &= func(tablename);
55	}
56
57	fclose(procfile);
58	return ret;
59}
60
61
62static int do_output(const char *tablename)
63{
64	struct ip6tc_handle *h;
65	const char *chain = NULL;
66
67	if (!tablename)
68		return for_each_table(&do_output);
69
70	h = ip6tc_init(tablename);
71	if (h == NULL) {
72		xtables_load_ko(xtables_modprobe_program, false);
73		h = ip6tc_init(tablename);
74	}
75	if (!h)
76		xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n",
77			   ip6tc_strerror(errno));
78
79	if (!show_binary) {
80		time_t now = time(NULL);
81
82		printf("# Generated by ip6tables-save v%s on %s",
83		       IPTABLES_VERSION, ctime(&now));
84		printf("*%s\n", tablename);
85
86		/* Dump out chain names first,
87		 * thereby preventing dependency conflicts */
88		for (chain = ip6tc_first_chain(h);
89		     chain;
90		     chain = ip6tc_next_chain(h)) {
91
92			printf(":%s ", chain);
93			if (ip6tc_builtin(chain, h)) {
94				struct ip6t_counters count;
95				printf("%s ",
96				       ip6tc_get_policy(chain, &count, h));
97				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
98			} else {
99				printf("- [0:0]\n");
100			}
101		}
102
103
104		for (chain = ip6tc_first_chain(h);
105		     chain;
106		     chain = ip6tc_next_chain(h)) {
107			const struct ip6t_entry *e;
108
109			/* Dump out rules */
110			e = ip6tc_first_rule(chain, h);
111			while(e) {
112				print_rule6(e, h, chain, show_counters);
113				e = ip6tc_next_rule(e, h);
114			}
115		}
116
117		now = time(NULL);
118		printf("COMMIT\n");
119		printf("# Completed on %s", ctime(&now));
120	} else {
121		/* Binary, huh?  OK. */
122		xtables_error(OTHER_PROBLEM, "Binary NYI\n");
123	}
124
125	ip6tc_free(h);
126
127	return 1;
128}
129
130/* Format:
131 * :Chain name POLICY packets bytes
132 * rule
133 */
134#ifdef IPTABLES_MULTI
135int ip6tables_save_main(int argc, char *argv[])
136#else
137int main(int argc, char *argv[])
138#endif
139{
140	const char *tablename = NULL;
141	int c;
142
143	ip6tables_globals.program_name = "ip6tables-save";
144	c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
145	if (c < 0) {
146		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
147				ip6tables_globals.program_name,
148				ip6tables_globals.program_version);
149		exit(1);
150	}
151#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
152	init_extensions();
153	init_extensions6();
154#endif
155
156	while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
157		switch (c) {
158		case 'b':
159			show_binary = 1;
160			break;
161
162		case 'c':
163			show_counters = 1;
164			break;
165
166		case 't':
167			/* Select specific table. */
168			tablename = optarg;
169			break;
170		case 'M':
171			xtables_modprobe_program = optarg;
172			break;
173		case 'd':
174			do_output(tablename);
175			exit(0);
176		}
177	}
178
179	if (optind < argc) {
180		fprintf(stderr, "Unknown arguments found on commandline\n");
181		exit(1);
182	}
183
184	return !do_output(tablename);
185}
186