blob: 4ec1bf41131a5770c21beec490a9b91afd41822c [file] [log] [blame]
András Kis-Szabó2f523792001-02-27 09:59:48 +00001/* Code to save the ip6tables state, in human readable-form. */
2/* Author: Andras Kis-Szabo <kisza@sch.bme.hu>
3 * Original code: iptables-save
4 * Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
5 * Harald Welte <laforge@gnumonks.org>
6 */
7#include <getopt.h>
8#include <sys/errno.h>
9#include <stdio.h>
10#include <fcntl.h>
11#include <stdlib.h>
12#include <string.h>
13#include <dlfcn.h>
14#include <time.h>
15#include <netdb.h>
16#include <arpa/inet.h>
17#include "libiptc/libip6tc.h"
18#include "ip6tables.h"
19
András Kis-Szabó2f523792001-02-27 09:59:48 +000020static int binary = 0, counters = 0;
21
22static struct option options[] = {
23 { "binary", 0, 0, 'b' },
24 { "counters", 0, 0, 'c' },
25 { "dump", 0, 0, 'd' },
26 { "table", 1, 0, 't' },
27 { 0 }
28};
29
András Kis-Szabó97fd91a2002-03-03 09:44:31 +000030/*
András Kis-Szabó2f523792001-02-27 09:59:48 +000031extern struct ip6tables_match *find_match(const char *name, enum ip6t_tryload tryload);
32extern struct ip6tables_target *find_target(const char *name, enum ip6t_tryload tryload);
András Kis-Szabó97fd91a2002-03-03 09:44:31 +000033*/
András Kis-Szabó2f523792001-02-27 09:59:48 +000034
35/* This assumes that mask is contiguous, and byte-bounded. */
36static void
37print_iface(char letter, const char *iface, const unsigned char *mask,
38 int invert)
39{
40 unsigned int i;
41
42 if (mask[0] == 0)
43 return;
44
45 printf("-%c %s", letter, invert ? "! " : "");
46
47 for (i = 0; i < IFNAMSIZ; i++) {
48 if (mask[i] != 0) {
49 if (iface[i] != '\0')
50 printf("%c", iface[i]);
51 } else {
András Kis-Szabó97fd91a2002-03-03 09:44:31 +000052 /* we can access iface[i-1] here, because
53 * a few lines above we make sure that mask[0] != 0 */
54 if (iface[i-1] != '\0')
András Kis-Szabó2f523792001-02-27 09:59:48 +000055 printf("+");
56 break;
57 }
58 }
59
60 printf(" ");
61}
62
63/* These are hardcoded backups in ip6tables.c, so they are safe */
64struct pprot {
65 char *name;
66 u_int8_t num;
67};
68
69static const struct pprot chain_protos[] = {
70 { "tcp", IPPROTO_TCP },
71 { "udp", IPPROTO_UDP },
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000072 { "icmpv6", IPPROTO_ICMPV6 },
András Kis-Szabó2f523792001-02-27 09:59:48 +000073 { "esp", IPPROTO_ESP },
74 { "ah", IPPROTO_AH },
75};
76
77/* The ip6tables looks up the /etc/protocols. */
78static void print_proto(u_int16_t proto, int invert)
79{
80 if (proto) {
81 unsigned int i;
82 const char *invertstr = invert ? "! " : "";
83
84 struct protoent *pent = getprotobynumber(proto);
85 if (pent) {
86 printf("-p %s%s ",
87 invertstr, pent->p_name);
88 return;
89 }
90
91 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
92 if (chain_protos[i].num == proto) {
93 printf("-p %s%s ",
94 invertstr, chain_protos[i].name);
95 return;
96 }
97
98 printf("-p %s%u ", invertstr, proto);
99 }
100}
101
102static int print_match(const struct ip6t_entry_match *e,
103 const struct ip6t_ip6 *ip)
104{
105 struct ip6tables_match *match
106 = find_match(e->u.user.name, TRY_LOAD);
107
108 if (match) {
109 printf("-m %s ", e->u.user.name);
110
111 /* some matches don't provide a save function */
112 if (match->save)
113 match->save(ip, e);
114 } else {
115 if (e->u.match_size) {
116 fprintf(stderr,
117 "Can't find library for match `%s'\n",
118 e->u.user.name);
119 exit(1);
120 }
121 }
122 return 0;
123}
124
125/* print a given ip including mask if neccessary */
126static void print_ip(char *prefix, const struct in6_addr *ip, const struct in6_addr *mask, int invert)
127{
128 char buf[51];
129 int l = ipv6_prefix_length(mask);
130
131 if (!mask && !ip)
132 return;
133
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000134 printf("%s %s%s",
András Kis-Szabó2f523792001-02-27 09:59:48 +0000135 prefix,
136 invert ? "! " : "",
137 inet_ntop(AF_INET6, ip, buf, sizeof buf));
138
139 if (l == -1)
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000140 printf("/%s ", inet_ntop(AF_INET6, mask, buf, sizeof buf));
András Kis-Szabó2f523792001-02-27 09:59:48 +0000141 else
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000142 printf("/%d ", l);
András Kis-Szabó2f523792001-02-27 09:59:48 +0000143}
144
145/* We want this to be readable, so only print out neccessary fields.
146 * Because that's the kind of world I want to live in. */
147static void print_rule(const struct ip6t_entry *e,
Harald Welte885c6eb2001-10-04 08:30:46 +0000148 ip6tc_handle_t *h, const char *chain, int counters)
András Kis-Szabó2f523792001-02-27 09:59:48 +0000149{
150 struct ip6t_entry_target *t;
Harald Welteace8a012001-07-05 06:29:10 +0000151 const char *target_name;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000152
153 /* print counters */
154 if (counters)
155 printf("[%llu:%llu] ", e->counters.pcnt, e->counters.bcnt);
156
Harald Welte885c6eb2001-10-04 08:30:46 +0000157 /* print chain name */
158 printf("-A %s ", chain);
159
András Kis-Szabó2f523792001-02-27 09:59:48 +0000160 /* Print IP part. */
161 print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk),
162 e->ipv6.invflags & IP6T_INV_SRCIP);
163
164 print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk),
165 e->ipv6.invflags & IP6T_INV_DSTIP);
166
167 print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask,
168 e->ipv6.invflags & IP6T_INV_VIA_IN);
169
170 print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask,
171 e->ipv6.invflags & IP6T_INV_VIA_OUT);
172
173 print_proto(e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
174
175#if 0
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000176 /* not definied in ipv6
177 * FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? */
András Kis-Szabó2f523792001-02-27 09:59:48 +0000178 if (e->ipv6.flags & IPT_F_FRAG)
179 printf("%s-f ",
180 e->ipv6.invflags & IP6T_INV_FRAG ? "! " : "");
181#endif
182
András Kis-Szabó2f523792001-02-27 09:59:48 +0000183 if (e->ipv6.flags & IP6T_F_TOS)
184 printf("%s-? %d ",
185 e->ipv6.invflags & IP6T_INV_TOS ? "! " : "",
186 e->ipv6.tos);
187
188 /* Print matchinfo part */
189 if (e->target_offset) {
190 IP6T_MATCH_ITERATE(e, print_match, &e->ipv6);
191 }
192
193 /* Print target name */
Harald Welteace8a012001-07-05 06:29:10 +0000194 target_name = ip6tc_get_target(e, h);
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000195 if (target_name && (*target_name != '\0'))
196 printf("-j %s ", target_name);
András Kis-Szabó2f523792001-02-27 09:59:48 +0000197
198 /* Print targinfo part */
199 t = ip6t_get_target((struct ip6t_entry *)e);
200 if (t->u.user.name[0]) {
201 struct ip6tables_target *target
202 = find_target(t->u.user.name, TRY_LOAD);
203
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000204 if (!target) {
205 fprintf(stderr, "Can't find library for target `%s'\n",
206 t->u.user.name);
207 exit(1);
208 }
209
210 if (target->save)
András Kis-Szabó2f523792001-02-27 09:59:48 +0000211 target->save(&e->ipv6, t);
212 else {
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000213 /* If the target size is greater than ip6t_entry_target
214 * there is something to be saved, we just don't know
215 * how to print it */
216 if (t->u.target_size !=
217 sizeof(struct ip6t_entry_target)) {
218 fprintf(stderr, "Target `%s' is missing "
219 "save function\n",
András Kis-Szabó2f523792001-02-27 09:59:48 +0000220 t->u.user.name);
221 exit(1);
222 }
223 }
224 }
225 printf("\n");
226}
227
228/* Debugging prototype. */
229static int for_each_table(int (*func)(const char *tablename))
230{
231 int ret = 1;
232 FILE *procfile = NULL;
233 char tablename[IP6T_TABLE_MAXNAMELEN+1];
234
235 procfile = fopen("/proc/net/ip6_tables_names", "r");
236 if (!procfile)
237 return 0;
238
239 while (fgets(tablename, sizeof(tablename), procfile)) {
240 if (tablename[strlen(tablename) - 1] != '\n')
241 exit_error(OTHER_PROBLEM,
242 "Badly formed tablename `%s'\n",
243 tablename);
244 tablename[strlen(tablename) - 1] = '\0';
245 ret &= func(tablename);
246 }
247
248 return ret;
249}
250
251
252static int do_output(const char *tablename)
253{
254 ip6tc_handle_t h;
255 const char *chain = NULL;
256
257 if (!tablename)
258 return for_each_table(&do_output);
259
260 h = ip6tc_init(tablename);
261 if (!h)
262 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
263 ip6tc_strerror(errno));
264
265 if (!binary) {
266 time_t now = time(NULL);
267
268 printf("# Generated by ip6tables-save v%s on %s",
269 NETFILTER_VERSION, ctime(&now));
270 printf("*%s\n", tablename);
271
Harald Welte885c6eb2001-10-04 08:30:46 +0000272 /* Dump out chain names first,
273 * thereby preventing dependency conflicts */
András Kis-Szabó2f523792001-02-27 09:59:48 +0000274 for (chain = ip6tc_first_chain(&h);
275 chain;
276 chain = ip6tc_next_chain(&h)) {
András Kis-Szabó2f523792001-02-27 09:59:48 +0000277
278 printf(":%s ", chain);
279 if (ip6tc_builtin(chain, h)) {
280 struct ip6t_counters count;
281 printf("%s ",
282 ip6tc_get_policy(chain, &count, &h));
283 printf("[%llu:%llu]\n", count.pcnt, count.bcnt);
284 } else {
285 printf("- [0:0]\n");
286 }
Harald Welte885c6eb2001-10-04 08:30:46 +0000287 }
288
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000289
Harald Welte885c6eb2001-10-04 08:30:46 +0000290 for (chain = ip6tc_first_chain(&h);
291 chain;
292 chain = ip6tc_next_chain(&h)) {
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000293 const struct ip6t_entry *e;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000294
295 /* Dump out rules */
296 e = ip6tc_first_rule(chain, &h);
297 while(e) {
Harald Welte885c6eb2001-10-04 08:30:46 +0000298 print_rule(e, &h, chain, counters);
András Kis-Szabó2f523792001-02-27 09:59:48 +0000299 e = ip6tc_next_rule(e, &h);
300 }
301 }
302
303 now = time(NULL);
304 printf("COMMIT\n");
305 printf("# Completed on %s", ctime(&now));
306 } else {
307 /* Binary, huh? OK. */
308 exit_error(OTHER_PROBLEM, "Binary NYI\n");
309 }
310
311 return 1;
312}
313
314/* Format:
315 * :Chain name POLICY packets bytes
316 * rule
317 */
318int main(int argc, char *argv[])
319{
320 const char *tablename = NULL;
321 int c;
322
323 program_name = "ip6tables-save";
324 program_version = NETFILTER_VERSION;
325
Harald Welte3efb6ea2001-08-06 18:50:21 +0000326#ifdef NO_SHARED_LIBS
327 init_extensions();
328#endif
329
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000330 while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
András Kis-Szabó2f523792001-02-27 09:59:48 +0000331 switch (c) {
332 case 'b':
333 binary = 1;
334 break;
335
336 case 'c':
337 counters = 1;
338 break;
339
340 case 't':
341 /* Select specific table. */
342 tablename = optarg;
343 break;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000344 case 'd':
345 do_output(tablename);
346 exit(0);
347 }
348 }
349
350 if (optind < argc) {
351 fprintf(stderr, "Unknown arguments found on commandline");
352 exit(1);
353 }
354
355 return !do_output(tablename);
356}