iptables-save.c revision ae1ff9f96a80379a650dec979b9902528a10d45a
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Code to save the iptables state, in human readable-form. */
2ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte/* Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
3ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte * 	    Harald Welte <laforge@gnumonks.org>
4ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte */
5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <getopt.h>
6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <sys/errno.h>
7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h>
8ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <fcntl.h>
9ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <stdlib.h>
10ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <string.h>
11e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <dlfcn.h>
12e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <time.h>
13b1f69befb5b35d0cbf607ed13a6e823a94cb79ffRusty Russell#include "libiptc/libiptc.h"
14b1f69befb5b35d0cbf607ed13a6e823a94cb79ffRusty Russell#include "iptables.h"
15e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int binary = 0, counters = 0;
17a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct option options[] = {
19a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	{ "binary", 0, 0, 'b' },
20a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	{ "counters", 0, 0, 'c' },
21a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	{ "dump", 0, 0, 'd' },
22a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	{ "table", 1, 0, 't' },
23e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ 0 }
24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
25e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS_NATIVE(n)			\
27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>24)&0xFF,			\
28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>16)&0xFF,			\
29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>8)&0xFF,			\
30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)&0xFF)
31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* This assumes that mask is contiguous, and byte-bounded. */
35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_iface(char letter, const char *iface, const unsigned char *mask,
37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    int invert)
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (mask[0] == 0)
42e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return;
437e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("-%c %s", letter, invert ? "! " : "");
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < IFNAMSIZ; i++) {
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (mask[i] != 0) {
48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (iface[i] != '\0')
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("%c", iface[i]);
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		} else {
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (iface[i] != '\0')
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("+");
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
56ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
57ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	printf(" ");
58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* These are hardcoded backups in iptables.c, so they are safe */
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct pprot {
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char *name;
63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	u_int8_t num;
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
66ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte/* FIXME: why don't we use /etc/services ? */
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const struct pprot chain_protos[] = {
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "tcp", IPPROTO_TCP },
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "udp", IPPROTO_UDP },
70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "icmp", IPPROTO_ICMP },
71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void print_proto(u_int16_t proto, int invert)
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (proto) {
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int i;
77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *invertstr = invert ? "! " : "";
78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (chain_protos[i].num == proto) {
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("-p %s%s ",
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				       invertstr, chain_protos[i].name);
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				return;
84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("-p %s%u ", invertstr, proto);
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
90ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#if 0
91e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int non_zero(const void *ptr, size_t size)
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
94e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
95e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < size; i++)
96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (((char *)ptr)[i])
97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
99e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
101ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#endif
102ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
103ae1ff9f96a80379a650dec979b9902528a10d45aHarald Weltestatic int print_match(const struct ipt_entry_match *e)
104ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte{
105ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	struct iptables_match *match
106ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		= find_match(e->u.user.name, TRY_LOAD);
107ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
108ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	if (match) {
109ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		printf("-m %s ", e->u.user.name);
110ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		match->save(NULL, e);
111ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	} else {
112ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		if (e->u.match_size) {
113ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			fprintf(stderr,
114ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte				"Can't find library for match `%s'\n",
115ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte				e->u.user.name);
116ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			exit(1);
117ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		}
118ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	}
119ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	return 0;
120ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte}
121ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
122ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte/* print a given ip including mask if neccessary */
123ae1ff9f96a80379a650dec979b9902528a10d45aHarald Weltestatic void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
124ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte{
125ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	if (!mask && !ip)
126ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		return;
127ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
128ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	printf("%s %s%u.%u.%u.%u",
129ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		prefix,
130ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		invert ? "! " : "",
131ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		IP_PARTS(ip));
132ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
133ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	if (mask != 0xffffffff)
134ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		printf("/%u.%u.%u.%u ", IP_PARTS(mask));
135ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	else
136ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		printf(" ");
137ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte}
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* We want this to be readable, so only print out neccessary fields.
140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Because that's the kind of world I want to live in.  */
141ae1ff9f96a80379a650dec979b9902528a10d45aHarald Weltestatic void print_rule(const struct ipt_entry *e,
142ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		iptc_handle_t *h, int counters)
143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
144ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	struct ipt_entry_target *t;
145ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
146ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	/* print counters */
147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (counters)
148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("[%llu,%llu] ", e->counters.pcnt, e->counters.bcnt);
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Print IP part. */
151ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
152ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			e->ip.invflags & IPT_INV_SRCIP);
153ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
154ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
155ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			e->ip.invflags & IPT_INV_SRCIP);
156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_iface('i', e->ip.iniface, e->ip.iniface_mask,
158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    e->ip.invflags & IPT_INV_VIA_IN);
159ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_iface('o', e->ip.outiface, e->ip.outiface_mask,
161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    e->ip.invflags & IPT_INV_VIA_OUT);
162ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->ip.flags & IPT_F_FRAG)
166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("%s-f ",
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       e->ip.invflags & IPT_INV_FRAG ? "! " : "");
168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Print matchinfo part */
170ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	if (e->target_offset) {
171ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		IPT_MATCH_ITERATE(e, print_match);
172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
174ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	/* Print target name */
175ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	printf("-j %s ", iptc_get_target(e, h));
176ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Print targinfo part */
178ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	t = ipt_get_target(e);
179ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	if (t->u.user.name[0]) {
180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct iptables_target *target
181ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			= find_target(t->u.user.name, TRY_LOAD);
182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (target)
184ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			target->save(NULL, t);
185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else {
186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* If some bits are non-zero, it implies we *need*
187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   to understand it */
188ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			if (t->u.target_size) {
189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				fprintf(stderr,
190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					"Can't find library for target `%s'\n",
191ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte					t->u.user.name);
192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit(1);
193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\n");
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Debugging prototype. */
200a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int for_each_table(int (*func)(const char *tablename))
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
202a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell        int ret = 1;
203ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	FILE *procfile = NULL;
204a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	char tablename[IPT_TABLE_MAXNAMELEN+1];
205a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
206ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	procfile = fopen("/proc/net/ip_tables_names", "r");
207a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!procfile)
208a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		return 0;
209a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
210a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	while (fgets(tablename, sizeof(tablename), procfile)) {
211a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		if (tablename[strlen(tablename) - 1] != '\n')
212a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			exit_error(OTHER_PROBLEM,
213a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell				   "Badly formed tablename `%s'\n",
214a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell				   tablename);
215a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		tablename[strlen(tablename) - 1] = '\0';
216a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		ret &= func(tablename);
217a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
219a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return ret;
220a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell}
221a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
223a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int do_output(const char *tablename)
224a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell{
225a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	iptc_handle_t h;
226a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	const char *chain = NULL;
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
228a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!tablename)
229a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		return for_each_table(&do_output);
230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
231a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	h = iptc_init(tablename);
232a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!h)
233a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell 		exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
234a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			   iptc_strerror(errno));
235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!binary) {
237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		time_t now = time(NULL);
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("# Generated by iptables-save v%s on %s",
240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       NETFILTER_VERSION, ctime(&now));
241ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		printf("*%s\n", tablename);
242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Dump out chain names */
244a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		for (chain = iptc_first_chain(&h);
245a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		     chain;
246a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		     chain = iptc_next_chain(&h)) {
247ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			const struct ipt_entry *e;
248ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(":%s ", chain);
250ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			if (iptc_builtin(chain, h)) {
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				struct ipt_counters count;
252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("%s ",
253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				       iptc_get_policy(chain, &count, &h));
254ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte				printf("%llu:%llu\n", count.pcnt, count.bcnt);
255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			} else {
256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("- 0 0\n");
257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
259ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			/* Dump out rules */
260ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			e = iptc_first_rule(chain, &h);
261ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			while(e) {
262ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte				print_rule(e, &h, counters);
263ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte				e = iptc_next_rule(e, &h);
264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		now = time(NULL);
268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("COMMIT\n");
269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("# Completed on %s", ctime(&now));
270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Binary, huh?  OK. */
272a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		exit_error(OTHER_PROBLEM, "Binary NYI\n");
273a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
274a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
275a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return 1;
276a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell}
277a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
278a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell/* Format:
279a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell * :Chain name POLICY packets bytes
280a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell * rule
281a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell */
282a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellint main(int argc, char *argv[])
283a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell{
284a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	const char *tablename = NULL;
285a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	int c;
286a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
287a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	program_name = "iptables-save";
288a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	program_version = NETFILTER_VERSION;
289a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
290a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	while ((c = getopt_long(argc, argv, "bc", options, NULL)) != -1) {
291a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		switch (c) {
292a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'b':
293a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			binary = 1;
294a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
295a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
296a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'c':
297a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			counters = 1;
298a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
299a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
300a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 't':
301a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			/* Select specific table. */
302a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			tablename = optarg;
303a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
304a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'd':
305ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			do_output(tablename);
306a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			exit(0);
307a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		}
308a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
309a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
310a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (optind < argc) {
311a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		fprintf(stderr, "Unknown arguments found on commandline");
312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
315a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return !do_output(tablename);
316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
317