iptables-save.c 6.25 KB
Newer Older
1
2
3
4
5
6
7
8
/* Code to save the iptables state, in human readable-form. */
/* (C) 1999 by Paul 'Rusty' Russell <rusty@rustcorp.com.au> and
 * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
 *
 * This code is distributed under the terms of GNU GPL v2
 *
 */
#include <getopt.h>
9
#include <errno.h>
10
11
12
13
14
15
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <netdb.h>
16
#include <unistd.h>
17
#include "libiptc/libiptc.h"
18
#include "libiptc/libip6tc.h"
19
#include "iptables.h"
20
#include "ip6tables.h"
21
#include "iptables-multi.h"
22
23
#include "ip6tables-multi.h"
#include "xshared.h"
24

25
static int show_counters;
26
27
28
29
30
31

static const struct option options[] = {
	{.name = "counters", .has_arg = false, .val = 'c'},
	{.name = "dump",     .has_arg = false, .val = 'd'},
	{.name = "table",    .has_arg = true,  .val = 't'},
	{.name = "modprobe", .has_arg = true,  .val = 'M'},
32
	{.name = "file",     .has_arg = true,  .val = 'f'},
33
	{.name = "version",  .has_arg = false, .val = 'V'},
34
35
36
	{NULL},
};

37
38
39
40
41
42
43
44
45
struct iptables_save_cb {
	const struct xtc_ops *ops;

	void (*dump_rules)(const char *chain, struct xtc_handle *handle);
};

static int
for_each_table(int (*func)(struct iptables_save_cb *cb, const char *tablename),
	       struct iptables_save_cb *cb)
46
47
48
49
50
{
	int ret = 1;
	FILE *procfile = NULL;
	char tablename[XT_TABLE_MAXNAMELEN+1];

51
	procfile = fopen(afinfo->proc_exists, "re");
52
53
54
55
	if (!procfile) {
		if (errno == ENOENT)
			return ret;
		fprintf(stderr, "Failed to list table names in %s: %s\n",
56
		        afinfo->proc_exists, strerror(errno));
57
58
		exit(1);
	}
59
60
61
62
63
64
65

	while (fgets(tablename, sizeof(tablename), procfile)) {
		if (tablename[strlen(tablename) - 1] != '\n')
			xtables_error(OTHER_PROBLEM,
				   "Badly formed tablename `%s'\n",
				   tablename);
		tablename[strlen(tablename) - 1] = '\0';
66
		ret &= func(cb, tablename);
67
68
69
70
71
72
	}

	fclose(procfile);
	return ret;
}

73
static int do_output(struct iptables_save_cb *cb, const char *tablename)
74
75
76
77
78
{
	struct xtc_handle *h;
	const char *chain = NULL;

	if (!tablename)
79
		return for_each_table(&do_output, cb);
80

81
	h = cb->ops->init(tablename);
82
83
	if (h == NULL) {
		xtables_load_ko(xtables_modprobe_program, false);
84
		h = cb->ops->init(tablename);
85
86
87
	}
	if (!h)
		xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n",
88
			      cb->ops->strerror(errno));
89
90
91

	time_t now = time(NULL);

92
93
	printf("# Generated by %s v%s on %s",
	       xt_params->program_name, IPTABLES_VERSION, ctime(&now));
94
95
96
97
	printf("*%s\n", tablename);

	/* Dump out chain names first,
	 * thereby preventing dependency conflicts */
98
	for (chain = cb->ops->first_chain(h);
99
	     chain;
100
	     chain = cb->ops->next_chain(h)) {
101
102

		printf(":%s ", chain);
103
		if (cb->ops->builtin(chain, h)) {
104
			struct xt_counters count;
105
106
107
108
109

			printf("%s ", cb->ops->get_policy(chain, &count, h));
			printf("[%llu:%llu]\n",
			       (unsigned long long)count.pcnt,
			       (unsigned long long)count.bcnt);
110
111
112
113
114
		} else {
			printf("- [0:0]\n");
		}
	}

115
	for (chain = cb->ops->first_chain(h);
116
	     chain;
117
118
	     chain = cb->ops->next_chain(h)) {
		cb->dump_rules(chain, h);
119
120
121
122
123
	}

	now = time(NULL);
	printf("COMMIT\n");
	printf("# Completed on %s", ctime(&now));
124
	cb->ops->free(h);
125
126
127
128
129
130
131
132

	return 1;
}

/* Format:
 * :Chain name POLICY packets bytes
 * rule
 */
133
134
static int
do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[])
135
136
{
	const char *tablename = NULL;
137
138
	FILE *file = NULL;
	int ret, c;
139

140
	while ((c = getopt_long(argc, argv, "bcdt:M:f:V", options, NULL)) != -1) {
141
		switch (c) {
142
143
144
		case 'b':
			fprintf(stderr, "-b/--binary option is not implemented\n");
			break;
145
146
147
148
149
150
151
152
153
154
155
		case 'c':
			show_counters = 1;
			break;

		case 't':
			/* Select specific table. */
			tablename = optarg;
			break;
		case 'M':
			xtables_modprobe_program = optarg;
			break;
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
		case 'f':
			file = fopen(optarg, "w");
			if (file == NULL) {
				fprintf(stderr, "Failed to open file, error: %s\n",
					strerror(errno));
				exit(1);
			}
			ret = dup2(fileno(file), STDOUT_FILENO);
			if (ret == -1) {
				fprintf(stderr, "Failed to redirect stdout, error: %s\n",
					strerror(errno));
				exit(1);
			}
			fclose(file);
			break;
171
		case 'd':
172
			do_output(cb, tablename);
173
			exit(0);
174
		case 'V':
175
176
177
			printf("%s v%s (legacy)\n",
			       xt_params->program_name,
			       xt_params->program_version);
178
			exit(0);
179
180
		default:
			fprintf(stderr,
181
182
				"Look at manual page `%s.8' for more information.\n",
				xt_params->program_name);
183
			exit(1);
184
185
186
187
188
189
190
191
		}
	}

	if (optind < argc) {
		fprintf(stderr, "Unknown arguments found on commandline\n");
		exit(1);
	}

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
	return !do_output(cb, tablename);
}

#ifdef ENABLE_IPV4
static void iptables_dump_rules(const char *chain, struct xtc_handle *h)
{
	const struct ipt_entry *e;

	/* Dump out rules */
	e = iptc_first_rule(chain, h);
	while(e) {
		print_rule4(e, h, chain, show_counters);
		e = iptc_next_rule(e, h);
	}
}

struct iptables_save_cb ipt_save_cb = {
	.ops		= &iptc_ops,
	.dump_rules	= iptables_dump_rules,
};

/* Format:
 * :Chain name POLICY packets bytes
 * rule
 */
int
iptables_save_main(int argc, char *argv[])
{
	iptables_globals.program_name = "iptables-save";
	if (xtables_init_all(&iptables_globals, NFPROTO_IPV4) < 0) {
		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
				iptables_globals.program_name,
				iptables_globals.program_version);
		exit(1);
	}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
	init_extensions();
	init_extensions4();
#endif

	return do_iptables_save(&ipt_save_cb, argc, argv);
}
#endif /* ENABLE_IPV4 */

#ifdef ENABLE_IPV6
static void ip6tables_dump_rules(const char *chain, struct xtc_handle *h)
{
	const struct ip6t_entry *e;

	/* Dump out rules */
	e = ip6tc_first_rule(chain, h);
	while(e) {
		print_rule6(e, h, chain, show_counters);
		e = ip6tc_next_rule(e, h);
	}
}

struct iptables_save_cb ip6t_save_cb = {
	.ops		= &ip6tc_ops,
	.dump_rules	= ip6tables_dump_rules,
};

/* Format:
 * :Chain name POLICY packets bytes
 * rule
 */
int
ip6tables_save_main(int argc, char *argv[])
{
	ip6tables_globals.program_name = "ip6tables-save";
	if (xtables_init_all(&ip6tables_globals, NFPROTO_IPV6) < 0) {
		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
				ip6tables_globals.program_name,
				ip6tables_globals.program_version);
		exit(1);
	}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
	init_extensions();
	init_extensions6();
#endif

	return do_iptables_save(&ip6t_save_cb, argc, argv);
274
}
275
#endif /* ENABLE_IPV6 */