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(¶m, 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(¶m, 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(¶m, 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