iptables-save.c 6.27 KB
Newer Older
1
2
3
4
5
6
7
/* 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
 *
 */
8
#include "config.h"
9
#include <getopt.h>
10
#include <errno.h>
11
12
13
14
15
16
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <netdb.h>
17
#include <unistd.h>
18
#include "libiptc/libiptc.h"
19
#include "libiptc/libip6tc.h"
20
#include "iptables.h"
21
#include "ip6tables.h"
22
#include "iptables-multi.h"
23
24
#include "ip6tables-multi.h"
#include "xshared.h"
25

26
static int show_counters;
27
28
29
30
31
32

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'},
33
	{.name = "file",     .has_arg = true,  .val = 'f'},
34
	{.name = "version",  .has_arg = false, .val = 'V'},
35
36
37
	{NULL},
};

38
39
40
41
42
43
44
45
46
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)
47
48
49
50
51
{
	int ret = 1;
	FILE *procfile = NULL;
	char tablename[XT_TABLE_MAXNAMELEN+1];

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

	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';
67
		ret &= func(cb, tablename);
68
69
70
71
72
73
	}

	fclose(procfile);
	return ret;
}

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

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

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

	time_t now = time(NULL);

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

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

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

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

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

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

	return 1;
}

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

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

		case 't':
			/* Select specific table. */
			tablename = optarg;
			break;
		case 'M':
			xtables_modprobe_program = optarg;
			break;
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
		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;
172
		case 'd':
173
			do_output(cb, tablename);
174
			exit(0);
175
		case 'V':
176
177
178
			printf("%s v%s (legacy)\n",
			       xt_params->program_name,
			       xt_params->program_version);
179
			exit(0);
180
181
		default:
			fprintf(stderr,
182
183
				"Look at manual page `%s.8' for more information.\n",
				xt_params->program_name);
184
			exit(1);
185
186
187
188
189
190
191
192
		}
	}

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

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
274
	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);
275
}
276
#endif /* ENABLE_IPV6 */