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
17 #include "libiptc/libiptc.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' },
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. */
40 print_iface(char letter
, const char *iface
, const unsigned char *mask
,
48 printf("-%c %s", letter
, invert
? "! " : "");
50 for (i
= 0; i
< IFNAMSIZ
; i
++) {
53 printf("%c", iface
[i
]);
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')
66 /* These are hardcoded backups in iptables.c, so they are safe */
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
},
79 { "sctp", IPPROTO_SCTP
},
82 static void print_proto(u_int16_t proto
, int invert
)
86 const char *invertstr
= invert
? "! " : "";
88 struct protoent
*pent
= getprotobynumber(proto
);
90 printf("-p %s%s ", invertstr
, pent
->p_name
);
94 for (i
= 0; i
< sizeof(chain_protos
)/sizeof(struct pprot
); i
++)
95 if (chain_protos
[i
].num
== proto
) {
97 invertstr
, chain_protos
[i
].name
);
101 printf("-p %s%u ", invertstr
, proto
);
106 static int non_zero(const void *ptr
, size_t size
)
110 for (i
= 0; i
< size
; i
++)
111 if (((char *)ptr
)[i
])
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
);
125 printf("-m %s ", e
->u
.user
.name
);
127 /* some matches don't provide a save function */
131 if (e
->u
.match_size
) {
133 "Can't find library for match `%s'\n",
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
)
147 printf("%s %s%u.%u.%u.%u",
152 if (mask
!= 0xffffffff)
153 printf("/%u.%u.%u.%u ", IP_PARTS(mask
));
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
;
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
);
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
)
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'))
201 printf("-%c %s ", e
->ip
.flags
& IPT_F_GOTO
? 'g' : 'j', target_name
);
203 printf("-j %s ", target_name
);
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
);
213 fprintf(stderr
, "Can't find library for target `%s'\n",
219 target
->save(&e
->ip
, t
);
221 /* If the target size is greater than ipt_entry_target
222 * there is something to be saved, we just don't know
224 if (t
->u
.target_size
!=
225 sizeof(struct ipt_entry_target
)) {
226 fprintf(stderr
, "Target `%s' is missing "
236 /* Debugging prototype. */
237 static int for_each_table(int (*func
)(const char *tablename
))
240 FILE *procfile
= NULL
;
241 char tablename
[IPT_TABLE_MAXNAMELEN
+1];
243 procfile
= fopen("/proc/net/ip_tables_names", "r");
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",
252 tablename
[strlen(tablename
) - 1] = '\0';
253 ret
&= func(tablename
);
260 static int do_output(const char *tablename
)
263 const char *chain
= NULL
;
266 return for_each_table(&do_output
);
268 h
= iptc_init(tablename
);
270 exit_error(OTHER_PROBLEM
, "Can't initialize: %s\n",
271 iptc_strerror(errno
));
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
);
284 chain
= iptc_next_chain(&h
)) {
286 printf(":%s ", chain
);
287 if (iptc_builtin(chain
, h
)) {
288 struct ipt_counters count
;
290 iptc_get_policy(chain
, &count
, &h
));
291 printf("[%llu:%llu]\n", (unsigned long long)count
.pcnt
, (unsigned long long)count
.bcnt
);
298 for (chain
= iptc_first_chain(&h
);
300 chain
= iptc_next_chain(&h
)) {
301 const struct ipt_entry
*e
;
304 e
= iptc_first_rule(chain
, &h
);
306 print_rule(e
, &h
, chain
, counters
);
307 e
= iptc_next_rule(e
, &h
);
313 printf("# Completed on %s", ctime(&now
));
315 /* Binary, huh? OK. */
316 exit_error(OTHER_PROBLEM
, "Binary NYI\n");
325 * :Chain name POLICY packets bytes
328 #ifdef IPTABLES_MULTI
330 iptables_save_main(int argc
, char *argv
[])
333 main(int argc
, char *argv
[])
336 const char *tablename
= NULL
;
339 program_name
= "iptables-save";
340 program_version
= IPTABLES_VERSION
;
342 lib_dir
= getenv("IPTABLES_LIB_DIR");
344 lib_dir
= IPT_LIB_DIR
;
346 #ifdef NO_SHARED_LIBS
350 while ((c
= getopt_long(argc
, argv
, "bcdt:", options
, NULL
)) != -1) {
361 /* Select specific table. */
365 do_output(tablename
);
371 fprintf(stderr
, "Unknown arguments found on commandline\n");
375 return !do_output(tablename
);