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 */
134int ip6tables_save_main(int argc, char *argv[])
135{
136	const char *tablename = NULL;
137	int c;
138
139	ip6tables_globals.program_name = "ip6tables-save";
140	c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
141	if (c < 0) {
142		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
143				ip6tables_globals.program_name,
144				ip6tables_globals.program_version);
145		exit(1);
146	}
147#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
148	init_extensions();
149	init_extensions6();
150#endif
151
152	while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
153		switch (c) {
154		case 'b':
155			show_binary = 1;
156			break;
157
158		case 'c':
159			show_counters = 1;
160			break;
161
162		case 't':
163			/* Select specific table. */
164			tablename = optarg;
165			break;
166		case 'M':
167			xtables_modprobe_program = optarg;
168			break;
169		case 'd':
170			do_output(tablename);
171			exit(0);
172		}
173	}
174
175	if (optind < argc) {
176		fprintf(stderr, "Unknown arguments found on commandline\n");
177		exit(1);
178	}
179
180	return !do_output(tablename);
181}
182