• 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 <sys/file.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15 #include <sys/time.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <xtables.h>
19 #include <math.h>
20 #include "xshared.h"
21 
22 /*
23  * Print out any special helps. A user might like to be able to add a --help
24  * to the commandline, and see expected results. So we call help for all
25  * specified matches and targets.
26  */
print_extension_helps(const struct xtables_target * t,const struct xtables_rule_match * m)27 void print_extension_helps(const struct xtables_target *t,
28     const struct xtables_rule_match *m)
29 {
30 	for (; t != NULL; t = t->next) {
31 		if (t->used) {
32 			printf("\n");
33 			if (t->help == NULL)
34 				printf("%s does not take any options\n",
35 				       t->name);
36 			else
37 				t->help();
38 		}
39 	}
40 	for (; m != NULL; m = m->next) {
41 		printf("\n");
42 		if (m->match->help == NULL)
43 			printf("%s does not take any options\n",
44 			       m->match->name);
45 		else
46 			m->match->help();
47 	}
48 }
49 
50 const char *
proto_to_name(uint8_t proto,int nolookup)51 proto_to_name(uint8_t proto, int nolookup)
52 {
53 	unsigned int i;
54 
55 	if (proto && !nolookup) {
56 		struct protoent *pent = getprotobynumber(proto);
57 		if (pent)
58 			return pent->p_name;
59 	}
60 
61 	for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
62 		if (xtables_chain_protos[i].num == proto)
63 			return xtables_chain_protos[i].name;
64 
65 	return NULL;
66 }
67 
68 static struct xtables_match *
find_proto(const char * pname,enum xtables_tryload tryload,int nolookup,struct xtables_rule_match ** matches)69 find_proto(const char *pname, enum xtables_tryload tryload,
70 	   int nolookup, struct xtables_rule_match **matches)
71 {
72 	unsigned int proto;
73 
74 	if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) {
75 		const char *protoname = proto_to_name(proto, nolookup);
76 
77 		if (protoname)
78 			return xtables_find_match(protoname, tryload, matches);
79 	} else
80 		return xtables_find_match(pname, tryload, matches);
81 
82 	return NULL;
83 }
84 
85 /*
86  * Some explanations (after four different bugs in 3 different releases): If
87  * we encounter a parameter, that has not been parsed yet, it's not an option
88  * of an explicitly loaded match or a target. However, we support implicit
89  * loading of the protocol match extension. '-p tcp' means 'l4 proto 6' and at
90  * the same time 'load tcp protocol match on demand if we specify --dport'.
91  *
92  * To make this work, we need to make sure:
93  * - the parameter has not been parsed by a match (m above)
94  * - a protocol has been specified
95  * - the protocol extension has not been loaded yet, or is loaded and unused
96  *   [think of ip6tables-restore!]
97  * - the protocol extension can be successively loaded
98  */
should_load_proto(struct iptables_command_state * cs)99 static bool should_load_proto(struct iptables_command_state *cs)
100 {
101 	if (cs->protocol == NULL)
102 		return false;
103 	if (find_proto(cs->protocol, XTF_DONT_LOAD,
104 	    cs->options & OPT_NUMERIC, NULL) == NULL)
105 		return true;
106 	return !cs->proto_used;
107 }
108 
load_proto(struct iptables_command_state * cs)109 struct xtables_match *load_proto(struct iptables_command_state *cs)
110 {
111 	if (!should_load_proto(cs))
112 		return NULL;
113 	return find_proto(cs->protocol, XTF_TRY_LOAD,
114 			  cs->options & OPT_NUMERIC, &cs->matches);
115 }
116 
command_default(struct iptables_command_state * cs,struct xtables_globals * gl)117 int command_default(struct iptables_command_state *cs,
118 		    struct xtables_globals *gl)
119 {
120 	struct xtables_rule_match *matchp;
121 	struct xtables_match *m;
122 
123 	if (cs->target != NULL &&
124 	    (cs->target->parse != NULL || cs->target->x6_parse != NULL) &&
125 	    cs->c >= cs->target->option_offset &&
126 	    cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) {
127 		xtables_option_tpcall(cs->c, cs->argv, cs->invert,
128 				      cs->target, &cs->fw);
129 		return 0;
130 	}
131 
132 	for (matchp = cs->matches; matchp; matchp = matchp->next) {
133 		m = matchp->match;
134 
135 		if (matchp->completed ||
136 		    (m->x6_parse == NULL && m->parse == NULL))
137 			continue;
138 		if (cs->c < matchp->match->option_offset ||
139 		    cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE)
140 			continue;
141 		xtables_option_mpcall(cs->c, cs->argv, cs->invert, m, &cs->fw);
142 		return 0;
143 	}
144 
145 	/* Try loading protocol */
146 	m = load_proto(cs);
147 	if (m != NULL) {
148 		size_t size;
149 
150 		cs->proto_used = 1;
151 
152 		size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
153 
154 		m->m = xtables_calloc(1, size);
155 		m->m->u.match_size = size;
156 		strcpy(m->m->u.user.name, m->name);
157 		m->m->u.user.revision = m->revision;
158 		xs_init_match(m);
159 
160 		if (m->x6_options != NULL)
161 			gl->opts = xtables_options_xfrm(gl->orig_opts,
162 							gl->opts,
163 							m->x6_options,
164 							&m->option_offset);
165 		else
166 			gl->opts = xtables_merge_options(gl->orig_opts,
167 							 gl->opts,
168 							 m->extra_opts,
169 							 &m->option_offset);
170 		if (gl->opts == NULL)
171 			xtables_error(OTHER_PROBLEM, "can't alloc memory!");
172 		optind--;
173 		/* Indicate to rerun getopt *immediately* */
174  		return 1;
175 	}
176 
177 	if (cs->c == ':')
178 		xtables_error(PARAMETER_PROBLEM, "option \"%s\" "
179 		              "requires an argument", cs->argv[optind-1]);
180 	if (cs->c == '?')
181 		xtables_error(PARAMETER_PROBLEM, "unknown option "
182 			      "\"%s\"", cs->argv[optind-1]);
183 	xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
184 }
185 
subcmd_get(const char * cmd,const struct subcommand * cb)186 static mainfunc_t subcmd_get(const char *cmd, const struct subcommand *cb)
187 {
188 	for (; cb->name != NULL; ++cb)
189 		if (strcmp(cb->name, cmd) == 0)
190 			return cb->main;
191 	return NULL;
192 }
193 
subcmd_main(int argc,char ** argv,const struct subcommand * cb)194 int subcmd_main(int argc, char **argv, const struct subcommand *cb)
195 {
196 	const char *cmd = basename(*argv);
197 	mainfunc_t f = subcmd_get(cmd, cb);
198 
199 	if (f == NULL && argc > 1) {
200 		/*
201 		 * Unable to find a main method for our command name?
202 		 * Let's try again with the first argument!
203 		 */
204 		++argv;
205 		--argc;
206 		f = subcmd_get(*argv, cb);
207 	}
208 
209 	/* now we should have a valid function pointer */
210 	if (f != NULL)
211 		return f(argc, argv);
212 
213 	fprintf(stderr, "ERROR: No valid subcommand given.\nValid subcommands:\n");
214 	for (; cb->name != NULL; ++cb)
215 		fprintf(stderr, " * %s\n", cb->name);
216 	exit(EXIT_FAILURE);
217 }
218 
xs_init_target(struct xtables_target * target)219 void xs_init_target(struct xtables_target *target)
220 {
221 	if (target->udata_size != 0) {
222 		free(target->udata);
223 		target->udata = calloc(1, target->udata_size);
224 		if (target->udata == NULL)
225 			xtables_error(RESOURCE_PROBLEM, "malloc");
226 	}
227 	if (target->init != NULL)
228 		target->init(target->t);
229 }
230 
xs_init_match(struct xtables_match * match)231 void xs_init_match(struct xtables_match *match)
232 {
233 	if (match->udata_size != 0) {
234 		/*
235 		 * As soon as a subsequent instance of the same match
236 		 * is used, e.g. "-m time -m time", the first instance
237 		 * is no longer reachable anyway, so we can free udata.
238 		 * Same goes for target.
239 		 */
240 		free(match->udata);
241 		match->udata = calloc(1, match->udata_size);
242 		if (match->udata == NULL)
243 			xtables_error(RESOURCE_PROBLEM, "malloc");
244 	}
245 	if (match->init != NULL)
246 		match->init(match->m);
247 }
248 
xtables_lock(int wait,struct timeval * wait_interval)249 static int xtables_lock(int wait, struct timeval *wait_interval)
250 {
251 	struct timeval time_left, wait_time;
252 	int fd, i = 0;
253 
254 	time_left.tv_sec = wait;
255 	time_left.tv_usec = 0;
256 
257 	fd = open(XT_LOCK_NAME, O_CREAT, 0600);
258 	if (fd < 0) {
259 		fprintf(stderr, "Fatal: can't open lock file %s: %s\n",
260 			XT_LOCK_NAME, strerror(errno));
261 		return XT_LOCK_FAILED;
262 	}
263 
264 	if (wait == -1) {
265 		if (flock(fd, LOCK_EX) == 0)
266 			return fd;
267 
268 		fprintf(stderr, "Can't lock %s: %s\n", XT_LOCK_NAME,
269 			strerror(errno));
270 		return XT_LOCK_BUSY;
271 	}
272 
273 	while (1) {
274 		if (flock(fd, LOCK_EX | LOCK_NB) == 0)
275 			return fd;
276 		else if (timercmp(&time_left, wait_interval, <))
277 			return XT_LOCK_BUSY;
278 
279 		if (++i % 10 == 0) {
280 			fprintf(stderr, "Another app is currently holding the xtables lock; "
281 				"still %lds %ldus time ahead to have a chance to grab the lock...\n",
282 				time_left.tv_sec, time_left.tv_usec);
283 		}
284 
285 		wait_time = *wait_interval;
286 		select(0, NULL, NULL, NULL, &wait_time);
287 		timersub(&time_left, wait_interval, &time_left);
288 	}
289 }
290 
xtables_unlock(int lock)291 void xtables_unlock(int lock)
292 {
293 	if (lock >= 0)
294 		close(lock);
295 }
296 
xtables_lock_or_exit(int wait,struct timeval * wait_interval)297 int xtables_lock_or_exit(int wait, struct timeval *wait_interval)
298 {
299 	int lock = xtables_lock(wait, wait_interval);
300 
301 	if (lock == XT_LOCK_FAILED) {
302 		xtables_free_opts(1);
303 		exit(RESOURCE_PROBLEM);
304 	}
305 
306 	if (lock == XT_LOCK_BUSY) {
307 		fprintf(stderr, "Another app is currently holding the xtables lock. ");
308 		if (wait == 0)
309 			fprintf(stderr, "Perhaps you want to use the -w option?\n");
310 		else
311 			fprintf(stderr, "Stopped waiting after %ds.\n", wait);
312 		xtables_free_opts(1);
313 		exit(RESOURCE_PROBLEM);
314 	}
315 
316 	return lock;
317 }
318 
parse_wait_time(int argc,char * argv[])319 int parse_wait_time(int argc, char *argv[])
320 {
321 	int wait = -1;
322 
323 	if (optarg) {
324 		if (sscanf(optarg, "%i", &wait) != 1)
325 			xtables_error(PARAMETER_PROBLEM,
326 				"wait seconds not numeric");
327 	} else if (xs_has_arg(argc, argv))
328 		if (sscanf(argv[optind++], "%i", &wait) != 1)
329 			xtables_error(PARAMETER_PROBLEM,
330 				"wait seconds not numeric");
331 
332 	return wait;
333 }
334 
parse_wait_interval(int argc,char * argv[],struct timeval * wait_interval)335 void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval)
336 {
337 	const char *arg;
338 	unsigned int usec;
339 	int ret;
340 
341 	if (optarg)
342 		arg = optarg;
343 	else if (xs_has_arg(argc, argv))
344 		arg = argv[optind++];
345 	else
346 		xtables_error(PARAMETER_PROBLEM, "wait interval value required");
347 
348 	ret = sscanf(arg, "%u", &usec);
349 	if (ret == 1) {
350 		if (usec > 999999)
351 			xtables_error(PARAMETER_PROBLEM,
352 				      "too long usec wait %u > 999999 usec",
353 				      usec);
354 
355 		wait_interval->tv_sec = 0;
356 		wait_interval->tv_usec = usec;
357 		return;
358 	}
359 	xtables_error(PARAMETER_PROBLEM, "wait interval not numeric");
360 }
361 
parse_counters(const char * string,struct xt_counters * ctr)362 int parse_counters(const char *string, struct xt_counters *ctr)
363 {
364 	int ret;
365 
366 	if (!string)
367 		return 0;
368 
369 	ret = sscanf(string, "[%llu:%llu]",
370 		     (unsigned long long *)&ctr->pcnt,
371 		     (unsigned long long *)&ctr->bcnt);
372 
373 	return ret == 2;
374 }
375 
376 /* Tokenize counters argument of typical iptables-restore format rule.
377  *
378  * If *bufferp contains counters, update *pcntp and *bcntp to point at them,
379  * change bytes after counters in *bufferp to nul-bytes, update *bufferp to
380  * point to after the counters and return true.
381  * If *bufferp does not contain counters, return false.
382  * If syntax is wrong in *bufferp, call xtables_error() and hence exit().
383  * */
tokenize_rule_counters(char ** bufferp,char ** pcntp,char ** bcntp,int line)384 bool tokenize_rule_counters(char **bufferp, char **pcntp, char **bcntp, int line)
385 {
386 	char *ptr, *buffer = *bufferp, *pcnt, *bcnt;
387 
388 	if (buffer[0] != '[')
389 		return false;
390 
391 	/* we have counters in our input */
392 
393 	ptr = strchr(buffer, ']');
394 	if (!ptr)
395 		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
396 
397 	pcnt = strtok(buffer+1, ":");
398 	if (!pcnt)
399 		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line);
400 
401 	bcnt = strtok(NULL, "]");
402 	if (!bcnt)
403 		xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
404 
405 	*pcntp = pcnt;
406 	*bcntp = bcnt;
407 	/* start command parsing after counter */
408 	*bufferp = ptr + 1;
409 
410 	return true;
411 }
412 
xs_has_arg(int argc,char * argv[])413 inline bool xs_has_arg(int argc, char *argv[])
414 {
415 	return optind < argc &&
416 	       argv[optind][0] != '-' &&
417 	       argv[optind][0] != '!';
418 }
419 
420 /* function adding one argument to store, updating argc
421  * returns if argument added, does not return otherwise */
add_argv(struct argv_store * store,const char * what,int quoted)422 void add_argv(struct argv_store *store, const char *what, int quoted)
423 {
424 	DEBUGP("add_argv: %s\n", what);
425 
426 	if (store->argc + 1 >= MAX_ARGC)
427 		xtables_error(PARAMETER_PROBLEM,
428 			      "Parser cannot handle more arguments\n");
429 	if (!what)
430 		xtables_error(PARAMETER_PROBLEM,
431 			      "Trying to store NULL argument\n");
432 
433 	store->argv[store->argc] = strdup(what);
434 	store->argvattr[store->argc] = quoted;
435 	store->argv[++store->argc] = NULL;
436 }
437 
free_argv(struct argv_store * store)438 void free_argv(struct argv_store *store)
439 {
440 	while (store->argc) {
441 		store->argc--;
442 		free(store->argv[store->argc]);
443 		store->argvattr[store->argc] = 0;
444 	}
445 }
446 
447 /* Save parsed rule for comparison with next rule to perform action aggregation
448  * on duplicate conditions.
449  */
save_argv(struct argv_store * dst,struct argv_store * src)450 void save_argv(struct argv_store *dst, struct argv_store *src)
451 {
452 	int i;
453 
454 	free_argv(dst);
455 	for (i = 0; i < src->argc; i++) {
456 		dst->argvattr[i] = src->argvattr[i];
457 		dst->argv[i] = src->argv[i];
458 		src->argv[i] = NULL;
459 	}
460 	dst->argc = src->argc;
461 	src->argc = 0;
462 }
463 
464 struct xt_param_buf {
465 	char	buffer[1024];
466 	int 	len;
467 };
468 
add_param(struct xt_param_buf * param,const char * curchar)469 static void add_param(struct xt_param_buf *param, const char *curchar)
470 {
471 	param->buffer[param->len++] = *curchar;
472 	if (param->len >= sizeof(param->buffer))
473 		xtables_error(PARAMETER_PROBLEM,
474 			      "Parameter too long!");
475 }
476 
add_param_to_argv(struct argv_store * store,char * parsestart,int line)477 void add_param_to_argv(struct argv_store *store, char *parsestart, int line)
478 {
479 	int quote_open = 0, escaped = 0, quoted = 0;
480 	struct xt_param_buf param = {};
481 	char *curchar;
482 
483 	/* After fighting with strtok enough, here's now
484 	 * a 'real' parser. According to Rusty I'm now no
485 	 * longer a real hacker, but I can live with that */
486 
487 	for (curchar = parsestart; *curchar; curchar++) {
488 		if (quote_open) {
489 			if (escaped) {
490 				add_param(&param, curchar);
491 				escaped = 0;
492 				continue;
493 			} else if (*curchar == '\\') {
494 				escaped = 1;
495 				continue;
496 			} else if (*curchar == '"') {
497 				quote_open = 0;
498 				*curchar = '"';
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 
ipv4_addr_to_string(const struct in_addr * addr,const struct in_addr * mask,unsigned int format)549 static const char *ipv4_addr_to_string(const struct in_addr *addr,
550 				       const struct in_addr *mask,
551 				       unsigned int format)
552 {
553 	static char buf[BUFSIZ];
554 
555 	if (!mask->s_addr && !(format & FMT_NUMERIC))
556 		return "anywhere";
557 
558 	if (format & FMT_NUMERIC)
559 		strncpy(buf, xtables_ipaddr_to_numeric(addr), BUFSIZ - 1);
560 	else
561 		strncpy(buf, xtables_ipaddr_to_anyname(addr), BUFSIZ - 1);
562 	buf[BUFSIZ - 1] = '\0';
563 
564 	strncat(buf, xtables_ipmask_to_numeric(mask),
565 		BUFSIZ - strlen(buf) - 1);
566 
567 	return buf;
568 }
569 
print_ipv4_addresses(const struct ipt_entry * fw,unsigned int format)570 void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format)
571 {
572 	fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
573 	printf(FMT("%-19s ", "%s "),
574 	       ipv4_addr_to_string(&fw->ip.src, &fw->ip.smsk, format));
575 
576 	fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
577 	printf(FMT("%-19s ", "-> %s"),
578 	       ipv4_addr_to_string(&fw->ip.dst, &fw->ip.dmsk, format));
579 }
580 
ipv6_addr_to_string(const struct in6_addr * addr,const struct in6_addr * mask,unsigned int format)581 static const char *ipv6_addr_to_string(const struct in6_addr *addr,
582 				       const struct in6_addr *mask,
583 				       unsigned int format)
584 {
585 	static char buf[BUFSIZ];
586 
587 	if (IN6_IS_ADDR_UNSPECIFIED(addr) && !(format & FMT_NUMERIC))
588 		return "anywhere";
589 
590 	if (format & FMT_NUMERIC)
591 		strncpy(buf, xtables_ip6addr_to_numeric(addr), BUFSIZ - 1);
592 	else
593 		strncpy(buf, xtables_ip6addr_to_anyname(addr), BUFSIZ - 1);
594 	buf[BUFSIZ - 1] = '\0';
595 
596 	strncat(buf, xtables_ip6mask_to_numeric(mask),
597 		BUFSIZ - strlen(buf) - 1);
598 
599 	return buf;
600 }
601 
print_ipv6_addresses(const struct ip6t_entry * fw6,unsigned int format)602 void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format)
603 {
604 	fputc(fw6->ipv6.invflags & IP6T_INV_SRCIP ? '!' : ' ', stdout);
605 	printf(FMT("%-19s ", "%s "),
606 	       ipv6_addr_to_string(&fw6->ipv6.src,
607 				   &fw6->ipv6.smsk, format));
608 
609 	fputc(fw6->ipv6.invflags & IP6T_INV_DSTIP ? '!' : ' ', stdout);
610 	printf(FMT("%-19s ", "-> %s"),
611 	       ipv6_addr_to_string(&fw6->ipv6.dst,
612 				   &fw6->ipv6.dmsk, format));
613 }
614 
615 /* Luckily, IPT_INV_VIA_IN and IPT_INV_VIA_OUT
616  * have the same values as IP6T_INV_VIA_IN and IP6T_INV_VIA_OUT
617  * so this function serves for both iptables and ip6tables */
print_ifaces(const char * iniface,const char * outiface,uint8_t invflags,unsigned int format)618 void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
619 		  unsigned int format)
620 {
621 	const char *anyname = format & FMT_NUMERIC ? "*" : "any";
622 	char iface[IFNAMSIZ + 2];
623 
624 	if (!(format & FMT_VIA))
625 		return;
626 
627 	snprintf(iface, IFNAMSIZ + 2, "%s%s",
628 		 invflags & IPT_INV_VIA_IN ? "!" : "",
629 		 iniface[0] != '\0' ? iniface : anyname);
630 
631 	printf(FMT(" %-6s ", "in %s "), iface);
632 
633 	snprintf(iface, IFNAMSIZ + 2, "%s%s",
634 		 invflags & IPT_INV_VIA_OUT ? "!" : "",
635 		 outiface[0] != '\0' ? outiface : anyname);
636 
637 	printf(FMT("%-6s ", "out %s "), iface);
638 }
639 
command_match(struct iptables_command_state * cs)640 void command_match(struct iptables_command_state *cs)
641 {
642 	struct option *opts = xt_params->opts;
643 	struct xtables_match *m;
644 	size_t size;
645 
646 	if (cs->invert)
647 		xtables_error(PARAMETER_PROBLEM,
648 			   "unexpected ! flag before --match");
649 
650 	m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches);
651 	size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
652 	m->m = xtables_calloc(1, size);
653 	m->m->u.match_size = size;
654 	if (m->real_name == NULL) {
655 		strcpy(m->m->u.user.name, m->name);
656 	} else {
657 		strcpy(m->m->u.user.name, m->real_name);
658 		if (!(m->ext_flags & XTABLES_EXT_ALIAS))
659 			fprintf(stderr, "Notice: the %s match is converted into %s match "
660 				"in rule listing and saving.\n", m->name, m->real_name);
661 	}
662 	m->m->u.user.revision = m->revision;
663 	xs_init_match(m);
664 	if (m == m->next)
665 		return;
666 	/* Merge options for non-cloned matches */
667 	if (m->x6_options != NULL)
668 		opts = xtables_options_xfrm(xt_params->orig_opts, opts,
669 					    m->x6_options, &m->option_offset);
670 	else if (m->extra_opts != NULL)
671 		opts = xtables_merge_options(xt_params->orig_opts, opts,
672 					     m->extra_opts, &m->option_offset);
673 	if (opts == NULL)
674 		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
675 	xt_params->opts = opts;
676 }
677 
xt_parse_target(const char * targetname)678 const char *xt_parse_target(const char *targetname)
679 {
680 	const char *ptr;
681 
682 	if (strlen(targetname) < 1)
683 		xtables_error(PARAMETER_PROBLEM,
684 			   "Invalid target name (too short)");
685 
686 	if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN)
687 		xtables_error(PARAMETER_PROBLEM,
688 			   "Invalid target name `%s' (%u chars max)",
689 			   targetname, XT_EXTENSION_MAXNAMELEN - 1);
690 
691 	for (ptr = targetname; *ptr; ptr++)
692 		if (isspace(*ptr))
693 			xtables_error(PARAMETER_PROBLEM,
694 				   "Invalid target name `%s'", targetname);
695 	return targetname;
696 }
697 
command_jump(struct iptables_command_state * cs,const char * jumpto)698 void command_jump(struct iptables_command_state *cs, const char *jumpto)
699 {
700 	struct option *opts = xt_params->opts;
701 	size_t size;
702 
703 	cs->jumpto = xt_parse_target(jumpto);
704 	/* TRY_LOAD (may be chain name) */
705 	cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
706 
707 	if (cs->target == NULL)
708 		return;
709 
710 	size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
711 
712 	cs->target->t = xtables_calloc(1, size);
713 	cs->target->t->u.target_size = size;
714 	if (cs->target->real_name == NULL) {
715 		strcpy(cs->target->t->u.user.name, cs->jumpto);
716 	} else {
717 		/* Alias support for userspace side */
718 		strcpy(cs->target->t->u.user.name, cs->target->real_name);
719 		if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS))
720 			fprintf(stderr, "Notice: The %s target is converted into %s target "
721 				"in rule listing and saving.\n",
722 				cs->jumpto, cs->target->real_name);
723 	}
724 	cs->target->t->u.user.revision = cs->target->revision;
725 	xs_init_target(cs->target);
726 
727 	if (cs->target->x6_options != NULL)
728 		opts = xtables_options_xfrm(xt_params->orig_opts, opts,
729 					    cs->target->x6_options,
730 					    &cs->target->option_offset);
731 	else
732 		opts = xtables_merge_options(xt_params->orig_opts, opts,
733 					     cs->target->extra_opts,
734 					     &cs->target->option_offset);
735 	if (opts == NULL)
736 		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
737 	xt_params->opts = opts;
738 }
739 
cmd2char(int option)740 char cmd2char(int option)
741 {
742 	/* cmdflags index corresponds with position of bit in CMD_* values */
743 	static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
744 					 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
745 	int i;
746 
747 	for (i = 0; option > 1; option >>= 1, i++)
748 		;
749 	if (i >= ARRAY_SIZE(cmdflags))
750 		xtables_error(OTHER_PROBLEM,
751 			      "cmd2char(): Invalid command number %u.\n",
752 			      1 << i);
753 	return cmdflags[i];
754 }
755 
add_command(unsigned int * cmd,const int newcmd,const int othercmds,int invert)756 void add_command(unsigned int *cmd, const int newcmd,
757 		 const int othercmds, int invert)
758 {
759 	if (invert)
760 		xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag");
761 	if (*cmd & (~othercmds))
762 		xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
763 			   cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
764 	*cmd |= newcmd;
765 }
766 
767 /* Can't be zero. */
parse_rulenumber(const char * rule)768 int parse_rulenumber(const char *rule)
769 {
770 	unsigned int rulenum;
771 
772 	if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
773 		xtables_error(PARAMETER_PROBLEM,
774 			   "Invalid rule number `%s'", rule);
775 
776 	return rulenum;
777 }
778