blob: d858817eb9157f705edcd280ab164b2ae5866807 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Code to save the iptables state, in human readable-form. */
2#include <getopt.h>
3#include <sys/errno.h>
4#include <stdio.h>
5#include <dlfcn.h>
6#include <time.h>
Rusty Russellb1f69be2000-08-27 07:42:54 +00007#include "libiptc/libiptc.h"
8#include "iptables.h"
Marc Bouchere6869a82000-03-20 06:03:29 +00009
Rusty Russella8f033e2000-07-30 01:43:01 +000010static int binary = 0, counters = 0;
11
Marc Bouchere6869a82000-03-20 06:03:29 +000012static struct option options[] = {
Rusty Russella8f033e2000-07-30 01:43:01 +000013 { "binary", 0, 0, 'b' },
14 { "counters", 0, 0, 'c' },
15 { "dump", 0, 0, 'd' },
16 { "table", 1, 0, 't' },
Marc Bouchere6869a82000-03-20 06:03:29 +000017 { 0 }
18};
19
20#define IP_PARTS_NATIVE(n) \
21(unsigned int)((n)>>24)&0xFF, \
22(unsigned int)((n)>>16)&0xFF, \
23(unsigned int)((n)>>8)&0xFF, \
24(unsigned int)((n)&0xFF)
25
26#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
27
28/* This assumes that mask is contiguous, and byte-bounded. */
29static void
30print_iface(char letter, const char *iface, const unsigned char *mask,
31 int invert)
32{
33 unsigned int i;
34
35 if (mask[0] == 0)
36 return;
Rusty Russell7e53bf92000-03-20 07:03:28 +000037
Marc Bouchere6869a82000-03-20 06:03:29 +000038 printf("-%c %s", letter, invert ? "! " : "");
39
40 for (i = 0; i < IFNAMSIZ; i++) {
41 if (mask[i] != 0) {
42 if (iface[i] != '\0')
43 printf("%c", iface[i]);
44 } else {
45 if (iface[i] != '\0')
46 printf("+");
47 break;
48 }
49 }
50}
51
52/* These are hardcoded backups in iptables.c, so they are safe */
53struct pprot {
54 char *name;
55 u_int8_t num;
56};
57
58static const struct pprot chain_protos[] = {
59 { "tcp", IPPROTO_TCP },
60 { "udp", IPPROTO_UDP },
61 { "icmp", IPPROTO_ICMP },
62};
63
64static void print_proto(u_int16_t proto, int invert)
65{
66 if (proto) {
67 unsigned int i;
68 const char *invertstr = invert ? "! " : "";
69
70 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
71 if (chain_protos[i].num == proto) {
72 printf("-p %s%s ",
73 invertstr, chain_protos[i].name);
74 return;
75 }
76
77 printf("-p %s%u ", invertstr, proto);
78 }
79}
80
81static int non_zero(const void *ptr, size_t size)
82{
83 unsigned int i;
84
85 for (i = 0; i < size; i++)
86 if (((char *)ptr)[i])
87 return 0;
88
89 return 1;
90}
91
92/* We want this to be readable, so only print out neccessary fields.
93 * Because that's the kind of world I want to live in. */
94static void print_rule(const struct ipt_entry *e, int counters)
95{
96 if (counters)
97 printf("[%llu,%llu] ", e->counters.pcnt, e->counters.bcnt);
98
99 /* Print IP part. */
100 if (e->ip.smsk.s_addr)
101 printf("-s %s%u.%u.%u.%u/%u.%u.%u.%u ",
102 e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
103 IP_PARTS(e->ip.src.s_addr),
104 IP_PARTS(e->ip.smsk.s_addr));
105 if (e->ip.dmsk.s_addr)
106 printf("-d %s%u.%u.%u.%u/%u.%u.%u.%u ",
107 e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
108 IP_PARTS(e->ip.dst.s_addr),
109 IP_PARTS(e->ip.dmsk.s_addr));
110
111 print_iface('i', e->ip.iniface, e->ip.iniface_mask,
112 e->ip.invflags & IPT_INV_VIA_IN);
113 print_iface('o', e->ip.outiface, e->ip.outiface_mask,
114 e->ip.invflags & IPT_INV_VIA_OUT);
115 print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
116
117 if (e->ip.flags & IPT_F_FRAG)
118 printf("%s-f ",
119 e->ip.invflags & IPT_INV_FRAG ? "! " : "");
120
121 if (e->ip.flags & IPT_F_TOS)
122 printf("-t %s0x%02X ",
123 e->ip.invflags & IPT_INV_TOS ? "! " : "",
124 e->ip.tos);
125
126 /* Print matchinfo part */
127 if (e->match_name[0]) {
Rusty Russell52a51492000-05-02 16:44:29 +0000128 struct iptables_match *match
129 = find_match(e->match_name, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +0000130
131 if (match)
132 match->save(e);
133 else {
134 /* If some bits are non-zero, it implies we *need*
135 to understand it */
136 if (non_zero(&e->matchinfo, sizeof(e->matchinfo))) {
137 fprintf(stderr,
138 "Can't find library for match `%s'\n",
139 e->match_name);
140 exit(1);
141 }
142 }
143 }
144
145 /* Print targinfo part */
146 if (e->target_name[0]) {
147 struct iptables_target *target
Rusty Russell52a51492000-05-02 16:44:29 +0000148 = find_target(e->target_name, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +0000149
150 if (target)
151 target->save(e);
152 else {
153 /* If some bits are non-zero, it implies we *need*
154 to understand it */
155 if (non_zero(&e->targinfo, sizeof(e->targinfo))) {
156 fprintf(stderr,
157 "Can't find library for target `%s'\n",
158 e->target_name);
159 exit(1);
160 }
161 }
162 }
163 printf("\n");
164}
165
166/* Debugging prototype. */
167extern void dump_entries(iptc_handle_t handle);
168
Rusty Russella8f033e2000-07-30 01:43:01 +0000169static int for_each_table(int (*func)(const char *tablename))
170{
171 int ret = 1;
172 FILE *procfile;
173 char tablename[IPT_TABLE_MAXNAMELEN+1];
174
175 procfile = fopen("/proc/net/ip_tables_names", O_RDONLY);
176 if (!procfile)
177 return 0;
178
179 while (fgets(tablename, sizeof(tablename), procfile)) {
180 if (tablename[strlen(tablename) - 1] != '\n')
181 exit_error(OTHER_PROBLEM,
182 "Badly formed tablename `%s'\n",
183 tablename);
184 tablename[strlen(tablename) - 1] = '\0';
185 ret &= func(tablename);
186 }
187
188 return ret;
189}
190
191
192static int dump_table(const char *tablename)
193{
194 iptc_handle_t h;
195
196 if (!tablename)
197 return for_each_table(&dump_table);
198
199 /* Debugging dump. */
200 h = iptc_init(tablename);
201 if (!h)
202 exit_error(OTHER_PROBLEM, "iptc_init: %s\n",
203 iptc_strerror(errno));
204 dump_entries(h);
205}
206
207static int do_output(const char *tablename)
208{
209 iptc_handle_t h;
210 const char *chain = NULL;
211
212 if (!tablename)
213 return for_each_table(&do_output);
214
215 h = iptc_init(tablename);
216 if (!h)
217 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
218 iptc_strerror(errno));
219
220 if (!binary) {
221 time_t now = time(NULL);
222
223 printf("# Generated by iptables-save v%s on %s",
224 NETFILTER_VERSION, ctime(&now));
225
226 /* Dump out chain names */
227 for (chain = iptc_first_chain(&h);
228 chain;
229 chain = iptc_next_chain(&h)) {
230 printf(":%s ", chain);
231 if (iptc_builtin(chain, &h)) {
232 struct ipt_counters count;
233 printf("%s ",
234 iptc_get_policy(chain, &count, &h));
235 printf("%llu %llu\n", count.pcnt, count.bcnt);
236 } else {
237 printf("- 0 0\n");
238 }
239 }
240
241 /* Dump out rules */
242 for (chain = iptc_first_chain(&h);
243 chain;
244 chain = iptc_next_chain(&h)) {
245 unsigned int i;
246
247 for (i = 0; i < iptc_num_rules(chain, &h); i++) {
248 const struct ipt_entry *e
249 = iptc_get_rule(chain, i, &h);
250
251 if (!e)
252 exit_error(OTHER_PROBLEM,
253 "Can't read rule %u"
254 " of chain %s: %s\n",
255 i, chain,
256 iptc_strerror(errno));
257 print_rule(e, counters);
258 }
259 }
260
261 now = time(NULL);
262 printf("COMMIT\n");
263 printf("# Completed on %s", ctime(&now));
264 } else {
265 /* Binary, huh? OK. */
266 exit_error(OTHER_PROBLEM, "Binary NYI\n");
267 }
268
269 return 1;
270}
271
Marc Bouchere6869a82000-03-20 06:03:29 +0000272/* Format:
273 * :Chain name POLICY packets bytes
274 * rule
275 */
276int main(int argc, char *argv[])
277{
Rusty Russella8f033e2000-07-30 01:43:01 +0000278 const char *tablename = NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +0000279 int c;
Marc Bouchere6869a82000-03-20 06:03:29 +0000280
281 program_name = "iptables-save";
282 program_version = NETFILTER_VERSION;
283
284 while ((c = getopt_long(argc, argv, "bc", options, NULL)) != -1) {
285 switch (c) {
286 case 'b':
287 binary = 1;
288 break;
289
290 case 'c':
291 counters = 1;
292 break;
293
Rusty Russella8f033e2000-07-30 01:43:01 +0000294 case 't':
295 /* Select specific table. */
296 tablename = optarg;
297 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000298 case 'd':
Rusty Russella8f033e2000-07-30 01:43:01 +0000299 dump_table(tablename);
Marc Bouchere6869a82000-03-20 06:03:29 +0000300 exit(0);
301 }
302 }
303
304 if (optind < argc) {
305 fprintf(stderr, "Unknown arguments found on commandline");
306 exit(1);
307 }
308
Rusty Russella8f033e2000-07-30 01:43:01 +0000309 return !do_output(tablename);
Marc Bouchere6869a82000-03-20 06:03:29 +0000310}