• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Code to save the iptables state, in human readable-form. */
2 /* (C) 1999 by Paul 'Rusty' Russell <rusty@rustcorp.com.au> and
3  * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
4  *
5  * This code is distributed under the terms of GNU GPL v2
6  *
7  */
8 #include "config.h"
9 #include <getopt.h>
10 #include <errno.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16 #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 #include "ip6tables-multi.h"
24 #include "xshared.h"
25 
26 static int show_counters;
27 
28 static const struct option options[] = {
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 	{.name = "file",     .has_arg = true,  .val = 'f'},
34 	{.name = "version",  .has_arg = false, .val = 'V'},
35 	{NULL},
36 };
37 
38 struct iptables_save_cb {
39 	const struct xtc_ops *ops;
40 
41 	void (*dump_rules)(const char *chain, struct xtc_handle *handle);
42 };
43 
44 static int
for_each_table(int (* func)(struct iptables_save_cb * cb,const char * tablename),struct iptables_save_cb * cb)45 for_each_table(int (*func)(struct iptables_save_cb *cb, const char *tablename),
46 	       struct iptables_save_cb *cb)
47 {
48 	int ret = 1;
49 	FILE *procfile = NULL;
50 	char tablename[XT_TABLE_MAXNAMELEN+1];
51 
52 	procfile = fopen(afinfo->proc_exists, "re");
53 	if (!procfile) {
54 		if (errno == ENOENT)
55 			return ret;
56 		fprintf(stderr, "Failed to list table names in %s: %s\n",
57 		        afinfo->proc_exists, strerror(errno));
58 		exit(1);
59 	}
60 
61 	while (fgets(tablename, sizeof(tablename), procfile)) {
62 		if (tablename[strlen(tablename) - 1] != '\n')
63 			xtables_error(OTHER_PROBLEM,
64 				   "Badly formed tablename `%s'\n",
65 				   tablename);
66 		tablename[strlen(tablename) - 1] = '\0';
67 		ret &= func(cb, tablename);
68 	}
69 
70 	fclose(procfile);
71 	return ret;
72 }
73 
do_output(struct iptables_save_cb * cb,const char * tablename)74 static int do_output(struct iptables_save_cb *cb, const char *tablename)
75 {
76 	struct xtc_handle *h;
77 	const char *chain = NULL;
78 
79 	if (!tablename)
80 		return for_each_table(&do_output, cb);
81 
82 	h = cb->ops->init(tablename);
83 	if (h == NULL) {
84 		xtables_load_ko(xtables_modprobe_program, false);
85 		h = cb->ops->init(tablename);
86 	}
87 	if (!h)
88 		xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n",
89 			      cb->ops->strerror(errno));
90 
91 	time_t now = time(NULL);
92 
93 	printf("# Generated by %s v%s on %s",
94 	       xt_params->program_name, PACKAGE_VERSION, ctime(&now));
95 	printf("*%s\n", tablename);
96 
97 	/* Dump out chain names first,
98 	 * 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 			printf("%s ", cb->ops->get_policy(chain, &count, h));
108 			printf("[%llu:%llu]\n",
109 			       (unsigned long long)count.pcnt,
110 			       (unsigned long long)count.bcnt);
111 		} else {
112 			printf("- [0:0]\n");
113 		}
114 	}
115 
116 	for (chain = cb->ops->first_chain(h);
117 	     chain;
118 	     chain = cb->ops->next_chain(h)) {
119 		cb->dump_rules(chain, h);
120 	}
121 
122 	now = time(NULL);
123 	printf("COMMIT\n");
124 	printf("# Completed on %s", ctime(&now));
125 	cb->ops->free(h);
126 
127 	return 1;
128 }
129 
130 /* Format:
131  * :Chain name POLICY packets bytes
132  * rule
133  */
134 static int
do_iptables_save(struct iptables_save_cb * cb,int argc,char * argv[])135 do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[])
136 {
137 	const char *tablename = NULL;
138 	FILE *file = NULL;
139 	int ret, c;
140 
141 	while ((c = getopt_long(argc, argv, "bcdt:M:f:V", options, NULL)) != -1) {
142 		switch (c) {
143 		case 'b':
144 			fprintf(stderr, "-b/--binary option is not implemented\n");
145 			break;
146 		case 'c':
147 			show_counters = 1;
148 			break;
149 
150 		case 't':
151 			/* Select specific table. */
152 			tablename = optarg;
153 			break;
154 		case 'M':
155 			xtables_modprobe_program = optarg;
156 			break;
157 		case 'f':
158 			file = fopen(optarg, "w");
159 			if (file == NULL) {
160 				fprintf(stderr, "Failed to open file, error: %s\n",
161 					strerror(errno));
162 				exit(1);
163 			}
164 			ret = dup2(fileno(file), STDOUT_FILENO);
165 			if (ret == -1) {
166 				fprintf(stderr, "Failed to redirect stdout, error: %s\n",
167 					strerror(errno));
168 				exit(1);
169 			}
170 			fclose(file);
171 			break;
172 		case 'd':
173 			do_output(cb, tablename);
174 			exit(0);
175 		case 'V':
176 			printf("%s v%s (legacy)\n",
177 			       xt_params->program_name,
178 			       xt_params->program_version);
179 			exit(0);
180 		default:
181 			fprintf(stderr,
182 				"Look at manual page `%s.8' for more information.\n",
183 				xt_params->program_name);
184 			exit(1);
185 		}
186 	}
187 
188 	if (optind < argc) {
189 		fprintf(stderr, "Unknown arguments found on commandline\n");
190 		exit(1);
191 	}
192 
193 	return !do_output(cb, tablename);
194 }
195 
196 #ifdef ENABLE_IPV4
iptables_dump_rules(const char * chain,struct xtc_handle * h)197 static void iptables_dump_rules(const char *chain, struct xtc_handle *h)
198 {
199 	const struct ipt_entry *e;
200 
201 	/* Dump out rules */
202 	e = iptc_first_rule(chain, h);
203 	while(e) {
204 		print_rule4(e, h, chain, show_counters);
205 		e = iptc_next_rule(e, h);
206 	}
207 }
208 
209 struct iptables_save_cb ipt_save_cb = {
210 	.ops		= &iptc_ops,
211 	.dump_rules	= iptables_dump_rules,
212 };
213 
214 /* Format:
215  * :Chain name POLICY packets bytes
216  * rule
217  */
218 int
iptables_save_main(int argc,char * argv[])219 iptables_save_main(int argc, char *argv[])
220 {
221 	int ret;
222 
223 	iptables_globals.program_name = "iptables-save";
224 	if (xtables_init_all(&iptables_globals, NFPROTO_IPV4) < 0) {
225 		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
226 				iptables_globals.program_name,
227 				iptables_globals.program_version);
228 		exit(1);
229 	}
230 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
231 	init_extensions();
232 	init_extensions4();
233 #endif
234 
235 	ret = do_iptables_save(&ipt_save_cb, argc, argv);
236 
237 	xtables_fini();
238 	return ret;
239 }
240 #endif /* ENABLE_IPV4 */
241 
242 #ifdef ENABLE_IPV6
ip6tables_dump_rules(const char * chain,struct xtc_handle * h)243 static void ip6tables_dump_rules(const char *chain, struct xtc_handle *h)
244 {
245 	const struct ip6t_entry *e;
246 
247 	/* Dump out rules */
248 	e = ip6tc_first_rule(chain, h);
249 	while(e) {
250 		print_rule6(e, h, chain, show_counters);
251 		e = ip6tc_next_rule(e, h);
252 	}
253 }
254 
255 struct iptables_save_cb ip6t_save_cb = {
256 	.ops		= &ip6tc_ops,
257 	.dump_rules	= ip6tables_dump_rules,
258 };
259 
260 /* Format:
261  * :Chain name POLICY packets bytes
262  * rule
263  */
264 int
ip6tables_save_main(int argc,char * argv[])265 ip6tables_save_main(int argc, char *argv[])
266 {
267 	int ret;
268 
269 	ip6tables_globals.program_name = "ip6tables-save";
270 	if (xtables_init_all(&ip6tables_globals, NFPROTO_IPV6) < 0) {
271 		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
272 				ip6tables_globals.program_name,
273 				ip6tables_globals.program_version);
274 		exit(1);
275 	}
276 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
277 	init_extensions();
278 	init_extensions6();
279 #endif
280 
281 	ret = do_iptables_save(&ip6t_save_cb, argc, argv);
282 
283 	xtables_fini();
284 	return ret;
285 }
286 #endif /* ENABLE_IPV6 */
287