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 const char *lock_file;
253 int fd, i = 0;
254
255 time_left.tv_sec = wait;
256 time_left.tv_usec = 0;
257
258 lock_file = getenv("XTABLES_LOCKFILE");
259 if (lock_file == NULL || lock_file[0] == '\0')
260 lock_file = XT_LOCK_NAME;
261
262 fd = open(lock_file, O_CREAT, 0600);
263 if (fd < 0) {
264 fprintf(stderr, "Fatal: can't open lock file %s: %s\n",
265 lock_file, strerror(errno));
266 return XT_LOCK_FAILED;
267 }
268
269 if (wait == -1) {
270 if (flock(fd, LOCK_EX) == 0)
271 return fd;
272
273 fprintf(stderr, "Can't lock %s: %s\n", lock_file,
274 strerror(errno));
275 return XT_LOCK_BUSY;
276 }
277
278 while (1) {
279 if (flock(fd, LOCK_EX | LOCK_NB) == 0)
280 return fd;
281 else if (timercmp(&time_left, wait_interval, <))
282 return XT_LOCK_BUSY;
283
284 if (++i % 10 == 0) {
285 fprintf(stderr, "Another app is currently holding the xtables lock; "
286 "still %lds %ldus time ahead to have a chance to grab the lock...\n",
287 time_left.tv_sec, time_left.tv_usec);
288 }
289
290 wait_time = *wait_interval;
291 select(0, NULL, NULL, NULL, &wait_time);
292 timersub(&time_left, wait_interval, &time_left);
293 }
294 }
295
xtables_unlock(int lock)296 void xtables_unlock(int lock)
297 {
298 if (lock >= 0)
299 close(lock);
300 }
301
xtables_lock_or_exit(int wait,struct timeval * wait_interval)302 int xtables_lock_or_exit(int wait, struct timeval *wait_interval)
303 {
304 int lock = xtables_lock(wait, wait_interval);
305
306 if (lock == XT_LOCK_FAILED) {
307 xtables_free_opts(1);
308 exit(RESOURCE_PROBLEM);
309 }
310
311 if (lock == XT_LOCK_BUSY) {
312 fprintf(stderr, "Another app is currently holding the xtables lock. ");
313 if (wait == 0)
314 fprintf(stderr, "Perhaps you want to use the -w option?\n");
315 else
316 fprintf(stderr, "Stopped waiting after %ds.\n", wait);
317 xtables_free_opts(1);
318 exit(RESOURCE_PROBLEM);
319 }
320
321 return lock;
322 }
323
parse_wait_time(int argc,char * argv[])324 int parse_wait_time(int argc, char *argv[])
325 {
326 int wait = -1;
327
328 if (optarg) {
329 if (sscanf(optarg, "%i", &wait) != 1)
330 xtables_error(PARAMETER_PROBLEM,
331 "wait seconds not numeric");
332 } else if (xs_has_arg(argc, argv))
333 if (sscanf(argv[optind++], "%i", &wait) != 1)
334 xtables_error(PARAMETER_PROBLEM,
335 "wait seconds not numeric");
336
337 return wait;
338 }
339
parse_wait_interval(int argc,char * argv[],struct timeval * wait_interval)340 void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval)
341 {
342 const char *arg;
343 unsigned int usec;
344 int ret;
345
346 if (optarg)
347 arg = optarg;
348 else if (xs_has_arg(argc, argv))
349 arg = argv[optind++];
350 else
351 xtables_error(PARAMETER_PROBLEM, "wait interval value required");
352
353 ret = sscanf(arg, "%u", &usec);
354 if (ret == 1) {
355 if (usec > 999999)
356 xtables_error(PARAMETER_PROBLEM,
357 "too long usec wait %u > 999999 usec",
358 usec);
359
360 wait_interval->tv_sec = 0;
361 wait_interval->tv_usec = usec;
362 return;
363 }
364 xtables_error(PARAMETER_PROBLEM, "wait interval not numeric");
365 }
366
parse_counters(const char * string,struct xt_counters * ctr)367 int parse_counters(const char *string, struct xt_counters *ctr)
368 {
369 int ret;
370
371 if (!string)
372 return 0;
373
374 ret = sscanf(string, "[%llu:%llu]",
375 (unsigned long long *)&ctr->pcnt,
376 (unsigned long long *)&ctr->bcnt);
377
378 return ret == 2;
379 }
380
381 /* Tokenize counters argument of typical iptables-restore format rule.
382 *
383 * If *bufferp contains counters, update *pcntp and *bcntp to point at them,
384 * change bytes after counters in *bufferp to nul-bytes, update *bufferp to
385 * point to after the counters and return true.
386 * If *bufferp does not contain counters, return false.
387 * If syntax is wrong in *bufferp, call xtables_error() and hence exit().
388 * */
tokenize_rule_counters(char ** bufferp,char ** pcntp,char ** bcntp,int line)389 bool tokenize_rule_counters(char **bufferp, char **pcntp, char **bcntp, int line)
390 {
391 char *ptr, *buffer = *bufferp, *pcnt, *bcnt;
392
393 if (buffer[0] != '[')
394 return false;
395
396 /* we have counters in our input */
397
398 ptr = strchr(buffer, ']');
399 if (!ptr)
400 xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
401
402 pcnt = strtok(buffer+1, ":");
403 if (!pcnt)
404 xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line);
405
406 bcnt = strtok(NULL, "]");
407 if (!bcnt)
408 xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
409
410 *pcntp = pcnt;
411 *bcntp = bcnt;
412 /* start command parsing after counter */
413 *bufferp = ptr + 1;
414
415 return true;
416 }
417
xs_has_arg(int argc,char * argv[])418 inline bool xs_has_arg(int argc, char *argv[])
419 {
420 return optind < argc &&
421 argv[optind][0] != '-' &&
422 argv[optind][0] != '!';
423 }
424
425 /* function adding one argument to store, updating argc
426 * returns if argument added, does not return otherwise */
add_argv(struct argv_store * store,const char * what,int quoted)427 void add_argv(struct argv_store *store, const char *what, int quoted)
428 {
429 DEBUGP("add_argv: %s\n", what);
430
431 if (store->argc + 1 >= MAX_ARGC)
432 xtables_error(PARAMETER_PROBLEM,
433 "Parser cannot handle more arguments\n");
434 if (!what)
435 xtables_error(PARAMETER_PROBLEM,
436 "Trying to store NULL argument\n");
437
438 store->argv[store->argc] = strdup(what);
439 store->argvattr[store->argc] = quoted;
440 store->argv[++store->argc] = NULL;
441 }
442
free_argv(struct argv_store * store)443 void free_argv(struct argv_store *store)
444 {
445 while (store->argc) {
446 store->argc--;
447 free(store->argv[store->argc]);
448 store->argvattr[store->argc] = 0;
449 }
450 }
451
452 /* Save parsed rule for comparison with next rule to perform action aggregation
453 * on duplicate conditions.
454 */
save_argv(struct argv_store * dst,struct argv_store * src)455 void save_argv(struct argv_store *dst, struct argv_store *src)
456 {
457 int i;
458
459 free_argv(dst);
460 for (i = 0; i < src->argc; i++) {
461 dst->argvattr[i] = src->argvattr[i];
462 dst->argv[i] = src->argv[i];
463 src->argv[i] = NULL;
464 }
465 dst->argc = src->argc;
466 src->argc = 0;
467 }
468
469 struct xt_param_buf {
470 char buffer[1024];
471 int len;
472 };
473
add_param(struct xt_param_buf * param,const char * curchar)474 static void add_param(struct xt_param_buf *param, const char *curchar)
475 {
476 param->buffer[param->len++] = *curchar;
477 if (param->len >= sizeof(param->buffer))
478 xtables_error(PARAMETER_PROBLEM,
479 "Parameter too long!");
480 }
481
add_param_to_argv(struct argv_store * store,char * parsestart,int line)482 void add_param_to_argv(struct argv_store *store, char *parsestart, int line)
483 {
484 int quote_open = 0, escaped = 0, quoted = 0;
485 struct xt_param_buf param = {};
486 char *curchar;
487
488 /* After fighting with strtok enough, here's now
489 * a 'real' parser. According to Rusty I'm now no
490 * longer a real hacker, but I can live with that */
491
492 for (curchar = parsestart; *curchar; curchar++) {
493 if (quote_open) {
494 if (escaped) {
495 add_param(¶m, curchar);
496 escaped = 0;
497 continue;
498 } else if (*curchar == '\\') {
499 escaped = 1;
500 continue;
501 } else if (*curchar == '"') {
502 quote_open = 0;
503 } else {
504 add_param(¶m, curchar);
505 continue;
506 }
507 } else {
508 if (*curchar == '"') {
509 quote_open = 1;
510 quoted = 1;
511 continue;
512 }
513 }
514
515 switch (*curchar) {
516 case '"':
517 break;
518 case ' ':
519 case '\t':
520 case '\n':
521 if (!param.len) {
522 /* two spaces? */
523 continue;
524 }
525 break;
526 default:
527 /* regular character, copy to buffer */
528 add_param(¶m, curchar);
529 continue;
530 }
531
532 param.buffer[param.len] = '\0';
533 add_argv(store, param.buffer, quoted);
534 param.len = 0;
535 quoted = 0;
536 }
537 if (param.len) {
538 param.buffer[param.len] = '\0';
539 add_argv(store, param.buffer, 0);
540 }
541 }
542
543 #ifdef DEBUG
debug_print_argv(struct argv_store * store)544 void debug_print_argv(struct argv_store *store)
545 {
546 int i;
547
548 for (i = 0; i < store->argc; i++)
549 fprintf(stderr, "argv[%d]: %s\n", i, store->argv[i]);
550 }
551 #endif
552
ipv4_addr_to_string(const struct in_addr * addr,const struct in_addr * mask,unsigned int format)553 static const char *ipv4_addr_to_string(const struct in_addr *addr,
554 const struct in_addr *mask,
555 unsigned int format)
556 {
557 static char buf[BUFSIZ];
558
559 if (!mask->s_addr && !(format & FMT_NUMERIC))
560 return "anywhere";
561
562 if (format & FMT_NUMERIC)
563 strncpy(buf, xtables_ipaddr_to_numeric(addr), BUFSIZ - 1);
564 else
565 strncpy(buf, xtables_ipaddr_to_anyname(addr), BUFSIZ - 1);
566 buf[BUFSIZ - 1] = '\0';
567
568 strncat(buf, xtables_ipmask_to_numeric(mask),
569 BUFSIZ - strlen(buf) - 1);
570
571 return buf;
572 }
573
print_ipv4_addresses(const struct ipt_entry * fw,unsigned int format)574 void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format)
575 {
576 fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
577 printf(FMT("%-19s ", "%s "),
578 ipv4_addr_to_string(&fw->ip.src, &fw->ip.smsk, format));
579
580 fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
581 printf(FMT("%-19s ", "-> %s"),
582 ipv4_addr_to_string(&fw->ip.dst, &fw->ip.dmsk, format));
583 }
584
ipv6_addr_to_string(const struct in6_addr * addr,const struct in6_addr * mask,unsigned int format)585 static const char *ipv6_addr_to_string(const struct in6_addr *addr,
586 const struct in6_addr *mask,
587 unsigned int format)
588 {
589 static char buf[BUFSIZ];
590
591 if (IN6_IS_ADDR_UNSPECIFIED(addr) && !(format & FMT_NUMERIC))
592 return "anywhere";
593
594 if (format & FMT_NUMERIC)
595 strncpy(buf, xtables_ip6addr_to_numeric(addr), BUFSIZ - 1);
596 else
597 strncpy(buf, xtables_ip6addr_to_anyname(addr), BUFSIZ - 1);
598 buf[BUFSIZ - 1] = '\0';
599
600 strncat(buf, xtables_ip6mask_to_numeric(mask),
601 BUFSIZ - strlen(buf) - 1);
602
603 return buf;
604 }
605
print_ipv6_addresses(const struct ip6t_entry * fw6,unsigned int format)606 void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format)
607 {
608 fputc(fw6->ipv6.invflags & IP6T_INV_SRCIP ? '!' : ' ', stdout);
609 printf(FMT("%-19s ", "%s "),
610 ipv6_addr_to_string(&fw6->ipv6.src,
611 &fw6->ipv6.smsk, format));
612
613 fputc(fw6->ipv6.invflags & IP6T_INV_DSTIP ? '!' : ' ', stdout);
614 printf(FMT("%-19s ", "-> %s"),
615 ipv6_addr_to_string(&fw6->ipv6.dst,
616 &fw6->ipv6.dmsk, format));
617 }
618
619 /* Luckily, IPT_INV_VIA_IN and IPT_INV_VIA_OUT
620 * have the same values as IP6T_INV_VIA_IN and IP6T_INV_VIA_OUT
621 * so this function serves for both iptables and ip6tables */
print_ifaces(const char * iniface,const char * outiface,uint8_t invflags,unsigned int format)622 void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
623 unsigned int format)
624 {
625 const char *anyname = format & FMT_NUMERIC ? "*" : "any";
626 char iface[IFNAMSIZ + 2];
627
628 if (!(format & FMT_VIA))
629 return;
630
631 snprintf(iface, IFNAMSIZ + 2, "%s%s",
632 invflags & IPT_INV_VIA_IN ? "!" : "",
633 iniface[0] != '\0' ? iniface : anyname);
634
635 printf(FMT(" %-6s ", "in %s "), iface);
636
637 snprintf(iface, IFNAMSIZ + 2, "%s%s",
638 invflags & IPT_INV_VIA_OUT ? "!" : "",
639 outiface[0] != '\0' ? outiface : anyname);
640
641 printf(FMT("%-6s ", "out %s "), iface);
642 }
643
command_match(struct iptables_command_state * cs)644 void command_match(struct iptables_command_state *cs)
645 {
646 struct option *opts = xt_params->opts;
647 struct xtables_match *m;
648 size_t size;
649
650 if (cs->invert)
651 xtables_error(PARAMETER_PROBLEM,
652 "unexpected ! flag before --match");
653
654 m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches);
655 size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
656 m->m = xtables_calloc(1, size);
657 m->m->u.match_size = size;
658 if (m->real_name == NULL) {
659 strcpy(m->m->u.user.name, m->name);
660 } else {
661 strcpy(m->m->u.user.name, m->real_name);
662 if (!(m->ext_flags & XTABLES_EXT_ALIAS))
663 fprintf(stderr, "Notice: the %s match is converted into %s match "
664 "in rule listing and saving.\n", m->name, m->real_name);
665 }
666 m->m->u.user.revision = m->revision;
667 xs_init_match(m);
668 if (m == m->next)
669 return;
670 /* Merge options for non-cloned matches */
671 if (m->x6_options != NULL)
672 opts = xtables_options_xfrm(xt_params->orig_opts, opts,
673 m->x6_options, &m->option_offset);
674 else if (m->extra_opts != NULL)
675 opts = xtables_merge_options(xt_params->orig_opts, opts,
676 m->extra_opts, &m->option_offset);
677 if (opts == NULL)
678 xtables_error(OTHER_PROBLEM, "can't alloc memory!");
679 xt_params->opts = opts;
680 }
681
xt_parse_target(const char * targetname)682 const char *xt_parse_target(const char *targetname)
683 {
684 const char *ptr;
685
686 if (strlen(targetname) < 1)
687 xtables_error(PARAMETER_PROBLEM,
688 "Invalid target name (too short)");
689
690 if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN)
691 xtables_error(PARAMETER_PROBLEM,
692 "Invalid target name `%s' (%u chars max)",
693 targetname, XT_EXTENSION_MAXNAMELEN - 1);
694
695 for (ptr = targetname; *ptr; ptr++)
696 if (isspace(*ptr))
697 xtables_error(PARAMETER_PROBLEM,
698 "Invalid target name `%s'", targetname);
699 return targetname;
700 }
701
command_jump(struct iptables_command_state * cs,const char * jumpto)702 void command_jump(struct iptables_command_state *cs, const char *jumpto)
703 {
704 struct option *opts = xt_params->opts;
705 size_t size;
706
707 cs->jumpto = xt_parse_target(jumpto);
708 /* TRY_LOAD (may be chain name) */
709 cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
710
711 if (cs->target == NULL)
712 return;
713
714 size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
715
716 cs->target->t = xtables_calloc(1, size);
717 cs->target->t->u.target_size = size;
718 if (cs->target->real_name == NULL) {
719 strcpy(cs->target->t->u.user.name, cs->jumpto);
720 } else {
721 /* Alias support for userspace side */
722 strcpy(cs->target->t->u.user.name, cs->target->real_name);
723 if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS))
724 fprintf(stderr, "Notice: The %s target is converted into %s target "
725 "in rule listing and saving.\n",
726 cs->jumpto, cs->target->real_name);
727 }
728 cs->target->t->u.user.revision = cs->target->revision;
729 xs_init_target(cs->target);
730
731 if (cs->target->x6_options != NULL)
732 opts = xtables_options_xfrm(xt_params->orig_opts, opts,
733 cs->target->x6_options,
734 &cs->target->option_offset);
735 else
736 opts = xtables_merge_options(xt_params->orig_opts, opts,
737 cs->target->extra_opts,
738 &cs->target->option_offset);
739 if (opts == NULL)
740 xtables_error(OTHER_PROBLEM, "can't alloc memory!");
741 xt_params->opts = opts;
742 }
743
cmd2char(int option)744 char cmd2char(int option)
745 {
746 /* cmdflags index corresponds with position of bit in CMD_* values */
747 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
748 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
749 int i;
750
751 for (i = 0; option > 1; option >>= 1, i++)
752 ;
753 if (i >= ARRAY_SIZE(cmdflags))
754 xtables_error(OTHER_PROBLEM,
755 "cmd2char(): Invalid command number %u.\n",
756 1 << i);
757 return cmdflags[i];
758 }
759
add_command(unsigned int * cmd,const int newcmd,const int othercmds,int invert)760 void add_command(unsigned int *cmd, const int newcmd,
761 const int othercmds, int invert)
762 {
763 if (invert)
764 xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag");
765 if (*cmd & (~othercmds))
766 xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
767 cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
768 *cmd |= newcmd;
769 }
770
771 /* Can't be zero. */
parse_rulenumber(const char * rule)772 int parse_rulenumber(const char *rule)
773 {
774 unsigned int rulenum;
775
776 if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
777 xtables_error(PARAMETER_PROBLEM,
778 "Invalid rule number `%s'", rule);
779
780 return rulenum;
781 }
782
783 /* Table of legal combinations of commands and options. If any of the
784 * given commands make an option legal, that option is legal (applies to
785 * CMD_LIST and CMD_ZERO only).
786 * Key:
787 * + compulsory
788 * x illegal
789 * optional
790 */
791 static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
792 /* Well, it's better than "Re: Linux vs FreeBSD" */
793 {
794 /* -n -s -d -p -j -v -x -i -o --line -c -f 2 3 l 4 5 6 */
795 /*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
796 /*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
797 /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
798 /*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
799 /*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
800 /*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x','x','x','x','x','x','x'},
801 /*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
802 /*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
803 /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
804 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
805 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x','x','x','x','x','x','x'},
806 /*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
807 /*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
808 /*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
809 /*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
810 };
811
generic_opt_check(int command,int options)812 void generic_opt_check(int command, int options)
813 {
814 int i, j, legal = 0;
815
816 /* Check that commands are valid with options. Complicated by the
817 * fact that if an option is legal with *any* command given, it is
818 * legal overall (ie. -z and -l).
819 */
820 for (i = 0; i < NUMBER_OF_OPT; i++) {
821 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
822
823 for (j = 0; j < NUMBER_OF_CMD; j++) {
824 if (!(command & (1<<j)))
825 continue;
826
827 if (!(options & (1<<i))) {
828 if (commands_v_options[j][i] == '+')
829 xtables_error(PARAMETER_PROBLEM,
830 "You need to supply the `-%c' "
831 "option for this command\n",
832 optflags[i]);
833 } else {
834 if (commands_v_options[j][i] != 'x')
835 legal = 1;
836 else if (legal == 0)
837 legal = -1;
838 }
839 }
840 if (legal == -1)
841 xtables_error(PARAMETER_PROBLEM,
842 "Illegal option `-%c' with this command\n",
843 optflags[i]);
844 }
845 }
846
opt2char(int option)847 char opt2char(int option)
848 {
849 const char *ptr;
850
851 for (ptr = optflags; option > 1; option >>= 1, ptr++)
852 ;
853
854 return *ptr;
855 }
856