xref: /aosp_15_r20/external/iptables/iptables/iptables-save.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 /* Code to save the iptables state, in human readable-form. */
2 /* (C) 1999 by Paul 'Rusty' Russell <[email protected]> and
3  * (C) 2000-2002 by Harald Welte <[email protected]>
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'", tablename);
65 		tablename[strlen(tablename) - 1] = '\0';
66 		ret &= func(cb, tablename);
67 	}
68 
69 	fclose(procfile);
70 	return ret;
71 }
72 
do_output(struct iptables_save_cb * cb,const char * tablename)73 static int do_output(struct iptables_save_cb *cb, const char *tablename)
74 {
75 	struct xtc_handle *h;
76 	const char *chain = NULL;
77 
78 	if (!tablename)
79 		return for_each_table(&do_output, cb);
80 
81 	h = cb->ops->init(tablename);
82 	if (h == NULL) {
83 		xtables_load_ko(xtables_modprobe_program, false);
84 		h = cb->ops->init(tablename);
85 	}
86 	if (!h)
87 		xtables_error(OTHER_PROBLEM, "Cannot initialize: %s",
88 			      cb->ops->strerror(errno));
89 
90 	time_t now = time(NULL);
91 
92 	printf("# Generated by %s v%s on %s",
93 	       xt_params->program_name, PACKAGE_VERSION, ctime(&now));
94 	printf("*%s\n", tablename);
95 
96 	/* Dump out chain names first,
97 	 * 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 			printf("%s ", cb->ops->get_policy(chain, &count, h));
107 			printf("[%llu:%llu]\n",
108 			       (unsigned long long)count.pcnt,
109 			       (unsigned long long)count.bcnt);
110 		} else {
111 			printf("- [0:0]\n");
112 		}
113 	}
114 
115 	for (chain = cb->ops->first_chain(h);
116 	     chain;
117 	     chain = cb->ops->next_chain(h)) {
118 		cb->dump_rules(chain, h);
119 	}
120 
121 	now = time(NULL);
122 	printf("COMMIT\n");
123 	printf("# Completed on %s", ctime(&now));
124 	cb->ops->free(h);
125 
126 	return 1;
127 }
128 
129 /* Format:
130  * :Chain name POLICY packets bytes
131  * rule
132  */
133 static int
do_iptables_save(struct iptables_save_cb * cb,int argc,char * argv[])134 do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[])
135 {
136 	const char *tablename = NULL;
137 	FILE *file = NULL;
138 	int ret, c;
139 
140 	while ((c = getopt_long(argc, argv, "bcdt:M:f:V", options, NULL)) != -1) {
141 		switch (c) {
142 		case 'b':
143 			fprintf(stderr, "-b/--binary option is not implemented\n");
144 			break;
145 		case 'c':
146 			show_counters = 1;
147 			break;
148 
149 		case 't':
150 			/* Select specific table. */
151 			tablename = optarg;
152 			break;
153 		case 'M':
154 			xtables_modprobe_program = optarg;
155 			break;
156 		case 'f':
157 			file = fopen(optarg, "w");
158 			if (file == NULL) {
159 				fprintf(stderr, "Failed to open file, error: %s\n",
160 					strerror(errno));
161 				exit(1);
162 			}
163 			ret = dup2(fileno(file), STDOUT_FILENO);
164 			if (ret == -1) {
165 				fprintf(stderr, "Failed to redirect stdout, error: %s\n",
166 					strerror(errno));
167 				exit(1);
168 			}
169 			fclose(file);
170 			break;
171 		case 'd':
172 			do_output(cb, tablename);
173 			exit(0);
174 		case 'V':
175 			printf("%s v%s\n",
176 			       xt_params->program_name,
177 			       xt_params->program_version);
178 			exit(0);
179 		default:
180 			fprintf(stderr,
181 				"Look at manual page `%s.8' for more information.\n",
182 				xt_params->program_name);
183 			exit(1);
184 		}
185 	}
186 
187 	if (optind < argc) {
188 		fprintf(stderr, "Unknown arguments found on commandline\n");
189 		exit(1);
190 	}
191 
192 	return !do_output(cb, tablename);
193 }
194 
195 #ifdef ENABLE_IPV4
iptables_dump_rules(const char * chain,struct xtc_handle * h)196 static void iptables_dump_rules(const char *chain, struct xtc_handle *h)
197 {
198 	const struct ipt_entry *e;
199 
200 	/* Dump out rules */
201 	e = iptc_first_rule(chain, h);
202 	while(e) {
203 		print_rule4(e, h, chain, show_counters);
204 		e = iptc_next_rule(e, h);
205 	}
206 }
207 
208 struct iptables_save_cb ipt_save_cb = {
209 	.ops		= &iptc_ops,
210 	.dump_rules	= iptables_dump_rules,
211 };
212 
213 /* Format:
214  * :Chain name POLICY packets bytes
215  * rule
216  */
217 int
iptables_save_main(int argc,char * argv[])218 iptables_save_main(int argc, char *argv[])
219 {
220 	int ret;
221 
222 	iptables_globals.program_name = "iptables-save";
223 	if (xtables_init_all(&iptables_globals, NFPROTO_IPV4) < 0) {
224 		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
225 				iptables_globals.program_name,
226 				iptables_globals.program_version);
227 		exit(1);
228 	}
229 	init_extensions();
230 	init_extensions4();
231 
232 	ret = do_iptables_save(&ipt_save_cb, argc, argv);
233 
234 	xtables_fini();
235 	return ret;
236 }
237 #endif /* ENABLE_IPV4 */
238 
239 #ifdef ENABLE_IPV6
ip6tables_dump_rules(const char * chain,struct xtc_handle * h)240 static void ip6tables_dump_rules(const char *chain, struct xtc_handle *h)
241 {
242 	const struct ip6t_entry *e;
243 
244 	/* Dump out rules */
245 	e = ip6tc_first_rule(chain, h);
246 	while(e) {
247 		print_rule6(e, h, chain, show_counters);
248 		e = ip6tc_next_rule(e, h);
249 	}
250 }
251 
252 struct iptables_save_cb ip6t_save_cb = {
253 	.ops		= &ip6tc_ops,
254 	.dump_rules	= ip6tables_dump_rules,
255 };
256 
257 /* Format:
258  * :Chain name POLICY packets bytes
259  * rule
260  */
261 int
ip6tables_save_main(int argc,char * argv[])262 ip6tables_save_main(int argc, char *argv[])
263 {
264 	int ret;
265 
266 	ip6tables_globals.program_name = "ip6tables-save";
267 	if (xtables_init_all(&ip6tables_globals, NFPROTO_IPV6) < 0) {
268 		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
269 				ip6tables_globals.program_name,
270 				ip6tables_globals.program_version);
271 		exit(1);
272 	}
273 	init_extensions();
274 	init_extensions6();
275 
276 	ret = do_iptables_save(&ip6t_save_cb, argc, argv);
277 
278 	xtables_fini();
279 	return ret;
280 }
281 #endif /* ENABLE_IPV6 */
282