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