iptables-save.c revision 5b76f682f722bebc2f0616fca4600eee2c08dfe2
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Code to save the iptables state, in human readable-form. */
210a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte/* (C) 1999 by Paul 'Rusty' Russell <rusty@rustcorp.com.au> and
310a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
410a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte *
510a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte * This code is distributed under the terms of GNU GPL v2
610a907f6736864f3f60d36f78c78e655b6bb64eeHarald Welte *
7ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte */
8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <getopt.h>
9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <sys/errno.h>
10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h>
11ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <fcntl.h>
12ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <stdlib.h>
13ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#include <string.h>
14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <time.h>
15d8ac967249f78212e1fe5eb55e9a417ac1d737d6Harald Welte#include <netdb.h>
16b1f69befb5b35d0cbf607ed13a6e823a94cb79ffRusty Russell#include "libiptc/libiptc.h"
17b1f69befb5b35d0cbf607ed13a6e823a94cb79ffRusty Russell#include "iptables.h"
18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
195a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
205a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
215a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
225a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
23a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int binary = 0, counters = 0;
24a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
25e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct option options[] = {
26a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	{ "binary", 0, 0, 'b' },
27a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	{ "counters", 0, 0, 'c' },
28a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	{ "dump", 0, 0, 'd' },
29a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	{ "table", 1, 0, 't' },
30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ 0 }
31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS_NATIVE(n)			\
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>24)&0xFF,			\
35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>16)&0xFF,			\
36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>8)&0xFF,			\
37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)&0xFF)
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* This assumes that mask is contiguous, and byte-bounded. */
42e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_iface(char letter, const char *iface, const unsigned char *mask,
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    int invert)
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (mask[0] == 0)
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return;
507e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("-%c %s", letter, invert ? "! " : "");
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < IFNAMSIZ; i++) {
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (mask[i] != 0) {
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (iface[i] != '\0')
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("%c", iface[i]);
57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		} else {
585b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann			/* we can access iface[i-1] here, because
599535e687b3b5756ca7afec273d25cffdd62f653dHarald Welte			 * a few lines above we make sure that mask[0] != 0 */
609535e687b3b5756ca7afec273d25cffdd62f653dHarald Welte			if (iface[i-1] != '\0')
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("+");
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
65ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
66ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	printf(" ");
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* These are hardcoded backups in iptables.c, so they are safe */
70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct pprot {
71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char *name;
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	u_int8_t num;
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
75764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó/* FIXME: why don't we use /etc/protocols ? */
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const struct pprot chain_protos[] = {
77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "tcp", IPPROTO_TCP },
78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "udp", IPPROTO_UDP },
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "icmp", IPPROTO_ICMP },
80764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó	{ "esp", IPPROTO_ESP },
81764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó	{ "ah", IPPROTO_AH },
82129152307ba7b09c9ad667eee2c4e0d23f7c500bHarald Welte	{ "sctp", IPPROTO_SCTP },
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void print_proto(u_int16_t proto, int invert)
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (proto) {
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int i;
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *invertstr = invert ? "! " : "";
90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
910e3b3379abec1695a68871862b6c22b59de3c5a5Pedro Lamarão		struct protoent *pent = getprotobynumber(proto);
920e3b3379abec1695a68871862b6c22b59de3c5a5Pedro Lamarão		if (pent) {
930e3b3379abec1695a68871862b6c22b59de3c5a5Pedro Lamarão			printf("-p %s%s ", invertstr, pent->p_name);
940e3b3379abec1695a68871862b6c22b59de3c5a5Pedro Lamarão			return;
950e3b3379abec1695a68871862b6c22b59de3c5a5Pedro Lamarão		}
960e3b3379abec1695a68871862b6c22b59de3c5a5Pedro Lamarão
97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (chain_protos[i].num == proto) {
99e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("-p %s%s ",
100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				       invertstr, chain_protos[i].name);
101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				return;
102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("-p %s%u ", invertstr, proto);
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
108ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#if 0
109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int non_zero(const void *ptr, size_t size)
110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < size; i++)
114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (((char *)ptr)[i])
115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
119ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte#endif
120ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
12132db524ab38b3258c6bae0b9b7fa76bff544085aHarald Weltestatic int print_match(const struct ipt_entry_match *e,
12232db524ab38b3258c6bae0b9b7fa76bff544085aHarald Welte			const struct ipt_ip *ip)
123ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte{
124ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	struct iptables_match *match
12578cafdaf474a333fa39efab4aa4c9aed88ab9518Martin Josefsson		= find_match(e->u.user.name, TRY_LOAD, NULL);
126ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
127ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	if (match) {
128ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		printf("-m %s ", e->u.user.name);
129e81377974336cad22e721e55e142749182877065Harald Welte
130e81377974336cad22e721e55e142749182877065Harald Welte		/* some matches don't provide a save function */
131e81377974336cad22e721e55e142749182877065Harald Welte		if (match->save)
132e81377974336cad22e721e55e142749182877065Harald Welte			match->save(ip, e);
133ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	} else {
134ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		if (e->u.match_size) {
135ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			fprintf(stderr,
136ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte				"Can't find library for match `%s'\n",
137ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte				e->u.user.name);
138ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			exit(1);
139ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		}
140ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	}
141ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	return 0;
142ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte}
143ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
144ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte/* print a given ip including mask if neccessary */
145ae1ff9f96a80379a650dec979b9902528a10d45aHarald Weltestatic void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
146ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte{
147db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt	u_int32_t bits, hmask = ntohl(mask);
148db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt	int i;
149db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt
150f9b7af8bc031472e488eb1feaca06cebbfe28e83Patrick McHardy	if (!mask && !ip && !invert)
151ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		return;
152ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
153ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	printf("%s %s%u.%u.%u.%u",
154ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		prefix,
155ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		invert ? "! " : "",
156ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		IP_PARTS(ip));
157ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
158db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt	if (mask == 0xFFFFFFFFU) {
159db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt		printf("/32 ");
160db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt		return;
161db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt	}
162db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt
163db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt	i    = 32;
164db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt	bits = 0xFFFFFFFEU;
165db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt	while (--i >= 0 && hmask != bits)
166db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt		bits <<= 1;
167db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt	if (i >= 0)
168db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt		printf("/%u ", i);
169ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	else
170db09b39196b537f3898b9454a5758e6540f9f121Jan Engelhardt		printf("/%u.%u.%u.%u ", IP_PARTS(mask));
171ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte}
172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* We want this to be readable, so only print out neccessary fields.
174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Because that's the kind of world I want to live in.  */
1755b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermannstatic void print_rule(const struct ipt_entry *e,
1769f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		iptc_handle_t *h, const char *chain, int counters)
177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
178ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	struct ipt_entry_target *t;
179ace8a01d5a0ae1a0b99fc2dabdab64a5275c3259Harald Welte	const char *target_name;
180ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
181ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	/* print counters */
182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (counters)
183a28d495285ad7dd9f286d63958cf20d74eec6bcbMartin Josefsson		printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1859f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte	/* print chain name */
1869f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte	printf("-A %s ", chain);
1879f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte
188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Print IP part. */
189ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
1905b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann			e->ip.invflags & IPT_INV_SRCIP);
191ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
192ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
193fa7625a99f77e78c686d8ad890ca0a278e9475a7Harald Welte			e->ip.invflags & IPT_INV_DSTIP);
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_iface('i', e->ip.iniface, e->ip.iniface_mask,
196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    e->ip.invflags & IPT_INV_VIA_IN);
197ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_iface('o', e->ip.outiface, e->ip.outiface_mask,
199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    e->ip.invflags & IPT_INV_VIA_OUT);
200ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->ip.flags & IPT_F_FRAG)
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("%s-f ",
205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       e->ip.invflags & IPT_INV_FRAG ? "! " : "");
206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Print matchinfo part */
208ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	if (e->target_offset) {
20932db524ab38b3258c6bae0b9b7fa76bff544085aHarald Welte		IPT_MATCH_ITERATE(e, print_match, &e->ip);
210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2125b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann	/* Print target name */
2136f83cf034de43e3360675cff492c8ce01c47818aHarald Welte	target_name = iptc_get_target(e, h);
2146f83cf034de43e3360675cff492c8ce01c47818aHarald Welte	if (target_name && (*target_name != '\0'))
21572bd87e13b76818f5c690a9097080123ff698bc2Harald Welte#ifdef IPT_F_GOTO
21617fc163babc348780bae4321071845748f7b7985Henrik Nordstrom		printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
21772bd87e13b76818f5c690a9097080123ff698bc2Harald Welte#else
21872bd87e13b76818f5c690a9097080123ff698bc2Harald Welte		printf("-j %s ", target_name);
21972bd87e13b76818f5c690a9097080123ff698bc2Harald Welte#endif
220ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte
221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Print targinfo part */
222082ba02f9ce9c64bb4beb76f7075e7324d738e41Rusty Russell	t = ipt_get_target((struct ipt_entry *)e);
223ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	if (t->u.user.name[0]) {
224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct iptables_target *target
225ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			= find_target(t->u.user.name, TRY_LOAD);
226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
22731098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte		if (!target) {
22831098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte			fprintf(stderr, "Can't find library for target `%s'\n",
22931098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte				t->u.user.name);
23031098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte			exit(1);
23131098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte		}
23231098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte
23331098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte		if (target->save)
23432db524ab38b3258c6bae0b9b7fa76bff544085aHarald Welte			target->save(&e->ip, t);
235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else {
23631098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte			/* If the target size is greater than ipt_entry_target
23731098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte			 * there is something to be saved, we just don't know
23831098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte			 * how to print it */
2395b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann			if (t->u.target_size !=
24031098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte			    sizeof(struct ipt_entry_target)) {
24131098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte				fprintf(stderr, "Target `%s' is missing "
24231098adc568dafa3e1e361f830a2dc514c107c8dHarald Welte						"save function\n",
243ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte					t->u.user.name);
244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit(1);
245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\n");
249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Debugging prototype. */
252a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int for_each_table(int (*func)(const char *tablename))
253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2545b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann	int ret = 1;
255ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	FILE *procfile = NULL;
256a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	char tablename[IPT_TABLE_MAXNAMELEN+1];
257a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
258ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte	procfile = fopen("/proc/net/ip_tables_names", "r");
259a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!procfile)
26065334ad262ffe9e7ad82a3b9b42ec4b03cd515e1Victor Stinner		exit_error(OTHER_PROBLEM,
26165334ad262ffe9e7ad82a3b9b42ec4b03cd515e1Victor Stinner			   "Unable to open /proc/net/ip_tables_names: %s\n",
26265334ad262ffe9e7ad82a3b9b42ec4b03cd515e1Victor Stinner			   strerror(errno));
263a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
264a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	while (fgets(tablename, sizeof(tablename), procfile)) {
265a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		if (tablename[strlen(tablename) - 1] != '\n')
266a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			exit_error(OTHER_PROBLEM,
267a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell				   "Badly formed tablename `%s'\n",
268a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell				   tablename);
269a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		tablename[strlen(tablename) - 1] = '\0';
270a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		ret &= func(tablename);
271a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
273a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return ret;
274a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell}
2755b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
277a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russellstatic int do_output(const char *tablename)
278a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell{
279a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	iptc_handle_t h;
280a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	const char *chain = NULL;
281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
282a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!tablename)
283a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		return for_each_table(&do_output);
284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
285a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	h = iptc_init(tablename);
286a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (!h)
2875b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann		exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
288a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			   iptc_strerror(errno));
289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!binary) {
291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		time_t now = time(NULL);
292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("# Generated by iptables-save v%s on %s",
29480fe35d6339b53a12ddaec41885613e4e37ed031Harald Welte		       IPTABLES_VERSION, ctime(&now));
295ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte		printf("*%s\n", tablename);
296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2975b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann		/* Dump out chain names first,
2989f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		 * thereby preventing dependency conflicts */
299a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		for (chain = iptc_first_chain(&h);
300a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		     chain;
301a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		     chain = iptc_next_chain(&h)) {
3025b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(":%s ", chain);
304ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			if (iptc_builtin(chain, h)) {
305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				struct ipt_counters count;
306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("%s ",
307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				       iptc_get_policy(chain, &count, &h));
308a28d495285ad7dd9f286d63958cf20d74eec6bcbMartin Josefsson				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			} else {
310d8e6563430ab692cf093a81b9b6ac997739d9504Harald Welte				printf("- [0:0]\n");
311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
3129f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		}
3135b76f682f722bebc2f0616fca4600eee2c08dfe2Max Kellermann
3149f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte
3159f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		for (chain = iptc_first_chain(&h);
3169f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		     chain;
3179f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte		     chain = iptc_next_chain(&h)) {
3189f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte			const struct ipt_entry *e;
319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
320ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			/* Dump out rules */
321ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			e = iptc_first_rule(chain, &h);
322ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			while(e) {
3239f7fa49a6e1cd803de8a42fa849582d5d72822bfHarald Welte				print_rule(e, &h, chain, counters);
324ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte				e = iptc_next_rule(e, &h);
325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		now = time(NULL);
329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("COMMIT\n");
330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("# Completed on %s", ctime(&now));
331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Binary, huh?  OK. */
333a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		exit_error(OTHER_PROBLEM, "Binary NYI\n");
334a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
335a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
336841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	iptc_free(&h);
337841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
338a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return 1;
339a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell}
340a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
341a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell/* Format:
342a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell * :Chain name POLICY packets bytes
343a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell * rule
344a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell */
3454e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#ifdef IPTABLES_MULTI
3464e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkerint
3474e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkeriptables_save_main(int argc, char *argv[])
3484e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#else
3494e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkerint
3504e3771f04687657753f2a3666225341a3525f07eBastiaan Bakkermain(int argc, char *argv[])
3514e3771f04687657753f2a3666225341a3525f07eBastiaan Bakker#endif
352a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell{
353a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	const char *tablename = NULL;
354a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	int c;
355a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
356a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	program_name = "iptables-save";
35780fe35d6339b53a12ddaec41885613e4e37ed031Harald Welte	program_version = IPTABLES_VERSION;
358a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
359357d59dcfcbd125e2aa8c07b30cea9635efec2a7Martin Josefsson	lib_dir = getenv("IPTABLES_LIB_DIR");
360357d59dcfcbd125e2aa8c07b30cea9635efec2a7Martin Josefsson	if (!lib_dir)
361357d59dcfcbd125e2aa8c07b30cea9635efec2a7Martin Josefsson		lib_dir = IPT_LIB_DIR;
362357d59dcfcbd125e2aa8c07b30cea9635efec2a7Martin Josefsson
3633efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte#ifdef NO_SHARED_LIBS
3643efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte	init_extensions();
3653efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte#endif
3663efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7cHarald Welte
367163ad7801e93e4d8d3308741d34bcc1ee695d87bMarc Boucher	while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
368a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		switch (c) {
369a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'b':
370a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			binary = 1;
371a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
372a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
373a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'c':
374a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			counters = 1;
375a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
376a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
377a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 't':
378a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			/* Select specific table. */
379a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			tablename = optarg;
380a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			break;
381a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		case 'd':
382ae1ff9f96a80379a650dec979b9902528a10d45aHarald Welte			do_output(tablename);
383a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell			exit(0);
384a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell		}
385a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	}
386a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell
387a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	if (optind < argc) {
388972af09e79618c5086e26ef6438bd38c45c4bb3fPavel Rusnak		fprintf(stderr, "Unknown arguments found on commandline\n");
389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
392a8f033e89981d019c8a4214b9094f2b2411bea18Rusty Russell	return !do_output(tablename);
393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
394