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'))
193 printf("-j %s ", target_name);
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);
202 fprintf(stderr, "Can't find library for target `%s'\n",
208 target->save(&e->ipv6, t);
210 /* If the target size is greater than ip6t_entry_target
211 * there is something to be saved, we just don't know
213 if (t->u.target_size !=
214 sizeof(struct ip6t_entry_target)) {
215 fprintf(stderr, "Target `%s' is missing "
225 /* Debugging prototype. */
226 static int for_each_table(int (*func)(const char *tablename))
229 FILE *procfile = NULL;
230 char tablename[IP6T_TABLE_MAXNAMELEN+1];
232 procfile = fopen("/proc/net/ip6_tables_names", "r");
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",
241 tablename[strlen(tablename) - 1] = '\0';
242 ret &= func(tablename);
249 static int do_output(const char *tablename)
252 const char *chain = NULL;
255 return for_each_table(&do_output);
257 h = ip6tc_init(tablename);
259 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
260 ip6tc_strerror(errno));
263 time_t now = time(NULL);
265 printf("# Generated by ip6tables-save v%s on %s",
266 IPTABLES_VERSION, ctime(&now));
267 printf("*%s\n", tablename);
269 /* Dump out chain names first,
270 * thereby preventing dependency conflicts */
271 for (chain = ip6tc_first_chain(&h);
273 chain = ip6tc_next_chain(&h)) {
275 printf(":%s ", chain);
276 if (ip6tc_builtin(chain, h)) {
277 struct ip6t_counters count;
279 ip6tc_get_policy(chain, &count, &h));
280 printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
287 for (chain = ip6tc_first_chain(&h);
289 chain = ip6tc_next_chain(&h)) {
290 const struct ip6t_entry *e;
293 e = ip6tc_first_rule(chain, &h);
295 print_rule(e, &h, chain, counters);
296 e = ip6tc_next_rule(e, &h);
302 printf("# Completed on %s", ctime(&now));
304 /* Binary, huh? OK. */
305 exit_error(OTHER_PROBLEM, "Binary NYI\n");
314 * :Chain name POLICY packets bytes
317 int main(int argc, char *argv[])
319 const char *tablename = NULL;
322 program_name = "ip6tables-save";
323 program_version = IPTABLES_VERSION;
325 lib_dir = getenv("IP6TABLES_LIB_DIR");
327 lib_dir = IP6T_LIB_DIR;
329 #ifdef NO_SHARED_LIBS
333 while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
344 /* Select specific table. */
348 do_output(tablename);
354 fprintf(stderr, "Unknown arguments found on commandline\n");
358 return !do_output(tablename);