Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / iptables / iptables-save.c
bloba8a17aac75075aa88dfdfb6efcbf92e60a70d4a9
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>
5 * This code is distributed under the terms of GNU GPL v2
7 */
8 #include <getopt.h>
9 #include <sys/errno.h>
10 #include <stdio.h>
11 #include <fcntl.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <dlfcn.h>
15 #include <time.h>
16 #include <netdb.h>
17 #include "libiptc/libiptc.h"
18 #include "iptables.h"
20 static int binary = 0, counters = 0;
22 static struct option options[] = {
23 { "binary", 0, 0, 'b' },
24 { "counters", 0, 0, 'c' },
25 { "dump", 0, 0, 'd' },
26 { "table", 1, 0, 't' },
27 { 0 }
30 #define IP_PARTS_NATIVE(n) \
31 (unsigned int)((n)>>24)&0xFF, \
32 (unsigned int)((n)>>16)&0xFF, \
33 (unsigned int)((n)>>8)&0xFF, \
34 (unsigned int)((n)&0xFF)
36 #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
38 /* This assumes that mask is contiguous, and byte-bounded. */
39 static void
40 print_iface(char letter, const char *iface, const unsigned char *mask,
41 int invert)
43 unsigned int i;
45 if (mask[0] == 0)
46 return;
48 printf("-%c %s", letter, invert ? "! " : "");
50 for (i = 0; i < IFNAMSIZ; i++) {
51 if (mask[i] != 0) {
52 if (iface[i] != '\0')
53 printf("%c", iface[i]);
54 } else {
55 /* we can access iface[i-1] here, because
56 * a few lines above we make sure that mask[0] != 0 */
57 if (iface[i-1] != '\0')
58 printf("+");
59 break;
63 printf(" ");
66 /* These are hardcoded backups in iptables.c, so they are safe */
67 struct pprot {
68 char *name;
69 u_int8_t num;
72 /* FIXME: why don't we use /etc/protocols ? */
73 static const struct pprot chain_protos[] = {
74 { "tcp", IPPROTO_TCP },
75 { "udp", IPPROTO_UDP },
76 { "icmp", IPPROTO_ICMP },
77 { "esp", IPPROTO_ESP },
78 { "ah", IPPROTO_AH },
79 { "sctp", IPPROTO_SCTP },
82 static void print_proto(u_int16_t proto, int invert)
84 if (proto) {
85 unsigned int i;
86 const char *invertstr = invert ? "! " : "";
88 struct protoent *pent = getprotobynumber(proto);
89 if (pent) {
90 printf("-p %s%s ", invertstr, pent->p_name);
91 return;
94 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
95 if (chain_protos[i].num == proto) {
96 printf("-p %s%s ",
97 invertstr, chain_protos[i].name);
98 return;
101 printf("-p %s%u ", invertstr, proto);
105 #if 0
106 static int non_zero(const void *ptr, size_t size)
108 unsigned int i;
110 for (i = 0; i < size; i++)
111 if (((char *)ptr)[i])
112 return 0;
114 return 1;
116 #endif
118 static int print_match(const struct ipt_entry_match *e,
119 const struct ipt_ip *ip)
121 struct iptables_match *match
122 = find_match(e->u.user.name, TRY_LOAD, NULL);
124 if (match) {
125 printf("-m %s ", e->u.user.name);
127 /* some matches don't provide a save function */
128 if (match->save)
129 match->save(ip, e);
130 } else {
131 if (e->u.match_size) {
132 fprintf(stderr,
133 "Can't find library for match `%s'\n",
134 e->u.user.name);
135 exit(1);
138 return 0;
141 /* print a given ip including mask if neccessary */
142 static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
144 if (!mask && !ip && !invert)
145 return;
147 printf("%s %s%u.%u.%u.%u",
148 prefix,
149 invert ? "! " : "",
150 IP_PARTS(ip));
152 if (mask != 0xffffffff)
153 printf("/%u.%u.%u.%u ", IP_PARTS(mask));
154 else
155 printf(" ");
158 /* We want this to be readable, so only print out neccessary fields.
159 * Because that's the kind of world I want to live in. */
160 static void print_rule(const struct ipt_entry *e,
161 iptc_handle_t *h, const char *chain, int counters)
163 struct ipt_entry_target *t;
164 const char *target_name;
166 /* print counters */
167 if (counters)
168 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
170 /* print chain name */
171 printf("-A %s ", chain);
173 /* Print IP part. */
174 print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
175 e->ip.invflags & IPT_INV_SRCIP);
177 print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
178 e->ip.invflags & IPT_INV_DSTIP);
180 print_iface('i', e->ip.iniface, e->ip.iniface_mask,
181 e->ip.invflags & IPT_INV_VIA_IN);
183 print_iface('o', e->ip.outiface, e->ip.outiface_mask,
184 e->ip.invflags & IPT_INV_VIA_OUT);
186 print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
188 if (e->ip.flags & IPT_F_FRAG)
189 printf("%s-f ",
190 e->ip.invflags & IPT_INV_FRAG ? "! " : "");
192 /* Print matchinfo part */
193 if (e->target_offset) {
194 IPT_MATCH_ITERATE(e, print_match, &e->ip);
197 /* Print target name */
198 target_name = iptc_get_target(e, h);
199 if (target_name && (*target_name != '\0'))
200 #ifdef IPT_F_GOTO
201 printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
202 #else
203 printf("-j %s ", target_name);
204 #endif
206 /* Print targinfo part */
207 t = ipt_get_target((struct ipt_entry *)e);
208 if (t->u.user.name[0]) {
209 struct iptables_target *target
210 = find_target(t->u.user.name, TRY_LOAD);
212 if (!target) {
213 fprintf(stderr, "Can't find library for target `%s'\n",
214 t->u.user.name);
215 exit(1);
218 if (target->save)
219 target->save(&e->ip, t);
220 else {
221 /* If the target size is greater than ipt_entry_target
222 * there is something to be saved, we just don't know
223 * how to print it */
224 if (t->u.target_size !=
225 sizeof(struct ipt_entry_target)) {
226 fprintf(stderr, "Target `%s' is missing "
227 "save function\n",
228 t->u.user.name);
229 exit(1);
233 printf("\n");
236 /* Debugging prototype. */
237 static int for_each_table(int (*func)(const char *tablename))
239 int ret = 1;
240 FILE *procfile = NULL;
241 char tablename[IPT_TABLE_MAXNAMELEN+1];
243 procfile = fopen("/proc/net/ip_tables_names", "r");
244 if (!procfile)
245 return 0;
247 while (fgets(tablename, sizeof(tablename), procfile)) {
248 if (tablename[strlen(tablename) - 1] != '\n')
249 exit_error(OTHER_PROBLEM,
250 "Badly formed tablename `%s'\n",
251 tablename);
252 tablename[strlen(tablename) - 1] = '\0';
253 ret &= func(tablename);
256 return ret;
260 static int do_output(const char *tablename)
262 iptc_handle_t h;
263 const char *chain = NULL;
265 if (!tablename)
266 return for_each_table(&do_output);
268 h = iptc_init(tablename);
269 if (!h)
270 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
271 iptc_strerror(errno));
273 if (!binary) {
274 time_t now = time(NULL);
276 printf("# Generated by iptables-save v%s on %s",
277 IPTABLES_VERSION, ctime(&now));
278 printf("*%s\n", tablename);
280 /* Dump out chain names first,
281 * thereby preventing dependency conflicts */
282 for (chain = iptc_first_chain(&h);
283 chain;
284 chain = iptc_next_chain(&h)) {
286 printf(":%s ", chain);
287 if (iptc_builtin(chain, h)) {
288 struct ipt_counters count;
289 printf("%s ",
290 iptc_get_policy(chain, &count, &h));
291 printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
292 } else {
293 printf("- [0:0]\n");
298 for (chain = iptc_first_chain(&h);
299 chain;
300 chain = iptc_next_chain(&h)) {
301 const struct ipt_entry *e;
303 /* Dump out rules */
304 e = iptc_first_rule(chain, &h);
305 while(e) {
306 print_rule(e, &h, chain, counters);
307 e = iptc_next_rule(e, &h);
311 now = time(NULL);
312 printf("COMMIT\n");
313 printf("# Completed on %s", ctime(&now));
314 } else {
315 /* Binary, huh? OK. */
316 exit_error(OTHER_PROBLEM, "Binary NYI\n");
319 iptc_free(&h);
321 return 1;
324 /* Format:
325 * :Chain name POLICY packets bytes
326 * rule
328 #ifdef IPTABLES_MULTI
330 iptables_save_main(int argc, char *argv[])
331 #else
333 main(int argc, char *argv[])
334 #endif
336 const char *tablename = NULL;
337 int c;
339 program_name = "iptables-save";
340 program_version = IPTABLES_VERSION;
342 lib_dir = getenv("IPTABLES_LIB_DIR");
343 if (!lib_dir)
344 lib_dir = IPT_LIB_DIR;
346 #ifdef NO_SHARED_LIBS
347 init_extensions();
348 #endif
350 while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
351 switch (c) {
352 case 'b':
353 binary = 1;
354 break;
356 case 'c':
357 counters = 1;
358 break;
360 case 't':
361 /* Select specific table. */
362 tablename = optarg;
363 break;
364 case 'd':
365 do_output(tablename);
366 exit(0);
370 if (optind < argc) {
371 fprintf(stderr, "Unknown arguments found on commandline\n");
372 exit(1);
375 return !do_output(tablename);