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
16 #include "libiptc/libiptc.h"
19 static int binary = 0, counters = 0;
21 static struct option options[] = {
22 { "binary", 0, 0, 'b' },
23 { "counters", 0, 0, 'c' },
24 { "dump", 0, 0, 'd' },
25 { "table", 1, 0, 't' },
29 #define IP_PARTS_NATIVE(n) \
30 (unsigned int)((n)>>24)&0xFF, \
31 (unsigned int)((n)>>16)&0xFF, \
32 (unsigned int)((n)>>8)&0xFF, \
33 (unsigned int)((n)&0xFF)
35 #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
37 /* This assumes that mask is contiguous, and byte-bounded. */
39 print_iface(char letter, const char *iface, const unsigned char *mask,
47 printf("-%c %s", letter, invert ? "! " : "");
49 for (i = 0; i < IFNAMSIZ; i++) {
52 printf("%c", iface[i]);
54 /* we can access iface[i-1] here, because
55 * a few lines above we make sure that mask[0] != 0 */
56 if (iface[i-1] != '\0')
65 /* These are hardcoded backups in iptables.c, so they are safe */
71 /* FIXME: why don't we use /etc/protocols ? */
72 static const struct pprot chain_protos[] = {
73 { "tcp", IPPROTO_TCP },
74 { "udp", IPPROTO_UDP },
75 { "icmp", IPPROTO_ICMP },
76 { "esp", IPPROTO_ESP },
80 static void print_proto(u_int16_t proto, int invert)
84 const char *invertstr = invert ? "! " : "";
86 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
87 if (chain_protos[i].num == proto) {
89 invertstr, chain_protos[i].name);
93 printf("-p %s%u ", invertstr, proto);
98 static int non_zero(const void *ptr, size_t size)
102 for (i = 0; i < size; i++)
103 if (((char *)ptr)[i])
110 static int print_match(const struct ipt_entry_match *e,
111 const struct ipt_ip *ip)
113 struct iptables_match *match
114 = find_match(e->u.user.name, TRY_LOAD);
117 printf("-m %s ", e->u.user.name);
119 /* some matches don't provide a save function */
123 if (e->u.match_size) {
125 "Can't find library for match `%s'\n",
133 /* print a given ip including mask if neccessary */
134 static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
139 printf("%s %s%u.%u.%u.%u",
144 if (mask != 0xffffffff)
145 printf("/%u.%u.%u.%u ", IP_PARTS(mask));
150 /* We want this to be readable, so only print out neccessary fields.
151 * Because that's the kind of world I want to live in. */
152 static void print_rule(const struct ipt_entry *e,
153 iptc_handle_t *h, const char *chain, int counters)
155 struct ipt_entry_target *t;
156 const char *target_name;
160 printf("[%llu:%llu] ", e->counters.pcnt, e->counters.bcnt);
162 /* print chain name */
163 printf("-A %s ", chain);
166 print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
167 e->ip.invflags & IPT_INV_SRCIP);
169 print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
170 e->ip.invflags & IPT_INV_DSTIP);
172 print_iface('i', e->ip.iniface, e->ip.iniface_mask,
173 e->ip.invflags & IPT_INV_VIA_IN);
175 print_iface('o', e->ip.outiface, e->ip.outiface_mask,
176 e->ip.invflags & IPT_INV_VIA_OUT);
178 print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
180 if (e->ip.flags & IPT_F_FRAG)
182 e->ip.invflags & IPT_INV_FRAG ? "! " : "");
184 /* Print matchinfo part */
185 if (e->target_offset) {
186 IPT_MATCH_ITERATE(e, print_match, &e->ip);
189 /* Print target name */
190 target_name = iptc_get_target(e, h);
191 if (target_name && (*target_name != '\0'))
192 printf("-j %s ", target_name);
194 /* Print targinfo part */
195 t = ipt_get_target((struct ipt_entry *)e);
196 if (t->u.user.name[0]) {
197 struct iptables_target *target
198 = find_target(t->u.user.name, TRY_LOAD);
201 fprintf(stderr, "Can't find library for target `%s'\n",
207 target->save(&e->ip, t);
209 /* If the target size is greater than ipt_entry_target
210 * there is something to be saved, we just don't know
212 if (t->u.target_size !=
213 sizeof(struct ipt_entry_target)) {
214 fprintf(stderr, "Target `%s' is missing "
224 /* Debugging prototype. */
225 static int for_each_table(int (*func)(const char *tablename))
228 FILE *procfile = NULL;
229 char tablename[IPT_TABLE_MAXNAMELEN+1];
231 procfile = fopen("/proc/net/ip_tables_names", "r");
235 while (fgets(tablename, sizeof(tablename), procfile)) {
236 if (tablename[strlen(tablename) - 1] != '\n')
237 exit_error(OTHER_PROBLEM,
238 "Badly formed tablename `%s'\n",
240 tablename[strlen(tablename) - 1] = '\0';
241 ret &= func(tablename);
248 static int do_output(const char *tablename)
251 const char *chain = NULL;
254 return for_each_table(&do_output);
256 h = iptc_init(tablename);
258 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
259 iptc_strerror(errno));
262 time_t now = time(NULL);
264 printf("# Generated by iptables-save v%s on %s",
265 IPTABLES_VERSION, ctime(&now));
266 printf("*%s\n", tablename);
268 /* Dump out chain names first,
269 * thereby preventing dependency conflicts */
270 for (chain = iptc_first_chain(&h);
272 chain = iptc_next_chain(&h)) {
274 printf(":%s ", chain);
275 if (iptc_builtin(chain, h)) {
276 struct ipt_counters count;
278 iptc_get_policy(chain, &count, &h));
279 printf("[%llu:%llu]\n", count.pcnt, count.bcnt);
286 for (chain = iptc_first_chain(&h);
288 chain = iptc_next_chain(&h)) {
289 const struct ipt_entry *e;
292 e = iptc_first_rule(chain, &h);
294 print_rule(e, &h, chain, counters);
295 e = iptc_next_rule(e, &h);
301 printf("# Completed on %s", ctime(&now));
303 /* Binary, huh? OK. */
304 exit_error(OTHER_PROBLEM, "Binary NYI\n");
313 * :Chain name POLICY packets bytes
316 int main(int argc, char *argv[])
318 const char *tablename = NULL;
321 program_name = "iptables-save";
322 program_version = IPTABLES_VERSION;
324 #ifdef NO_SHARED_LIBS
328 while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
339 /* Select specific table. */
343 do_output(tablename);
349 fprintf(stderr, "Unknown arguments found on commandline");
353 return !do_output(tablename);