• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <config.h>
2 #include <ctype.h>
3 #include <getopt.h>
4 #include <errno.h>
5 #include <libgen.h>
6 #include <netdb.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <arpa/inet.h>
13 #include <sys/file.h>
14 #include <sys/socket.h>
15 #include <sys/un.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <xtables.h>
19 #include <math.h>
20 #include <signal.h>
21 #include "xshared.h"
22 
23 /* a few arp opcode names */
24 char *arp_opcodes[] =
25 {
26 	"Request",
27 	"Reply",
28 	"Request_Reverse",
29 	"Reply_Reverse",
30 	"DRARP_Request",
31 	"DRARP_Reply",
32 	"DRARP_Error",
33 	"InARP_Request",
34 	"ARP_NAK",
35 };
36 
37 /*
38  * Print out any special helps. A user might like to be able to add a --help
39  * to the commandline, and see expected results. So we call help for all
40  * specified matches and targets.
41  */
print_extension_helps(const struct xtables_target * t,const struct xtables_rule_match * m)42 static void print_extension_helps(const struct xtables_target *t,
43 				  const struct xtables_rule_match *m)
44 {
45 	for (; t != NULL; t = t->next) {
46 		if (t->used) {
47 			printf("\n");
48 			if (t->help == NULL)
49 				printf("%s does not take any options\n",
50 				       t->name);
51 			else
52 				t->help();
53 		}
54 	}
55 	for (; m != NULL; m = m->next) {
56 		printf("\n");
57 		if (m->match->help == NULL)
58 			printf("%s does not take any options\n",
59 			       m->match->name);
60 		else
61 			m->match->help();
62 	}
63 }
64 
65 const char *
proto_to_name(uint16_t proto,int nolookup)66 proto_to_name(uint16_t proto, int nolookup)
67 {
68 	unsigned int i;
69 
70 	for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
71 		if (xtables_chain_protos[i].num == proto)
72 			return xtables_chain_protos[i].name;
73 
74 	if (proto && !nolookup) {
75 		struct protoent *pent = getprotobynumber(proto);
76 		if (pent)
77 			return pent->p_name;
78 	}
79 
80 	return NULL;
81 }
82 
83 static struct xtables_match *
find_proto(const char * pname,enum xtables_tryload tryload,int nolookup,struct xtables_rule_match ** matches)84 find_proto(const char *pname, enum xtables_tryload tryload,
85 	   int nolookup, struct xtables_rule_match **matches)
86 {
87 	unsigned int proto;
88 
89 	if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) {
90 		const char *protoname = proto_to_name(proto, nolookup);
91 
92 		if (protoname)
93 			return xtables_find_match(protoname, tryload, matches);
94 	} else
95 		return xtables_find_match(pname, tryload, matches);
96 
97 	return NULL;
98 }
99 
100 /*
101  * Some explanations (after four different bugs in 3 different releases): If
102  * we encounter a parameter, that has not been parsed yet, it's not an option
103  * of an explicitly loaded match or a target. However, we support implicit
104  * loading of the protocol match extension. '-p tcp' means 'l4 proto 6' and at
105  * the same time 'load tcp protocol match on demand if we specify --dport'.
106  *
107  * To make this work, we need to make sure:
108  * - the parameter has not been parsed by a match (m above)
109  * - a protocol has been specified
110  * - the protocol extension has not been loaded yet, or is loaded and unused
111  *   [think of ip6tables-restore!]
112  * - the protocol extension can be successively loaded
113  */
load_proto(struct iptables_command_state * cs)114 static struct xtables_match *load_proto(struct iptables_command_state *cs)
115 {
116 	if (cs->protocol == NULL)
117 		return NULL;
118 	if (cs->proto_used)
119 		return NULL;
120 	cs->proto_used = true;
121 	return find_proto(cs->protocol, XTF_TRY_LOAD,
122 			  cs->options & OPT_NUMERIC, &cs->matches);
123 }
124 
command_default(struct iptables_command_state * cs,struct xtables_globals * gl,bool invert)125 int command_default(struct iptables_command_state *cs,
126 		    struct xtables_globals *gl, bool invert)
127 {
128 	struct xtables_rule_match *matchp;
129 	struct xtables_match *m;
130 
131 	if (cs->target != NULL &&
132 	    (cs->target->parse != NULL || cs->target->x6_parse != NULL) &&
133 	    cs->c >= cs->target->option_offset &&
134 	    cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) {
135 		xtables_option_tpcall(cs->c, cs->argv, invert,
136 				      cs->target, &cs->fw);
137 		return 0;
138 	}
139 
140 	for (matchp = cs->matches; matchp; matchp = matchp->next) {
141 		m = matchp->match;
142 
143 		if (matchp->completed ||
144 		    (m->x6_parse == NULL && m->parse == NULL))
145 			continue;
146 		if (cs->c < matchp->match->option_offset ||
147 		    cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE)
148 			continue;
149 		xtables_option_mpcall(cs->c, cs->argv, invert, m, &cs->fw);
150 		return 0;
151 	}
152 
153 	m = load_proto(cs);
154 	if (m != NULL) {
155 		size_t size;
156 
157 		size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
158 
159 		m->m = xtables_calloc(1, size);
160 		m->m->u.match_size = size;
161 		strcpy(m->m->u.user.name, m->name);
162 		m->m->u.user.revision = m->revision;
163 		xs_init_match(m);
164 
165 		if (m->x6_options != NULL)
166 			gl->opts = xtables_options_xfrm(gl->orig_opts,
167 							gl->opts,
168 							m->x6_options,
169 							&m->option_offset);
170 		else
171 			gl->opts = xtables_merge_options(gl->orig_opts,
172 							 gl->opts,
173 							 m->extra_opts,
174 							 &m->option_offset);
175 		if (gl->opts == NULL)
176 			xtables_error(OTHER_PROBLEM, "can't alloc memory!");
177 		optind--;
178 		/* Indicate to rerun getopt *immediately* */
179  		return 1;
180 	}
181 
182 	if (cs->c == ':')
183 		xtables_error(PARAMETER_PROBLEM, "option \"%s\" "
184 		              "requires an argument", cs->argv[optind-1]);
185 	if (cs->c == '?') {
186 		char optoptstr[3] = {'-', optopt, '\0'};
187 
188 		xtables_error(PARAMETER_PROBLEM, "unknown option \"%s\"",
189 			      optopt ? optoptstr : cs->argv[optind - 1]);
190 	}
191 	xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
192 }
193 
subcmd_get(const char * cmd,const struct subcommand * cb)194 static mainfunc_t subcmd_get(const char *cmd, const struct subcommand *cb)
195 {
196 	for (; cb->name != NULL; ++cb)
197 		if (strcmp(cb->name, cmd) == 0)
198 			return cb->main;
199 	return NULL;
200 }
201 
subcmd_main(int argc,char ** argv,const struct subcommand * cb)202 int subcmd_main(int argc, char **argv, const struct subcommand *cb)
203 {
204 	const char *cmd = basename(*argv);
205 	mainfunc_t f = subcmd_get(cmd, cb);
206 
207 	if (f == NULL && argc > 1) {
208 		/*
209 		 * Unable to find a main method for our command name?
210 		 * Let's try again with the first argument!
211 		 */
212 		++argv;
213 		--argc;
214 		f = subcmd_get(*argv, cb);
215 	}
216 
217 	/* now we should have a valid function pointer */
218 	if (f != NULL)
219 		return f(argc, argv);
220 
221 	fprintf(stderr, "ERROR: No valid subcommand given.\nValid subcommands:\n");
222 	for (; cb->name != NULL; ++cb)
223 		fprintf(stderr, " * %s\n", cb->name);
224 	exit(EXIT_FAILURE);
225 }
226 
xs_init_target(struct xtables_target * target)227 void xs_init_target(struct xtables_target *target)
228 {
229 	if (target->udata_size != 0) {
230 		free(target->udata);
231 		target->udata = xtables_calloc(1, target->udata_size);
232 	}
233 	if (target->init != NULL)
234 		target->init(target->t);
235 }
236 
xs_init_match(struct xtables_match * match)237 void xs_init_match(struct xtables_match *match)
238 {
239 	if (match->udata_size != 0) {
240 		/*
241 		 * As soon as a subsequent instance of the same match
242 		 * is used, e.g. "-m time -m time", the first instance
243 		 * is no longer reachable anyway, so we can free udata.
244 		 * Same goes for target.
245 		 */
246 		free(match->udata);
247 		match->udata = xtables_calloc(1, match->udata_size);
248 	}
249 	if (match->init != NULL)
250 		match->init(match->m);
251 }
252 
alarm_ignore(int i)253 static void alarm_ignore(int i) {
254 }
255 
xtables_lock(int wait)256 static int xtables_lock(int wait)
257 {
258 	struct sigaction sigact_alarm;
259 	const char *lock_file;
260 	int fd;
261 
262 	lock_file = getenv("XTABLES_LOCKFILE");
263 	if (lock_file == NULL || lock_file[0] == '\0')
264 		lock_file = XT_LOCK_NAME;
265 
266 	fd = open(lock_file, O_CREAT, 0600);
267 	if (fd < 0) {
268 		fprintf(stderr, "Fatal: can't open lock file %s: %s\n",
269 			lock_file, strerror(errno));
270 		return XT_LOCK_FAILED;
271 	}
272 
273 	if (wait > 0) {
274 		sigact_alarm.sa_handler = alarm_ignore;
275 		sigact_alarm.sa_flags = SA_RESETHAND;
276 		sigemptyset(&sigact_alarm.sa_mask);
277 		sigaction(SIGALRM, &sigact_alarm, NULL);
278 		alarm(wait);
279 	}
280 
281 	if (flock(fd, LOCK_EX | (wait ? 0 : LOCK_NB)) == 0)
282 		return fd;
283 
284 	if (errno == EINTR) {
285 		errno = EWOULDBLOCK;
286 	}
287 
288 	fprintf(stderr, "Can't lock %s: %s\n", lock_file,
289 		strerror(errno));
290 	return XT_LOCK_BUSY;
291 }
292 
xtables_unlock(int lock)293 void xtables_unlock(int lock)
294 {
295 	if (lock >= 0)
296 		close(lock);
297 }
298 
xtables_lock_or_exit(int wait)299 int xtables_lock_or_exit(int wait)
300 {
301 	int lock = xtables_lock(wait);
302 
303 	if (lock == XT_LOCK_FAILED) {
304 		xtables_free_opts(1);
305 		exit(RESOURCE_PROBLEM);
306 	}
307 
308 	if (lock == XT_LOCK_BUSY) {
309 		fprintf(stderr, "Another app is currently holding the xtables lock. ");
310 		if (wait == 0)
311 			fprintf(stderr, "Perhaps you want to use the -w option?\n");
312 		else
313 			fprintf(stderr, "Stopped waiting after %ds.\n", wait);
314 		xtables_free_opts(1);
315 		exit(RESOURCE_PROBLEM);
316 	}
317 
318 	return lock;
319 }
320 
parse_wait_time(int argc,char * argv[])321 int parse_wait_time(int argc, char *argv[])
322 {
323 	int wait = -1;
324 
325 	if (optarg) {
326 		if (sscanf(optarg, "%i", &wait) != 1)
327 			xtables_error(PARAMETER_PROBLEM,
328 				"wait seconds not numeric");
329 	} else if (xs_has_arg(argc, argv))
330 		if (sscanf(argv[optind++], "%i", &wait) != 1)
331 			xtables_error(PARAMETER_PROBLEM,
332 				"wait seconds not numeric");
333 
334 	return wait;
335 }
336 
parse_wait_interval(int argc,char * argv[])337 void parse_wait_interval(int argc, char *argv[])
338 {
339 	const char *arg;
340 	unsigned int usec;
341 	int ret;
342 
343 	if (optarg)
344 		arg = optarg;
345 	else if (xs_has_arg(argc, argv))
346 		arg = argv[optind++];
347 	else
348 		xtables_error(PARAMETER_PROBLEM, "wait interval value required");
349 
350 	ret = sscanf(arg, "%u", &usec);
351 	if (ret == 1) {
352 		if (usec > 999999)
353 			xtables_error(PARAMETER_PROBLEM,
354 				      "too long usec wait %u > 999999 usec",
355 				      usec);
356 
357 		fprintf(stderr, "Ignoring deprecated --wait-interval option.\n");
358 		return;
359 	}
360 	xtables_error(PARAMETER_PROBLEM, "wait interval not numeric");
361 }
362 
parse_counters(const char * string,struct xt_counters * ctr)363 int parse_counters(const char *string, struct xt_counters *ctr)
364 {
365 	int ret;
366 
367 	if (!string)
368 		return 0;
369 
370 	ret = sscanf(string, "[%llu:%llu]",
371 		     (unsigned long long *)&ctr->pcnt,
372 		     (unsigned long long *)&ctr->bcnt);
373 
374 	return ret == 2;
375 }
376 
377 /* Tokenize counters argument of typical iptables-restore format rule.
378  *
379  * If *bufferp contains counters, update *pcntp and *bcntp to point at them,
380  * change bytes after counters in *bufferp to nul-bytes, update *bufferp to
381  * point to after the counters and return true.
382  * If *bufferp does not contain counters, return false.
383  * If syntax is wrong in *bufferp, call xtables_error() and hence exit().
384  * */
tokenize_rule_counters(char ** bufferp,char ** pcntp,char ** bcntp,int line)385 bool tokenize_rule_counters(char **bufferp, char **pcntp, char **bcntp, int line)
386 {
387 	char *ptr, *buffer = *bufferp, *pcnt, *bcnt;
388 
389 	if (buffer[0] != '[')
390 		return false;
391 
392 	/* we have counters in our input */
393 
394 	ptr = strchr(buffer, ']');
395 	if (!ptr)
396 		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]", line);
397 
398 	pcnt = strtok(buffer+1, ":");
399 	if (!pcnt)
400 		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :", line);
401 
402 	bcnt = strtok(NULL, "]");
403 	if (!bcnt)
404 		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]", line);
405 
406 	*pcntp = pcnt;
407 	*bcntp = bcnt;
408 	/* start command parsing after counter */
409 	*bufferp = ptr + 1;
410 
411 	return true;
412 }
413 
xs_has_arg(int argc,char * argv[])414 inline bool xs_has_arg(int argc, char *argv[])
415 {
416 	return optind < argc &&
417 	       argv[optind][0] != '-' &&
418 	       argv[optind][0] != '!';
419 }
420 
421 /* function adding one argument to store, updating argc
422  * returns if argument added, does not return otherwise */
add_argv(struct argv_store * store,const char * what,int quoted)423 void add_argv(struct argv_store *store, const char *what, int quoted)
424 {
425 	DEBUGP("add_argv: %s\n", what);
426 
427 	if (store->argc + 1 >= MAX_ARGC)
428 		xtables_error(PARAMETER_PROBLEM,
429 			      "Parser cannot handle more arguments");
430 	if (!what)
431 		xtables_error(PARAMETER_PROBLEM,
432 			      "Trying to store NULL argument");
433 
434 	store->argv[store->argc] = xtables_strdup(what);
435 	store->argvattr[store->argc] = quoted;
436 	store->argv[++store->argc] = NULL;
437 }
438 
free_argv(struct argv_store * store)439 void free_argv(struct argv_store *store)
440 {
441 	while (store->argc) {
442 		store->argc--;
443 		free(store->argv[store->argc]);
444 		store->argvattr[store->argc] = 0;
445 	}
446 }
447 
448 /* Save parsed rule for comparison with next rule to perform action aggregation
449  * on duplicate conditions.
450  */
save_argv(struct argv_store * dst,struct argv_store * src)451 void save_argv(struct argv_store *dst, struct argv_store *src)
452 {
453 	int i;
454 
455 	free_argv(dst);
456 	for (i = 0; i < src->argc; i++) {
457 		dst->argvattr[i] = src->argvattr[i];
458 		dst->argv[i] = src->argv[i];
459 		src->argv[i] = NULL;
460 	}
461 	dst->argc = src->argc;
462 	src->argc = 0;
463 }
464 
465 struct xt_param_buf {
466 	char	buffer[1024];
467 	int 	len;
468 };
469 
add_param(struct xt_param_buf * param,const char * curchar)470 static void add_param(struct xt_param_buf *param, const char *curchar)
471 {
472 	param->buffer[param->len++] = *curchar;
473 	if (param->len >= sizeof(param->buffer))
474 		xtables_error(PARAMETER_PROBLEM,
475 			      "Parameter too long!");
476 }
477 
add_param_to_argv(struct argv_store * store,char * parsestart,int line)478 void add_param_to_argv(struct argv_store *store, char *parsestart, int line)
479 {
480 	int quote_open = 0, escaped = 0, quoted = 0;
481 	struct xt_param_buf param = {};
482 	char *curchar;
483 
484 	/* After fighting with strtok enough, here's now
485 	 * a 'real' parser. According to Rusty I'm now no
486 	 * longer a real hacker, but I can live with that */
487 
488 	for (curchar = parsestart; *curchar; curchar++) {
489 		if (quote_open) {
490 			if (escaped) {
491 				add_param(&param, curchar);
492 				escaped = 0;
493 				continue;
494 			} else if (*curchar == '\\') {
495 				escaped = 1;
496 				continue;
497 			} else if (*curchar == '"') {
498 				quote_open = 0;
499 			} else {
500 				add_param(&param, curchar);
501 				continue;
502 			}
503 		} else {
504 			if (*curchar == '"') {
505 				quote_open = 1;
506 				quoted = 1;
507 				continue;
508 			}
509 		}
510 
511 		switch (*curchar) {
512 		case '"':
513 			break;
514 		case ' ':
515 		case '\t':
516 		case '\n':
517 			if (!param.len) {
518 				/* two spaces? */
519 				continue;
520 			}
521 			break;
522 		default:
523 			/* regular character, copy to buffer */
524 			add_param(&param, curchar);
525 			continue;
526 		}
527 
528 		param.buffer[param.len] = '\0';
529 		add_argv(store, param.buffer, quoted);
530 		param.len = 0;
531 		quoted = 0;
532 	}
533 	if (param.len) {
534 		param.buffer[param.len] = '\0';
535 		add_argv(store, param.buffer, 0);
536 	}
537 }
538 
539 #ifdef DEBUG
debug_print_argv(struct argv_store * store)540 void debug_print_argv(struct argv_store *store)
541 {
542 	int i;
543 
544 	for (i = 0; i < store->argc; i++)
545 		fprintf(stderr, "argv[%d]: %s\n", i, store->argv[i]);
546 }
547 #endif
548 
print_header(unsigned int format,const char * chain,const char * pol,const struct xt_counters * counters,int refs,uint32_t entries)549 void print_header(unsigned int format, const char *chain, const char *pol,
550 		  const struct xt_counters *counters,
551 		  int refs, uint32_t entries)
552 {
553 	printf("Chain %s", chain);
554 	if (pol) {
555 		printf(" (policy %s", pol);
556 		if (!(format & FMT_NOCOUNTS)) {
557 			fputc(' ', stdout);
558 			xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
559 			fputs("packets, ", stdout);
560 			xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
561 			fputs("bytes", stdout);
562 		}
563 		printf(")\n");
564 	} else if (refs < 0) {
565 		printf(" (ERROR obtaining refs)\n");
566 	} else {
567 		printf(" (%d references)\n", refs);
568 	}
569 
570 	if (format & FMT_LINENUMBERS)
571 		printf(FMT("%-4s ", "%s "), "num");
572 	if (!(format & FMT_NOCOUNTS)) {
573 		if (format & FMT_KILOMEGAGIGA) {
574 			printf(FMT("%5s ","%s "), "pkts");
575 			printf(FMT("%5s ","%s "), "bytes");
576 		} else {
577 			printf(FMT("%8s ","%s "), "pkts");
578 			printf(FMT("%10s ","%s "), "bytes");
579 		}
580 	}
581 	if (!(format & FMT_NOTARGET))
582 		printf(FMT("%-9s ","%s "), "target");
583 	fputs(" prot ", stdout);
584 	if (format & FMT_OPTIONS)
585 		fputs("opt", stdout);
586 	if (format & FMT_VIA) {
587 		printf(FMT(" %-6s ","%s "), "in");
588 		printf(FMT("%-6s ","%s "), "out");
589 	}
590 	printf(FMT(" %-19s ","%s "), "source");
591 	printf(FMT(" %-19s "," %s "), "destination");
592 	printf("\n");
593 }
594 
ipv4_addr_to_string(const struct in_addr * addr,const struct in_addr * mask,unsigned int format)595 const char *ipv4_addr_to_string(const struct in_addr *addr,
596 				const struct in_addr *mask,
597 				unsigned int format)
598 {
599 	static char buf[BUFSIZ];
600 
601 	if (!mask->s_addr && !(format & FMT_NUMERIC))
602 		return "anywhere";
603 
604 	if (format & FMT_NUMERIC)
605 		strncpy(buf, xtables_ipaddr_to_numeric(addr), BUFSIZ - 1);
606 	else
607 		strncpy(buf, xtables_ipaddr_to_anyname(addr), BUFSIZ - 1);
608 	buf[BUFSIZ - 1] = '\0';
609 
610 	strncat(buf, xtables_ipmask_to_numeric(mask),
611 		BUFSIZ - strlen(buf) - 1);
612 
613 	return buf;
614 }
615 
print_ipv4_addresses(const struct ipt_entry * fw,unsigned int format)616 void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format)
617 {
618 	fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
619 	printf(FMT("%-19s ", "%s "),
620 	       ipv4_addr_to_string(&fw->ip.src, &fw->ip.smsk, format));
621 
622 	fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
623 	printf(FMT("%-19s ", "-> %s"),
624 	       ipv4_addr_to_string(&fw->ip.dst, &fw->ip.dmsk, format));
625 }
626 
mask_to_str(const struct in_addr * mask)627 static const char *mask_to_str(const struct in_addr *mask)
628 {
629 	uint32_t bits, hmask = ntohl(mask->s_addr);
630 	static char mask_str[INET_ADDRSTRLEN];
631 	int i;
632 
633 	if (mask->s_addr == 0xFFFFFFFFU) {
634 		sprintf(mask_str, "32");
635 		return mask_str;
636 	}
637 
638 	i    = 32;
639 	bits = 0xFFFFFFFEU;
640 	while (--i >= 0 && hmask != bits)
641 		bits <<= 1;
642 	if (i >= 0)
643 		sprintf(mask_str, "%u", i);
644 	else
645 		inet_ntop(AF_INET, mask, mask_str, sizeof(mask_str));
646 
647 	return mask_str;
648 }
649 
save_ipv4_addr(char letter,const struct in_addr * addr,const struct in_addr * mask,int invert)650 void save_ipv4_addr(char letter, const struct in_addr *addr,
651 		    const struct in_addr *mask, int invert)
652 {
653 	char addrbuf[INET_ADDRSTRLEN];
654 
655 	if (!mask->s_addr && !invert && !addr->s_addr)
656 		return;
657 
658 	printf("%s -%c %s/%s", invert ? " !" : "", letter,
659 	       inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)),
660 	       mask_to_str(mask));
661 }
662 
ipv6_addr_to_string(const struct in6_addr * addr,const struct in6_addr * mask,unsigned int format)663 static const char *ipv6_addr_to_string(const struct in6_addr *addr,
664 				       const struct in6_addr *mask,
665 				       unsigned int format)
666 {
667 	static char buf[BUFSIZ];
668 
669 	if (IN6_IS_ADDR_UNSPECIFIED(addr) && !(format & FMT_NUMERIC))
670 		return "anywhere";
671 
672 	if (format & FMT_NUMERIC)
673 		strncpy(buf, xtables_ip6addr_to_numeric(addr), BUFSIZ - 1);
674 	else
675 		strncpy(buf, xtables_ip6addr_to_anyname(addr), BUFSIZ - 1);
676 	buf[BUFSIZ - 1] = '\0';
677 
678 	strncat(buf, xtables_ip6mask_to_numeric(mask),
679 		BUFSIZ - strlen(buf) - 1);
680 
681 	return buf;
682 }
683 
print_ipv6_addresses(const struct ip6t_entry * fw6,unsigned int format)684 void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format)
685 {
686 	fputc(fw6->ipv6.invflags & IP6T_INV_SRCIP ? '!' : ' ', stdout);
687 	printf(FMT("%-19s ", "%s "),
688 	       ipv6_addr_to_string(&fw6->ipv6.src,
689 				   &fw6->ipv6.smsk, format));
690 
691 	fputc(fw6->ipv6.invflags & IP6T_INV_DSTIP ? '!' : ' ', stdout);
692 	printf(FMT("%-19s ", "-> %s"),
693 	       ipv6_addr_to_string(&fw6->ipv6.dst,
694 				   &fw6->ipv6.dmsk, format));
695 }
696 
save_ipv6_addr(char letter,const struct in6_addr * addr,const struct in6_addr * mask,int invert)697 void save_ipv6_addr(char letter, const struct in6_addr *addr,
698 		    const struct in6_addr *mask, int invert)
699 {
700 	int l = xtables_ip6mask_to_cidr(mask);
701 	char addr_str[INET6_ADDRSTRLEN];
702 
703 	if (!invert && l == 0)
704 		return;
705 
706 	printf("%s -%c %s",
707 		invert ? " !" : "", letter,
708 		inet_ntop(AF_INET6, addr, addr_str, sizeof(addr_str)));
709 
710 	if (l == -1)
711 		printf("/%s", inet_ntop(AF_INET6, mask,
712 					addr_str, sizeof(addr_str)));
713 	else
714 		printf("/%d", l);
715 }
716 
print_fragment(unsigned int flags,unsigned int invflags,unsigned int format,bool fake)717 void print_fragment(unsigned int flags, unsigned int invflags,
718 		    unsigned int format, bool fake)
719 {
720 	if (!(format & FMT_OPTIONS))
721 		return;
722 
723 	if (format & FMT_NOTABLE)
724 		fputs("opt ", stdout);
725 
726 	if (fake) {
727 		fputs("--", stdout);
728 	} else {
729 		fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout);
730 		fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
731 	}
732 	fputc(' ', stdout);
733 }
734 
735 /* Luckily, IPT_INV_VIA_IN and IPT_INV_VIA_OUT
736  * have the same values as IP6T_INV_VIA_IN and IP6T_INV_VIA_OUT
737  * so this function serves for both iptables and ip6tables */
print_ifaces(const char * iniface,const char * outiface,uint8_t invflags,unsigned int format)738 void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
739 		  unsigned int format)
740 {
741 	const char *anyname = format & FMT_NUMERIC ? "*" : "any";
742 	char iface[IFNAMSIZ + 2];
743 
744 	if (!(format & FMT_VIA))
745 		return;
746 
747 	snprintf(iface, IFNAMSIZ + 2, "%s%s",
748 		 invflags & IPT_INV_VIA_IN ? "!" : "",
749 		 iniface[0] != '\0' ? iniface : anyname);
750 
751 	printf(FMT(" %-6s ", "in %s "), iface);
752 
753 	snprintf(iface, IFNAMSIZ + 2, "%s%s",
754 		 invflags & IPT_INV_VIA_OUT ? "!" : "",
755 		 outiface[0] != '\0' ? outiface : anyname);
756 
757 	printf(FMT("%-6s ", "out %s "), iface);
758 }
759 
save_iface(char letter,const char * iface,int invert)760 static void save_iface(char letter, const char *iface, int invert)
761 {
762 	if (iface && strlen(iface) && (strcmp(iface, "+") || invert))
763 		printf("%s -%c %s", invert ? " !" : "", letter, iface);
764 }
765 
command_match(struct iptables_command_state * cs,bool invert)766 static void command_match(struct iptables_command_state *cs, bool invert)
767 {
768 	struct option *opts = xt_params->opts;
769 	struct xtables_match *m;
770 	size_t size;
771 
772 	if (invert)
773 		xtables_error(PARAMETER_PROBLEM,
774 			   "unexpected ! flag before --match");
775 
776 	m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches);
777 	size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
778 	m->m = xtables_calloc(1, size);
779 	m->m->u.match_size = size;
780 	if (m->real_name == NULL) {
781 		strcpy(m->m->u.user.name, m->name);
782 	} else {
783 		strcpy(m->m->u.user.name, m->real_name);
784 		if (!(m->ext_flags & XTABLES_EXT_ALIAS))
785 			fprintf(stderr, "Notice: the %s match is converted into %s match "
786 				"in rule listing and saving.\n", m->name, m->real_name);
787 	}
788 	m->m->u.user.revision = m->revision;
789 	xs_init_match(m);
790 	if (m == m->next)
791 		return;
792 	/* Merge options for non-cloned matches */
793 	if (m->x6_options != NULL)
794 		opts = xtables_options_xfrm(xt_params->orig_opts, opts,
795 					    m->x6_options, &m->option_offset);
796 	else if (m->extra_opts != NULL)
797 		opts = xtables_merge_options(xt_params->orig_opts, opts,
798 					     m->extra_opts, &m->option_offset);
799 	else
800 		return;
801 
802 	if (opts == NULL)
803 		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
804 	xt_params->opts = opts;
805 }
806 
xt_parse_target(const char * targetname)807 static const char *xt_parse_target(const char *targetname)
808 {
809 	const char *ptr;
810 
811 	if (strlen(targetname) < 1)
812 		xtables_error(PARAMETER_PROBLEM,
813 			   "Invalid target name (too short)");
814 
815 	if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN)
816 		xtables_error(PARAMETER_PROBLEM,
817 			   "Invalid target name `%s' (%u chars max)",
818 			   targetname, XT_EXTENSION_MAXNAMELEN - 1);
819 
820 	for (ptr = targetname; *ptr; ptr++)
821 		if (isspace(*ptr))
822 			xtables_error(PARAMETER_PROBLEM,
823 				   "Invalid target name `%s'", targetname);
824 	return targetname;
825 }
826 
command_jump(struct iptables_command_state * cs,const char * jumpto)827 void command_jump(struct iptables_command_state *cs, const char *jumpto)
828 {
829 	struct option *opts = xt_params->opts;
830 	size_t size;
831 
832 	cs->jumpto = xt_parse_target(jumpto);
833 	/* TRY_LOAD (may be chain name) */
834 	cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
835 
836 	if (cs->target == NULL)
837 		return;
838 
839 	size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
840 
841 	cs->target->t = xtables_calloc(1, size);
842 	cs->target->t->u.target_size = size;
843 	if (cs->target->real_name == NULL) {
844 		strcpy(cs->target->t->u.user.name, cs->jumpto);
845 	} else {
846 		/* Alias support for userspace side */
847 		strcpy(cs->target->t->u.user.name, cs->target->real_name);
848 		if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS))
849 			fprintf(stderr, "Notice: The %s target is converted into %s target "
850 				"in rule listing and saving.\n",
851 				cs->jumpto, cs->target->real_name);
852 	}
853 	cs->target->t->u.user.revision = cs->target->revision;
854 	xs_init_target(cs->target);
855 
856 	if (cs->target->x6_options != NULL)
857 		opts = xtables_options_xfrm(xt_params->orig_opts, opts,
858 					    cs->target->x6_options,
859 					    &cs->target->option_offset);
860 	else if (cs->target->extra_opts != NULL)
861 		opts = xtables_merge_options(xt_params->orig_opts, opts,
862 					     cs->target->extra_opts,
863 					     &cs->target->option_offset);
864 	else
865 		return;
866 
867 	if (opts == NULL)
868 		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
869 	xt_params->opts = opts;
870 }
871 
cmd2char(int option)872 static char cmd2char(int option)
873 {
874 	/* cmdflags index corresponds with position of bit in CMD_* values */
875 	static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
876 					 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
877 	int i;
878 
879 	for (i = 0; option > 1; option >>= 1, i++)
880 		;
881 	if (i >= ARRAY_SIZE(cmdflags))
882 		xtables_error(OTHER_PROBLEM,
883 			      "cmd2char(): Invalid command number %u.", 1 << i);
884 	return cmdflags[i];
885 }
886 
add_command(unsigned int * cmd,const int newcmd,const int othercmds,int invert)887 static void add_command(unsigned int *cmd, const int newcmd,
888 			const int othercmds, int invert)
889 {
890 	if (invert)
891 		xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag");
892 	if (*cmd & (~othercmds))
893 		xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c",
894 			      cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
895 	*cmd |= newcmd;
896 }
897 
898 /* Can't be zero. */
parse_rulenumber(const char * rule)899 static int parse_rulenumber(const char *rule)
900 {
901 	unsigned int rulenum;
902 
903 	if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
904 		xtables_error(PARAMETER_PROBLEM,
905 			   "Invalid rule number `%s'", rule);
906 
907 	return rulenum;
908 }
909 
parse_rule_range(struct xt_cmd_parse * p,const char * argv)910 static void parse_rule_range(struct xt_cmd_parse *p, const char *argv)
911 {
912 	char *colon = strchr(argv, ':'), *buffer;
913 
914 	if (colon) {
915 		if (!p->rule_ranges)
916 			xtables_error(PARAMETER_PROBLEM,
917 				      "Rule ranges are not supported");
918 
919 		*colon = '\0';
920 		if (*(colon + 1) == '\0')
921 			p->rulenum_end = -1; /* Until the last rule */
922 		else {
923 			p->rulenum_end = strtol(colon + 1, &buffer, 10);
924 			if (*buffer != '\0' || p->rulenum_end == 0)
925 				xtables_error(PARAMETER_PROBLEM,
926 					      "Invalid rule range end`%s'",
927 					      colon + 1);
928 		}
929 	}
930 	if (colon == argv)
931 		p->rulenum = 1; /* Beginning with the first rule */
932 	else {
933 		p->rulenum = strtol(argv, &buffer, 10);
934 		if (*buffer != '\0' || p->rulenum == 0)
935 			xtables_error(PARAMETER_PROBLEM,
936 				      "Invalid rule number `%s'", argv);
937 	}
938 	if (!colon)
939 		p->rulenum_end = p->rulenum;
940 }
941 
942 /* list the commands an option is allowed with */
943 #define CMD_IDRAC	CMD_INSERT | CMD_DELETE | CMD_REPLACE | \
944 			CMD_APPEND | CMD_CHECK | CMD_CHANGE_COUNTERS
945 static const unsigned int options_v_commands[NUMBER_OF_OPT] = {
946 /*OPT_NUMERIC*/		CMD_LIST,
947 /*OPT_SOURCE*/		CMD_IDRAC,
948 /*OPT_DESTINATION*/	CMD_IDRAC,
949 /*OPT_PROTOCOL*/	CMD_IDRAC,
950 /*OPT_JUMP*/		CMD_IDRAC,
951 /*OPT_VERBOSE*/		UINT_MAX,
952 /*OPT_EXPANDED*/	CMD_LIST,
953 /*OPT_VIANAMEIN*/	CMD_IDRAC,
954 /*OPT_VIANAMEOUT*/	CMD_IDRAC,
955 /*OPT_LINENUMBERS*/	CMD_LIST,
956 /*OPT_COUNTERS*/	CMD_INSERT | CMD_REPLACE | CMD_APPEND | CMD_SET_POLICY,
957 /*OPT_FRAGMENT*/	CMD_IDRAC,
958 /*OPT_S_MAC*/		CMD_IDRAC,
959 /*OPT_D_MAC*/		CMD_IDRAC,
960 /*OPT_H_LENGTH*/	CMD_IDRAC,
961 /*OPT_OPCODE*/		CMD_IDRAC,
962 /*OPT_H_TYPE*/		CMD_IDRAC,
963 /*OPT_P_TYPE*/		CMD_IDRAC,
964 /*OPT_LOGICALIN*/	CMD_IDRAC,
965 /*OPT_LOGICALOUT*/	CMD_IDRAC,
966 /*OPT_LIST_C*/		CMD_LIST,
967 /*OPT_LIST_X*/		CMD_LIST,
968 /*OPT_LIST_MAC2*/	CMD_LIST,
969 };
970 #undef CMD_IDRAC
971 
generic_opt_check(struct xt_cmd_parse_ops * ops,int command,int options)972 static void generic_opt_check(struct xt_cmd_parse_ops *ops,
973 			      int command, int options)
974 {
975 	int i, optval;
976 
977 	/* Check that commands are valid with options. Complicated by the
978 	 * fact that if an option is legal with *any* command given, it is
979 	 * legal overall (ie. -z and -l).
980 	 */
981 	for (i = 0, optval = 1; i < NUMBER_OF_OPT; optval = (1 << ++i)) {
982 		if ((options & optval) &&
983 		    (options_v_commands[i] & command) != command)
984 			xtables_error(PARAMETER_PROBLEM,
985 				      "Illegal option `%s' with this command",
986 				      ops->option_name(optval));
987 	}
988 }
989 
ip46t_option_name(int option)990 const char *ip46t_option_name(int option)
991 {
992 	switch (option) {
993 	case OPT_NUMERIC:	return "--numeric";
994 	case OPT_SOURCE:	return "--source";
995 	case OPT_DESTINATION:	return "--destination";
996 	case OPT_PROTOCOL:	return "--protocol";
997 	case OPT_JUMP:		return "--jump";
998 	case OPT_VERBOSE:	return "--verbose";
999 	case OPT_EXPANDED:	return "--exact";
1000 	case OPT_VIANAMEIN:	return "--in-interface";
1001 	case OPT_VIANAMEOUT:	return "--out-interface";
1002 	case OPT_LINENUMBERS:	return "--line-numbers";
1003 	case OPT_COUNTERS:	return "--set-counters";
1004 	case OPT_FRAGMENT:	return "--fragments";
1005 	default:		return "unknown option";
1006 	}
1007 }
1008 
ip46t_option_invert(int option)1009 int ip46t_option_invert(int option)
1010 {
1011 	switch (option) {
1012 	case OPT_SOURCE:	return IPT_INV_SRCIP;
1013 	case OPT_DESTINATION:	return IPT_INV_DSTIP;
1014 	case OPT_PROTOCOL:	return XT_INV_PROTO;
1015 	case OPT_VIANAMEIN:	return IPT_INV_VIA_IN;
1016 	case OPT_VIANAMEOUT:	return IPT_INV_VIA_OUT;
1017 	case OPT_FRAGMENT:	return IPT_INV_FRAG;
1018 	default:		return -1;
1019 	}
1020 }
1021 
1022 static void
set_option(struct xt_cmd_parse_ops * ops,unsigned int * options,unsigned int option,uint16_t * invflg,bool invert)1023 set_option(struct xt_cmd_parse_ops *ops,
1024 	   unsigned int *options, unsigned int option,
1025 	   uint16_t *invflg, bool invert)
1026 {
1027 	if (*options & option)
1028 		xtables_error(PARAMETER_PROBLEM,
1029 			      "multiple %s options not allowed",
1030 			      ops->option_name(option));
1031 	*options |= option;
1032 
1033 	if (invert) {
1034 		int invopt = ops->option_invert(option);
1035 
1036 		if (invopt < 0)
1037 			xtables_error(PARAMETER_PROBLEM,
1038 				      "cannot have ! before %s",
1039 				      ops->option_name(option));
1040 		*invflg |= invopt;
1041 	}
1042 }
1043 
assert_valid_chain_name(const char * chainname)1044 void assert_valid_chain_name(const char *chainname)
1045 {
1046 	const char *ptr;
1047 
1048 	if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
1049 		xtables_error(PARAMETER_PROBLEM,
1050 			      "chain name `%s' too long (must be under %u chars)",
1051 			      chainname, XT_EXTENSION_MAXNAMELEN);
1052 
1053 	if (*chainname == '-' || *chainname == '!')
1054 		xtables_error(PARAMETER_PROBLEM,
1055 			      "chain name not allowed to start with `%c'",
1056 			      *chainname);
1057 
1058 	if (xtables_find_target(chainname, XTF_TRY_LOAD))
1059 		xtables_error(PARAMETER_PROBLEM,
1060 			      "chain name may not clash with target name");
1061 
1062 	for (ptr = chainname; *ptr; ptr++)
1063 		if (isspace(*ptr))
1064 			xtables_error(PARAMETER_PROBLEM,
1065 				      "Invalid chain name `%s'", chainname);
1066 }
1067 
print_rule_details(unsigned int linenum,const struct xt_counters * ctrs,const char * targname,uint8_t proto,uint8_t flags,uint8_t invflags,unsigned int format)1068 void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs,
1069 			const char *targname, uint8_t proto, uint8_t flags,
1070 			uint8_t invflags, unsigned int format)
1071 {
1072 	const char *pname = proto_to_name(proto, format&FMT_NUMERIC);
1073 
1074 	if (format & FMT_LINENUMBERS)
1075 		printf(FMT("%-4u ", "%u "), linenum);
1076 
1077 	if (!(format & FMT_NOCOUNTS)) {
1078 		xtables_print_num(ctrs->pcnt, format);
1079 		xtables_print_num(ctrs->bcnt, format);
1080 	}
1081 
1082 	if (!(format & FMT_NOTARGET))
1083 		printf(FMT("%-9s ", "%s "), targname ? targname : "");
1084 
1085 	fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout);
1086 
1087 	if (pname)
1088 		printf(FMT("%-4s ", "%s "), pname);
1089 	else
1090 		printf(FMT("%-4hu ", "%hu "), proto);
1091 }
1092 
save_rule_details(const char * iniface,const char * outiface,uint16_t proto,int frag,uint8_t invflags)1093 void save_rule_details(const char *iniface, const char *outiface,
1094 		       uint16_t proto, int frag, uint8_t invflags)
1095 {
1096 	save_iface('i', iniface, invflags & IPT_INV_VIA_IN);
1097 	save_iface('o', outiface, invflags & IPT_INV_VIA_OUT);
1098 
1099 	if (proto > 0) {
1100 		const char *pname = proto_to_name(proto, true);
1101 
1102 		if (invflags & XT_INV_PROTO)
1103 			printf(" !");
1104 
1105 		if (pname)
1106 			printf(" -p %s", pname);
1107 		else
1108 			printf(" -p %u", proto);
1109 	}
1110 
1111 	if (frag) {
1112 		if (invflags & IPT_INV_FRAG)
1113 			printf(" !");
1114 		printf(" -f");
1115 	}
1116 }
1117 
print_match_save(const struct xt_entry_match * e,const void * ip)1118 int print_match_save(const struct xt_entry_match *e, const void *ip)
1119 {
1120 	const char *name = e->u.user.name;
1121 	const int revision = e->u.user.revision;
1122 	struct xtables_match *match, *mt, *mt2;
1123 
1124 	match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
1125 	if (match) {
1126 		mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
1127 						       match, revision);
1128 		if (!mt2)
1129 			mt2 = match;
1130 		printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
1131 
1132 		/* some matches don't provide a save function */
1133 		if (mt && mt->save)
1134 			mt->save(ip, e);
1135 		else if (match->save)
1136 			printf(" [unsupported revision]");
1137 	} else {
1138 		if (e->u.match_size) {
1139 			fprintf(stderr,
1140 				"Can't find library for match `%s'\n",
1141 				name);
1142 			exit(1);
1143 		}
1144 	}
1145 	return 0;
1146 }
1147 
xtables_printhelp(struct iptables_command_state * cs)1148 void xtables_printhelp(struct iptables_command_state *cs)
1149 {
1150 	const struct xtables_rule_match *matches = cs->matches;
1151 	const char *prog_name = xt_params->program_name;
1152 	const char *prog_vers = xt_params->program_version;
1153 
1154 	printf("%s v%s\n\n"
1155 "Usage: %s -[ACD] chain rule-specification [options]\n"
1156 "       %s -I chain [rulenum] rule-specification [options]\n"
1157 "       %s -R chain rulenum rule-specification [options]\n"
1158 "       %s -D chain rulenum [options]\n"
1159 "       %s -[LS] [chain [rulenum]] [options]\n"
1160 "       %s -[FZ] [chain] [options]\n"
1161 "       %s -[NX] chain\n"
1162 "       %s -E old-chain-name new-chain-name\n"
1163 "       %s -P chain target [options]\n"
1164 "       %s -h (print this help information)\n\n",
1165 	       prog_name, prog_vers, prog_name, prog_name,
1166 	       prog_name, prog_name, prog_name, prog_name,
1167 	       prog_name, prog_name, prog_name, prog_name);
1168 
1169 	printf(
1170 "Commands:\n"
1171 "Either long or short options are allowed.\n"
1172 "  --append  -A chain		Append to chain\n"
1173 "  --check   -C chain		Check for the existence of a rule\n"
1174 "  --delete  -D chain		Delete matching rule from chain\n"
1175 "  --delete  -D chain rulenum\n"
1176 "				Delete rule rulenum (1 = first) from chain\n"
1177 "  --insert  -I chain [rulenum]\n"
1178 "				Insert in chain as rulenum (default 1=first)\n"
1179 "  --replace -R chain rulenum\n"
1180 "				Replace rule rulenum (1 = first) in chain\n"
1181 "  --list    -L [chain [rulenum]]\n"
1182 "				List the rules in a chain or all chains\n"
1183 "  --list-rules -S [chain [rulenum]]\n"
1184 "				Print the rules in a chain or all chains\n"
1185 "  --flush   -F [chain]		Delete all rules in  chain or all chains\n"
1186 "  --zero    -Z [chain [rulenum]]\n"
1187 "				Zero counters in chain or all chains\n"
1188 "  --new     -N chain		Create a new user-defined chain\n"
1189 "  --delete-chain\n"
1190 "            -X [chain]		Delete a user-defined chain\n"
1191 "  --policy  -P chain target\n"
1192 "				Change policy on chain to target\n"
1193 "  --rename-chain\n"
1194 "            -E old-chain new-chain\n"
1195 "				Change chain name, (moving any references)\n"
1196 "\n"
1197 "Options:\n");
1198 
1199 	if (afinfo->family == NFPROTO_ARP) {
1200 		printf(
1201 "[!] --source-ip	-s address[/mask]\n"
1202 "				source specification\n"
1203 "[!] --destination-ip -d address[/mask]\n"
1204 "				destination specification\n"
1205 "[!] --source-mac address[/mask]\n"
1206 "[!] --destination-mac address[/mask]\n"
1207 "    --h-length   -l   length[/mask] hardware length (nr of bytes)\n"
1208 "    --opcode code[/mask] operation code (2 bytes)\n"
1209 "    --h-type   type[/mask]  hardware type (2 bytes, hexadecimal)\n"
1210 "    --proto-type   type[/mask]  protocol type (2 bytes)\n");
1211 	} else {
1212 		printf(
1213 "    --ipv4	-4		%s (line is ignored by ip6tables-restore)\n"
1214 "    --ipv6	-6		%s (line is ignored by iptables-restore)\n"
1215 "[!] --protocol	-p proto	protocol: by number or name, eg. `tcp'\n"
1216 "[!] --source	-s address[/mask][...]\n"
1217 "				source specification\n"
1218 "[!] --destination -d address[/mask][...]\n"
1219 "				destination specification\n",
1220 		afinfo->family == NFPROTO_IPV4 ? "Nothing" : "Error",
1221 		afinfo->family == NFPROTO_IPV4 ? "Error" : "Nothing");
1222 	}
1223 
1224 	printf(
1225 "[!] --in-interface -i input name[+]\n"
1226 "				network interface name ([+] for wildcard)\n"
1227 " --jump	-j target\n"
1228 "				target for rule (may load target extension)\n");
1229 
1230 	if (0
1231 #ifdef IPT_F_GOTO
1232 	    || afinfo->family == NFPROTO_IPV4
1233 #endif
1234 #ifdef IP6T_F_GOTO
1235 	    || afinfo->family == NFPROTO_IPV6
1236 #endif
1237 	   )
1238 		printf(
1239 "  --goto      -g chain\n"
1240 "			       jump to chain with no return\n");
1241 	printf(
1242 "  --match	-m match\n"
1243 "				extended match (may load extension)\n"
1244 "  --numeric	-n		numeric output of addresses and ports\n"
1245 "[!] --out-interface -o output name[+]\n"
1246 "				network interface name ([+] for wildcard)\n"
1247 "  --table	-t table	table to manipulate (default: `filter')\n"
1248 "  --verbose	-v		verbose mode\n"
1249 "  --wait	-w [seconds]	maximum wait to acquire xtables lock before give up\n"
1250 "  --line-numbers		print line numbers when listing\n"
1251 "  --exact	-x		expand numbers (display exact values)\n");
1252 
1253 	if (afinfo->family == NFPROTO_IPV4)
1254 		printf(
1255 "[!] --fragment	-f		match second or further fragments only\n");
1256 
1257 	printf(
1258 "  --modprobe=<command>		try to insert modules using this command\n"
1259 "  --set-counters -c PKTS BYTES	set the counter during insert/append\n"
1260 "[!] --version	-V		print package version.\n");
1261 
1262 	if (afinfo->family == NFPROTO_ARP) {
1263 		int i;
1264 
1265 		printf(" opcode strings: \n");
1266 		for (i = 0; i < ARP_NUMOPCODES; i++)
1267 			printf(" %d = %s\n", i + 1, arp_opcodes[i]);
1268 		printf(
1269 	" hardware type string: 1 = Ethernet\n"
1270 	" protocol type string: 0x800 = IPv4\n");
1271 
1272 		xtables_find_target("standard", XTF_TRY_LOAD);
1273 		xtables_find_target("mangle", XTF_TRY_LOAD);
1274 		xtables_find_target("CLASSIFY", XTF_TRY_LOAD);
1275 		xtables_find_target("MARK", XTF_TRY_LOAD);
1276 	}
1277 
1278 	print_extension_helps(xtables_targets, matches);
1279 }
1280 
exit_tryhelp(int status,int line)1281 void exit_tryhelp(int status, int line)
1282 {
1283 	if (line != -1)
1284 		fprintf(stderr, "Error occurred at line: %d\n", line);
1285 	fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
1286 			xt_params->program_name, xt_params->program_name);
1287 	xtables_free_opts(1);
1288 	exit(status);
1289 }
1290 
check_empty_interface(struct xtables_args * args,const char * arg)1291 static void check_empty_interface(struct xtables_args *args, const char *arg)
1292 {
1293 	const char *msg = "Empty interface is likely to be undesired";
1294 
1295 	if (*arg != '\0')
1296 		return;
1297 
1298 	if (args->family != NFPROTO_ARP)
1299 		xtables_error(PARAMETER_PROBLEM, "%s", msg);
1300 
1301 	fprintf(stderr, "%s", msg);
1302 }
1303 
check_inverse(struct xtables_args * args,const char option[],bool * invert,int argc,char ** argv)1304 static void check_inverse(struct xtables_args *args, const char option[],
1305 			  bool *invert, int argc, char **argv)
1306 {
1307 	switch (args->family) {
1308 	case NFPROTO_ARP:
1309 	case NFPROTO_BRIDGE:
1310 		break;
1311 	default:
1312 		return;
1313 	}
1314 
1315 	if (!option || strcmp(option, "!"))
1316 		return;
1317 
1318 	fprintf(stderr, "Using intrapositioned negation (`--option ! this`) "
1319 		"is deprecated in favor of extrapositioned (`! --option this`).\n");
1320 
1321 	if (*invert)
1322 		xtables_error(PARAMETER_PROBLEM,
1323 			      "Multiple `!' flags not allowed");
1324 	*invert = true;
1325 	optind++;
1326 	if (optind > argc)
1327 		xtables_error(PARAMETER_PROBLEM, "no argument following `!'");
1328 
1329 	optarg = argv[optind - 1];
1330 }
1331 
optstring_lookup(int family)1332 static const char *optstring_lookup(int family)
1333 {
1334 	switch (family) {
1335 	case AF_INET:
1336 	case AF_INET6:
1337 		return IPT_OPTSTRING;
1338 	case NFPROTO_ARP:
1339 		return ARPT_OPTSTRING;
1340 	case NFPROTO_BRIDGE:
1341 		return EBT_OPTSTRING;
1342 	}
1343 	return "";
1344 }
1345 
xtables_clear_iptables_command_state(struct iptables_command_state * cs)1346 void xtables_clear_iptables_command_state(struct iptables_command_state *cs)
1347 {
1348 	xtables_rule_matches_free(&cs->matches);
1349 	if (cs->target) {
1350 		free(cs->target->t);
1351 		cs->target->t = NULL;
1352 
1353 		free(cs->target->udata);
1354 		cs->target->udata = NULL;
1355 
1356 		if (cs->target == cs->target->next) {
1357 			free(cs->target);
1358 			cs->target = NULL;
1359 		}
1360 	}
1361 }
1362 
iface_to_mask(const char * iface,unsigned char * mask)1363 void iface_to_mask(const char *iface, unsigned char *mask)
1364 {
1365 	unsigned int len = strlen(iface);
1366 
1367 	memset(mask, 0, IFNAMSIZ);
1368 
1369 	if (!len) {
1370 		return;
1371 	} else if (iface[len - 1] == '+') {
1372 		memset(mask, 0xff, len - 1);
1373 		/* Don't remove `+' here! -HW */
1374 	} else {
1375 		/* Include nul-terminator in match */
1376 		memset(mask, 0xff, len + 1);
1377 	}
1378 }
1379 
parse_interface(const char * arg,char * iface)1380 static void parse_interface(const char *arg, char *iface)
1381 {
1382 	unsigned int len = strlen(arg);
1383 
1384 	memset(iface, 0, IFNAMSIZ);
1385 
1386 	if (!len)
1387 		return;
1388 	if (len >= IFNAMSIZ)
1389 		xtables_error(PARAMETER_PROBLEM,
1390 			      "interface name `%s' must be shorter than %d characters",
1391 			      arg, IFNAMSIZ);
1392 
1393 	if (strchr(arg, '/') || strchr(arg, ' '))
1394 		fprintf(stderr,
1395 			"Warning: weird character in interface `%s' ('/' and ' ' are not allowed by the kernel).\n",
1396 			arg);
1397 
1398 	strcpy(iface, arg);
1399 }
1400 
1401 static bool
parse_signed_counter(char * argv,unsigned long long * val,uint8_t * ctr_op,uint8_t flag_inc,uint8_t flag_dec)1402 parse_signed_counter(char *argv, unsigned long long *val, uint8_t *ctr_op,
1403 		     uint8_t flag_inc, uint8_t flag_dec)
1404 {
1405 	char *endptr, *p = argv;
1406 
1407 	switch (*p) {
1408 	case '+':
1409 		*ctr_op |= flag_inc;
1410 		p++;
1411 		break;
1412 	case '-':
1413 		*ctr_op |= flag_dec;
1414 		p++;
1415 		break;
1416 	}
1417 	*val = strtoull(p, &endptr, 10);
1418 	return *endptr == '\0';
1419 }
1420 
parse_change_counters_rule(int argc,char ** argv,struct xt_cmd_parse * p,struct xtables_args * args)1421 static void parse_change_counters_rule(int argc, char **argv,
1422 				       struct xt_cmd_parse *p,
1423 				       struct xtables_args *args)
1424 {
1425 	if (optind + 1 >= argc ||
1426 	    (argv[optind][0] == '-' && !isdigit(argv[optind][1])) ||
1427 	    (argv[optind + 1][0] == '-' && !isdigit(argv[optind + 1][1])))
1428 		xtables_error(PARAMETER_PROBLEM,
1429 			      "The command -C needs at least 2 arguments");
1430 	if (optind + 2 < argc &&
1431 	    (argv[optind + 2][0] != '-' || isdigit(argv[optind + 2][1]))) {
1432 		if (optind + 3 != argc)
1433 			xtables_error(PARAMETER_PROBLEM,
1434 				      "No extra options allowed with -C start_nr[:end_nr] pcnt bcnt");
1435 		parse_rule_range(p, argv[optind++]);
1436 	}
1437 
1438 	if (!parse_signed_counter(argv[optind++], &args->pcnt_cnt,
1439 				  &args->counter_op,
1440 				  CTR_OP_INC_PKTS, CTR_OP_DEC_PKTS) ||
1441 	    !parse_signed_counter(argv[optind++], &args->bcnt_cnt,
1442 				  &args->counter_op,
1443 				  CTR_OP_INC_BYTES, CTR_OP_DEC_BYTES))
1444 		xtables_error(PARAMETER_PROBLEM,
1445 			      "Packet counter '%s' invalid", argv[optind - 1]);
1446 }
1447 
option_test_and_reject(struct xt_cmd_parse * p,struct iptables_command_state * cs,unsigned int option)1448 static void option_test_and_reject(struct xt_cmd_parse *p,
1449 				   struct iptables_command_state *cs,
1450 				   unsigned int option)
1451 {
1452 	if (cs->options & option)
1453 		xtables_error(PARAMETER_PROBLEM, "Can't use %s with %s",
1454 			      p->ops->option_name(option), p->chain);
1455 }
1456 
do_parse(int argc,char * argv[],struct xt_cmd_parse * p,struct iptables_command_state * cs,struct xtables_args * args)1457 void do_parse(int argc, char *argv[],
1458 	      struct xt_cmd_parse *p, struct iptables_command_state *cs,
1459 	      struct xtables_args *args)
1460 {
1461 	bool family_is_bridge = args->family == NFPROTO_BRIDGE;
1462 	struct xtables_match *m;
1463 	struct xtables_rule_match *matchp;
1464 	bool wait_interval_set = false;
1465 	struct xtables_target *t;
1466 	bool table_set = false;
1467 	bool invert = false;
1468 
1469 	/* re-set optind to 0 in case do_command4 gets called
1470 	 * a second time */
1471 	optind = 0;
1472 
1473 	/* clear mflags in case do_command4 gets called a second time
1474 	 * (we clear the global list of all matches for security)*/
1475 	for (m = xtables_matches; m; m = m->next)
1476 		m->mflags = 0;
1477 
1478 	for (t = xtables_targets; t; t = t->next) {
1479 		t->tflags = 0;
1480 		t->used = 0;
1481 	}
1482 
1483 	/* Suppress error messages: we may add new options if we
1484 	   demand-load a protocol. */
1485 	opterr = 0;
1486 
1487 	while ((cs->c = getopt_long(argc, argv,
1488 				    optstring_lookup(afinfo->family),
1489 				    xt_params->opts ?: xt_params->orig_opts,
1490 				    NULL)) != -1) {
1491 		switch (cs->c) {
1492 			/*
1493 			 * Command selection
1494 			 */
1495 		case 'A':
1496 			add_command(&p->command, CMD_APPEND, CMD_NONE, invert);
1497 			p->chain = optarg;
1498 			break;
1499 
1500 		case 'C':
1501 			if (family_is_bridge) {
1502 				add_command(&p->command, CMD_CHANGE_COUNTERS,
1503 					    CMD_NONE, invert);
1504 				p->chain = optarg;
1505 				parse_change_counters_rule(argc, argv, p, args);
1506 				break;
1507 			}
1508 			/* fall through */
1509 		case 14: /* ebtables --check */
1510 			add_command(&p->command, CMD_CHECK, CMD_NONE, invert);
1511 			p->chain = optarg;
1512 			break;
1513 
1514 		case 'D':
1515 			add_command(&p->command, CMD_DELETE, CMD_NONE, invert);
1516 			p->chain = optarg;
1517 			if (xs_has_arg(argc, argv)) {
1518 				parse_rule_range(p, argv[optind++]);
1519 				p->command = CMD_DELETE_NUM;
1520 			}
1521 			break;
1522 
1523 		case 'R':
1524 			add_command(&p->command, CMD_REPLACE, CMD_NONE, invert);
1525 			p->chain = optarg;
1526 			if (xs_has_arg(argc, argv))
1527 				p->rulenum = parse_rulenumber(argv[optind++]);
1528 			else
1529 				xtables_error(PARAMETER_PROBLEM,
1530 					   "-%c requires a rule number",
1531 					   cmd2char(CMD_REPLACE));
1532 			break;
1533 
1534 		case 'I':
1535 			add_command(&p->command, CMD_INSERT, CMD_NONE, invert);
1536 			p->chain = optarg;
1537 			if (xs_has_arg(argc, argv))
1538 				p->rulenum = parse_rulenumber(argv[optind++]);
1539 			else
1540 				p->rulenum = 1;
1541 			break;
1542 
1543 		case 'L':
1544 			add_command(&p->command, CMD_LIST,
1545 				    CMD_ZERO | CMD_ZERO_NUM, invert);
1546 			if (optarg)
1547 				p->chain = optarg;
1548 			else if (xs_has_arg(argc, argv))
1549 				p->chain = argv[optind++];
1550 			if (xs_has_arg(argc, argv))
1551 				p->rulenum = parse_rulenumber(argv[optind++]);
1552 			break;
1553 
1554 		case 'S':
1555 			add_command(&p->command, CMD_LIST_RULES,
1556 				    CMD_ZERO|CMD_ZERO_NUM, invert);
1557 			if (optarg)
1558 				p->chain = optarg;
1559 			else if (xs_has_arg(argc, argv))
1560 				p->chain = argv[optind++];
1561 			if (xs_has_arg(argc, argv))
1562 				p->rulenum = parse_rulenumber(argv[optind++]);
1563 			break;
1564 
1565 		case 'F':
1566 			add_command(&p->command, CMD_FLUSH, CMD_NONE, invert);
1567 			if (optarg)
1568 				p->chain = optarg;
1569 			else if (xs_has_arg(argc, argv))
1570 				p->chain = argv[optind++];
1571 			break;
1572 
1573 		case 'Z':
1574 			add_command(&p->command, CMD_ZERO,
1575 				    CMD_LIST|CMD_LIST_RULES, invert);
1576 			if (optarg)
1577 				p->chain = optarg;
1578 			else if (xs_has_arg(argc, argv))
1579 				p->chain = argv[optind++];
1580 			if (xs_has_arg(argc, argv)) {
1581 				p->rulenum = parse_rulenumber(argv[optind++]);
1582 				p->command = CMD_ZERO_NUM;
1583 			}
1584 			break;
1585 
1586 		case 'N':
1587 			assert_valid_chain_name(optarg);
1588 			add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
1589 				    invert);
1590 			p->chain = optarg;
1591 			break;
1592 
1593 		case 'X':
1594 			add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
1595 				    invert);
1596 			if (optarg)
1597 				p->chain = optarg;
1598 			else if (xs_has_arg(argc, argv))
1599 				p->chain = argv[optind++];
1600 			break;
1601 
1602 		case 'E':
1603 			add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
1604 				    invert);
1605 			p->chain = optarg;
1606 			if (xs_has_arg(argc, argv))
1607 				p->newname = argv[optind++];
1608 			else
1609 				xtables_error(PARAMETER_PROBLEM,
1610 					   "-%c requires old-chain-name and "
1611 					   "new-chain-name",
1612 					    cmd2char(CMD_RENAME_CHAIN));
1613 			assert_valid_chain_name(p->newname);
1614 			break;
1615 
1616 		case 'P':
1617 			add_command(&p->command, CMD_SET_POLICY,
1618 				    family_is_bridge ? CMD_NEW_CHAIN : CMD_NONE,
1619 				    invert);
1620 			if (p->command & CMD_NEW_CHAIN) {
1621 				p->policy = optarg;
1622 			} else if (xs_has_arg(argc, argv)) {
1623 				p->chain = optarg;
1624 				p->policy = argv[optind++];
1625 			} else {
1626 				xtables_error(PARAMETER_PROBLEM,
1627 					   "-%c requires a chain and a policy",
1628 					   cmd2char(CMD_SET_POLICY));
1629 			}
1630 			break;
1631 
1632 		case 'h':
1633 			/* iptables -p icmp -h */
1634 			if (!cs->matches && cs->protocol)
1635 				xtables_find_match(cs->protocol,
1636 					XTF_TRY_LOAD, &cs->matches);
1637 
1638 			p->ops->print_help(cs);
1639 			xtables_clear_iptables_command_state(cs);
1640 			xtables_free_opts(1);
1641 			xtables_fini();
1642 			exit(0);
1643 
1644 			/*
1645 			 * Option selection
1646 			 */
1647 		case 'p':
1648 			check_inverse(args, optarg, &invert, argc, argv);
1649 			set_option(p->ops, &cs->options, OPT_PROTOCOL,
1650 				   &args->invflags, invert);
1651 
1652 			/* Canonicalize into lower case */
1653 			for (cs->protocol = optarg;
1654 			     *cs->protocol; cs->protocol++)
1655 				*cs->protocol = tolower(*cs->protocol);
1656 
1657 			cs->protocol = optarg;
1658 
1659 			/* This needs to happen here to parse extensions */
1660 			if (p->ops->proto_parse)
1661 				p->ops->proto_parse(cs, args);
1662 			break;
1663 
1664 		case 's':
1665 			check_inverse(args, optarg, &invert, argc, argv);
1666 			set_option(p->ops, &cs->options, OPT_SOURCE,
1667 				   &args->invflags, invert);
1668 			args->shostnetworkmask = optarg;
1669 			break;
1670 
1671 		case 'd':
1672 			check_inverse(args, optarg, &invert, argc, argv);
1673 			set_option(p->ops, &cs->options, OPT_DESTINATION,
1674 				   &args->invflags, invert);
1675 			args->dhostnetworkmask = optarg;
1676 			break;
1677 
1678 #ifdef IPT_F_GOTO
1679 		case 'g':
1680 			set_option(p->ops, &cs->options, OPT_JUMP,
1681 				   &args->invflags, invert);
1682 			args->goto_set = true;
1683 			cs->jumpto = xt_parse_target(optarg);
1684 			break;
1685 #endif
1686 
1687 		case 2:/* src-mac */
1688 			check_inverse(args, optarg, &invert, argc, argv);
1689 			set_option(p->ops, &cs->options, OPT_S_MAC,
1690 				   &args->invflags, invert);
1691 			args->src_mac = optarg;
1692 			break;
1693 
1694 		case 3:/* dst-mac */
1695 			check_inverse(args, optarg, &invert, argc, argv);
1696 			set_option(p->ops, &cs->options, OPT_D_MAC,
1697 				   &args->invflags, invert);
1698 			args->dst_mac = optarg;
1699 			break;
1700 
1701 		case 'l':/* hardware length */
1702 			check_inverse(args, optarg, &invert, argc, argv);
1703 			set_option(p->ops, &cs->options, OPT_H_LENGTH,
1704 				   &args->invflags, invert);
1705 			args->arp_hlen = optarg;
1706 			break;
1707 
1708 		case 8: /* was never supported, not even in arptables-legacy */
1709 			xtables_error(PARAMETER_PROBLEM, "not supported");
1710 		case 4:/* opcode */
1711 			check_inverse(args, optarg, &invert, argc, argv);
1712 			set_option(p->ops, &cs->options, OPT_OPCODE,
1713 				   &args->invflags, invert);
1714 			args->arp_opcode = optarg;
1715 			break;
1716 
1717 		case 5:/* h-type */
1718 			check_inverse(args, optarg, &invert, argc, argv);
1719 			set_option(p->ops, &cs->options, OPT_H_TYPE,
1720 				   &args->invflags, invert);
1721 			args->arp_htype = optarg;
1722 			break;
1723 
1724 		case 6:/* proto-type */
1725 			check_inverse(args, optarg, &invert, argc, argv);
1726 			set_option(p->ops, &cs->options, OPT_P_TYPE,
1727 				   &args->invflags, invert);
1728 			args->arp_ptype = optarg;
1729 			break;
1730 
1731 		case 11: /* ebtables --init-table */
1732 			if (p->restore)
1733 				xtables_error(PARAMETER_PROBLEM,
1734 					      "--init-table is not supported in daemon mode");
1735 			add_command(&p->command, CMD_INIT_TABLE, CMD_NONE, invert);
1736 			break;
1737 
1738 		case 12 : /* ebtables --Lmac2 */
1739 			set_option(p->ops, &cs->options, OPT_LIST_MAC2,
1740 				   &args->invflags, invert);
1741 			break;
1742 
1743 		case 13 : /* ebtables --concurrent */
1744 			break;
1745 
1746 		case 15 : /* ebtables --logical-in */
1747 			check_inverse(args, optarg, &invert, argc, argv);
1748 			set_option(p->ops, &cs->options, OPT_LOGICALIN,
1749 				   &args->invflags, invert);
1750 			parse_interface(optarg, args->bri_iniface);
1751 			break;
1752 
1753 		case 16 : /* ebtables --logical-out */
1754 			check_inverse(args, optarg, &invert, argc, argv);
1755 			set_option(p->ops, &cs->options, OPT_LOGICALOUT,
1756 				   &args->invflags, invert);
1757 			parse_interface(optarg, args->bri_outiface);
1758 			break;
1759 
1760 		case 17 : /* ebtables --Lc */
1761 			set_option(p->ops, &cs->options, OPT_LIST_C,
1762 				   &args->invflags, invert);
1763 			break;
1764 
1765 		case 19 : /* ebtables --Lx */
1766 			set_option(p->ops, &cs->options, OPT_LIST_X,
1767 				   &args->invflags, invert);
1768 			break;
1769 
1770 		case 'j':
1771 			set_option(p->ops, &cs->options, OPT_JUMP,
1772 				   &args->invflags, invert);
1773 			if (strcmp(optarg, "CONTINUE"))
1774 				command_jump(cs, optarg);
1775 			break;
1776 
1777 		case 'i':
1778 			check_empty_interface(args, optarg);
1779 			check_inverse(args, optarg, &invert, argc, argv);
1780 			set_option(p->ops, &cs->options, OPT_VIANAMEIN,
1781 				   &args->invflags, invert);
1782 			parse_interface(optarg, args->iniface);
1783 			break;
1784 
1785 		case 'o':
1786 			check_empty_interface(args, optarg);
1787 			check_inverse(args, optarg, &invert, argc, argv);
1788 			set_option(p->ops, &cs->options, OPT_VIANAMEOUT,
1789 				   &args->invflags, invert);
1790 			parse_interface(optarg, args->outiface);
1791 			break;
1792 
1793 		case 'f':
1794 			if (args->family == AF_INET6) {
1795 				xtables_error(PARAMETER_PROBLEM,
1796 					"`-f' is not supported in IPv6, "
1797 					"use -m frag instead");
1798 			}
1799 			set_option(p->ops, &cs->options, OPT_FRAGMENT,
1800 				   &args->invflags, invert);
1801 			args->flags |= IPT_F_FRAG;
1802 			break;
1803 
1804 		case 'v':
1805 			if (!p->verbose)
1806 				set_option(p->ops, &cs->options, OPT_VERBOSE,
1807 					   &args->invflags, invert);
1808 			p->verbose++;
1809 			break;
1810 
1811 		case 'm':
1812 			command_match(cs, invert);
1813 			break;
1814 
1815 		case 'n':
1816 			set_option(p->ops, &cs->options, OPT_NUMERIC,
1817 				   &args->invflags, invert);
1818 			break;
1819 
1820 		case 't':
1821 			if (invert)
1822 				xtables_error(PARAMETER_PROBLEM,
1823 					   "unexpected ! flag before --table");
1824 			if (p->restore && table_set)
1825 				xtables_error(PARAMETER_PROBLEM,
1826 					      "The -t option cannot be used in %s.\n",
1827 					      xt_params->program_name);
1828 			p->table = optarg;
1829 			table_set = true;
1830 			break;
1831 
1832 		case 'x':
1833 			set_option(p->ops, &cs->options, OPT_EXPANDED,
1834 				   &args->invflags, invert);
1835 			break;
1836 
1837 		case 'V':
1838 			if (invert)
1839 				printf("Not %s ;-)\n",
1840 				       xt_params->program_version);
1841 			else
1842 				printf("%s v%s\n",
1843 				       xt_params->program_name,
1844 				       xt_params->program_version);
1845 			exit(0);
1846 
1847 		case 'w':
1848 			if (p->restore) {
1849 				xtables_error(PARAMETER_PROBLEM,
1850 					      "You cannot use `-w' from "
1851 					      "iptables-restore");
1852 			}
1853 
1854 			args->wait = parse_wait_time(argc, argv);
1855 			break;
1856 
1857 		case 'W':
1858 			if (p->restore) {
1859 				xtables_error(PARAMETER_PROBLEM,
1860 					      "You cannot use `-W' from "
1861 					      "iptables-restore");
1862 			}
1863 
1864 			parse_wait_interval(argc, argv);
1865 			wait_interval_set = true;
1866 			break;
1867 
1868 		case '0':
1869 		case 18 : /* ebtables --Ln */
1870 			set_option(p->ops, &cs->options, OPT_LINENUMBERS,
1871 				   &args->invflags, invert);
1872 			break;
1873 
1874 		case 'M':
1875 			xtables_modprobe_program = optarg;
1876 			break;
1877 
1878 		case 'c':
1879 			set_option(p->ops, &cs->options, OPT_COUNTERS,
1880 				   &args->invflags, invert);
1881 			args->pcnt = optarg;
1882 			args->bcnt = strchr(args->pcnt, ',');
1883 			if (args->bcnt)
1884 			    args->bcnt++;
1885 			if (!args->bcnt && xs_has_arg(argc, argv))
1886 				args->bcnt = argv[optind++];
1887 			if (!args->bcnt)
1888 				xtables_error(PARAMETER_PROBLEM,
1889 					      "%s requires packet and byte counter",
1890 					      p->ops->option_name(OPT_COUNTERS));
1891 
1892 			if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
1893 				xtables_error(PARAMETER_PROBLEM,
1894 					      "%s packet counter not numeric",
1895 					      p->ops->option_name(OPT_COUNTERS));
1896 
1897 			if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
1898 				xtables_error(PARAMETER_PROBLEM,
1899 					      "%s byte counter not numeric",
1900 					      p->ops->option_name(OPT_COUNTERS));
1901 			break;
1902 
1903 		case '4':
1904 			if (args->family == AF_INET)
1905 				break;
1906 
1907 			if (p->restore && args->family == AF_INET6)
1908 				return;
1909 
1910 			exit_tryhelp(2, p->line);
1911 
1912 		case '6':
1913 			if (args->family == AF_INET6)
1914 				break;
1915 
1916 			if (p->restore && args->family == AF_INET)
1917 				return;
1918 
1919 			exit_tryhelp(2, p->line);
1920 
1921 		case 1: /* non option */
1922 			if (optarg[0] == '!' && optarg[1] == '\0') {
1923 				if (invert)
1924 					xtables_error(PARAMETER_PROBLEM,
1925 						   "multiple consecutive ! not"
1926 						   " allowed");
1927 				invert = true;
1928 				optarg[0] = '\0';
1929 				continue;
1930 			}
1931 			fprintf(stderr, "Bad argument `%s'\n", optarg);
1932 			exit_tryhelp(2, p->line);
1933 
1934 		default:
1935 			check_inverse(args, optarg, &invert, argc, argv);
1936 			if (p->ops->command_default(cs, xt_params, invert))
1937 				/* cf. ip6tables.c */
1938 				continue;
1939 			break;
1940 		}
1941 		invert = false;
1942 	}
1943 
1944 	if (!family_is_bridge &&
1945 	    strcmp(p->table, "nat") == 0 &&
1946 	    ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
1947 	    (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
1948 		xtables_error(PARAMETER_PROBLEM,
1949 			"\nThe \"nat\" table is not intended for filtering, "
1950 			"the use of DROP is therefore inhibited.\n\n");
1951 
1952 	if (!args->wait && wait_interval_set)
1953 		xtables_error(PARAMETER_PROBLEM,
1954 			      "--wait-interval only makes sense with --wait\n");
1955 
1956 	for (matchp = cs->matches; matchp; matchp = matchp->next)
1957 		xtables_option_mfcall(matchp->match);
1958 	if (cs->target != NULL)
1959 		xtables_option_tfcall(cs->target);
1960 
1961 	/* Fix me: must put inverse options checking here --MN */
1962 
1963 	if (optind < argc)
1964 		xtables_error(PARAMETER_PROBLEM,
1965 			   "unknown arguments found on commandline");
1966 	if (!p->command)
1967 		xtables_error(PARAMETER_PROBLEM, "no command specified");
1968 	if (invert)
1969 		xtables_error(PARAMETER_PROBLEM,
1970 			   "nothing appropriate following !");
1971 
1972 	if (p->ops->post_parse)
1973 		p->ops->post_parse(p->command, cs, args);
1974 
1975 	generic_opt_check(p->ops, p->command, cs->options);
1976 
1977 	if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
1978 		xtables_error(PARAMETER_PROBLEM,
1979 			   "chain name `%s' too long (must be under %u chars)",
1980 			   p->chain, XT_EXTENSION_MAXNAMELEN);
1981 
1982 	if (p->command == CMD_APPEND ||
1983 	    p->command == CMD_DELETE ||
1984 	    p->command == CMD_CHECK ||
1985 	    p->command == CMD_INSERT ||
1986 	    p->command == CMD_REPLACE ||
1987 	    p->command == CMD_CHANGE_COUNTERS) {
1988 		if (strcmp(p->chain, "PREROUTING") == 0
1989 		    || strcmp(p->chain, "INPUT") == 0) {
1990 			/* -o not valid with incoming packets. */
1991 			option_test_and_reject(p, cs, OPT_VIANAMEOUT);
1992 			/* same with --logical-out */
1993 			option_test_and_reject(p, cs, OPT_LOGICALOUT);
1994 		}
1995 
1996 		if (strcmp(p->chain, "POSTROUTING") == 0
1997 		    || strcmp(p->chain, "OUTPUT") == 0) {
1998 			/* -i not valid with outgoing packets */
1999 			option_test_and_reject(p, cs, OPT_VIANAMEIN);
2000 			/* same with --logical-in */
2001 			option_test_and_reject(p, cs, OPT_LOGICALIN);
2002 		}
2003 	}
2004 }
2005 
ipv4_proto_parse(struct iptables_command_state * cs,struct xtables_args * args)2006 void ipv4_proto_parse(struct iptables_command_state *cs,
2007 		      struct xtables_args *args)
2008 {
2009 	cs->fw.ip.proto = xtables_parse_protocol(cs->protocol);
2010 
2011 	if (cs->fw.ip.proto == 0 &&
2012 	    (args->invflags & XT_INV_PROTO))
2013 		xtables_error(PARAMETER_PROBLEM,
2014 			      "rule would never match protocol");
2015 
2016 	cs->fw.ip.invflags = args->invflags;
2017 }
2018 
2019 /* These are invalid numbers as upper layer protocol */
is_exthdr(uint16_t proto)2020 static int is_exthdr(uint16_t proto)
2021 {
2022 	return (proto == IPPROTO_ROUTING ||
2023 		proto == IPPROTO_FRAGMENT ||
2024 		proto == IPPROTO_AH ||
2025 		proto == IPPROTO_DSTOPTS);
2026 }
2027 
ipv6_proto_parse(struct iptables_command_state * cs,struct xtables_args * args)2028 void ipv6_proto_parse(struct iptables_command_state *cs,
2029 		      struct xtables_args *args)
2030 {
2031 	cs->fw6.ipv6.proto = xtables_parse_protocol(cs->protocol);
2032 
2033 	if (cs->fw6.ipv6.proto == 0 &&
2034 	    (args->invflags & XT_INV_PROTO))
2035 		xtables_error(PARAMETER_PROBLEM,
2036 			      "rule would never match protocol");
2037 
2038 	cs->fw6.ipv6.invflags = args->invflags;
2039 
2040 	/* this is needed for ip6tables-legacy only */
2041 	args->flags |= IP6T_F_PROTO;
2042 	cs->fw6.ipv6.flags |= IP6T_F_PROTO;
2043 
2044 	if (is_exthdr(cs->fw6.ipv6.proto)
2045 	    && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0)
2046 		fprintf(stderr,
2047 			"Warning: never matched protocol: %s. "
2048 			"use extension match instead.\n",
2049 			cs->protocol);
2050 }
2051 
ipv4_post_parse(int command,struct iptables_command_state * cs,struct xtables_args * args)2052 void ipv4_post_parse(int command, struct iptables_command_state *cs,
2053 		     struct xtables_args *args)
2054 {
2055 	cs->fw.ip.flags = args->flags;
2056 	/* We already set invflags in proto_parse, but we need to refresh it
2057 	 * to include new parsed options.
2058 	 */
2059 	cs->fw.ip.invflags = args->invflags;
2060 
2061 	memcpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ);
2062 	memcpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ);
2063 
2064 	if (args->goto_set)
2065 		cs->fw.ip.flags |= IPT_F_GOTO;
2066 
2067 	/* nft-variants use cs->counters, legacy uses cs->fw.counters */
2068 	cs->counters.pcnt = args->pcnt_cnt;
2069 	cs->counters.bcnt = args->bcnt_cnt;
2070 	cs->fw.counters.pcnt = args->pcnt_cnt;
2071 	cs->fw.counters.bcnt = args->bcnt_cnt;
2072 
2073 	if (command & (CMD_REPLACE | CMD_INSERT |
2074 			CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
2075 		if (!(cs->options & OPT_DESTINATION))
2076 			args->dhostnetworkmask = "0.0.0.0/0";
2077 		if (!(cs->options & OPT_SOURCE))
2078 			args->shostnetworkmask = "0.0.0.0/0";
2079 	}
2080 
2081 	if (args->shostnetworkmask)
2082 		xtables_ipparse_multiple(args->shostnetworkmask,
2083 					 &args->s.addr.v4, &args->s.mask.v4,
2084 					 &args->s.naddrs);
2085 	if (args->dhostnetworkmask)
2086 		xtables_ipparse_multiple(args->dhostnetworkmask,
2087 					 &args->d.addr.v4, &args->d.mask.v4,
2088 					 &args->d.naddrs);
2089 
2090 	if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
2091 	    (cs->fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
2092 		xtables_error(PARAMETER_PROBLEM,
2093 			      "! not allowed with multiple"
2094 			      " source or destination IP addresses");
2095 }
2096 
ipv6_post_parse(int command,struct iptables_command_state * cs,struct xtables_args * args)2097 void ipv6_post_parse(int command, struct iptables_command_state *cs,
2098 		     struct xtables_args *args)
2099 {
2100 	cs->fw6.ipv6.flags = args->flags;
2101 	/* We already set invflags in proto_parse, but we need to refresh it
2102 	 * to include new parsed options.
2103 	 */
2104 	cs->fw6.ipv6.invflags = args->invflags;
2105 
2106 	memcpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ);
2107 	memcpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ);
2108 
2109 	if (args->goto_set)
2110 		cs->fw6.ipv6.flags |= IP6T_F_GOTO;
2111 
2112 	/* nft-variants use cs->counters, legacy uses cs->fw6.counters */
2113 	cs->counters.pcnt = args->pcnt_cnt;
2114 	cs->counters.bcnt = args->bcnt_cnt;
2115 	cs->fw6.counters.pcnt = args->pcnt_cnt;
2116 	cs->fw6.counters.bcnt = args->bcnt_cnt;
2117 
2118 	if (command & (CMD_REPLACE | CMD_INSERT |
2119 			CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
2120 		if (!(cs->options & OPT_DESTINATION))
2121 			args->dhostnetworkmask = "::0/0";
2122 		if (!(cs->options & OPT_SOURCE))
2123 			args->shostnetworkmask = "::0/0";
2124 	}
2125 
2126 	if (args->shostnetworkmask)
2127 		xtables_ip6parse_multiple(args->shostnetworkmask,
2128 					  &args->s.addr.v6,
2129 					  &args->s.mask.v6,
2130 					  &args->s.naddrs);
2131 	if (args->dhostnetworkmask)
2132 		xtables_ip6parse_multiple(args->dhostnetworkmask,
2133 					  &args->d.addr.v6,
2134 					  &args->d.mask.v6,
2135 					  &args->d.naddrs);
2136 
2137 	if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
2138 	    (cs->fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
2139 		xtables_error(PARAMETER_PROBLEM,
2140 			      "! not allowed with multiple"
2141 			      " source or destination IP addresses");
2142 }
2143 
2144 unsigned char *
make_delete_mask(const struct xtables_rule_match * matches,const struct xtables_target * target,size_t entry_size)2145 make_delete_mask(const struct xtables_rule_match *matches,
2146 		 const struct xtables_target *target,
2147 		 size_t entry_size)
2148 {
2149 	/* Establish mask for comparison */
2150 	unsigned int size = entry_size;
2151 	const struct xtables_rule_match *matchp;
2152 	unsigned char *mask, *mptr;
2153 
2154 	for (matchp = matches; matchp; matchp = matchp->next)
2155 		size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
2156 
2157 	mask = xtables_calloc(1, size
2158 			 + XT_ALIGN(sizeof(struct xt_entry_target))
2159 			 + target->size);
2160 
2161 	memset(mask, 0xFF, entry_size);
2162 	mptr = mask + entry_size;
2163 
2164 	for (matchp = matches; matchp; matchp = matchp->next) {
2165 		memset(mptr, 0xFF,
2166 		       XT_ALIGN(sizeof(struct xt_entry_match))
2167 		       + matchp->match->userspacesize);
2168 		mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
2169 	}
2170 
2171 	memset(mptr, 0xFF,
2172 	       XT_ALIGN(sizeof(struct xt_entry_target))
2173 	       + target->userspacesize);
2174 
2175 	return mask;
2176 }
2177 
xtables_clear_args(struct xtables_args * args)2178 void xtables_clear_args(struct xtables_args *args)
2179 {
2180 	free(args->s.addr.ptr);
2181 	free(args->s.mask.ptr);
2182 	free(args->d.addr.ptr);
2183 	free(args->d.mask.ptr);
2184 }
2185