blob: 413e1ad3393f927fcc285aa646801f6fbbcb06b7 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Code to save the iptables state, in human readable-form. */
Harald Welteae1ff9f2000-12-01 14:26:20 +00002/* Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
3 * Harald Welte <laforge@gnumonks.org>
4 */
Marc Bouchere6869a82000-03-20 06:03:29 +00005#include <getopt.h>
6#include <sys/errno.h>
7#include <stdio.h>
Harald Welteae1ff9f2000-12-01 14:26:20 +00008#include <fcntl.h>
9#include <stdlib.h>
10#include <string.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000011#include <dlfcn.h>
12#include <time.h>
Rusty Russellb1f69be2000-08-27 07:42:54 +000013#include "libiptc/libiptc.h"
14#include "iptables.h"
Marc Bouchere6869a82000-03-20 06:03:29 +000015
Rusty Russella8f033e2000-07-30 01:43:01 +000016static int binary = 0, counters = 0;
17
Marc Bouchere6869a82000-03-20 06:03:29 +000018static struct option options[] = {
Rusty Russella8f033e2000-07-30 01:43:01 +000019 { "binary", 0, 0, 'b' },
20 { "counters", 0, 0, 'c' },
21 { "dump", 0, 0, 'd' },
22 { "table", 1, 0, 't' },
Marc Bouchere6869a82000-03-20 06:03:29 +000023 { 0 }
24};
25
26#define IP_PARTS_NATIVE(n) \
27(unsigned int)((n)>>24)&0xFF, \
28(unsigned int)((n)>>16)&0xFF, \
29(unsigned int)((n)>>8)&0xFF, \
30(unsigned int)((n)&0xFF)
31
32#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
33
34/* This assumes that mask is contiguous, and byte-bounded. */
35static void
36print_iface(char letter, const char *iface, const unsigned char *mask,
37 int invert)
38{
39 unsigned int i;
40
41 if (mask[0] == 0)
42 return;
Rusty Russell7e53bf92000-03-20 07:03:28 +000043
Marc Bouchere6869a82000-03-20 06:03:29 +000044 printf("-%c %s", letter, invert ? "! " : "");
45
46 for (i = 0; i < IFNAMSIZ; i++) {
47 if (mask[i] != 0) {
48 if (iface[i] != '\0')
49 printf("%c", iface[i]);
50 } else {
51 if (iface[i] != '\0')
52 printf("+");
53 break;
54 }
55 }
Harald Welteae1ff9f2000-12-01 14:26:20 +000056
57 printf(" ");
Marc Bouchere6869a82000-03-20 06:03:29 +000058}
59
60/* These are hardcoded backups in iptables.c, so they are safe */
61struct pprot {
62 char *name;
63 u_int8_t num;
64};
65
Harald Welteae1ff9f2000-12-01 14:26:20 +000066/* FIXME: why don't we use /etc/services ? */
Marc Bouchere6869a82000-03-20 06:03:29 +000067static const struct pprot chain_protos[] = {
68 { "tcp", IPPROTO_TCP },
69 { "udp", IPPROTO_UDP },
70 { "icmp", IPPROTO_ICMP },
71};
72
73static void print_proto(u_int16_t proto, int invert)
74{
75 if (proto) {
76 unsigned int i;
77 const char *invertstr = invert ? "! " : "";
78
79 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
80 if (chain_protos[i].num == proto) {
81 printf("-p %s%s ",
82 invertstr, chain_protos[i].name);
83 return;
84 }
85
86 printf("-p %s%u ", invertstr, proto);
87 }
88}
89
Harald Welteae1ff9f2000-12-01 14:26:20 +000090#if 0
Marc Bouchere6869a82000-03-20 06:03:29 +000091static int non_zero(const void *ptr, size_t size)
92{
93 unsigned int i;
94
95 for (i = 0; i < size; i++)
96 if (((char *)ptr)[i])
97 return 0;
98
99 return 1;
100}
Harald Welteae1ff9f2000-12-01 14:26:20 +0000101#endif
102
103static int print_match(const struct ipt_entry_match *e)
104{
105 struct iptables_match *match
106 = find_match(e->u.user.name, TRY_LOAD);
107
108 if (match) {
109 printf("-m %s ", e->u.user.name);
110 match->save(NULL, e);
111 } else {
112 if (e->u.match_size) {
113 fprintf(stderr,
114 "Can't find library for match `%s'\n",
115 e->u.user.name);
116 exit(1);
117 }
118 }
119 return 0;
120}
121
122/* print a given ip including mask if neccessary */
123static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
124{
125 if (!mask && !ip)
126 return;
127
128 printf("%s %s%u.%u.%u.%u",
129 prefix,
130 invert ? "! " : "",
131 IP_PARTS(ip));
132
133 if (mask != 0xffffffff)
134 printf("/%u.%u.%u.%u ", IP_PARTS(mask));
135 else
136 printf(" ");
137}
Marc Bouchere6869a82000-03-20 06:03:29 +0000138
139/* We want this to be readable, so only print out neccessary fields.
140 * Because that's the kind of world I want to live in. */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000141static void print_rule(const struct ipt_entry *e,
142 iptc_handle_t *h, int counters)
Marc Bouchere6869a82000-03-20 06:03:29 +0000143{
Harald Welteae1ff9f2000-12-01 14:26:20 +0000144 struct ipt_entry_target *t;
145
146 /* print counters */
Marc Bouchere6869a82000-03-20 06:03:29 +0000147 if (counters)
148 printf("[%llu,%llu] ", e->counters.pcnt, e->counters.bcnt);
149
150 /* Print IP part. */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000151 print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
152 e->ip.invflags & IPT_INV_SRCIP);
153
154 print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
155 e->ip.invflags & IPT_INV_SRCIP);
Marc Bouchere6869a82000-03-20 06:03:29 +0000156
157 print_iface('i', e->ip.iniface, e->ip.iniface_mask,
158 e->ip.invflags & IPT_INV_VIA_IN);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000159
Marc Bouchere6869a82000-03-20 06:03:29 +0000160 print_iface('o', e->ip.outiface, e->ip.outiface_mask,
161 e->ip.invflags & IPT_INV_VIA_OUT);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000162
Marc Bouchere6869a82000-03-20 06:03:29 +0000163 print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
164
165 if (e->ip.flags & IPT_F_FRAG)
166 printf("%s-f ",
167 e->ip.invflags & IPT_INV_FRAG ? "! " : "");
168
Marc Bouchere6869a82000-03-20 06:03:29 +0000169 /* Print matchinfo part */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000170 if (e->target_offset) {
171 IPT_MATCH_ITERATE(e, print_match);
Marc Bouchere6869a82000-03-20 06:03:29 +0000172 }
173
Harald Welteae1ff9f2000-12-01 14:26:20 +0000174 /* Print target name */
175 printf("-j %s ", iptc_get_target(e, h));
176
Marc Bouchere6869a82000-03-20 06:03:29 +0000177 /* Print targinfo part */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000178 t = ipt_get_target(e);
179 if (t->u.user.name[0]) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000180 struct iptables_target *target
Harald Welteae1ff9f2000-12-01 14:26:20 +0000181 = find_target(t->u.user.name, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +0000182
183 if (target)
Harald Welteae1ff9f2000-12-01 14:26:20 +0000184 target->save(NULL, t);
Marc Bouchere6869a82000-03-20 06:03:29 +0000185 else {
186 /* If some bits are non-zero, it implies we *need*
187 to understand it */
Harald Welteae1ff9f2000-12-01 14:26:20 +0000188 if (t->u.target_size) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000189 fprintf(stderr,
190 "Can't find library for target `%s'\n",
Harald Welteae1ff9f2000-12-01 14:26:20 +0000191 t->u.user.name);
Marc Bouchere6869a82000-03-20 06:03:29 +0000192 exit(1);
193 }
194 }
195 }
196 printf("\n");
197}
198
199/* Debugging prototype. */
Rusty Russella8f033e2000-07-30 01:43:01 +0000200static int for_each_table(int (*func)(const char *tablename))
201{
202 int ret = 1;
Harald Welteae1ff9f2000-12-01 14:26:20 +0000203 FILE *procfile = NULL;
Rusty Russella8f033e2000-07-30 01:43:01 +0000204 char tablename[IPT_TABLE_MAXNAMELEN+1];
205
Harald Welteae1ff9f2000-12-01 14:26:20 +0000206 procfile = fopen("/proc/net/ip_tables_names", "r");
Rusty Russella8f033e2000-07-30 01:43:01 +0000207 if (!procfile)
208 return 0;
209
210 while (fgets(tablename, sizeof(tablename), procfile)) {
211 if (tablename[strlen(tablename) - 1] != '\n')
212 exit_error(OTHER_PROBLEM,
213 "Badly formed tablename `%s'\n",
214 tablename);
215 tablename[strlen(tablename) - 1] = '\0';
216 ret &= func(tablename);
217 }
218
219 return ret;
220}
221
222
Rusty Russella8f033e2000-07-30 01:43:01 +0000223static int do_output(const char *tablename)
224{
225 iptc_handle_t h;
226 const char *chain = NULL;
227
228 if (!tablename)
229 return for_each_table(&do_output);
230
231 h = iptc_init(tablename);
232 if (!h)
233 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
234 iptc_strerror(errno));
235
236 if (!binary) {
237 time_t now = time(NULL);
238
239 printf("# Generated by iptables-save v%s on %s",
240 NETFILTER_VERSION, ctime(&now));
Harald Welteae1ff9f2000-12-01 14:26:20 +0000241 printf("*%s\n", tablename);
Rusty Russella8f033e2000-07-30 01:43:01 +0000242
243 /* Dump out chain names */
244 for (chain = iptc_first_chain(&h);
245 chain;
246 chain = iptc_next_chain(&h)) {
Harald Welteae1ff9f2000-12-01 14:26:20 +0000247 const struct ipt_entry *e;
248
Rusty Russella8f033e2000-07-30 01:43:01 +0000249 printf(":%s ", chain);
Harald Welteae1ff9f2000-12-01 14:26:20 +0000250 if (iptc_builtin(chain, h)) {
Rusty Russella8f033e2000-07-30 01:43:01 +0000251 struct ipt_counters count;
252 printf("%s ",
253 iptc_get_policy(chain, &count, &h));
Harald Welteae1ff9f2000-12-01 14:26:20 +0000254 printf("%llu:%llu\n", count.pcnt, count.bcnt);
Rusty Russella8f033e2000-07-30 01:43:01 +0000255 } else {
256 printf("- 0 0\n");
257 }
Rusty Russella8f033e2000-07-30 01:43:01 +0000258
Harald Welteae1ff9f2000-12-01 14:26:20 +0000259 /* Dump out rules */
260 e = iptc_first_rule(chain, &h);
261 while(e) {
262 print_rule(e, &h, counters);
263 e = iptc_next_rule(e, &h);
Rusty Russella8f033e2000-07-30 01:43:01 +0000264 }
265 }
266
267 now = time(NULL);
268 printf("COMMIT\n");
269 printf("# Completed on %s", ctime(&now));
270 } else {
271 /* Binary, huh? OK. */
272 exit_error(OTHER_PROBLEM, "Binary NYI\n");
273 }
274
275 return 1;
276}
277
Marc Bouchere6869a82000-03-20 06:03:29 +0000278/* Format:
279 * :Chain name POLICY packets bytes
280 * rule
281 */
282int main(int argc, char *argv[])
283{
Rusty Russella8f033e2000-07-30 01:43:01 +0000284 const char *tablename = NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +0000285 int c;
Marc Bouchere6869a82000-03-20 06:03:29 +0000286
287 program_name = "iptables-save";
288 program_version = NETFILTER_VERSION;
289
290 while ((c = getopt_long(argc, argv, "bc", options, NULL)) != -1) {
291 switch (c) {
292 case 'b':
293 binary = 1;
294 break;
295
296 case 'c':
297 counters = 1;
298 break;
299
Rusty Russella8f033e2000-07-30 01:43:01 +0000300 case 't':
301 /* Select specific table. */
302 tablename = optarg;
303 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000304 case 'd':
Harald Welteae1ff9f2000-12-01 14:26:20 +0000305 do_output(tablename);
Marc Bouchere6869a82000-03-20 06:03:29 +0000306 exit(0);
307 }
308 }
309
310 if (optind < argc) {
311 fprintf(stderr, "Unknown arguments found on commandline");
312 exit(1);
313 }
314
Rusty Russella8f033e2000-07-30 01:43:01 +0000315 return !do_output(tablename);
Marc Bouchere6869a82000-03-20 06:03:29 +0000316}