blob: 40e9d6a55335cf72b7f8ab61ad4b195a50074eef [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;
35
36 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]) {
126 struct iptables_match *match = find_match(e->match_name, 1);
127
128 if (match)
129 match->save(e);
130 else {
131 /* If some bits are non-zero, it implies we *need*
132 to understand it */
133 if (non_zero(&e->matchinfo, sizeof(e->matchinfo))) {
134 fprintf(stderr,
135 "Can't find library for match `%s'\n",
136 e->match_name);
137 exit(1);
138 }
139 }
140 }
141
142 /* Print targinfo part */
143 if (e->target_name[0]) {
144 struct iptables_target *target
145 = find_target(e->target_name, 1);
146
147 if (target)
148 target->save(e);
149 else {
150 /* If some bits are non-zero, it implies we *need*
151 to understand it */
152 if (non_zero(&e->targinfo, sizeof(e->targinfo))) {
153 fprintf(stderr,
154 "Can't find library for target `%s'\n",
155 e->target_name);
156 exit(1);
157 }
158 }
159 }
160 printf("\n");
161}
162
163/* Debugging prototype. */
164extern void dump_entries(iptc_handle_t handle);
165
166/* Format:
167 * :Chain name POLICY packets bytes
168 * rule
169 */
170int main(int argc, char *argv[])
171{
172 iptc_handle_t h;
173 const char *chain = NULL;
174 int c;
175 int binary = 0, counters = 0;
176
177 program_name = "iptables-save";
178 program_version = NETFILTER_VERSION;
179
180 while ((c = getopt_long(argc, argv, "bc", options, NULL)) != -1) {
181 switch (c) {
182 case 'b':
183 binary = 1;
184 break;
185
186 case 'c':
187 counters = 1;
188 break;
189
190 case 'd':
191 /* Debugging dump. */
192 h = iptc_init();
193 if (!h)
194 exit_error(OTHER_PROBLEM, "iptc_init: %s\n",
195 iptc_strerror(errno));
196 dump_entries(h);
197 exit(0);
198 }
199 }
200
201 if (optind < argc) {
202 fprintf(stderr, "Unknown arguments found on commandline");
203 exit(1);
204 }
205
206 h = iptc_init();
207 if (!h) {
208 fprintf(stderr, "Can't initialize: %s\n",
209 iptc_strerror(errno));
210 exit(1);
211 }
212
213 if (!binary) {
214 time_t now = time(NULL);
215
216 printf("# Generated by iptables-save v%s on %s",
217 NETFILTER_VERSION, ctime(&now));
218
219 /* Dump out chain names */
220 while ((chain = iptc_next_chain(chain, &h)) != NULL) {
221 printf(":%s ", chain);
222 if (iptc_builtin(chain, &h)) {
223 struct ipt_counters count;
224 printf("%s ",
225 iptc_get_policy(chain, &count, &h));
226 printf("%llu %llu\n", count.pcnt, count.bcnt);
227 } else {
228 printf("- 0 0\n");
229 }
230 }
231
232 /* Dump out rules */
233 while ((chain = iptc_next_chain(chain, &h)) != NULL) {
234 unsigned int i;
235
236 for (i = 0; i < iptc_num_rules(chain, &h); i++) {
237 const struct ipt_entry *e
238 = iptc_get_rule(chain, i, &h);
239
240 if (!e) {
241 fprintf(stderr,
242 "Can't read rule %u of chain %s: %s\n",
243 i, chain, iptc_strerror(errno));
244 exit(1);
245 }
246 print_rule(e, counters);
247 }
248 }
249
250 now = time(NULL);
251 printf("COMMIT\n");
252 printf("# Completed on %s", ctime(&now));
253 } else {
254 /* Binary, huh? OK. */
255 fprintf(stderr, "Binary NYI\n");
256 exit(1);
257 }
258
259 return 0;
260}