blob: 2a86718e25689d2d42dc87188d5e1440d2ef3290 [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>
7#include "packet-match/userspace/libiptc/libiptc.h"
8#include "packet-match/userspace/iptables.h"
9
10/* Keeping track of external matches and targets. */
11static struct option options[] = {
12 { "binary", 1, 0, 'b' },
13 { "counters", 1, 0, 'c' },
14 { "dump", 1, 0, 'd' },
15 { 0 }
16};
17
18#define IP_PARTS_NATIVE(n) \
19(unsigned int)((n)>>24)&0xFF, \
20(unsigned int)((n)>>16)&0xFF, \
21(unsigned int)((n)>>8)&0xFF, \
22(unsigned int)((n)&0xFF)
23
24#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
25
26/* This assumes that mask is contiguous, and byte-bounded. */
27static void
28print_iface(char letter, const char *iface, const unsigned char *mask,
29 int invert)
30{
31 unsigned int i;
32
33 if (mask[0] == 0)
34 return;
Rusty Russell7e53bf92000-03-20 07:03:28 +000035
Marc Bouchere6869a82000-03-20 06:03:29 +000036 printf("-%c %s", letter, invert ? "! " : "");
37
38 for (i = 0; i < IFNAMSIZ; i++) {
39 if (mask[i] != 0) {
40 if (iface[i] != '\0')
41 printf("%c", iface[i]);
42 } else {
43 if (iface[i] != '\0')
44 printf("+");
45 break;
46 }
47 }
48}
49
50/* These are hardcoded backups in iptables.c, so they are safe */
51struct pprot {
52 char *name;
53 u_int8_t num;
54};
55
56static const struct pprot chain_protos[] = {
57 { "tcp", IPPROTO_TCP },
58 { "udp", IPPROTO_UDP },
59 { "icmp", IPPROTO_ICMP },
60};
61
62static void print_proto(u_int16_t proto, int invert)
63{
64 if (proto) {
65 unsigned int i;
66 const char *invertstr = invert ? "! " : "";
67
68 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
69 if (chain_protos[i].num == proto) {
70 printf("-p %s%s ",
71 invertstr, chain_protos[i].name);
72 return;
73 }
74
75 printf("-p %s%u ", invertstr, proto);
76 }
77}
78
79static int non_zero(const void *ptr, size_t size)
80{
81 unsigned int i;
82
83 for (i = 0; i < size; i++)
84 if (((char *)ptr)[i])
85 return 0;
86
87 return 1;
88}
89
90/* We want this to be readable, so only print out neccessary fields.
91 * Because that's the kind of world I want to live in. */
92static void print_rule(const struct ipt_entry *e, int counters)
93{
94 if (counters)
95 printf("[%llu,%llu] ", e->counters.pcnt, e->counters.bcnt);
96
97 /* Print IP part. */
98 if (e->ip.smsk.s_addr)
99 printf("-s %s%u.%u.%u.%u/%u.%u.%u.%u ",
100 e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
101 IP_PARTS(e->ip.src.s_addr),
102 IP_PARTS(e->ip.smsk.s_addr));
103 if (e->ip.dmsk.s_addr)
104 printf("-d %s%u.%u.%u.%u/%u.%u.%u.%u ",
105 e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
106 IP_PARTS(e->ip.dst.s_addr),
107 IP_PARTS(e->ip.dmsk.s_addr));
108
109 print_iface('i', e->ip.iniface, e->ip.iniface_mask,
110 e->ip.invflags & IPT_INV_VIA_IN);
111 print_iface('o', e->ip.outiface, e->ip.outiface_mask,
112 e->ip.invflags & IPT_INV_VIA_OUT);
113 print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
114
115 if (e->ip.flags & IPT_F_FRAG)
116 printf("%s-f ",
117 e->ip.invflags & IPT_INV_FRAG ? "! " : "");
118
119 if (e->ip.flags & IPT_F_TOS)
120 printf("-t %s0x%02X ",
121 e->ip.invflags & IPT_INV_TOS ? "! " : "",
122 e->ip.tos);
123
124 /* Print matchinfo part */
125 if (e->match_name[0]) {
Rusty Russell52a51492000-05-02 16:44:29 +0000126 struct iptables_match *match
127 = find_match(e->match_name, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +0000128
129 if (match)
130 match->save(e);
131 else {
132 /* If some bits are non-zero, it implies we *need*
133 to understand it */
134 if (non_zero(&e->matchinfo, sizeof(e->matchinfo))) {
135 fprintf(stderr,
136 "Can't find library for match `%s'\n",
137 e->match_name);
138 exit(1);
139 }
140 }
141 }
142
143 /* Print targinfo part */
144 if (e->target_name[0]) {
145 struct iptables_target *target
Rusty Russell52a51492000-05-02 16:44:29 +0000146 = find_target(e->target_name, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +0000147
148 if (target)
149 target->save(e);
150 else {
151 /* If some bits are non-zero, it implies we *need*
152 to understand it */
153 if (non_zero(&e->targinfo, sizeof(e->targinfo))) {
154 fprintf(stderr,
155 "Can't find library for target `%s'\n",
156 e->target_name);
157 exit(1);
158 }
159 }
160 }
161 printf("\n");
162}
163
164/* Debugging prototype. */
165extern void dump_entries(iptc_handle_t handle);
166
167/* Format:
168 * :Chain name POLICY packets bytes
169 * rule
170 */
171int main(int argc, char *argv[])
172{
173 iptc_handle_t h;
174 const char *chain = NULL;
175 int c;
176 int binary = 0, counters = 0;
177
178 program_name = "iptables-save";
179 program_version = NETFILTER_VERSION;
180
181 while ((c = getopt_long(argc, argv, "bc", options, NULL)) != -1) {
182 switch (c) {
183 case 'b':
184 binary = 1;
185 break;
186
187 case 'c':
188 counters = 1;
189 break;
190
191 case 'd':
192 /* Debugging dump. */
193 h = iptc_init();
194 if (!h)
195 exit_error(OTHER_PROBLEM, "iptc_init: %s\n",
196 iptc_strerror(errno));
197 dump_entries(h);
198 exit(0);
199 }
200 }
201
202 if (optind < argc) {
203 fprintf(stderr, "Unknown arguments found on commandline");
204 exit(1);
205 }
206
207 h = iptc_init();
208 if (!h) {
209 fprintf(stderr, "Can't initialize: %s\n",
210 iptc_strerror(errno));
211 exit(1);
212 }
213
214 if (!binary) {
215 time_t now = time(NULL);
216
217 printf("# Generated by iptables-save v%s on %s",
218 NETFILTER_VERSION, ctime(&now));
219
220 /* Dump out chain names */
221 while ((chain = iptc_next_chain(chain, &h)) != NULL) {
222 printf(":%s ", chain);
223 if (iptc_builtin(chain, &h)) {
224 struct ipt_counters count;
225 printf("%s ",
226 iptc_get_policy(chain, &count, &h));
227 printf("%llu %llu\n", count.pcnt, count.bcnt);
228 } else {
229 printf("- 0 0\n");
230 }
231 }
232
233 /* Dump out rules */
234 while ((chain = iptc_next_chain(chain, &h)) != NULL) {
235 unsigned int i;
236
237 for (i = 0; i < iptc_num_rules(chain, &h); i++) {
238 const struct ipt_entry *e
239 = iptc_get_rule(chain, i, &h);
240
241 if (!e) {
242 fprintf(stderr,
243 "Can't read rule %u of chain %s: %s\n",
244 i, chain, iptc_strerror(errno));
245 exit(1);
246 }
247 print_rule(e, counters);
248 }
249 }
250
251 now = time(NULL);
252 printf("COMMIT\n");
253 printf("# Completed on %s", ctime(&now));
254 } else {
255 /* Binary, huh? OK. */
256 fprintf(stderr, "Binary NYI\n");
257 exit(1);
258 }
259
260 return 0;
261}