1 /* 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 * This code is distributed under the terms of GNU GPL v2
17 #include <arpa/inet.h>
18 #include "libiptc/libip6tc.h"
19 #include "ip6tables.h"
21 static int binary
= 0, counters
= 0;
23 static struct option options
[] = {
24 { "binary", 0, 0, 'b' },
25 { "counters", 0, 0, 'c' },
26 { "dump", 0, 0, 'd' },
27 { "table", 1, 0, 't' },
32 /* This assumes that mask is contiguous, and byte-bounded. */
34 print_iface(char letter
, const char *iface
, const unsigned char *mask
,
42 printf("-%c %s", letter
, invert
? "! " : "");
44 for (i
= 0; i
< IFNAMSIZ
; i
++) {
47 printf("%c", iface
[i
]);
49 /* 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')
60 /* These are hardcoded backups in ip6tables.c, so they are safe */
66 static const struct pprot chain_protos
[] = {
67 { "tcp", IPPROTO_TCP
},
68 { "udp", IPPROTO_UDP
},
69 { "icmpv6", IPPROTO_ICMPV6
},
70 { "esp", IPPROTO_ESP
},
74 /* The ip6tables looks up the /etc/protocols. */
75 static void print_proto(u_int16_t proto
, int invert
)
79 const char *invertstr
= invert
? "! " : "";
81 struct protoent
*pent
= getprotobynumber(proto
);
84 invertstr
, pent
->p_name
);
88 for (i
= 0; i
< sizeof(chain_protos
)/sizeof(struct pprot
); i
++)
89 if (chain_protos
[i
].num
== proto
) {
91 invertstr
, chain_protos
[i
].name
);
95 printf("-p %s%u ", invertstr
, proto
);
99 static int print_match(const struct ip6t_entry_match
*e
,
100 const struct ip6t_ip6
*ip
)
102 struct ip6tables_match
*match
103 = find_match(e
->u
.user
.name
, TRY_LOAD
, NULL
);
106 printf("-m %s ", e
->u
.user
.name
);
108 /* some matches don't provide a save function */
112 if (e
->u
.match_size
) {
114 "Can't find library for match `%s'\n",
122 /* print a given ip including mask if neccessary */
123 static void print_ip(char *prefix
, const struct in6_addr
*ip
, const struct in6_addr
*mask
, int invert
)
126 int l
= ipv6_prefix_length(mask
);
128 if (l
== 0 && !invert
)
134 inet_ntop(AF_INET6
, ip
, buf
, sizeof buf
));
137 printf("/%s ", inet_ntop(AF_INET6
, mask
, buf
, sizeof buf
));
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. */
144 static void print_rule(const struct ip6t_entry
*e
,
145 ip6tc_handle_t
*h
, const char *chain
, int counters
)
147 struct ip6t_entry_target
*t
;
148 const char *target_name
;
152 printf("[%llu:%llu] ", (unsigned long long)e
->counters
.pcnt
, (unsigned long long)e
->counters
.bcnt
);
154 /* print chain name */
155 printf("-A %s ", chain
);
158 print_ip("-s", &(e
->ipv6
.src
), &(e
->ipv6
.smsk
),
159 e
->ipv6
.invflags
& IP6T_INV_SRCIP
);
161 print_ip("-d", &(e
->ipv6
.dst
), &(e
->ipv6
.dmsk
),
162 e
->ipv6
.invflags
& IP6T_INV_DSTIP
);
164 print_iface('i', e
->ipv6
.iniface
, e
->ipv6
.iniface_mask
,
165 e
->ipv6
.invflags
& IP6T_INV_VIA_IN
);
167 print_iface('o', e
->ipv6
.outiface
, e
->ipv6
.outiface_mask
,
168 e
->ipv6
.invflags
& IP6T_INV_VIA_OUT
);
170 print_proto(e
->ipv6
.proto
, e
->ipv6
.invflags
& IP6T_INV_PROTO
);
173 /* not definied in ipv6
174 * FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? */
175 if (e
->ipv6
.flags
& IPT_F_FRAG
)
177 e
->ipv6
.invflags
& IP6T_INV_FRAG
? "! " : "");
180 if (e
->ipv6
.flags
& IP6T_F_TOS
)
182 e
->ipv6
.invflags
& IP6T_INV_TOS
? "! " : "",
185 /* Print matchinfo part */
186 if (e
->target_offset
) {
187 IP6T_MATCH_ITERATE(e
, print_match
, &e
->ipv6
);
190 /* Print target name */
191 target_name
= ip6tc_get_target(e
, h
);
192 if (target_name
&& (*target_name
!= '\0'))
194 printf("-%c %s ", e
->ipv6
.flags
& IP6T_F_GOTO
? 'g' : 'j', target_name
);
196 printf("-j %s ", target_name
);
199 /* Print targinfo part */
200 t
= ip6t_get_target((struct ip6t_entry
*)e
);
201 if (t
->u
.user
.name
[0]) {
202 struct ip6tables_target
*target
203 = find_target(t
->u
.user
.name
, TRY_LOAD
);
206 fprintf(stderr
, "Can't find library for target `%s'\n",
212 target
->save(&e
->ipv6
, t
);
214 /* If the target size is greater than ip6t_entry_target
215 * there is something to be saved, we just don't know
217 if (t
->u
.target_size
!=
218 sizeof(struct ip6t_entry_target
)) {
219 fprintf(stderr
, "Target `%s' is missing "
229 /* Debugging prototype. */
230 static int for_each_table(int (*func
)(const char *tablename
))
233 FILE *procfile
= NULL
;
234 char tablename
[IP6T_TABLE_MAXNAMELEN
+1];
236 procfile
= fopen("/proc/net/ip6_tables_names", "r");
240 while (fgets(tablename
, sizeof(tablename
), procfile
)) {
241 if (tablename
[strlen(tablename
) - 1] != '\n')
242 exit_error(OTHER_PROBLEM
,
243 "Badly formed tablename `%s'\n",
245 tablename
[strlen(tablename
) - 1] = '\0';
246 ret
&= func(tablename
);
253 static int do_output(const char *tablename
)
256 const char *chain
= NULL
;
259 return for_each_table(&do_output
);
261 h
= ip6tc_init(tablename
);
263 exit_error(OTHER_PROBLEM
, "Can't initialize: %s\n",
264 ip6tc_strerror(errno
));
267 time_t now
= time(NULL
);
269 printf("# Generated by ip6tables-save v%s on %s",
270 IPTABLES_VERSION
, ctime(&now
));
271 printf("*%s\n", tablename
);
273 /* Dump out chain names first,
274 * thereby preventing dependency conflicts */
275 for (chain
= ip6tc_first_chain(&h
);
277 chain
= ip6tc_next_chain(&h
)) {
279 printf(":%s ", chain
);
280 if (ip6tc_builtin(chain
, h
)) {
281 struct ip6t_counters count
;
283 ip6tc_get_policy(chain
, &count
, &h
));
284 printf("[%llu:%llu]\n", (unsigned long long)count
.pcnt
, (unsigned long long)count
.bcnt
);
291 for (chain
= ip6tc_first_chain(&h
);
293 chain
= ip6tc_next_chain(&h
)) {
294 const struct ip6t_entry
*e
;
297 e
= ip6tc_first_rule(chain
, &h
);
299 print_rule(e
, &h
, chain
, counters
);
300 e
= ip6tc_next_rule(e
, &h
);
306 printf("# Completed on %s", ctime(&now
));
308 /* Binary, huh? OK. */
309 exit_error(OTHER_PROBLEM
, "Binary NYI\n");
318 * :Chain name POLICY packets bytes
321 #ifdef IPTABLES_MULTI
322 int ip6tables_save_main(int argc
, char *argv
[])
324 int main(int argc
, char *argv
[])
327 const char *tablename
= NULL
;
330 program_name
= "ip6tables-save";
331 program_version
= IPTABLES_VERSION
;
333 lib_dir
= getenv("IP6TABLES_LIB_DIR");
335 lib_dir
= IP6T_LIB_DIR
;
337 #ifdef NO_SHARED_LIBS
341 while ((c
= getopt_long(argc
, argv
, "bcdt:", options
, NULL
)) != -1) {
352 /* Select specific table. */
356 do_output(tablename
);
362 fprintf(stderr
, "Unknown arguments found on commandline\n");
366 return !do_output(tablename
);