• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Code to take an ip6tables-style command line and do it. */
2 
3 /*
4  * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
5  *
6  * (C) 2000-2002 by the netfilter coreteam <coreteam@netfilter.org>:
7  * 		    Paul 'Rusty' Russell <rusty@rustcorp.com.au>
8  * 		    Marc Boucher <marc+nf@mbsi.ca>
9  * 		    James Morris <jmorris@intercode.com.au>
10  * 		    Harald Welte <laforge@gnumonks.org>
11  * 		    Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
12  *
13  *	This program is free software; you can redistribute it and/or modify
14  *	it under the terms of the GNU General Public License as published by
15  *	the Free Software Foundation; either version 2 of the License, or
16  *	(at your option) any later version.
17  *
18  *	This program is distributed in the hope that it will be useful,
19  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *	GNU General Public License for more details.
22  *
23  *	You should have received a copy of the GNU General Public License
24  *	along with this program; if not, write to the Free Software
25  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  */
27 #include "config.h"
28 #include <getopt.h>
29 #include <string.h>
30 #include <netdb.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <stdbool.h>
37 #include <limits.h>
38 #include <ip6tables.h>
39 #include <xtables.h>
40 #include <arpa/inet.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include "ip6tables-multi.h"
46 #include "xshared.h"
47 
48 static const char unsupported_rev[] = " [unsupported revision]";
49 
50 static struct option original_opts[] = {
51 	{.name = "append",        .has_arg = 1, .val = 'A'},
52 	{.name = "delete",        .has_arg = 1, .val = 'D'},
53 	{.name = "check" ,        .has_arg = 1, .val = 'C'},
54 	{.name = "insert",        .has_arg = 1, .val = 'I'},
55 	{.name = "replace",       .has_arg = 1, .val = 'R'},
56 	{.name = "list",          .has_arg = 2, .val = 'L'},
57 	{.name = "list-rules",    .has_arg = 2, .val = 'S'},
58 	{.name = "flush",         .has_arg = 2, .val = 'F'},
59 	{.name = "zero",          .has_arg = 2, .val = 'Z'},
60 	{.name = "new-chain",     .has_arg = 1, .val = 'N'},
61 	{.name = "delete-chain",  .has_arg = 2, .val = 'X'},
62 	{.name = "rename-chain",  .has_arg = 1, .val = 'E'},
63 	{.name = "policy",        .has_arg = 1, .val = 'P'},
64 	{.name = "source",        .has_arg = 1, .val = 's'},
65 	{.name = "destination",   .has_arg = 1, .val = 'd'},
66 	{.name = "src",           .has_arg = 1, .val = 's'}, /* synonym */
67 	{.name = "dst",           .has_arg = 1, .val = 'd'}, /* synonym */
68 	{.name = "protocol",      .has_arg = 1, .val = 'p'},
69 	{.name = "in-interface",  .has_arg = 1, .val = 'i'},
70 	{.name = "jump",          .has_arg = 1, .val = 'j'},
71 	{.name = "table",         .has_arg = 1, .val = 't'},
72 	{.name = "match",         .has_arg = 1, .val = 'm'},
73 	{.name = "numeric",       .has_arg = 0, .val = 'n'},
74 	{.name = "out-interface", .has_arg = 1, .val = 'o'},
75 	{.name = "verbose",       .has_arg = 0, .val = 'v'},
76 	{.name = "wait",          .has_arg = 2, .val = 'w'},
77 	{.name = "wait-interval", .has_arg = 2, .val = 'W'},
78 	{.name = "exact",         .has_arg = 0, .val = 'x'},
79 	{.name = "version",       .has_arg = 0, .val = 'V'},
80 	{.name = "help",          .has_arg = 2, .val = 'h'},
81 	{.name = "line-numbers",  .has_arg = 0, .val = '0'},
82 	{.name = "modprobe",      .has_arg = 1, .val = 'M'},
83 	{.name = "set-counters",  .has_arg = 1, .val = 'c'},
84 	{.name = "goto",          .has_arg = 1, .val = 'g'},
85 	{.name = "ipv4",          .has_arg = 0, .val = '4'},
86 	{.name = "ipv6",          .has_arg = 0, .val = '6'},
87 	{NULL},
88 };
89 
90 struct xtables_globals ip6tables_globals = {
91 	.option_offset = 0,
92 	.program_version = PACKAGE_VERSION " (legacy)",
93 	.orig_opts = original_opts,
94 	.compat_rev = xtables_compatible_revision,
95 };
96 
97 /*
98  *	All functions starting with "parse" should succeed, otherwise
99  *	the program fails.
100  *	Most routines return pointers to static data that may change
101  *	between calls to the same or other routines with a few exceptions:
102  *	"host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
103  *	return global static data.
104 */
105 
106 static int
print_match(const struct xt_entry_match * m,const struct ip6t_ip6 * ip,int numeric)107 print_match(const struct xt_entry_match *m,
108 	    const struct ip6t_ip6 *ip,
109 	    int numeric)
110 {
111 	const char *name = m->u.user.name;
112 	const int revision = m->u.user.revision;
113 	struct xtables_match *match, *mt;
114 
115 	match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
116 	if (match) {
117 		mt = xtables_find_match_revision(name, XTF_TRY_LOAD,
118 						 match, revision);
119 		if (mt && mt->print)
120 			mt->print(ip, m, numeric);
121 		else if (match->print)
122 			printf("%s%s ", match->name, unsupported_rev);
123 		else
124 			printf("%s ", match->name);
125 
126 		if (match->next == match)
127 			free(match);
128 	} else {
129 		if (name[0])
130 			printf("UNKNOWN match `%s' ", name);
131 	}
132 	/* Don't stop iterating. */
133 	return 0;
134 }
135 
136 /* e is called `fw' here for historical reasons */
137 static void
print_firewall(const struct ip6t_entry * fw,const char * targname,unsigned int num,unsigned int format,struct xtc_handle * const handle)138 print_firewall(const struct ip6t_entry *fw,
139 	       const char *targname,
140 	       unsigned int num,
141 	       unsigned int format,
142 	       struct xtc_handle *const handle)
143 {
144 	struct xtables_target *target, *tg;
145 	const struct xt_entry_target *t;
146 
147 	if (!ip6tc_is_chain(targname, handle))
148 		target = xtables_find_target(targname, XTF_TRY_LOAD);
149 	else
150 		target = xtables_find_target(XT_STANDARD_TARGET,
151 		         XTF_LOAD_MUST_SUCCEED);
152 
153 	t = ip6t_get_target((struct ip6t_entry *)fw);
154 
155 	print_rule_details(num, &fw->counters, targname, fw->ipv6.proto,
156 			   fw->ipv6.flags, fw->ipv6.invflags, format);
157 
158 	print_fragment(fw->ipv6.flags, fw->ipv6.invflags, format, true);
159 
160 	print_ifaces(fw->ipv6.iniface, fw->ipv6.outiface,
161 		     fw->ipv6.invflags, format);
162 
163 	print_ipv6_addresses(fw, format);
164 
165 	if (format & FMT_NOTABLE)
166 		fputs("  ", stdout);
167 
168 #ifdef IP6T_F_GOTO
169 	if(fw->ipv6.flags & IP6T_F_GOTO)
170 		printf("[goto] ");
171 #endif
172 
173 	IP6T_MATCH_ITERATE(fw, print_match, &fw->ipv6, format & FMT_NUMERIC);
174 
175 	if (target) {
176 		const int revision = t->u.user.revision;
177 
178 		tg = xtables_find_target_revision(targname, XTF_TRY_LOAD,
179 						  target, revision);
180 		if (tg && tg->print)
181 			/* Print the target information. */
182 			tg->print(&fw->ipv6, t, format & FMT_NUMERIC);
183 		else if (target->print)
184 			printf(" %s%s", target->name, unsupported_rev);
185 
186 		if (target->next == target)
187 			free(target);
188 	} else if (t->u.target_size != sizeof(*t))
189 		printf("[%u bytes of unknown target data] ",
190 		       (unsigned int)(t->u.target_size - sizeof(*t)));
191 
192 	if (!(format & FMT_NONEWLINE))
193 		fputc('\n', stdout);
194 }
195 
196 static void
print_firewall_line(const struct ip6t_entry * fw,struct xtc_handle * const h)197 print_firewall_line(const struct ip6t_entry *fw,
198 		    struct xtc_handle *const h)
199 {
200 	struct xt_entry_target *t;
201 
202 	t = ip6t_get_target((struct ip6t_entry *)fw);
203 	print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h);
204 }
205 
206 static int
append_entry(const xt_chainlabel chain,struct ip6t_entry * fw,unsigned int nsaddrs,const struct in6_addr saddrs[],const struct in6_addr smasks[],unsigned int ndaddrs,const struct in6_addr daddrs[],const struct in6_addr dmasks[],int verbose,struct xtc_handle * handle)207 append_entry(const xt_chainlabel chain,
208 	     struct ip6t_entry *fw,
209 	     unsigned int nsaddrs,
210 	     const struct in6_addr saddrs[],
211 	     const struct in6_addr smasks[],
212 	     unsigned int ndaddrs,
213 	     const struct in6_addr daddrs[],
214 	     const struct in6_addr dmasks[],
215 	     int verbose,
216 	     struct xtc_handle *handle)
217 {
218 	unsigned int i, j;
219 	int ret = 1;
220 
221 	for (i = 0; i < nsaddrs; i++) {
222 		fw->ipv6.src = saddrs[i];
223 		fw->ipv6.smsk = smasks[i];
224 		for (j = 0; j < ndaddrs; j++) {
225 			fw->ipv6.dst = daddrs[j];
226 			fw->ipv6.dmsk = dmasks[j];
227 			if (verbose)
228 				print_firewall_line(fw, handle);
229 			ret &= ip6tc_append_entry(chain, fw, handle);
230 		}
231 	}
232 
233 	return ret;
234 }
235 
236 static int
replace_entry(const xt_chainlabel chain,struct ip6t_entry * fw,unsigned int rulenum,const struct in6_addr * saddr,const struct in6_addr * smask,const struct in6_addr * daddr,const struct in6_addr * dmask,int verbose,struct xtc_handle * handle)237 replace_entry(const xt_chainlabel chain,
238 	      struct ip6t_entry *fw,
239 	      unsigned int rulenum,
240 	      const struct in6_addr *saddr, const struct in6_addr *smask,
241 	      const struct in6_addr *daddr, const struct in6_addr *dmask,
242 	      int verbose,
243 	      struct xtc_handle *handle)
244 {
245 	fw->ipv6.src = *saddr;
246 	fw->ipv6.dst = *daddr;
247 	fw->ipv6.smsk = *smask;
248 	fw->ipv6.dmsk = *dmask;
249 
250 	if (verbose)
251 		print_firewall_line(fw, handle);
252 	return ip6tc_replace_entry(chain, fw, rulenum, handle);
253 }
254 
255 static int
insert_entry(const xt_chainlabel chain,struct ip6t_entry * fw,unsigned int rulenum,unsigned int nsaddrs,const struct in6_addr saddrs[],const struct in6_addr smasks[],unsigned int ndaddrs,const struct in6_addr daddrs[],const struct in6_addr dmasks[],int verbose,struct xtc_handle * handle)256 insert_entry(const xt_chainlabel chain,
257 	     struct ip6t_entry *fw,
258 	     unsigned int rulenum,
259 	     unsigned int nsaddrs,
260 	     const struct in6_addr saddrs[],
261 	     const struct in6_addr smasks[],
262 	     unsigned int ndaddrs,
263 	     const struct in6_addr daddrs[],
264 	     const struct in6_addr dmasks[],
265 	     int verbose,
266 	     struct xtc_handle *handle)
267 {
268 	unsigned int i, j;
269 	int ret = 1;
270 
271 	for (i = 0; i < nsaddrs; i++) {
272 		fw->ipv6.src = saddrs[i];
273 		fw->ipv6.smsk = smasks[i];
274 		for (j = 0; j < ndaddrs; j++) {
275 			fw->ipv6.dst = daddrs[j];
276 			fw->ipv6.dmsk = dmasks[j];
277 			if (verbose)
278 				print_firewall_line(fw, handle);
279 			ret &= ip6tc_insert_entry(chain, fw, rulenum, handle);
280 		}
281 	}
282 
283 	return ret;
284 }
285 
286 static int
delete_entry(const xt_chainlabel chain,struct ip6t_entry * fw,unsigned int nsaddrs,const struct in6_addr saddrs[],const struct in6_addr smasks[],unsigned int ndaddrs,const struct in6_addr daddrs[],const struct in6_addr dmasks[],int verbose,struct xtc_handle * handle,struct xtables_rule_match * matches,const struct xtables_target * target)287 delete_entry(const xt_chainlabel chain,
288 	     struct ip6t_entry *fw,
289 	     unsigned int nsaddrs,
290 	     const struct in6_addr saddrs[],
291 	     const struct in6_addr smasks[],
292 	     unsigned int ndaddrs,
293 	     const struct in6_addr daddrs[],
294 	     const struct in6_addr dmasks[],
295 	     int verbose,
296 	     struct xtc_handle *handle,
297 	     struct xtables_rule_match *matches,
298 	     const struct xtables_target *target)
299 {
300 	unsigned int i, j;
301 	int ret = 1;
302 	unsigned char *mask;
303 
304 	mask = make_delete_mask(matches, target, sizeof(*fw));
305 	for (i = 0; i < nsaddrs; i++) {
306 		fw->ipv6.src = saddrs[i];
307 		fw->ipv6.smsk = smasks[i];
308 		for (j = 0; j < ndaddrs; j++) {
309 			fw->ipv6.dst = daddrs[j];
310 			fw->ipv6.dmsk = dmasks[j];
311 			if (verbose)
312 				print_firewall_line(fw, handle);
313 			ret &= ip6tc_delete_entry(chain, fw, mask, handle);
314 		}
315 	}
316 	free(mask);
317 
318 	return ret;
319 }
320 
321 static int
check_entry(const xt_chainlabel chain,struct ip6t_entry * fw,unsigned int nsaddrs,const struct in6_addr * saddrs,const struct in6_addr * smasks,unsigned int ndaddrs,const struct in6_addr * daddrs,const struct in6_addr * dmasks,bool verbose,struct xtc_handle * handle,struct xtables_rule_match * matches,const struct xtables_target * target)322 check_entry(const xt_chainlabel chain, struct ip6t_entry *fw,
323 	    unsigned int nsaddrs, const struct in6_addr *saddrs,
324 	    const struct in6_addr *smasks, unsigned int ndaddrs,
325 	    const struct in6_addr *daddrs, const struct in6_addr *dmasks,
326 	    bool verbose, struct xtc_handle *handle,
327 	    struct xtables_rule_match *matches,
328 	    const struct xtables_target *target)
329 {
330 	unsigned int i, j;
331 	int ret = 1;
332 	unsigned char *mask;
333 
334 	mask = make_delete_mask(matches, target, sizeof(*fw));
335 	for (i = 0; i < nsaddrs; i++) {
336 		fw->ipv6.src = saddrs[i];
337 		fw->ipv6.smsk = smasks[i];
338 		for (j = 0; j < ndaddrs; j++) {
339 			fw->ipv6.dst = daddrs[j];
340 			fw->ipv6.dmsk = dmasks[j];
341 			if (verbose)
342 				print_firewall_line(fw, handle);
343 			ret &= ip6tc_check_entry(chain, fw, mask, handle);
344 		}
345 	}
346 
347 	free(mask);
348 	return ret;
349 }
350 
351 int
for_each_chain6(int (* fn)(const xt_chainlabel,int,struct xtc_handle *),int verbose,int builtinstoo,struct xtc_handle * handle)352 for_each_chain6(int (*fn)(const xt_chainlabel, int, struct xtc_handle *),
353 	       int verbose, int builtinstoo, struct xtc_handle *handle)
354 {
355 	int ret = 1;
356 	const char *chain;
357 	char *chains;
358 	unsigned int i, chaincount = 0;
359 
360 	chain = ip6tc_first_chain(handle);
361 	while (chain) {
362 		chaincount++;
363 		chain = ip6tc_next_chain(handle);
364 	}
365 
366 	chains = xtables_malloc(sizeof(xt_chainlabel) * chaincount);
367 	i = 0;
368 	chain = ip6tc_first_chain(handle);
369 	while (chain) {
370 		strcpy(chains + i*sizeof(xt_chainlabel), chain);
371 		i++;
372 		chain = ip6tc_next_chain(handle);
373 	}
374 
375 	for (i = 0; i < chaincount; i++) {
376 		if (!builtinstoo
377 		    && ip6tc_builtin(chains + i*sizeof(xt_chainlabel),
378 				    handle) == 1)
379 			continue;
380 		ret &= fn(chains + i*sizeof(xt_chainlabel), verbose, handle);
381 	}
382 
383 	free(chains);
384 	return ret;
385 }
386 
387 int
flush_entries6(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)388 flush_entries6(const xt_chainlabel chain, int verbose,
389 	      struct xtc_handle *handle)
390 {
391 	if (!chain)
392 		return for_each_chain6(flush_entries6, verbose, 1, handle);
393 
394 	if (verbose)
395 		fprintf(stdout, "Flushing chain `%s'\n", chain);
396 	return ip6tc_flush_entries(chain, handle);
397 }
398 
399 static int
zero_entries(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)400 zero_entries(const xt_chainlabel chain, int verbose,
401 	     struct xtc_handle *handle)
402 {
403 	if (!chain)
404 		return for_each_chain6(zero_entries, verbose, 1, handle);
405 
406 	if (verbose)
407 		fprintf(stdout, "Zeroing chain `%s'\n", chain);
408 	return ip6tc_zero_entries(chain, handle);
409 }
410 
411 int
delete_chain6(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)412 delete_chain6(const xt_chainlabel chain, int verbose,
413 	     struct xtc_handle *handle)
414 {
415 	if (!chain)
416 		return for_each_chain6(delete_chain6, verbose, 0, handle);
417 
418 	if (verbose)
419 		fprintf(stdout, "Deleting chain `%s'\n", chain);
420 	return ip6tc_delete_chain(chain, handle);
421 }
422 
423 static int
list_entries(const xt_chainlabel chain,int rulenum,int verbose,int numeric,int expanded,int linenumbers,struct xtc_handle * handle)424 list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
425 	     int expanded, int linenumbers, struct xtc_handle *handle)
426 {
427 	int found = 0;
428 	unsigned int format;
429 	const char *this;
430 
431 	format = FMT_OPTIONS;
432 	if (!verbose)
433 		format |= FMT_NOCOUNTS;
434 	else
435 		format |= FMT_VIA;
436 
437 	if (numeric)
438 		format |= FMT_NUMERIC;
439 
440 	if (!expanded)
441 		format |= FMT_KILOMEGAGIGA;
442 
443 	if (linenumbers)
444 		format |= FMT_LINENUMBERS;
445 
446 	for (this = ip6tc_first_chain(handle);
447 	     this;
448 	     this = ip6tc_next_chain(handle)) {
449 		const struct ip6t_entry *i;
450 		unsigned int num;
451 
452 		if (chain && strcmp(chain, this) != 0)
453 			continue;
454 
455 		if (found) printf("\n");
456 
457 		if (!rulenum) {
458 			struct xt_counters counters;
459 			unsigned int urefs;
460 			const char *pol;
461 			int refs = - 1;
462 
463 			pol = ip6tc_get_policy(this, &counters, handle);
464 			if (!pol && ip6tc_get_references(&urefs, this, handle))
465 				refs = urefs;
466 
467 			print_header(format, this, pol, &counters, refs, 0);
468 		}
469 		i = ip6tc_first_rule(this, handle);
470 
471 		num = 0;
472 		while (i) {
473 			num++;
474 			if (!rulenum || num == rulenum)
475 				print_firewall(i,
476 					       ip6tc_get_target(i, handle),
477 					       num,
478 					       format,
479 					       handle);
480 			i = ip6tc_next_rule(i, handle);
481 		}
482 		found = 1;
483 	}
484 
485 	errno = ENOENT;
486 	return found;
487 }
488 
489 /* We want this to be readable, so only print out necessary fields.
490  * Because that's the kind of world I want to live in.
491  */
print_rule6(const struct ip6t_entry * e,struct xtc_handle * h,const char * chain,int counters)492 void print_rule6(const struct ip6t_entry *e,
493 		       struct xtc_handle *h, const char *chain, int counters)
494 {
495 	const struct xt_entry_target *t;
496 	const char *target_name;
497 
498 	/* print counters for iptables-save */
499 	if (counters > 0)
500 		printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
501 
502 	/* print chain name */
503 	printf("-A %s", chain);
504 
505 	/* Print IP part. */
506 	save_ipv6_addr('s', &e->ipv6.src, &e->ipv6.smsk,
507 		       e->ipv6.invflags & IP6T_INV_SRCIP);
508 
509 	save_ipv6_addr('d', &e->ipv6.dst, &e->ipv6.dmsk,
510 		       e->ipv6.invflags & IP6T_INV_DSTIP);
511 
512 	save_rule_details(e->ipv6.iniface, e->ipv6.outiface,
513 			  e->ipv6.proto, 0, e->ipv6.invflags);
514 
515 #if 0
516 	/* not definied in ipv6
517 	 * FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? */
518 	if (e->ipv6.flags & IPT_F_FRAG)
519 		printf("%s -f",
520 		       e->ipv6.invflags & IP6T_INV_FRAG ? " !" : "");
521 #endif
522 
523 	if (e->ipv6.flags & IP6T_F_TOS)
524 		printf("%s -? %d",
525 		       e->ipv6.invflags & IP6T_INV_TOS ? " !" : "",
526 		       e->ipv6.tos);
527 
528 	/* Print matchinfo part */
529 	if (e->target_offset) {
530 		IP6T_MATCH_ITERATE(e, print_match_save, &e->ipv6);
531 	}
532 
533 	/* print counters for iptables -R */
534 	if (counters < 0)
535 		printf(" -c %llu %llu", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
536 
537 	/* Print target name and targinfo part */
538 	target_name = ip6tc_get_target(e, h);
539 	t = ip6t_get_target((struct ip6t_entry *)e);
540 	if (t->u.user.name[0]) {
541 		const char *name = t->u.user.name;
542 		const int revision = t->u.user.revision;
543 		struct xtables_target *target, *tg, *tg2;
544 
545 		target = xtables_find_target(name, XTF_TRY_LOAD);
546 		if (!target) {
547 			fprintf(stderr, "Can't find library for target `%s'\n",
548 				name);
549 			exit(1);
550 		}
551 
552 		tg = tg2 = xtables_find_target_revision(name, XTF_TRY_LOAD,
553 							target, revision);
554 		if (!tg2)
555 			tg2 = target;
556 		printf(" -j %s", tg2->alias ? tg2->alias(t) : target_name);
557 
558 		if (tg && tg->save)
559 			tg->save(&e->ipv6, t);
560 		else if (target->save)
561 			printf(unsupported_rev);
562 		else {
563 			/* If the target size is greater than xt_entry_target
564 			 * there is something to be saved, we just don't know
565 			 * how to print it */
566 			if (t->u.target_size !=
567 			    sizeof(struct xt_entry_target)) {
568 				fprintf(stderr, "Target `%s' is missing "
569 						"save function\n",
570 					name);
571 				exit(1);
572 			}
573 		}
574 	} else if (target_name && (*target_name != '\0'))
575 #ifdef IP6T_F_GOTO
576 		printf(" -%c %s", e->ipv6.flags & IP6T_F_GOTO ? 'g' : 'j', target_name);
577 #else
578 		printf(" -j %s", target_name);
579 #endif
580 
581 	printf("\n");
582 }
583 
584 static int
list_rules(const xt_chainlabel chain,int rulenum,int counters,struct xtc_handle * handle)585 list_rules(const xt_chainlabel chain, int rulenum, int counters,
586 	     struct xtc_handle *handle)
587 {
588 	const char *this = NULL;
589 	int found = 0;
590 
591 	if (counters)
592 	    counters = -1;		/* iptables -c format */
593 
594 	/* Dump out chain names first,
595 	 * thereby preventing dependency conflicts */
596 	if (!rulenum) for (this = ip6tc_first_chain(handle);
597 	     this;
598 	     this = ip6tc_next_chain(handle)) {
599 		if (chain && strcmp(this, chain) != 0)
600 			continue;
601 
602 		if (ip6tc_builtin(this, handle)) {
603 			struct xt_counters count;
604 			printf("-P %s %s", this, ip6tc_get_policy(this, &count, handle));
605 			if (counters)
606 			    printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
607 			printf("\n");
608 		} else {
609 			printf("-N %s\n", this);
610 		}
611 	}
612 
613 	for (this = ip6tc_first_chain(handle);
614 	     this;
615 	     this = ip6tc_next_chain(handle)) {
616 		const struct ip6t_entry *e;
617 		int num = 0;
618 
619 		if (chain && strcmp(this, chain) != 0)
620 			continue;
621 
622 		/* Dump out rules */
623 		e = ip6tc_first_rule(this, handle);
624 		while(e) {
625 			num++;
626 			if (!rulenum || num == rulenum)
627 			    print_rule6(e, handle, this, counters);
628 			e = ip6tc_next_rule(e, handle);
629 		}
630 		found = 1;
631 	}
632 
633 	errno = ENOENT;
634 	return found;
635 }
636 
637 static struct ip6t_entry *
generate_entry(const struct ip6t_entry * fw,struct xtables_rule_match * matches,struct xt_entry_target * target)638 generate_entry(const struct ip6t_entry *fw,
639 	       struct xtables_rule_match *matches,
640 	       struct xt_entry_target *target)
641 {
642 	unsigned int size;
643 	struct xtables_rule_match *matchp;
644 	struct ip6t_entry *e;
645 
646 	size = sizeof(struct ip6t_entry);
647 	for (matchp = matches; matchp; matchp = matchp->next)
648 		size += matchp->match->m->u.match_size;
649 
650 	e = xtables_malloc(size + target->u.target_size);
651 	*e = *fw;
652 	e->target_offset = size;
653 	e->next_offset = size + target->u.target_size;
654 
655 	size = 0;
656 	for (matchp = matches; matchp; matchp = matchp->next) {
657 		memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
658 		size += matchp->match->m->u.match_size;
659 	}
660 	memcpy(e->elems + size, target, target->u.target_size);
661 
662 	return e;
663 }
664 
do_command6(int argc,char * argv[],char ** table,struct xtc_handle ** handle,bool restore)665 int do_command6(int argc, char *argv[], char **table,
666 		struct xtc_handle **handle, bool restore)
667 {
668 	struct xt_cmd_parse_ops cmd_parse_ops = {
669 		.proto_parse	= ipv6_proto_parse,
670 		.post_parse	= ipv6_post_parse,
671 		.option_name	= ip46t_option_name,
672 		.option_invert	= ip46t_option_invert,
673 		.command_default = command_default,
674 		.print_help	= xtables_printhelp,
675 	};
676 	struct xt_cmd_parse p = {
677 		.table		= *table,
678 		.restore	= restore,
679 		.line		= line,
680 		.ops		= &cmd_parse_ops,
681 	};
682 	struct iptables_command_state cs = {
683 		.jumpto	= "",
684 		.argv	= argv,
685 	};
686 	struct xtables_args args = {
687 		.family = AF_INET6,
688 	};
689 	struct ip6t_entry *e = NULL;
690 	unsigned int nsaddrs = 0, ndaddrs = 0;
691 	struct in6_addr *saddrs = NULL, *daddrs = NULL;
692 	struct in6_addr *smasks = NULL, *dmasks = NULL;
693 
694 	int verbose = 0;
695 	int wait = 0;
696 	const char *chain = NULL;
697 	const char *policy = NULL, *newname = NULL;
698 	unsigned int rulenum = 0, command = 0;
699 	int ret = 1;
700 
701 	do_parse(argc, argv, &p, &cs, &args);
702 
703 	command		= p.command;
704 	chain		= p.chain;
705 	*table		= p.table;
706 	rulenum		= p.rulenum;
707 	policy		= p.policy;
708 	newname		= p.newname;
709 	verbose		= p.verbose;
710 	wait		= args.wait;
711 	nsaddrs		= args.s.naddrs;
712 	ndaddrs		= args.d.naddrs;
713 	saddrs		= args.s.addr.v6;
714 	daddrs		= args.d.addr.v6;
715 	smasks		= args.s.mask.v6;
716 	dmasks		= args.d.mask.v6;
717 
718 	iface_to_mask(cs.fw6.ipv6.iniface, cs.fw6.ipv6.iniface_mask);
719 	iface_to_mask(cs.fw6.ipv6.outiface, cs.fw6.ipv6.outiface_mask);
720 
721 	/* Attempt to acquire the xtables lock */
722 	if (!restore)
723 		xtables_lock_or_exit(wait);
724 
725 	/* only allocate handle if we weren't called with a handle */
726 	if (!*handle)
727 		*handle = ip6tc_init(*table);
728 
729 	/* try to insmod the module if iptc_init failed */
730 	if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1)
731 		*handle = ip6tc_init(*table);
732 
733 	if (!*handle)
734 		xtables_error(VERSION_PROBLEM,
735 			"can't initialize ip6tables table `%s': %s",
736 			*table, ip6tc_strerror(errno));
737 
738 	if (command == CMD_APPEND
739 	    || command == CMD_DELETE
740 	    || command == CMD_CHECK
741 	    || command == CMD_INSERT
742 	    || command == CMD_REPLACE) {
743 		if (cs.target && ip6tc_is_chain(cs.jumpto, *handle)) {
744 			fprintf(stderr,
745 				"Warning: using chain %s, not extension\n",
746 				cs.jumpto);
747 
748 			if (cs.target->t)
749 				free(cs.target->t);
750 
751 			cs.target = NULL;
752 		}
753 
754 		/* If they didn't specify a target, or it's a chain
755 		   name, use standard. */
756 		if (!cs.target
757 		    && (strlen(cs.jumpto) == 0
758 			|| ip6tc_is_chain(cs.jumpto, *handle))) {
759 			size_t size;
760 
761 			cs.target = xtables_find_target(XT_STANDARD_TARGET,
762 					XTF_LOAD_MUST_SUCCEED);
763 
764 			size = sizeof(struct xt_entry_target)
765 				+ cs.target->size;
766 			cs.target->t = xtables_calloc(1, size);
767 			cs.target->t->u.target_size = size;
768 			strcpy(cs.target->t->u.user.name, cs.jumpto);
769 			xs_init_target(cs.target);
770 		}
771 
772 		if (!cs.target) {
773 			/* It is no chain, and we can't load a plugin.
774 			 * We cannot know if the plugin is corrupt, non
775 			 * existent OR if the user just misspelled a
776 			 * chain.
777 			 */
778 #ifdef IP6T_F_GOTO
779 			if (cs.fw6.ipv6.flags & IP6T_F_GOTO)
780 				xtables_error(PARAMETER_PROBLEM,
781 					      "goto '%s' is not a chain",
782 					      cs.jumpto);
783 #endif
784 			xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED);
785 		} else {
786 			e = generate_entry(&cs.fw6, cs.matches, cs.target->t);
787 		}
788 	}
789 
790 	switch (command) {
791 	case CMD_APPEND:
792 		ret = append_entry(chain, e,
793 				   nsaddrs, saddrs, smasks,
794 				   ndaddrs, daddrs, dmasks,
795 				   cs.options&OPT_VERBOSE,
796 				   *handle);
797 		break;
798 	case CMD_DELETE:
799 		ret = delete_entry(chain, e,
800 				   nsaddrs, saddrs, smasks,
801 				   ndaddrs, daddrs, dmasks,
802 				   cs.options&OPT_VERBOSE,
803 				   *handle, cs.matches, cs.target);
804 		break;
805 	case CMD_DELETE_NUM:
806 		ret = ip6tc_delete_num_entry(chain, rulenum - 1, *handle);
807 		break;
808 	case CMD_CHECK:
809 		ret = check_entry(chain, e,
810 				   nsaddrs, saddrs, smasks,
811 				   ndaddrs, daddrs, dmasks,
812 				   cs.options&OPT_VERBOSE,
813 				   *handle, cs.matches, cs.target);
814 		break;
815 	case CMD_REPLACE:
816 		ret = replace_entry(chain, e, rulenum - 1,
817 				    saddrs, smasks, daddrs, dmasks,
818 				    cs.options&OPT_VERBOSE, *handle);
819 		break;
820 	case CMD_INSERT:
821 		ret = insert_entry(chain, e, rulenum - 1,
822 				   nsaddrs, saddrs, smasks,
823 				   ndaddrs, daddrs, dmasks,
824 				   cs.options&OPT_VERBOSE,
825 				   *handle);
826 		break;
827 	case CMD_FLUSH:
828 		ret = flush_entries6(chain, cs.options&OPT_VERBOSE, *handle);
829 		break;
830 	case CMD_ZERO:
831 		ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle);
832 		break;
833 	case CMD_ZERO_NUM:
834 		ret = ip6tc_zero_counter(chain, rulenum, *handle);
835 		break;
836 	case CMD_LIST:
837 	case CMD_LIST|CMD_ZERO:
838 	case CMD_LIST|CMD_ZERO_NUM:
839 		ret = list_entries(chain,
840 				   rulenum,
841 				   cs.options&OPT_VERBOSE,
842 				   cs.options&OPT_NUMERIC,
843 				   cs.options&OPT_EXPANDED,
844 				   cs.options&OPT_LINENUMBERS,
845 				   *handle);
846 		if (ret && (command & CMD_ZERO))
847 			ret = zero_entries(chain,
848 					   cs.options&OPT_VERBOSE, *handle);
849 		if (ret && (command & CMD_ZERO_NUM))
850 			ret = ip6tc_zero_counter(chain, rulenum, *handle);
851 		break;
852 	case CMD_LIST_RULES:
853 	case CMD_LIST_RULES|CMD_ZERO:
854 	case CMD_LIST_RULES|CMD_ZERO_NUM:
855 		ret = list_rules(chain,
856 				   rulenum,
857 				   cs.options&OPT_VERBOSE,
858 				   *handle);
859 		if (ret && (command & CMD_ZERO))
860 			ret = zero_entries(chain,
861 					   cs.options&OPT_VERBOSE, *handle);
862 		if (ret && (command & CMD_ZERO_NUM))
863 			ret = ip6tc_zero_counter(chain, rulenum, *handle);
864 		break;
865 	case CMD_NEW_CHAIN:
866 		ret = ip6tc_create_chain(chain, *handle);
867 		break;
868 	case CMD_DELETE_CHAIN:
869 		ret = delete_chain6(chain, cs.options&OPT_VERBOSE, *handle);
870 		break;
871 	case CMD_RENAME_CHAIN:
872 		ret = ip6tc_rename_chain(chain, newname,	*handle);
873 		break;
874 	case CMD_SET_POLICY:
875 		ret = ip6tc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw6.counters : NULL, *handle);
876 		break;
877 	case CMD_NONE:
878 		/* do_parse ignored the line (eg: -4 with ip6tables-restore) */
879 		break;
880 	default:
881 		/* We should never reach this... */
882 		exit_tryhelp(2, line);
883 	}
884 
885 	if (verbose > 1)
886 		dump_entries6(*handle);
887 
888 	xtables_clear_iptables_command_state(&cs);
889 
890 	if (e != NULL) {
891 		free(e);
892 		e = NULL;
893 	}
894 
895 	xtables_clear_args(&args);
896 	xtables_free_opts(1);
897 
898 	return ret;
899 }
900