blob: 4272202ef1798e5734924191edf1ffe0e3e61a3f [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"
Jan Engelhardt33690a12008-02-11 00:54:00 +010018#include "iptables-multi.h"
Marc Bouchere6869a82000-03-20 06:03:29 +000019
Mike Frysinger5a26b5f2007-12-19 14:51:17 +000020#ifndef NO_SHARED_LIBS
21#include <dlfcn.h>
22#endif
23
Jan Engelhardtdbb77542008-02-11 00:33:30 +010024static int show_binary = 0, show_counters = 0;
Rusty Russella8f033e2000-07-30 01:43:01 +000025
Gáspár Lajos7bc3cb72008-03-27 08:20:39 +010026static const struct option options[] = {
27 {.name = "binary", .has_arg = false, .val = 'b'},
28 {.name = "counters", .has_arg = false, .val = 'c'},
29 {.name = "dump", .has_arg = false, .val = 'd'},
30 {.name = "table", .has_arg = true, .val = 't'},
31 {NULL},
Marc Bouchere6869a82000-03-20 06:03:29 +000032};
33
34#define IP_PARTS_NATIVE(n) \
35(unsigned int)((n)>>24)&0xFF, \
36(unsigned int)((n)>>16)&0xFF, \
37(unsigned int)((n)>>8)&0xFF, \
38(unsigned int)((n)&0xFF)
39
40#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
41
42/* This assumes that mask is contiguous, and byte-bounded. */
43static void
44print_iface(char letter, const char *iface, const unsigned char *mask,
45 int invert)
46{
47 unsigned int i;
48
49 if (mask[0] == 0)
50 return;
Rusty Russell7e53bf92000-03-20 07:03:28 +000051
Marc Bouchere6869a82000-03-20 06:03:29 +000052 printf("-%c %s", letter, invert ? "! " : "");
53
54 for (i = 0; i < IFNAMSIZ; i++) {
55 if (mask[i] != 0) {
56 if (iface[i] != '\0')
57 printf("%c", iface[i]);
58 } else {
Max Kellermann5b76f682008-01-29 13:42:48 +000059 /* we can access iface[i-1] here, because
Harald Welte9535e682001-11-08 22:28:23 +000060 * a few lines above we make sure that mask[0] != 0 */
61 if (iface[i-1] != '\0')
Marc Bouchere6869a82000-03-20 06:03:29 +000062 printf("+");
63 break;
64 }
65 }
Harald Welteae1ff9f2000-12-01 14:26:20 +000066
67 printf(" ");
Marc Bouchere6869a82000-03-20 06:03:29 +000068}
69
70/* These are hardcoded backups in iptables.c, so they are safe */
71struct pprot {
72 char *name;
73 u_int8_t num;
74};
75
András Kis-Szabó764316a2001-02-26 17:31:20 +000076/* FIXME: why don't we use /etc/protocols ? */
Marc Bouchere6869a82000-03-20 06:03:29 +000077static const struct pprot chain_protos[] = {
78 { "tcp", IPPROTO_TCP },
79 { "udp", IPPROTO_UDP },
80 { "icmp", IPPROTO_ICMP },
András Kis-Szabó764316a2001-02-26 17:31:20 +000081 { "esp", IPPROTO_ESP },
82 { "ah", IPPROTO_AH },
Harald Welte12915232004-02-21 09:20:34 +000083 { "sctp", IPPROTO_SCTP },
Marc Bouchere6869a82000-03-20 06:03:29 +000084};
85
86static void print_proto(u_int16_t proto, int invert)
87{
88 if (proto) {
89 unsigned int i;
90 const char *invertstr = invert ? "! " : "";
91
Pedro Lamarão0e3b3372004-04-07 09:33:17 +000092 struct protoent *pent = getprotobynumber(proto);
93 if (pent) {
94 printf("-p %s%s ", invertstr, pent->p_name);
95 return;
96 }
97
Marc Bouchere6869a82000-03-20 06:03:29 +000098 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
99 if (chain_protos[i].num == proto) {
100 printf("-p %s%s ",
101 invertstr, chain_protos[i].name);
102 return;
103 }
104
105 printf("-p %s%u ", invertstr, proto);
106 }
107}
108
Harald Welteae1ff9f2000-12-01 14:26:20 +0000109#if 0
Marc Bouchere6869a82000-03-20 06:03:29 +0000110static int non_zero(const void *ptr, size_t size)
111{
112 unsigned int i;
113
114 for (i = 0; i < size; i++)
115 if (((char *)ptr)[i])
116 return 0;
117
118 return 1;
119}
Harald Welteae1ff9f2000-12-01 14:26:20 +0000120#endif
121
Harald Welte32db5242001-01-23 22:46:22 +0000122static int print_match(const struct ipt_entry_match *e,
123 const struct ipt_ip *ip)
Harald Welteae1ff9f2000-12-01 14:26:20 +0000124{
125 struct iptables_match *match
Martin Josefsson78cafda2004-02-02 20:01:18 +0000126 = find_match(e->u.user.name, TRY_LOAD, NULL);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000127
128 if (match) {
129 printf("-m %s ", e->u.user.name);
Harald Weltee8137792001-01-24 01:32:51 +0000130
131 /* some matches don't provide a save function */
132 if (match->save)
133 match->save(ip, e);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000134 } else {
135 if (e->u.match_size) {
136 fprintf(stderr,
137 "Can't find library for match `%s'\n",
138 e->u.user.name);
139 exit(1);
140 }
141 }
142 return 0;
143}
144
145/* print a given ip including mask if neccessary */
146static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
147{
Jan Engelhardtdb09b392007-11-25 15:27:56 +0000148 u_int32_t bits, hmask = ntohl(mask);
149 int i;
150
Patrick McHardyf9b7af82006-12-02 17:17:33 +0000151 if (!mask && !ip && !invert)
Harald Welteae1ff9f2000-12-01 14:26:20 +0000152 return;
153
154 printf("%s %s%u.%u.%u.%u",
155 prefix,
156 invert ? "! " : "",
157 IP_PARTS(ip));
158
Jan Engelhardtdb09b392007-11-25 15:27:56 +0000159 if (mask == 0xFFFFFFFFU) {
160 printf("/32 ");
161 return;
162 }
163
164 i = 32;
165 bits = 0xFFFFFFFEU;
166 while (--i >= 0 && hmask != bits)
167 bits <<= 1;
168 if (i >= 0)
169 printf("/%u ", i);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000170 else
Jan Engelhardtdb09b392007-11-25 15:27:56 +0000171 printf("/%u.%u.%u.%u ", IP_PARTS(mask));
Harald Welteae1ff9f2000-12-01 14:26:20 +0000172}
Marc Bouchere6869a82000-03-20 06:03:29 +0000173
174/* We want this to be readable, so only print out neccessary fields.
175 * Because that's the kind of world I want to live in. */
Max Kellermann5b76f682008-01-29 13:42:48 +0000176static void print_rule(const struct ipt_entry *e,
Harald Welte9f7fa492001-03-15 15:12:02 +0000177 iptc_handle_t *h, const char *chain, int counters)
Marc Bouchere6869a82000-03-20 06:03:29 +0000178{
Harald Welteae1ff9f2000-12-01 14:26:20 +0000179 struct ipt_entry_target *t;
Harald Welteace8a012001-07-05 06:29:10 +0000180 const char *target_name;
Harald Welteae1ff9f2000-12-01 14:26:20 +0000181
182 /* print counters */
Marc Bouchere6869a82000-03-20 06:03:29 +0000183 if (counters)
Martin Josefssona28d4952004-05-26 16:04:48 +0000184 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
Marc Bouchere6869a82000-03-20 06:03:29 +0000185
Harald Welte9f7fa492001-03-15 15:12:02 +0000186 /* print chain name */
187 printf("-A %s ", chain);
188
Marc Bouchere6869a82000-03-20 06:03:29 +0000189 /* Print IP part. */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000190 print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
Max Kellermann5b76f682008-01-29 13:42:48 +0000191 e->ip.invflags & IPT_INV_SRCIP);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000192
193 print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
Harald Weltefa7625a2001-01-26 03:28:18 +0000194 e->ip.invflags & IPT_INV_DSTIP);
Marc Bouchere6869a82000-03-20 06:03:29 +0000195
196 print_iface('i', e->ip.iniface, e->ip.iniface_mask,
197 e->ip.invflags & IPT_INV_VIA_IN);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000198
Marc Bouchere6869a82000-03-20 06:03:29 +0000199 print_iface('o', e->ip.outiface, e->ip.outiface_mask,
200 e->ip.invflags & IPT_INV_VIA_OUT);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000201
Marc Bouchere6869a82000-03-20 06:03:29 +0000202 print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
203
204 if (e->ip.flags & IPT_F_FRAG)
205 printf("%s-f ",
206 e->ip.invflags & IPT_INV_FRAG ? "! " : "");
207
Marc Bouchere6869a82000-03-20 06:03:29 +0000208 /* Print matchinfo part */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000209 if (e->target_offset) {
Harald Welte32db5242001-01-23 22:46:22 +0000210 IPT_MATCH_ITERATE(e, print_match, &e->ip);
Marc Bouchere6869a82000-03-20 06:03:29 +0000211 }
212
Max Kellermann5b76f682008-01-29 13:42:48 +0000213 /* Print target name */
Harald Welte6f83cf02001-05-24 23:22:28 +0000214 target_name = iptc_get_target(e, h);
215 if (target_name && (*target_name != '\0'))
Harald Welte72bd87e2005-11-24 17:04:05 +0000216#ifdef IPT_F_GOTO
Henrik Nordstrom17fc1632005-11-05 09:26:40 +0000217 printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
Harald Welte72bd87e2005-11-24 17:04:05 +0000218#else
219 printf("-j %s ", target_name);
220#endif
Harald Welteae1ff9f2000-12-01 14:26:20 +0000221
Marc Bouchere6869a82000-03-20 06:03:29 +0000222 /* Print targinfo part */
Rusty Russell082ba022001-01-07 06:54:51 +0000223 t = ipt_get_target((struct ipt_entry *)e);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000224 if (t->u.user.name[0]) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000225 struct iptables_target *target
Harald Welteae1ff9f2000-12-01 14:26:20 +0000226 = find_target(t->u.user.name, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +0000227
Harald Welte31098ad2001-10-16 09:40:13 +0000228 if (!target) {
229 fprintf(stderr, "Can't find library for target `%s'\n",
230 t->u.user.name);
231 exit(1);
232 }
233
234 if (target->save)
Harald Welte32db5242001-01-23 22:46:22 +0000235 target->save(&e->ip, t);
Marc Bouchere6869a82000-03-20 06:03:29 +0000236 else {
Harald Welte31098ad2001-10-16 09:40:13 +0000237 /* If the target size is greater than ipt_entry_target
238 * there is something to be saved, we just don't know
239 * how to print it */
Max Kellermann5b76f682008-01-29 13:42:48 +0000240 if (t->u.target_size !=
Harald Welte31098ad2001-10-16 09:40:13 +0000241 sizeof(struct ipt_entry_target)) {
242 fprintf(stderr, "Target `%s' is missing "
243 "save function\n",
Harald Welteae1ff9f2000-12-01 14:26:20 +0000244 t->u.user.name);
Marc Bouchere6869a82000-03-20 06:03:29 +0000245 exit(1);
246 }
247 }
248 }
249 printf("\n");
250}
251
252/* Debugging prototype. */
Rusty Russella8f033e2000-07-30 01:43:01 +0000253static int for_each_table(int (*func)(const char *tablename))
254{
Max Kellermann5b76f682008-01-29 13:42:48 +0000255 int ret = 1;
Harald Welteae1ff9f2000-12-01 14:26:20 +0000256 FILE *procfile = NULL;
Rusty Russella8f033e2000-07-30 01:43:01 +0000257 char tablename[IPT_TABLE_MAXNAMELEN+1];
258
Harald Welteae1ff9f2000-12-01 14:26:20 +0000259 procfile = fopen("/proc/net/ip_tables_names", "r");
Rusty Russella8f033e2000-07-30 01:43:01 +0000260 if (!procfile)
Victor Stinner65334ad2007-10-18 14:27:03 +0000261 exit_error(OTHER_PROBLEM,
262 "Unable to open /proc/net/ip_tables_names: %s\n",
263 strerror(errno));
Rusty Russella8f033e2000-07-30 01:43:01 +0000264
265 while (fgets(tablename, sizeof(tablename), procfile)) {
266 if (tablename[strlen(tablename) - 1] != '\n')
267 exit_error(OTHER_PROBLEM,
268 "Badly formed tablename `%s'\n",
269 tablename);
270 tablename[strlen(tablename) - 1] = '\0';
271 ret &= func(tablename);
272 }
273
274 return ret;
275}
Max Kellermann5b76f682008-01-29 13:42:48 +0000276
Rusty Russella8f033e2000-07-30 01:43:01 +0000277
Rusty Russella8f033e2000-07-30 01:43:01 +0000278static int do_output(const char *tablename)
279{
280 iptc_handle_t h;
281 const char *chain = NULL;
282
283 if (!tablename)
284 return for_each_table(&do_output);
285
286 h = iptc_init(tablename);
287 if (!h)
Max Kellermann5b76f682008-01-29 13:42:48 +0000288 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
Rusty Russella8f033e2000-07-30 01:43:01 +0000289 iptc_strerror(errno));
290
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100291 if (!show_binary) {
Rusty Russella8f033e2000-07-30 01:43:01 +0000292 time_t now = time(NULL);
293
294 printf("# Generated by iptables-save v%s on %s",
Harald Welte80fe35d2002-05-29 13:08:15 +0000295 IPTABLES_VERSION, ctime(&now));
Harald Welteae1ff9f2000-12-01 14:26:20 +0000296 printf("*%s\n", tablename);
Rusty Russella8f033e2000-07-30 01:43:01 +0000297
Max Kellermann5b76f682008-01-29 13:42:48 +0000298 /* Dump out chain names first,
Harald Welte9f7fa492001-03-15 15:12:02 +0000299 * thereby preventing dependency conflicts */
Rusty Russella8f033e2000-07-30 01:43:01 +0000300 for (chain = iptc_first_chain(&h);
301 chain;
302 chain = iptc_next_chain(&h)) {
Max Kellermann5b76f682008-01-29 13:42:48 +0000303
Rusty Russella8f033e2000-07-30 01:43:01 +0000304 printf(":%s ", chain);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000305 if (iptc_builtin(chain, h)) {
Rusty Russella8f033e2000-07-30 01:43:01 +0000306 struct ipt_counters count;
307 printf("%s ",
308 iptc_get_policy(chain, &count, &h));
Martin Josefssona28d4952004-05-26 16:04:48 +0000309 printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
Rusty Russella8f033e2000-07-30 01:43:01 +0000310 } else {
Harald Welted8e65632001-01-05 15:20:07 +0000311 printf("- [0:0]\n");
Rusty Russella8f033e2000-07-30 01:43:01 +0000312 }
Harald Welte9f7fa492001-03-15 15:12:02 +0000313 }
Max Kellermann5b76f682008-01-29 13:42:48 +0000314
Harald Welte9f7fa492001-03-15 15:12:02 +0000315
316 for (chain = iptc_first_chain(&h);
317 chain;
318 chain = iptc_next_chain(&h)) {
319 const struct ipt_entry *e;
Rusty Russella8f033e2000-07-30 01:43:01 +0000320
Harald Welteae1ff9f2000-12-01 14:26:20 +0000321 /* Dump out rules */
322 e = iptc_first_rule(chain, &h);
323 while(e) {
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100324 print_rule(e, &h, chain, show_counters);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000325 e = iptc_next_rule(e, &h);
Rusty Russella8f033e2000-07-30 01:43:01 +0000326 }
327 }
328
329 now = time(NULL);
330 printf("COMMIT\n");
331 printf("# Completed on %s", ctime(&now));
332 } else {
333 /* Binary, huh? OK. */
334 exit_error(OTHER_PROBLEM, "Binary NYI\n");
335 }
336
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000337 iptc_free(&h);
338
Rusty Russella8f033e2000-07-30 01:43:01 +0000339 return 1;
340}
341
Marc Bouchere6869a82000-03-20 06:03:29 +0000342/* Format:
343 * :Chain name POLICY packets bytes
344 * rule
345 */
Bastiaan Bakker4e3771f2004-06-25 11:18:57 +0000346#ifdef IPTABLES_MULTI
347int
348iptables_save_main(int argc, char *argv[])
349#else
350int
351main(int argc, char *argv[])
352#endif
Marc Bouchere6869a82000-03-20 06:03:29 +0000353{
Rusty Russella8f033e2000-07-30 01:43:01 +0000354 const char *tablename = NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +0000355 int c;
Marc Bouchere6869a82000-03-20 06:03:29 +0000356
357 program_name = "iptables-save";
Harald Welte80fe35d2002-05-29 13:08:15 +0000358 program_version = IPTABLES_VERSION;
Marc Bouchere6869a82000-03-20 06:03:29 +0000359
Jan Engelhardt21b41ee2008-02-11 01:02:00 +0100360 lib_dir = getenv("XTABLES_LIBDIR");
361 if (lib_dir == NULL) {
362 lib_dir = getenv("IPTABLES_LIB_DIR");
363 if (lib_dir != NULL)
364 fprintf(stderr, "IPTABLES_LIB_DIR is deprecated\n");
365 }
366 if (lib_dir == NULL)
367 lib_dir = XTABLES_LIBDIR;
Martin Josefsson357d59d2004-12-27 19:49:28 +0000368
Harald Welte3efb6ea2001-08-06 18:50:21 +0000369#ifdef NO_SHARED_LIBS
370 init_extensions();
371#endif
372
Marc Boucher163ad782001-12-06 15:05:48 +0000373 while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000374 switch (c) {
375 case 'b':
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100376 show_binary = 1;
Marc Bouchere6869a82000-03-20 06:03:29 +0000377 break;
378
379 case 'c':
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100380 show_counters = 1;
Marc Bouchere6869a82000-03-20 06:03:29 +0000381 break;
382
Rusty Russella8f033e2000-07-30 01:43:01 +0000383 case 't':
384 /* Select specific table. */
385 tablename = optarg;
386 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000387 case 'd':
Harald Welteae1ff9f2000-12-01 14:26:20 +0000388 do_output(tablename);
Marc Bouchere6869a82000-03-20 06:03:29 +0000389 exit(0);
390 }
391 }
392
393 if (optind < argc) {
Pavel Rusnak972af092007-05-10 15:00:39 +0000394 fprintf(stderr, "Unknown arguments found on commandline\n");
Marc Bouchere6869a82000-03-20 06:03:29 +0000395 exit(1);
396 }
397
Rusty Russella8f033e2000-07-30 01:43:01 +0000398 return !do_output(tablename);
Marc Bouchere6869a82000-03-20 06:03:29 +0000399}