blob: f8a61c21dec30b1090e47e5342c13b051d11e3e4 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Code to save the iptables state, in human readable-form. */
Harald Welte10a907f2002-08-07 09:07:41 +00002/* (C) 1999 by Paul 'Rusty' Russell <rusty@rustcorp.com.au> and
3 * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
4 *
5 * This code is distributed under the terms of GNU GPL v2
6 *
Harald Welteae1ff9f2000-12-01 14:26:20 +00007 */
Marc Bouchere6869a82000-03-20 06:03:29 +00008#include <getopt.h>
9#include <sys/errno.h>
10#include <stdio.h>
Harald Welteae1ff9f2000-12-01 14:26:20 +000011#include <fcntl.h>
12#include <stdlib.h>
13#include <string.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000014#include <time.h>
Harald Welted8ac9672004-04-15 10:10:19 +000015#include <netdb.h>
Rusty Russellb1f69be2000-08-27 07:42:54 +000016#include "libiptc/libiptc.h"
17#include "iptables.h"
Marc Bouchere6869a82000-03-20 06:03:29 +000018
Mike Frysinger5a26b5f2007-12-19 14:51:17 +000019#ifndef NO_SHARED_LIBS
20#include <dlfcn.h>
21#endif
22
Rusty Russella8f033e2000-07-30 01:43:01 +000023static int binary = 0, counters = 0;
24
Marc Bouchere6869a82000-03-20 06:03:29 +000025static struct option options[] = {
Rusty Russella8f033e2000-07-30 01:43:01 +000026 { "binary", 0, 0, 'b' },
27 { "counters", 0, 0, 'c' },
28 { "dump", 0, 0, 'd' },
29 { "table", 1, 0, 't' },
Marc Bouchere6869a82000-03-20 06:03:29 +000030 { 0 }
31};
32
33#define IP_PARTS_NATIVE(n) \
34(unsigned int)((n)>>24)&0xFF, \
35(unsigned int)((n)>>16)&0xFF, \
36(unsigned int)((n)>>8)&0xFF, \
37(unsigned int)((n)&0xFF)
38
39#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
40
41/* This assumes that mask is contiguous, and byte-bounded. */
42static void
43print_iface(char letter, const char *iface, const unsigned char *mask,
44 int invert)
45{
46 unsigned int i;
47
48 if (mask[0] == 0)
49 return;
Rusty Russell7e53bf92000-03-20 07:03:28 +000050
Marc Bouchere6869a82000-03-20 06:03:29 +000051 printf("-%c %s", letter, invert ? "! " : "");
52
53 for (i = 0; i < IFNAMSIZ; i++) {
54 if (mask[i] != 0) {
55 if (iface[i] != '\0')
56 printf("%c", iface[i]);
57 } else {
Max Kellermann5b76f682008-01-29 13:42:48 +000058 /* we can access iface[i-1] here, because
Harald Welte9535e682001-11-08 22:28:23 +000059 * a few lines above we make sure that mask[0] != 0 */
60 if (iface[i-1] != '\0')
Marc Bouchere6869a82000-03-20 06:03:29 +000061 printf("+");
62 break;
63 }
64 }
Harald Welteae1ff9f2000-12-01 14:26:20 +000065
66 printf(" ");
Marc Bouchere6869a82000-03-20 06:03:29 +000067}
68
69/* These are hardcoded backups in iptables.c, so they are safe */
70struct pprot {
71 char *name;
72 u_int8_t num;
73};
74
András Kis-Szabó764316a2001-02-26 17:31:20 +000075/* FIXME: why don't we use /etc/protocols ? */
Marc Bouchere6869a82000-03-20 06:03:29 +000076static const struct pprot chain_protos[] = {
77 { "tcp", IPPROTO_TCP },
78 { "udp", IPPROTO_UDP },
79 { "icmp", IPPROTO_ICMP },
András Kis-Szabó764316a2001-02-26 17:31:20 +000080 { "esp", IPPROTO_ESP },
81 { "ah", IPPROTO_AH },
Harald Welte12915232004-02-21 09:20:34 +000082 { "sctp", IPPROTO_SCTP },
Marc Bouchere6869a82000-03-20 06:03:29 +000083};
84
85static void print_proto(u_int16_t proto, int invert)
86{
87 if (proto) {
88 unsigned int i;
89 const char *invertstr = invert ? "! " : "";
90
Pedro Lamarão0e3b3372004-04-07 09:33:17 +000091 struct protoent *pent = getprotobynumber(proto);
92 if (pent) {
93 printf("-p %s%s ", invertstr, pent->p_name);
94 return;
95 }
96
Marc Bouchere6869a82000-03-20 06:03:29 +000097 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
98 if (chain_protos[i].num == proto) {
99 printf("-p %s%s ",
100 invertstr, chain_protos[i].name);
101 return;
102 }
103
104 printf("-p %s%u ", invertstr, proto);
105 }
106}
107
Harald Welteae1ff9f2000-12-01 14:26:20 +0000108#if 0
Marc Bouchere6869a82000-03-20 06:03:29 +0000109static int non_zero(const void *ptr, size_t size)
110{
111 unsigned int i;
112
113 for (i = 0; i < size; i++)
114 if (((char *)ptr)[i])
115 return 0;
116
117 return 1;
118}
Harald Welteae1ff9f2000-12-01 14:26:20 +0000119#endif
120
Harald Welte32db5242001-01-23 22:46:22 +0000121static int print_match(const struct ipt_entry_match *e,
122 const struct ipt_ip *ip)
Harald Welteae1ff9f2000-12-01 14:26:20 +0000123{
124 struct iptables_match *match
Martin Josefsson78cafda2004-02-02 20:01:18 +0000125 = find_match(e->u.user.name, TRY_LOAD, NULL);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000126
127 if (match) {
128 printf("-m %s ", e->u.user.name);
Harald Weltee8137792001-01-24 01:32:51 +0000129
130 /* some matches don't provide a save function */
131 if (match->save)
132 match->save(ip, e);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000133 } else {
134 if (e->u.match_size) {
135 fprintf(stderr,
136 "Can't find library for match `%s'\n",
137 e->u.user.name);
138 exit(1);
139 }
140 }
141 return 0;
142}
143
144/* print a given ip including mask if neccessary */
145static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
146{
Jan Engelhardtdb09b392007-11-25 15:27:56 +0000147 u_int32_t bits, hmask = ntohl(mask);
148 int i;
149
Patrick McHardyf9b7af82006-12-02 17:17:33 +0000150 if (!mask && !ip && !invert)
Harald Welteae1ff9f2000-12-01 14:26:20 +0000151 return;
152
153 printf("%s %s%u.%u.%u.%u",
154 prefix,
155 invert ? "! " : "",
156 IP_PARTS(ip));
157
Jan Engelhardtdb09b392007-11-25 15:27:56 +0000158 if (mask == 0xFFFFFFFFU) {
159 printf("/32 ");
160 return;
161 }
162
163 i = 32;
164 bits = 0xFFFFFFFEU;
165 while (--i >= 0 && hmask != bits)
166 bits <<= 1;
167 if (i >= 0)
168 printf("/%u ", i);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000169 else
Jan Engelhardtdb09b392007-11-25 15:27:56 +0000170 printf("/%u.%u.%u.%u ", IP_PARTS(mask));
Harald Welteae1ff9f2000-12-01 14:26:20 +0000171}
Marc Bouchere6869a82000-03-20 06:03:29 +0000172
173/* We want this to be readable, so only print out neccessary fields.
174 * Because that's the kind of world I want to live in. */
Max Kellermann5b76f682008-01-29 13:42:48 +0000175static void print_rule(const struct ipt_entry *e,
Harald Welte9f7fa492001-03-15 15:12:02 +0000176 iptc_handle_t *h, const char *chain, int counters)
Marc Bouchere6869a82000-03-20 06:03:29 +0000177{
Harald Welteae1ff9f2000-12-01 14:26:20 +0000178 struct ipt_entry_target *t;
Harald Welteace8a012001-07-05 06:29:10 +0000179 const char *target_name;
Harald Welteae1ff9f2000-12-01 14:26:20 +0000180
181 /* print counters */
Marc Bouchere6869a82000-03-20 06:03:29 +0000182 if (counters)
Martin Josefssona28d4952004-05-26 16:04:48 +0000183 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
Marc Bouchere6869a82000-03-20 06:03:29 +0000184
Harald Welte9f7fa492001-03-15 15:12:02 +0000185 /* print chain name */
186 printf("-A %s ", chain);
187
Marc Bouchere6869a82000-03-20 06:03:29 +0000188 /* Print IP part. */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000189 print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
Max Kellermann5b76f682008-01-29 13:42:48 +0000190 e->ip.invflags & IPT_INV_SRCIP);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000191
192 print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
Harald Weltefa7625a2001-01-26 03:28:18 +0000193 e->ip.invflags & IPT_INV_DSTIP);
Marc Bouchere6869a82000-03-20 06:03:29 +0000194
195 print_iface('i', e->ip.iniface, e->ip.iniface_mask,
196 e->ip.invflags & IPT_INV_VIA_IN);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000197
Marc Bouchere6869a82000-03-20 06:03:29 +0000198 print_iface('o', e->ip.outiface, e->ip.outiface_mask,
199 e->ip.invflags & IPT_INV_VIA_OUT);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000200
Marc Bouchere6869a82000-03-20 06:03:29 +0000201 print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
202
203 if (e->ip.flags & IPT_F_FRAG)
204 printf("%s-f ",
205 e->ip.invflags & IPT_INV_FRAG ? "! " : "");
206
Marc Bouchere6869a82000-03-20 06:03:29 +0000207 /* Print matchinfo part */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000208 if (e->target_offset) {
Harald Welte32db5242001-01-23 22:46:22 +0000209 IPT_MATCH_ITERATE(e, print_match, &e->ip);
Marc Bouchere6869a82000-03-20 06:03:29 +0000210 }
211
Max Kellermann5b76f682008-01-29 13:42:48 +0000212 /* Print target name */
Harald Welte6f83cf02001-05-24 23:22:28 +0000213 target_name = iptc_get_target(e, h);
214 if (target_name && (*target_name != '\0'))
Harald Welte72bd87e2005-11-24 17:04:05 +0000215#ifdef IPT_F_GOTO
Henrik Nordstrom17fc1632005-11-05 09:26:40 +0000216 printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
Harald Welte72bd87e2005-11-24 17:04:05 +0000217#else
218 printf("-j %s ", target_name);
219#endif
Harald Welteae1ff9f2000-12-01 14:26:20 +0000220
Marc Bouchere6869a82000-03-20 06:03:29 +0000221 /* Print targinfo part */
Rusty Russell082ba022001-01-07 06:54:51 +0000222 t = ipt_get_target((struct ipt_entry *)e);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000223 if (t->u.user.name[0]) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000224 struct iptables_target *target
Harald Welteae1ff9f2000-12-01 14:26:20 +0000225 = find_target(t->u.user.name, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +0000226
Harald Welte31098ad2001-10-16 09:40:13 +0000227 if (!target) {
228 fprintf(stderr, "Can't find library for target `%s'\n",
229 t->u.user.name);
230 exit(1);
231 }
232
233 if (target->save)
Harald Welte32db5242001-01-23 22:46:22 +0000234 target->save(&e->ip, t);
Marc Bouchere6869a82000-03-20 06:03:29 +0000235 else {
Harald Welte31098ad2001-10-16 09:40:13 +0000236 /* If the target size is greater than ipt_entry_target
237 * there is something to be saved, we just don't know
238 * how to print it */
Max Kellermann5b76f682008-01-29 13:42:48 +0000239 if (t->u.target_size !=
Harald Welte31098ad2001-10-16 09:40:13 +0000240 sizeof(struct ipt_entry_target)) {
241 fprintf(stderr, "Target `%s' is missing "
242 "save function\n",
Harald Welteae1ff9f2000-12-01 14:26:20 +0000243 t->u.user.name);
Marc Bouchere6869a82000-03-20 06:03:29 +0000244 exit(1);
245 }
246 }
247 }
248 printf("\n");
249}
250
251/* Debugging prototype. */
Rusty Russella8f033e2000-07-30 01:43:01 +0000252static int for_each_table(int (*func)(const char *tablename))
253{
Max Kellermann5b76f682008-01-29 13:42:48 +0000254 int ret = 1;
Harald Welteae1ff9f2000-12-01 14:26:20 +0000255 FILE *procfile = NULL;
Rusty Russella8f033e2000-07-30 01:43:01 +0000256 char tablename[IPT_TABLE_MAXNAMELEN+1];
257
Harald Welteae1ff9f2000-12-01 14:26:20 +0000258 procfile = fopen("/proc/net/ip_tables_names", "r");
Rusty Russella8f033e2000-07-30 01:43:01 +0000259 if (!procfile)
Victor Stinner65334ad2007-10-18 14:27:03 +0000260 exit_error(OTHER_PROBLEM,
261 "Unable to open /proc/net/ip_tables_names: %s\n",
262 strerror(errno));
Rusty Russella8f033e2000-07-30 01:43:01 +0000263
264 while (fgets(tablename, sizeof(tablename), procfile)) {
265 if (tablename[strlen(tablename) - 1] != '\n')
266 exit_error(OTHER_PROBLEM,
267 "Badly formed tablename `%s'\n",
268 tablename);
269 tablename[strlen(tablename) - 1] = '\0';
270 ret &= func(tablename);
271 }
272
273 return ret;
274}
Max Kellermann5b76f682008-01-29 13:42:48 +0000275
Rusty Russella8f033e2000-07-30 01:43:01 +0000276
Rusty Russella8f033e2000-07-30 01:43:01 +0000277static int do_output(const char *tablename)
278{
279 iptc_handle_t h;
280 const char *chain = NULL;
281
282 if (!tablename)
283 return for_each_table(&do_output);
284
285 h = iptc_init(tablename);
286 if (!h)
Max Kellermann5b76f682008-01-29 13:42:48 +0000287 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
Rusty Russella8f033e2000-07-30 01:43:01 +0000288 iptc_strerror(errno));
289
290 if (!binary) {
291 time_t now = time(NULL);
292
293 printf("# Generated by iptables-save v%s on %s",
Harald Welte80fe35d2002-05-29 13:08:15 +0000294 IPTABLES_VERSION, ctime(&now));
Harald Welteae1ff9f2000-12-01 14:26:20 +0000295 printf("*%s\n", tablename);
Rusty Russella8f033e2000-07-30 01:43:01 +0000296
Max Kellermann5b76f682008-01-29 13:42:48 +0000297 /* Dump out chain names first,
Harald Welte9f7fa492001-03-15 15:12:02 +0000298 * thereby preventing dependency conflicts */
Rusty Russella8f033e2000-07-30 01:43:01 +0000299 for (chain = iptc_first_chain(&h);
300 chain;
301 chain = iptc_next_chain(&h)) {
Max Kellermann5b76f682008-01-29 13:42:48 +0000302
Rusty Russella8f033e2000-07-30 01:43:01 +0000303 printf(":%s ", chain);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000304 if (iptc_builtin(chain, h)) {
Rusty Russella8f033e2000-07-30 01:43:01 +0000305 struct ipt_counters count;
306 printf("%s ",
307 iptc_get_policy(chain, &count, &h));
Martin Josefssona28d4952004-05-26 16:04:48 +0000308 printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
Rusty Russella8f033e2000-07-30 01:43:01 +0000309 } else {
Harald Welted8e65632001-01-05 15:20:07 +0000310 printf("- [0:0]\n");
Rusty Russella8f033e2000-07-30 01:43:01 +0000311 }
Harald Welte9f7fa492001-03-15 15:12:02 +0000312 }
Max Kellermann5b76f682008-01-29 13:42:48 +0000313
Harald Welte9f7fa492001-03-15 15:12:02 +0000314
315 for (chain = iptc_first_chain(&h);
316 chain;
317 chain = iptc_next_chain(&h)) {
318 const struct ipt_entry *e;
Rusty Russella8f033e2000-07-30 01:43:01 +0000319
Harald Welteae1ff9f2000-12-01 14:26:20 +0000320 /* Dump out rules */
321 e = iptc_first_rule(chain, &h);
322 while(e) {
Harald Welte9f7fa492001-03-15 15:12:02 +0000323 print_rule(e, &h, chain, counters);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000324 e = iptc_next_rule(e, &h);
Rusty Russella8f033e2000-07-30 01:43:01 +0000325 }
326 }
327
328 now = time(NULL);
329 printf("COMMIT\n");
330 printf("# Completed on %s", ctime(&now));
331 } else {
332 /* Binary, huh? OK. */
333 exit_error(OTHER_PROBLEM, "Binary NYI\n");
334 }
335
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000336 iptc_free(&h);
337
Rusty Russella8f033e2000-07-30 01:43:01 +0000338 return 1;
339}
340
Marc Bouchere6869a82000-03-20 06:03:29 +0000341/* Format:
342 * :Chain name POLICY packets bytes
343 * rule
344 */
Bastiaan Bakker4e3771f2004-06-25 11:18:57 +0000345#ifdef IPTABLES_MULTI
346int
347iptables_save_main(int argc, char *argv[])
348#else
349int
350main(int argc, char *argv[])
351#endif
Marc Bouchere6869a82000-03-20 06:03:29 +0000352{
Rusty Russella8f033e2000-07-30 01:43:01 +0000353 const char *tablename = NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +0000354 int c;
Marc Bouchere6869a82000-03-20 06:03:29 +0000355
356 program_name = "iptables-save";
Harald Welte80fe35d2002-05-29 13:08:15 +0000357 program_version = IPTABLES_VERSION;
Marc Bouchere6869a82000-03-20 06:03:29 +0000358
Martin Josefsson357d59d2004-12-27 19:49:28 +0000359 lib_dir = getenv("IPTABLES_LIB_DIR");
360 if (!lib_dir)
361 lib_dir = IPT_LIB_DIR;
362
Harald Welte3efb6ea2001-08-06 18:50:21 +0000363#ifdef NO_SHARED_LIBS
364 init_extensions();
365#endif
366
Marc Boucher163ad782001-12-06 15:05:48 +0000367 while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000368 switch (c) {
369 case 'b':
370 binary = 1;
371 break;
372
373 case 'c':
374 counters = 1;
375 break;
376
Rusty Russella8f033e2000-07-30 01:43:01 +0000377 case 't':
378 /* Select specific table. */
379 tablename = optarg;
380 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000381 case 'd':
Harald Welteae1ff9f2000-12-01 14:26:20 +0000382 do_output(tablename);
Marc Bouchere6869a82000-03-20 06:03:29 +0000383 exit(0);
384 }
385 }
386
387 if (optind < argc) {
Pavel Rusnak972af092007-05-10 15:00:39 +0000388 fprintf(stderr, "Unknown arguments found on commandline\n");
Marc Bouchere6869a82000-03-20 06:03:29 +0000389 exit(1);
390 }
391
Rusty Russella8f033e2000-07-30 01:43:01 +0000392 return !do_output(tablename);
Marc Bouchere6869a82000-03-20 06:03:29 +0000393}