blob: 77cc3250e95bd64c5dc7ed33951f98ff4f902e98 [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>
András Kis-Szabó0c4188f2002-08-14 11:40:41 +00006 * This code is distributed under the terms of GNU GPL v2
András Kis-Szabó2f523792001-02-27 09:59:48 +00007 */
8#include <getopt.h>
9#include <sys/errno.h>
10#include <stdio.h>
11#include <fcntl.h>
12#include <stdlib.h>
13#include <string.h>
14#include <dlfcn.h>
15#include <time.h>
16#include <netdb.h>
17#include <arpa/inet.h>
18#include "libiptc/libip6tc.h"
19#include "ip6tables.h"
20
András Kis-Szabó2f523792001-02-27 09:59:48 +000021static int binary = 0, counters = 0;
22
23static struct option options[] = {
24 { "binary", 0, 0, 'b' },
25 { "counters", 0, 0, 'c' },
26 { "dump", 0, 0, 'd' },
27 { "table", 1, 0, 't' },
28 { 0 }
29};
30
András Kis-Szabó2f523792001-02-27 09:59:48 +000031
32/* This assumes that mask is contiguous, and byte-bounded. */
33static void
34print_iface(char letter, const char *iface, const unsigned char *mask,
35 int invert)
36{
37 unsigned int i;
38
39 if (mask[0] == 0)
40 return;
41
42 printf("-%c %s", letter, invert ? "! " : "");
43
44 for (i = 0; i < IFNAMSIZ; i++) {
45 if (mask[i] != 0) {
46 if (iface[i] != '\0')
47 printf("%c", iface[i]);
48 } else {
András Kis-Szabó97fd91a2002-03-03 09:44:31 +000049 /* we can access iface[i-1] here, because
50 * a few lines above we make sure that mask[0] != 0 */
51 if (iface[i-1] != '\0')
András Kis-Szabó2f523792001-02-27 09:59:48 +000052 printf("+");
53 break;
54 }
55 }
56
57 printf(" ");
58}
59
60/* These are hardcoded backups in ip6tables.c, so they are safe */
61struct pprot {
62 char *name;
63 u_int8_t num;
64};
65
66static const struct pprot chain_protos[] = {
67 { "tcp", IPPROTO_TCP },
68 { "udp", IPPROTO_UDP },
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000069 { "icmpv6", IPPROTO_ICMPV6 },
András Kis-Szabó2f523792001-02-27 09:59:48 +000070 { "esp", IPPROTO_ESP },
71 { "ah", IPPROTO_AH },
72};
73
74/* The ip6tables looks up the /etc/protocols. */
75static void print_proto(u_int16_t proto, int invert)
76{
77 if (proto) {
78 unsigned int i;
79 const char *invertstr = invert ? "! " : "";
80
81 struct protoent *pent = getprotobynumber(proto);
82 if (pent) {
83 printf("-p %s%s ",
84 invertstr, pent->p_name);
85 return;
86 }
87
88 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
89 if (chain_protos[i].num == proto) {
90 printf("-p %s%s ",
91 invertstr, chain_protos[i].name);
92 return;
93 }
94
95 printf("-p %s%u ", invertstr, proto);
96 }
97}
98
99static int print_match(const struct ip6t_entry_match *e,
100 const struct ip6t_ip6 *ip)
101{
102 struct ip6tables_match *match
103 = find_match(e->u.user.name, TRY_LOAD);
104
105 if (match) {
106 printf("-m %s ", e->u.user.name);
107
108 /* some matches don't provide a save function */
109 if (match->save)
110 match->save(ip, 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, const struct in6_addr *ip, const struct in6_addr *mask, int invert)
124{
125 char buf[51];
126 int l = ipv6_prefix_length(mask);
127
128 if (!mask && !ip)
129 return;
130
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000131 printf("%s %s%s",
András Kis-Szabó2f523792001-02-27 09:59:48 +0000132 prefix,
133 invert ? "! " : "",
134 inet_ntop(AF_INET6, ip, buf, sizeof buf));
135
136 if (l == -1)
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000137 printf("/%s ", inet_ntop(AF_INET6, mask, buf, sizeof buf));
András Kis-Szabó2f523792001-02-27 09:59:48 +0000138 else
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000139 printf("/%d ", l);
András Kis-Szabó2f523792001-02-27 09:59:48 +0000140}
141
142/* We want this to be readable, so only print out neccessary fields.
143 * Because that's the kind of world I want to live in. */
144static void print_rule(const struct ip6t_entry *e,
Harald Welte885c6eb2001-10-04 08:30:46 +0000145 ip6tc_handle_t *h, const char *chain, int counters)
András Kis-Szabó2f523792001-02-27 09:59:48 +0000146{
147 struct ip6t_entry_target *t;
Harald Welteace8a012001-07-05 06:29:10 +0000148 const char *target_name;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000149
150 /* print counters */
151 if (counters)
152 printf("[%llu:%llu] ", e->counters.pcnt, e->counters.bcnt);
153
Harald Welte885c6eb2001-10-04 08:30:46 +0000154 /* print chain name */
155 printf("-A %s ", chain);
156
András Kis-Szabó2f523792001-02-27 09:59:48 +0000157 /* Print IP part. */
158 print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk),
159 e->ipv6.invflags & IP6T_INV_SRCIP);
160
161 print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk),
162 e->ipv6.invflags & IP6T_INV_DSTIP);
163
164 print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask,
165 e->ipv6.invflags & IP6T_INV_VIA_IN);
166
167 print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask,
168 e->ipv6.invflags & IP6T_INV_VIA_OUT);
169
170 print_proto(e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
171
172#if 0
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000173 /* not definied in ipv6
174 * FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? */
András Kis-Szabó2f523792001-02-27 09:59:48 +0000175 if (e->ipv6.flags & IPT_F_FRAG)
176 printf("%s-f ",
177 e->ipv6.invflags & IP6T_INV_FRAG ? "! " : "");
178#endif
179
András Kis-Szabó2f523792001-02-27 09:59:48 +0000180 if (e->ipv6.flags & IP6T_F_TOS)
181 printf("%s-? %d ",
182 e->ipv6.invflags & IP6T_INV_TOS ? "! " : "",
183 e->ipv6.tos);
184
185 /* Print matchinfo part */
186 if (e->target_offset) {
187 IP6T_MATCH_ITERATE(e, print_match, &e->ipv6);
188 }
189
190 /* Print target name */
Harald Welteace8a012001-07-05 06:29:10 +0000191 target_name = ip6tc_get_target(e, h);
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000192 if (target_name && (*target_name != '\0'))
193 printf("-j %s ", target_name);
András Kis-Szabó2f523792001-02-27 09:59:48 +0000194
195 /* Print targinfo part */
196 t = ip6t_get_target((struct ip6t_entry *)e);
197 if (t->u.user.name[0]) {
198 struct ip6tables_target *target
199 = find_target(t->u.user.name, TRY_LOAD);
200
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000201 if (!target) {
202 fprintf(stderr, "Can't find library for target `%s'\n",
203 t->u.user.name);
204 exit(1);
205 }
206
207 if (target->save)
András Kis-Szabó2f523792001-02-27 09:59:48 +0000208 target->save(&e->ipv6, t);
209 else {
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000210 /* If the target size is greater than ip6t_entry_target
211 * there is something to be saved, we just don't know
212 * how to print it */
213 if (t->u.target_size !=
214 sizeof(struct ip6t_entry_target)) {
215 fprintf(stderr, "Target `%s' is missing "
216 "save function\n",
András Kis-Szabó2f523792001-02-27 09:59:48 +0000217 t->u.user.name);
218 exit(1);
219 }
220 }
221 }
222 printf("\n");
223}
224
225/* Debugging prototype. */
226static int for_each_table(int (*func)(const char *tablename))
227{
228 int ret = 1;
229 FILE *procfile = NULL;
230 char tablename[IP6T_TABLE_MAXNAMELEN+1];
231
232 procfile = fopen("/proc/net/ip6_tables_names", "r");
233 if (!procfile)
234 return 0;
235
236 while (fgets(tablename, sizeof(tablename), procfile)) {
237 if (tablename[strlen(tablename) - 1] != '\n')
238 exit_error(OTHER_PROBLEM,
239 "Badly formed tablename `%s'\n",
240 tablename);
241 tablename[strlen(tablename) - 1] = '\0';
242 ret &= func(tablename);
243 }
244
245 return ret;
246}
247
248
249static int do_output(const char *tablename)
250{
251 ip6tc_handle_t h;
252 const char *chain = NULL;
253
254 if (!tablename)
255 return for_each_table(&do_output);
256
257 h = ip6tc_init(tablename);
258 if (!h)
259 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
260 ip6tc_strerror(errno));
261
262 if (!binary) {
263 time_t now = time(NULL);
264
265 printf("# Generated by ip6tables-save v%s on %s",
Harald Welte80fe35d2002-05-29 13:08:15 +0000266 IPTABLES_VERSION, ctime(&now));
András Kis-Szabó2f523792001-02-27 09:59:48 +0000267 printf("*%s\n", tablename);
268
Harald Welte885c6eb2001-10-04 08:30:46 +0000269 /* Dump out chain names first,
270 * thereby preventing dependency conflicts */
András Kis-Szabó2f523792001-02-27 09:59:48 +0000271 for (chain = ip6tc_first_chain(&h);
272 chain;
273 chain = ip6tc_next_chain(&h)) {
András Kis-Szabó2f523792001-02-27 09:59:48 +0000274
275 printf(":%s ", chain);
276 if (ip6tc_builtin(chain, h)) {
277 struct ip6t_counters count;
278 printf("%s ",
279 ip6tc_get_policy(chain, &count, &h));
280 printf("[%llu:%llu]\n", count.pcnt, count.bcnt);
281 } else {
282 printf("- [0:0]\n");
283 }
Harald Welte885c6eb2001-10-04 08:30:46 +0000284 }
285
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000286
Harald Welte885c6eb2001-10-04 08:30:46 +0000287 for (chain = ip6tc_first_chain(&h);
288 chain;
289 chain = ip6tc_next_chain(&h)) {
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000290 const struct ip6t_entry *e;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000291
292 /* Dump out rules */
293 e = ip6tc_first_rule(chain, &h);
294 while(e) {
Harald Welte885c6eb2001-10-04 08:30:46 +0000295 print_rule(e, &h, chain, counters);
András Kis-Szabó2f523792001-02-27 09:59:48 +0000296 e = ip6tc_next_rule(e, &h);
297 }
298 }
299
300 now = time(NULL);
301 printf("COMMIT\n");
302 printf("# Completed on %s", ctime(&now));
303 } else {
304 /* Binary, huh? OK. */
305 exit_error(OTHER_PROBLEM, "Binary NYI\n");
306 }
307
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000308 ip6tc_free(&h);
309
András Kis-Szabó2f523792001-02-27 09:59:48 +0000310 return 1;
311}
312
313/* Format:
314 * :Chain name POLICY packets bytes
315 * rule
316 */
317int main(int argc, char *argv[])
318{
319 const char *tablename = NULL;
320 int c;
321
322 program_name = "ip6tables-save";
Harald Welte80fe35d2002-05-29 13:08:15 +0000323 program_version = IPTABLES_VERSION;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000324
Harald Welte3efb6ea2001-08-06 18:50:21 +0000325#ifdef NO_SHARED_LIBS
326 init_extensions();
327#endif
328
András Kis-Szabó97fd91a2002-03-03 09:44:31 +0000329 while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
András Kis-Szabó2f523792001-02-27 09:59:48 +0000330 switch (c) {
331 case 'b':
332 binary = 1;
333 break;
334
335 case 'c':
336 counters = 1;
337 break;
338
339 case 't':
340 /* Select specific table. */
341 tablename = optarg;
342 break;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000343 case 'd':
344 do_output(tablename);
345 exit(0);
346 }
347 }
348
349 if (optind < argc) {
350 fprintf(stderr, "Unknown arguments found on commandline");
351 exit(1);
352 }
353
354 return !do_output(tablename);
355}