• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7  */
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 
21 static int binary = 0, counters = 0;
22 
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' },
28 	{ 0 }
29 };
30 
31 
32 /* This assumes that mask is contiguous, and byte-bounded. */
33 static void
print_iface(char letter,const char * iface,const unsigned char * mask,int invert)34 print_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 {
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')
52 				printf("+");
53 			break;
54 		}
55 	}
56 
57 	printf(" ");
58 }
59 
60 /* These are hardcoded backups in ip6tables.c, so they are safe */
61 struct pprot {
62 	char *name;
63 	u_int8_t num;
64 };
65 
66 static const struct pprot chain_protos[] = {
67 	{ "tcp", IPPROTO_TCP },
68 	{ "udp", IPPROTO_UDP },
69 	{ "icmpv6", IPPROTO_ICMPV6 },
70 	{ "esp", IPPROTO_ESP },
71 	{ "ah", IPPROTO_AH },
72 };
73 
74 /* The ip6tables looks up the /etc/protocols. */
print_proto(u_int16_t proto,int invert)75 static 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 
print_match(const struct ip6t_entry_match * e,const struct ip6t_ip6 * ip)99 static 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, NULL);
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 */
print_ip(char * prefix,const struct in6_addr * ip,const struct in6_addr * mask,int invert)123 static 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 (l == 0 && !invert)
129 		return;
130 
131 	printf("%s %s%s",
132 		prefix,
133 		invert ? "! " : "",
134 		inet_ntop(AF_INET6, ip, buf, sizeof buf));
135 
136 	if (l == -1)
137 		printf("/%s ", inet_ntop(AF_INET6, mask, buf, sizeof buf));
138 	else
139 		printf("/%d ", l);
140 }
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.  */
print_rule(const struct ip6t_entry * e,ip6tc_handle_t * h,const char * chain,int counters)144 static void print_rule(const struct ip6t_entry *e,
145 		ip6tc_handle_t *h, const char *chain, int counters)
146 {
147 	struct ip6t_entry_target *t;
148 	const char *target_name;
149 
150 	/* print counters */
151 	if (counters)
152 		printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
153 
154 	/* print chain name */
155 	printf("-A %s ", chain);
156 
157 	/* 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
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)
176 		printf("%s-f ",
177 		       e->ipv6.invflags & IP6T_INV_FRAG ? "! " : "");
178 #endif
179 
180 	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 */
191 	target_name = ip6tc_get_target(e, h);
192 	if (target_name && (*target_name != '\0'))
193 		printf("-j %s ", target_name);
194 
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 
201 		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)
208 			target->save(&e->ipv6, t);
209 		else {
210 			/* 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",
217 					t->u.user.name);
218 				exit(1);
219 			}
220 		}
221 	}
222 	printf("\n");
223 }
224 
225 /* Debugging prototype. */
for_each_table(int (* func)(const char * tablename))226 static 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 
do_output(const char * tablename)249 static 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",
266 		       IPTABLES_VERSION, ctime(&now));
267 		printf("*%s\n", tablename);
268 
269 		/* Dump out chain names first,
270 		 * thereby preventing dependency conflicts */
271 		for (chain = ip6tc_first_chain(&h);
272 		     chain;
273 		     chain = ip6tc_next_chain(&h)) {
274 
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", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
281 			} else {
282 				printf("- [0:0]\n");
283 			}
284 		}
285 
286 
287 		for (chain = ip6tc_first_chain(&h);
288 		     chain;
289 		     chain = ip6tc_next_chain(&h)) {
290 			const struct ip6t_entry *e;
291 
292 			/* Dump out rules */
293 			e = ip6tc_first_rule(chain, &h);
294 			while(e) {
295 				print_rule(e, &h, chain, counters);
296 				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 
308 	ip6tc_free(&h);
309 
310 	return 1;
311 }
312 
313 /* Format:
314  * :Chain name POLICY packets bytes
315  * rule
316  */
main(int argc,char * argv[])317 int main(int argc, char *argv[])
318 {
319 	const char *tablename = NULL;
320 	int c;
321 
322 	program_name = "ip6tables-save";
323 	program_version = IPTABLES_VERSION;
324 
325 	lib_dir = getenv("IP6TABLES_LIB_DIR");
326 	if (!lib_dir)
327 		lib_dir = IP6T_LIB_DIR;
328 
329 #ifdef NO_SHARED_LIBS
330 	init_extensions();
331 #endif
332 
333 	while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
334 		switch (c) {
335 		case 'b':
336 			binary = 1;
337 			break;
338 
339 		case 'c':
340 			counters = 1;
341 			break;
342 
343 		case 't':
344 			/* Select specific table. */
345 			tablename = optarg;
346 			break;
347 		case 'd':
348 			do_output(tablename);
349 			exit(0);
350 		}
351 	}
352 
353 	if (optind < argc) {
354 		fprintf(stderr, "Unknown arguments found on commandline");
355 		exit(1);
356 	}
357 
358 	return !do_output(tablename);
359 }
360