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 static 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 static 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 != -1) {
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) == 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(¶m, 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(¶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
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
760 /* This assumes that mask is contiguous, and byte-bounded. */
save_iface(char letter,const char * iface,const unsigned char * mask,int invert)761 void save_iface(char letter, const char *iface,
762 const unsigned char *mask, int invert)
763 {
764 unsigned int i;
765
766 if (mask[0] == 0)
767 return;
768
769 printf("%s -%c ", invert ? " !" : "", letter);
770
771 for (i = 0; i < IFNAMSIZ; i++) {
772 if (mask[i] != 0) {
773 if (iface[i] != '\0')
774 printf("%c", iface[i]);
775 } else {
776 /* we can access iface[i-1] here, because
777 * a few lines above we make sure that mask[0] != 0 */
778 if (iface[i-1] != '\0')
779 printf("+");
780 break;
781 }
782 }
783 }
784
command_match(struct iptables_command_state * cs,bool invert)785 static void command_match(struct iptables_command_state *cs, bool invert)
786 {
787 struct option *opts = xt_params->opts;
788 struct xtables_match *m;
789 size_t size;
790
791 if (invert)
792 xtables_error(PARAMETER_PROBLEM,
793 "unexpected ! flag before --match");
794
795 m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches);
796 size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
797 m->m = xtables_calloc(1, size);
798 m->m->u.match_size = size;
799 if (m->real_name == NULL) {
800 strcpy(m->m->u.user.name, m->name);
801 } else {
802 strcpy(m->m->u.user.name, m->real_name);
803 if (!(m->ext_flags & XTABLES_EXT_ALIAS))
804 fprintf(stderr, "Notice: the %s match is converted into %s match "
805 "in rule listing and saving.\n", m->name, m->real_name);
806 }
807 m->m->u.user.revision = m->revision;
808 xs_init_match(m);
809 if (m == m->next)
810 return;
811 /* Merge options for non-cloned matches */
812 if (m->x6_options != NULL)
813 opts = xtables_options_xfrm(xt_params->orig_opts, opts,
814 m->x6_options, &m->option_offset);
815 else if (m->extra_opts != NULL)
816 opts = xtables_merge_options(xt_params->orig_opts, opts,
817 m->extra_opts, &m->option_offset);
818 if (opts == NULL)
819 xtables_error(OTHER_PROBLEM, "can't alloc memory!");
820 xt_params->opts = opts;
821 }
822
xt_parse_target(const char * targetname)823 static const char *xt_parse_target(const char *targetname)
824 {
825 const char *ptr;
826
827 if (strlen(targetname) < 1)
828 xtables_error(PARAMETER_PROBLEM,
829 "Invalid target name (too short)");
830
831 if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN)
832 xtables_error(PARAMETER_PROBLEM,
833 "Invalid target name `%s' (%u chars max)",
834 targetname, XT_EXTENSION_MAXNAMELEN - 1);
835
836 for (ptr = targetname; *ptr; ptr++)
837 if (isspace(*ptr))
838 xtables_error(PARAMETER_PROBLEM,
839 "Invalid target name `%s'", targetname);
840 return targetname;
841 }
842
command_jump(struct iptables_command_state * cs,const char * jumpto)843 void command_jump(struct iptables_command_state *cs, const char *jumpto)
844 {
845 struct option *opts = xt_params->opts;
846 size_t size;
847
848 cs->jumpto = xt_parse_target(jumpto);
849 /* TRY_LOAD (may be chain name) */
850 cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
851
852 if (cs->target == NULL)
853 return;
854
855 size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
856
857 cs->target->t = xtables_calloc(1, size);
858 cs->target->t->u.target_size = size;
859 if (cs->target->real_name == NULL) {
860 strcpy(cs->target->t->u.user.name, cs->jumpto);
861 } else {
862 /* Alias support for userspace side */
863 strcpy(cs->target->t->u.user.name, cs->target->real_name);
864 if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS))
865 fprintf(stderr, "Notice: The %s target is converted into %s target "
866 "in rule listing and saving.\n",
867 cs->jumpto, cs->target->real_name);
868 }
869 cs->target->t->u.user.revision = cs->target->revision;
870 xs_init_target(cs->target);
871
872 if (cs->target->x6_options != NULL)
873 opts = xtables_options_xfrm(xt_params->orig_opts, opts,
874 cs->target->x6_options,
875 &cs->target->option_offset);
876 else
877 opts = xtables_merge_options(xt_params->orig_opts, opts,
878 cs->target->extra_opts,
879 &cs->target->option_offset);
880 if (opts == NULL)
881 xtables_error(OTHER_PROBLEM, "can't alloc memory!");
882 xt_params->opts = opts;
883 }
884
cmd2char(int option)885 static char cmd2char(int option)
886 {
887 /* cmdflags index corresponds with position of bit in CMD_* values */
888 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
889 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
890 int i;
891
892 for (i = 0; option > 1; option >>= 1, i++)
893 ;
894 if (i >= ARRAY_SIZE(cmdflags))
895 xtables_error(OTHER_PROBLEM,
896 "cmd2char(): Invalid command number %u.", 1 << i);
897 return cmdflags[i];
898 }
899
add_command(unsigned int * cmd,const int newcmd,const int othercmds,int invert)900 static void add_command(unsigned int *cmd, const int newcmd,
901 const int othercmds, int invert)
902 {
903 if (invert)
904 xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag");
905 if (*cmd & (~othercmds))
906 xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c",
907 cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
908 *cmd |= newcmd;
909 }
910
911 /* Can't be zero. */
parse_rulenumber(const char * rule)912 static int parse_rulenumber(const char *rule)
913 {
914 unsigned int rulenum;
915
916 if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
917 xtables_error(PARAMETER_PROBLEM,
918 "Invalid rule number `%s'", rule);
919
920 return rulenum;
921 }
922
923 #define NUMBER_OF_OPT ARRAY_SIZE(optflags)
924 static const char optflags[]
925 = { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f', 2, 3, 'l', 4, 5, 6 };
926
927 /* Table of legal combinations of commands and options. If any of the
928 * given commands make an option legal, that option is legal (applies to
929 * CMD_LIST and CMD_ZERO only).
930 * Key:
931 * + compulsory
932 * x illegal
933 * optional
934 */
935 static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
936 /* Well, it's better than "Re: Linux vs FreeBSD" */
937 {
938 /* -n -s -d -p -j -v -x -i -o --line -c -f 2 3 l 4 5 6 */
939 /*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
940 /*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
941 /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
942 /*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
943 /*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
944 /*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x','x','x','x','x','x','x'},
945 /*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
946 /*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
947 /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
948 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
949 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x','x','x','x','x','x','x'},
950 /*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
951 /*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
952 /*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
953 /*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
954 };
955
generic_opt_check(int command,int options)956 static void generic_opt_check(int command, int options)
957 {
958 int i, j, legal = 0;
959
960 /* Check that commands are valid with options. Complicated by the
961 * fact that if an option is legal with *any* command given, it is
962 * legal overall (ie. -z and -l).
963 */
964 for (i = 0; i < NUMBER_OF_OPT; i++) {
965 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
966
967 for (j = 0; j < NUMBER_OF_CMD; j++) {
968 if (!(command & (1<<j)))
969 continue;
970
971 if (!(options & (1<<i))) {
972 if (commands_v_options[j][i] == '+')
973 xtables_error(PARAMETER_PROBLEM,
974 "You need to supply the `-%c' option for this command",
975 optflags[i]);
976 } else {
977 if (commands_v_options[j][i] != 'x')
978 legal = 1;
979 else if (legal == 0)
980 legal = -1;
981 }
982 }
983 if (legal == -1)
984 xtables_error(PARAMETER_PROBLEM,
985 "Illegal option `-%c' with this command",
986 optflags[i]);
987 }
988 }
989
opt2char(int option)990 static char opt2char(int option)
991 {
992 const char *ptr;
993
994 for (ptr = optflags; option > 1; option >>= 1, ptr++)
995 ;
996
997 return *ptr;
998 }
999
1000 static const int inverse_for_options[NUMBER_OF_OPT] =
1001 {
1002 /* -n */ 0,
1003 /* -s */ IPT_INV_SRCIP,
1004 /* -d */ IPT_INV_DSTIP,
1005 /* -p */ XT_INV_PROTO,
1006 /* -j */ 0,
1007 /* -v */ 0,
1008 /* -x */ 0,
1009 /* -i */ IPT_INV_VIA_IN,
1010 /* -o */ IPT_INV_VIA_OUT,
1011 /*--line*/ 0,
1012 /* -c */ 0,
1013 /* -f */ IPT_INV_FRAG,
1014 /* 2 */ IPT_INV_SRCDEVADDR,
1015 /* 3 */ IPT_INV_TGTDEVADDR,
1016 /* -l */ IPT_INV_ARPHLN,
1017 /* 4 */ IPT_INV_ARPOP,
1018 /* 5 */ IPT_INV_ARPHRD,
1019 /* 6 */ IPT_INV_PROTO,
1020 };
1021
1022 static void
set_option(unsigned int * options,unsigned int option,uint16_t * invflg,bool invert)1023 set_option(unsigned int *options, unsigned int option, uint16_t *invflg,
1024 bool invert)
1025 {
1026 if (*options & option)
1027 xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
1028 opt2char(option));
1029 *options |= option;
1030
1031 if (invert) {
1032 unsigned int i;
1033 for (i = 0; 1 << i != option; i++);
1034
1035 if (!inverse_for_options[i])
1036 xtables_error(PARAMETER_PROBLEM,
1037 "cannot have ! before -%c",
1038 opt2char(option));
1039 *invflg |= inverse_for_options[i];
1040 }
1041 }
1042
assert_valid_chain_name(const char * chainname)1043 void assert_valid_chain_name(const char *chainname)
1044 {
1045 const char *ptr;
1046
1047 if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
1048 xtables_error(PARAMETER_PROBLEM,
1049 "chain name `%s' too long (must be under %u chars)",
1050 chainname, XT_EXTENSION_MAXNAMELEN);
1051
1052 if (*chainname == '-' || *chainname == '!')
1053 xtables_error(PARAMETER_PROBLEM,
1054 "chain name not allowed to start with `%c'",
1055 *chainname);
1056
1057 if (xtables_find_target(chainname, XTF_TRY_LOAD))
1058 xtables_error(PARAMETER_PROBLEM,
1059 "chain name may not clash with target name");
1060
1061 for (ptr = chainname; *ptr; ptr++)
1062 if (isspace(*ptr))
1063 xtables_error(PARAMETER_PROBLEM,
1064 "Invalid chain name `%s'", chainname);
1065 }
1066
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)1067 void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs,
1068 const char *targname, uint8_t proto, uint8_t flags,
1069 uint8_t invflags, unsigned int format)
1070 {
1071 const char *pname = proto_to_name(proto, format&FMT_NUMERIC);
1072
1073 if (format & FMT_LINENUMBERS)
1074 printf(FMT("%-4u ", "%u "), linenum);
1075
1076 if (!(format & FMT_NOCOUNTS)) {
1077 xtables_print_num(ctrs->pcnt, format);
1078 xtables_print_num(ctrs->bcnt, format);
1079 }
1080
1081 if (!(format & FMT_NOTARGET))
1082 printf(FMT("%-9s ", "%s "), targname ? targname : "");
1083
1084 fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout);
1085
1086 if (!proto)
1087 printf(FMT("%-4s ", "%s "), "all");
1088 else if (((format & (FMT_NUMERIC | FMT_NOTABLE)) == FMT_NUMERIC) || !pname)
1089 printf(FMT("%-4hu ", "%hu "), proto);
1090 else
1091 printf(FMT("%-4s ", "%s "), pname);
1092 }
1093
save_rule_details(const char * iniface,unsigned const char * iniface_mask,const char * outiface,unsigned const char * outiface_mask,uint16_t proto,int frag,uint8_t invflags)1094 void save_rule_details(const char *iniface, unsigned const char *iniface_mask,
1095 const char *outiface, unsigned const char *outiface_mask,
1096 uint16_t proto, int frag, uint8_t invflags)
1097 {
1098 if (iniface != NULL) {
1099 save_iface('i', iniface, iniface_mask,
1100 invflags & IPT_INV_VIA_IN);
1101 }
1102 if (outiface != NULL) {
1103 save_iface('o', outiface, outiface_mask,
1104 invflags & IPT_INV_VIA_OUT);
1105 }
1106
1107 if (proto > 0) {
1108 const char *pname = proto_to_name(proto, 0);
1109
1110 if (invflags & XT_INV_PROTO)
1111 printf(" !");
1112
1113 if (pname)
1114 printf(" -p %s", pname);
1115 else
1116 printf(" -p %u", proto);
1117 }
1118
1119 if (frag) {
1120 if (invflags & IPT_INV_FRAG)
1121 printf(" !");
1122 printf(" -f");
1123 }
1124 }
1125
print_match_save(const struct xt_entry_match * e,const void * ip)1126 int print_match_save(const struct xt_entry_match *e, const void *ip)
1127 {
1128 const char *name = e->u.user.name;
1129 const int revision = e->u.user.revision;
1130 struct xtables_match *match, *mt, *mt2;
1131
1132 match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
1133 if (match) {
1134 mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
1135 match, revision);
1136 if (!mt2)
1137 mt2 = match;
1138 printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
1139
1140 /* some matches don't provide a save function */
1141 if (mt && mt->save)
1142 mt->save(ip, e);
1143 else if (match->save)
1144 printf(" [unsupported revision]");
1145 } else {
1146 if (e->u.match_size) {
1147 fprintf(stderr,
1148 "Can't find library for match `%s'\n",
1149 name);
1150 exit(1);
1151 }
1152 }
1153 return 0;
1154 }
1155
1156 static void
xtables_printhelp(const struct xtables_rule_match * matches)1157 xtables_printhelp(const struct xtables_rule_match *matches)
1158 {
1159 const char *prog_name = xt_params->program_name;
1160 const char *prog_vers = xt_params->program_version;
1161
1162 printf("%s v%s\n\n"
1163 "Usage: %s -[ACD] chain rule-specification [options]\n"
1164 " %s -I chain [rulenum] rule-specification [options]\n"
1165 " %s -R chain rulenum rule-specification [options]\n"
1166 " %s -D chain rulenum [options]\n"
1167 " %s -[LS] [chain [rulenum]] [options]\n"
1168 " %s -[FZ] [chain] [options]\n"
1169 " %s -[NX] chain\n"
1170 " %s -E old-chain-name new-chain-name\n"
1171 " %s -P chain target [options]\n"
1172 " %s -h (print this help information)\n\n",
1173 prog_name, prog_vers, prog_name, prog_name,
1174 prog_name, prog_name, prog_name, prog_name,
1175 prog_name, prog_name, prog_name, prog_name);
1176
1177 printf(
1178 "Commands:\n"
1179 "Either long or short options are allowed.\n"
1180 " --append -A chain Append to chain\n"
1181 " --check -C chain Check for the existence of a rule\n"
1182 " --delete -D chain Delete matching rule from chain\n"
1183 " --delete -D chain rulenum\n"
1184 " Delete rule rulenum (1 = first) from chain\n"
1185 " --insert -I chain [rulenum]\n"
1186 " Insert in chain as rulenum (default 1=first)\n"
1187 " --replace -R chain rulenum\n"
1188 " Replace rule rulenum (1 = first) in chain\n"
1189 " --list -L [chain [rulenum]]\n"
1190 " List the rules in a chain or all chains\n"
1191 " --list-rules -S [chain [rulenum]]\n"
1192 " Print the rules in a chain or all chains\n"
1193 " --flush -F [chain] Delete all rules in chain or all chains\n"
1194 " --zero -Z [chain [rulenum]]\n"
1195 " Zero counters in chain or all chains\n"
1196 " --new -N chain Create a new user-defined chain\n"
1197 " --delete-chain\n"
1198 " -X [chain] Delete a user-defined chain\n"
1199 " --policy -P chain target\n"
1200 " Change policy on chain to target\n"
1201 " --rename-chain\n"
1202 " -E old-chain new-chain\n"
1203 " Change chain name, (moving any references)\n"
1204 "\n"
1205 "Options:\n");
1206
1207 if (afinfo->family == NFPROTO_ARP) {
1208 printf(
1209 "[!] --source-ip -s address[/mask]\n"
1210 " source specification\n"
1211 "[!] --destination-ip -d address[/mask]\n"
1212 " destination specification\n"
1213 "[!] --source-mac address[/mask]\n"
1214 "[!] --destination-mac address[/mask]\n"
1215 " --h-length -l length[/mask] hardware length (nr of bytes)\n"
1216 " --opcode code[/mask] operation code (2 bytes)\n"
1217 " --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n"
1218 " --proto-type type[/mask] protocol type (2 bytes)\n");
1219 } else {
1220 printf(
1221 " --ipv4 -4 %s (line is ignored by ip6tables-restore)\n"
1222 " --ipv6 -6 %s (line is ignored by iptables-restore)\n"
1223 "[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n"
1224 "[!] --source -s address[/mask][...]\n"
1225 " source specification\n"
1226 "[!] --destination -d address[/mask][...]\n"
1227 " destination specification\n",
1228 afinfo->family == NFPROTO_IPV4 ? "Nothing" : "Error",
1229 afinfo->family == NFPROTO_IPV4 ? "Error" : "Nothing");
1230 }
1231
1232 printf(
1233 "[!] --in-interface -i input name[+]\n"
1234 " network interface name ([+] for wildcard)\n"
1235 " --jump -j target\n"
1236 " target for rule (may load target extension)\n");
1237
1238 if (0
1239 #ifdef IPT_F_GOTO
1240 || afinfo->family == NFPROTO_IPV4
1241 #endif
1242 #ifdef IP6T_F_GOTO
1243 || afinfo->family == NFPROTO_IPV6
1244 #endif
1245 )
1246 printf(
1247 " --goto -g chain\n"
1248 " jump to chain with no return\n");
1249 printf(
1250 " --match -m match\n"
1251 " extended match (may load extension)\n"
1252 " --numeric -n numeric output of addresses and ports\n"
1253 "[!] --out-interface -o output name[+]\n"
1254 " network interface name ([+] for wildcard)\n"
1255 " --table -t table table to manipulate (default: `filter')\n"
1256 " --verbose -v verbose mode\n"
1257 " --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
1258 " --line-numbers print line numbers when listing\n"
1259 " --exact -x expand numbers (display exact values)\n");
1260
1261 if (afinfo->family == NFPROTO_IPV4)
1262 printf(
1263 "[!] --fragment -f match second or further fragments only\n");
1264
1265 printf(
1266 " --modprobe=<command> try to insert modules using this command\n"
1267 " --set-counters -c PKTS BYTES set the counter during insert/append\n"
1268 "[!] --version -V print package version.\n");
1269
1270 if (afinfo->family == NFPROTO_ARP) {
1271 int i;
1272
1273 printf(" opcode strings: \n");
1274 for (i = 0; i < ARP_NUMOPCODES; i++)
1275 printf(" %d = %s\n", i + 1, arp_opcodes[i]);
1276 printf(
1277 " hardware type string: 1 = Ethernet\n"
1278 " protocol type string: 0x800 = IPv4\n");
1279
1280 xtables_find_target("standard", XTF_TRY_LOAD);
1281 xtables_find_target("mangle", XTF_TRY_LOAD);
1282 xtables_find_target("CLASSIFY", XTF_TRY_LOAD);
1283 xtables_find_target("MARK", XTF_TRY_LOAD);
1284 }
1285
1286 print_extension_helps(xtables_targets, matches);
1287 }
1288
exit_tryhelp(int status,int line)1289 void exit_tryhelp(int status, int line)
1290 {
1291 if (line != -1)
1292 fprintf(stderr, "Error occurred at line: %d\n", line);
1293 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
1294 xt_params->program_name, xt_params->program_name);
1295 xtables_free_opts(1);
1296 exit(status);
1297 }
1298
check_empty_interface(struct xtables_args * args,const char * arg)1299 static void check_empty_interface(struct xtables_args *args, const char *arg)
1300 {
1301 const char *msg = "Empty interface is likely to be undesired";
1302
1303 if (*arg != '\0')
1304 return;
1305
1306 if (args->family != NFPROTO_ARP)
1307 xtables_error(PARAMETER_PROBLEM, "%s", msg);
1308
1309 fprintf(stderr, "%s", msg);
1310 }
1311
check_inverse(struct xtables_args * args,const char option[],bool * invert,int argc,char ** argv)1312 static void check_inverse(struct xtables_args *args, const char option[],
1313 bool *invert, int argc, char **argv)
1314 {
1315 switch (args->family) {
1316 case NFPROTO_ARP:
1317 break;
1318 default:
1319 return;
1320 }
1321
1322 if (!option || strcmp(option, "!"))
1323 return;
1324
1325 fprintf(stderr, "Using intrapositioned negation (`--option ! this`) "
1326 "is deprecated in favor of extrapositioned (`! --option this`).\n");
1327
1328 if (*invert)
1329 xtables_error(PARAMETER_PROBLEM,
1330 "Multiple `!' flags not allowed");
1331 *invert = true;
1332 optind++;
1333 if (optind > argc)
1334 xtables_error(PARAMETER_PROBLEM, "no argument following `!'");
1335
1336 optarg = argv[optind - 1];
1337 }
1338
optstring_lookup(int family)1339 static const char *optstring_lookup(int family)
1340 {
1341 switch (family) {
1342 case AF_INET:
1343 case AF_INET6:
1344 return IPT_OPTSTRING;
1345 case NFPROTO_ARP:
1346 return ARPT_OPTSTRING;
1347 case NFPROTO_BRIDGE:
1348 return EBT_OPTSTRING;
1349 }
1350 return "";
1351 }
1352
xtables_clear_iptables_command_state(struct iptables_command_state * cs)1353 void xtables_clear_iptables_command_state(struct iptables_command_state *cs)
1354 {
1355 xtables_rule_matches_free(&cs->matches);
1356 if (cs->target) {
1357 free(cs->target->t);
1358 cs->target->t = NULL;
1359
1360 free(cs->target->udata);
1361 cs->target->udata = NULL;
1362
1363 if (cs->target == cs->target->next) {
1364 free(cs->target);
1365 cs->target = NULL;
1366 }
1367 }
1368 }
1369
do_parse(int argc,char * argv[],struct xt_cmd_parse * p,struct iptables_command_state * cs,struct xtables_args * args)1370 void do_parse(int argc, char *argv[],
1371 struct xt_cmd_parse *p, struct iptables_command_state *cs,
1372 struct xtables_args *args)
1373 {
1374 struct xtables_match *m;
1375 struct xtables_rule_match *matchp;
1376 bool wait_interval_set = false;
1377 struct xtables_target *t;
1378 bool table_set = false;
1379 bool invert = false;
1380
1381 /* re-set optind to 0 in case do_command4 gets called
1382 * a second time */
1383 optind = 0;
1384
1385 /* clear mflags in case do_command4 gets called a second time
1386 * (we clear the global list of all matches for security)*/
1387 for (m = xtables_matches; m; m = m->next)
1388 m->mflags = 0;
1389
1390 for (t = xtables_targets; t; t = t->next) {
1391 t->tflags = 0;
1392 t->used = 0;
1393 }
1394
1395 /* Suppress error messages: we may add new options if we
1396 demand-load a protocol. */
1397 opterr = 0;
1398
1399 xt_params->opts = xt_params->orig_opts;
1400 while ((cs->c = getopt_long(argc, argv,
1401 optstring_lookup(afinfo->family),
1402 xt_params->opts, NULL)) != -1) {
1403 switch (cs->c) {
1404 /*
1405 * Command selection
1406 */
1407 case 'A':
1408 add_command(&p->command, CMD_APPEND, CMD_NONE, invert);
1409 p->chain = optarg;
1410 break;
1411
1412 case 'C':
1413 add_command(&p->command, CMD_CHECK, CMD_NONE, invert);
1414 p->chain = optarg;
1415 break;
1416
1417 case 'D':
1418 add_command(&p->command, CMD_DELETE, CMD_NONE, invert);
1419 p->chain = optarg;
1420 if (xs_has_arg(argc, argv)) {
1421 p->rulenum = parse_rulenumber(argv[optind++]);
1422 p->command = CMD_DELETE_NUM;
1423 }
1424 break;
1425
1426 case 'R':
1427 add_command(&p->command, CMD_REPLACE, CMD_NONE, invert);
1428 p->chain = optarg;
1429 if (xs_has_arg(argc, argv))
1430 p->rulenum = parse_rulenumber(argv[optind++]);
1431 else
1432 xtables_error(PARAMETER_PROBLEM,
1433 "-%c requires a rule number",
1434 cmd2char(CMD_REPLACE));
1435 break;
1436
1437 case 'I':
1438 add_command(&p->command, CMD_INSERT, CMD_NONE, invert);
1439 p->chain = optarg;
1440 if (xs_has_arg(argc, argv))
1441 p->rulenum = parse_rulenumber(argv[optind++]);
1442 else
1443 p->rulenum = 1;
1444 break;
1445
1446 case 'L':
1447 add_command(&p->command, CMD_LIST,
1448 CMD_ZERO | CMD_ZERO_NUM, invert);
1449 if (optarg)
1450 p->chain = optarg;
1451 else if (xs_has_arg(argc, argv))
1452 p->chain = argv[optind++];
1453 if (xs_has_arg(argc, argv))
1454 p->rulenum = parse_rulenumber(argv[optind++]);
1455 break;
1456
1457 case 'S':
1458 add_command(&p->command, CMD_LIST_RULES,
1459 CMD_ZERO|CMD_ZERO_NUM, invert);
1460 if (optarg)
1461 p->chain = optarg;
1462 else if (xs_has_arg(argc, argv))
1463 p->chain = argv[optind++];
1464 if (xs_has_arg(argc, argv))
1465 p->rulenum = parse_rulenumber(argv[optind++]);
1466 break;
1467
1468 case 'F':
1469 add_command(&p->command, CMD_FLUSH, CMD_NONE, invert);
1470 if (optarg)
1471 p->chain = optarg;
1472 else if (xs_has_arg(argc, argv))
1473 p->chain = argv[optind++];
1474 break;
1475
1476 case 'Z':
1477 add_command(&p->command, CMD_ZERO,
1478 CMD_LIST|CMD_LIST_RULES, invert);
1479 if (optarg)
1480 p->chain = optarg;
1481 else if (xs_has_arg(argc, argv))
1482 p->chain = argv[optind++];
1483 if (xs_has_arg(argc, argv)) {
1484 p->rulenum = parse_rulenumber(argv[optind++]);
1485 p->command = CMD_ZERO_NUM;
1486 }
1487 break;
1488
1489 case 'N':
1490 assert_valid_chain_name(optarg);
1491 add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
1492 invert);
1493 p->chain = optarg;
1494 break;
1495
1496 case 'X':
1497 add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
1498 invert);
1499 if (optarg)
1500 p->chain = optarg;
1501 else if (xs_has_arg(argc, argv))
1502 p->chain = argv[optind++];
1503 break;
1504
1505 case 'E':
1506 add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
1507 invert);
1508 p->chain = optarg;
1509 if (xs_has_arg(argc, argv))
1510 p->newname = argv[optind++];
1511 else
1512 xtables_error(PARAMETER_PROBLEM,
1513 "-%c requires old-chain-name and "
1514 "new-chain-name",
1515 cmd2char(CMD_RENAME_CHAIN));
1516 assert_valid_chain_name(p->newname);
1517 break;
1518
1519 case 'P':
1520 add_command(&p->command, CMD_SET_POLICY, CMD_NONE,
1521 invert);
1522 p->chain = optarg;
1523 if (xs_has_arg(argc, argv))
1524 p->policy = argv[optind++];
1525 else
1526 xtables_error(PARAMETER_PROBLEM,
1527 "-%c requires a chain and a policy",
1528 cmd2char(CMD_SET_POLICY));
1529 break;
1530
1531 case 'h':
1532 if (!optarg)
1533 optarg = argv[optind];
1534
1535 /* iptables -p icmp -h */
1536 if (!cs->matches && cs->protocol)
1537 xtables_find_match(cs->protocol,
1538 XTF_TRY_LOAD, &cs->matches);
1539
1540 xtables_printhelp(cs->matches);
1541 xtables_clear_iptables_command_state(cs);
1542 xtables_free_opts(1);
1543 xtables_fini();
1544 exit(0);
1545
1546 /*
1547 * Option selection
1548 */
1549 case 'p':
1550 check_inverse(args, optarg, &invert, argc, argv);
1551 set_option(&cs->options, OPT_PROTOCOL,
1552 &args->invflags, invert);
1553
1554 /* Canonicalize into lower case */
1555 for (cs->protocol = optarg;
1556 *cs->protocol; cs->protocol++)
1557 *cs->protocol = tolower(*cs->protocol);
1558
1559 cs->protocol = optarg;
1560 args->proto = xtables_parse_protocol(cs->protocol);
1561
1562 if (args->proto == 0 &&
1563 (args->invflags & XT_INV_PROTO))
1564 xtables_error(PARAMETER_PROBLEM,
1565 "rule would never match protocol");
1566
1567 /* This needs to happen here to parse extensions */
1568 if (p->ops->proto_parse)
1569 p->ops->proto_parse(cs, args);
1570 break;
1571
1572 case 's':
1573 check_inverse(args, optarg, &invert, argc, argv);
1574 set_option(&cs->options, OPT_SOURCE,
1575 &args->invflags, invert);
1576 args->shostnetworkmask = optarg;
1577 break;
1578
1579 case 'd':
1580 check_inverse(args, optarg, &invert, argc, argv);
1581 set_option(&cs->options, OPT_DESTINATION,
1582 &args->invflags, invert);
1583 args->dhostnetworkmask = optarg;
1584 break;
1585
1586 #ifdef IPT_F_GOTO
1587 case 'g':
1588 set_option(&cs->options, OPT_JUMP, &args->invflags,
1589 invert);
1590 args->goto_set = true;
1591 cs->jumpto = xt_parse_target(optarg);
1592 break;
1593 #endif
1594
1595 case 2:/* src-mac */
1596 check_inverse(args, optarg, &invert, argc, argv);
1597 set_option(&cs->options, OPT_S_MAC, &args->invflags,
1598 invert);
1599 args->src_mac = optarg;
1600 break;
1601
1602 case 3:/* dst-mac */
1603 check_inverse(args, optarg, &invert, argc, argv);
1604 set_option(&cs->options, OPT_D_MAC, &args->invflags,
1605 invert);
1606 args->dst_mac = optarg;
1607 break;
1608
1609 case 'l':/* hardware length */
1610 check_inverse(args, optarg, &invert, argc, argv);
1611 set_option(&cs->options, OPT_H_LENGTH, &args->invflags,
1612 invert);
1613 args->arp_hlen = optarg;
1614 break;
1615
1616 case 8: /* was never supported, not even in arptables-legacy */
1617 xtables_error(PARAMETER_PROBLEM, "not supported");
1618 case 4:/* opcode */
1619 check_inverse(args, optarg, &invert, argc, argv);
1620 set_option(&cs->options, OPT_OPCODE, &args->invflags,
1621 invert);
1622 args->arp_opcode = optarg;
1623 break;
1624
1625 case 5:/* h-type */
1626 check_inverse(args, optarg, &invert, argc, argv);
1627 set_option(&cs->options, OPT_H_TYPE, &args->invflags,
1628 invert);
1629 args->arp_htype = optarg;
1630 break;
1631
1632 case 6:/* proto-type */
1633 check_inverse(args, optarg, &invert, argc, argv);
1634 set_option(&cs->options, OPT_P_TYPE, &args->invflags,
1635 invert);
1636 args->arp_ptype = optarg;
1637 break;
1638
1639 case 'j':
1640 set_option(&cs->options, OPT_JUMP, &args->invflags,
1641 invert);
1642 command_jump(cs, optarg);
1643 break;
1644
1645 case 'i':
1646 check_empty_interface(args, optarg);
1647 check_inverse(args, optarg, &invert, argc, argv);
1648 set_option(&cs->options, OPT_VIANAMEIN,
1649 &args->invflags, invert);
1650 xtables_parse_interface(optarg,
1651 args->iniface,
1652 args->iniface_mask);
1653 break;
1654
1655 case 'o':
1656 check_empty_interface(args, optarg);
1657 check_inverse(args, optarg, &invert, argc, argv);
1658 set_option(&cs->options, OPT_VIANAMEOUT,
1659 &args->invflags, invert);
1660 xtables_parse_interface(optarg,
1661 args->outiface,
1662 args->outiface_mask);
1663 break;
1664
1665 case 'f':
1666 if (args->family == AF_INET6) {
1667 xtables_error(PARAMETER_PROBLEM,
1668 "`-f' is not supported in IPv6, "
1669 "use -m frag instead");
1670 }
1671 set_option(&cs->options, OPT_FRAGMENT, &args->invflags,
1672 invert);
1673 args->flags |= IPT_F_FRAG;
1674 break;
1675
1676 case 'v':
1677 if (!p->verbose)
1678 set_option(&cs->options, OPT_VERBOSE,
1679 &args->invflags, invert);
1680 p->verbose++;
1681 break;
1682
1683 case 'm':
1684 command_match(cs, invert);
1685 break;
1686
1687 case 'n':
1688 set_option(&cs->options, OPT_NUMERIC, &args->invflags,
1689 invert);
1690 break;
1691
1692 case 't':
1693 if (invert)
1694 xtables_error(PARAMETER_PROBLEM,
1695 "unexpected ! flag before --table");
1696 if (p->restore && table_set)
1697 xtables_error(PARAMETER_PROBLEM,
1698 "The -t option cannot be used in %s.\n",
1699 xt_params->program_name);
1700 p->table = optarg;
1701 table_set = true;
1702 break;
1703
1704 case 'x':
1705 set_option(&cs->options, OPT_EXPANDED, &args->invflags,
1706 invert);
1707 break;
1708
1709 case 'V':
1710 if (invert)
1711 printf("Not %s ;-)\n",
1712 xt_params->program_version);
1713 else
1714 printf("%s v%s\n",
1715 xt_params->program_name,
1716 xt_params->program_version);
1717 exit(0);
1718
1719 case 'w':
1720 if (p->restore) {
1721 xtables_error(PARAMETER_PROBLEM,
1722 "You cannot use `-w' from "
1723 "iptables-restore");
1724 }
1725
1726 args->wait = parse_wait_time(argc, argv);
1727 break;
1728
1729 case 'W':
1730 if (p->restore) {
1731 xtables_error(PARAMETER_PROBLEM,
1732 "You cannot use `-W' from "
1733 "iptables-restore");
1734 }
1735
1736 parse_wait_interval(argc, argv);
1737 wait_interval_set = true;
1738 break;
1739
1740 case '0':
1741 set_option(&cs->options, OPT_LINENUMBERS,
1742 &args->invflags, invert);
1743 break;
1744
1745 case 'M':
1746 xtables_modprobe_program = optarg;
1747 break;
1748
1749 case 'c':
1750 set_option(&cs->options, OPT_COUNTERS, &args->invflags,
1751 invert);
1752 args->pcnt = optarg;
1753 args->bcnt = strchr(args->pcnt + 1, ',');
1754 if (args->bcnt)
1755 args->bcnt++;
1756 if (!args->bcnt && xs_has_arg(argc, argv))
1757 args->bcnt = argv[optind++];
1758 if (!args->bcnt)
1759 xtables_error(PARAMETER_PROBLEM,
1760 "-%c requires packet and byte counter",
1761 opt2char(OPT_COUNTERS));
1762
1763 if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
1764 xtables_error(PARAMETER_PROBLEM,
1765 "-%c packet counter not numeric",
1766 opt2char(OPT_COUNTERS));
1767
1768 if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
1769 xtables_error(PARAMETER_PROBLEM,
1770 "-%c byte counter not numeric",
1771 opt2char(OPT_COUNTERS));
1772 break;
1773
1774 case '4':
1775 if (args->family == AF_INET)
1776 break;
1777
1778 if (p->restore && args->family == AF_INET6)
1779 return;
1780
1781 exit_tryhelp(2, p->line);
1782
1783 case '6':
1784 if (args->family == AF_INET6)
1785 break;
1786
1787 if (p->restore && args->family == AF_INET)
1788 return;
1789
1790 exit_tryhelp(2, p->line);
1791
1792 case 1: /* non option */
1793 if (optarg[0] == '!' && optarg[1] == '\0') {
1794 if (invert)
1795 xtables_error(PARAMETER_PROBLEM,
1796 "multiple consecutive ! not"
1797 " allowed");
1798 invert = true;
1799 optarg[0] = '\0';
1800 continue;
1801 }
1802 fprintf(stderr, "Bad argument `%s'\n", optarg);
1803 exit_tryhelp(2, p->line);
1804
1805 default:
1806 if (command_default(cs, xt_params, invert))
1807 /* cf. ip6tables.c */
1808 continue;
1809 break;
1810 }
1811 invert = false;
1812 }
1813
1814 if (strcmp(p->table, "nat") == 0 &&
1815 ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
1816 (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
1817 xtables_error(PARAMETER_PROBLEM,
1818 "\nThe \"nat\" table is not intended for filtering, "
1819 "the use of DROP is therefore inhibited.\n\n");
1820
1821 if (!args->wait && wait_interval_set)
1822 xtables_error(PARAMETER_PROBLEM,
1823 "--wait-interval only makes sense with --wait\n");
1824
1825 for (matchp = cs->matches; matchp; matchp = matchp->next)
1826 xtables_option_mfcall(matchp->match);
1827 if (cs->target != NULL)
1828 xtables_option_tfcall(cs->target);
1829
1830 /* Fix me: must put inverse options checking here --MN */
1831
1832 if (optind < argc)
1833 xtables_error(PARAMETER_PROBLEM,
1834 "unknown arguments found on commandline");
1835 if (!p->command)
1836 xtables_error(PARAMETER_PROBLEM, "no command specified");
1837 if (invert)
1838 xtables_error(PARAMETER_PROBLEM,
1839 "nothing appropriate following !");
1840
1841 if (p->ops->post_parse)
1842 p->ops->post_parse(p->command, cs, args);
1843
1844 if (p->command == CMD_REPLACE &&
1845 (args->s.naddrs != 1 || args->d.naddrs != 1))
1846 xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
1847 "specify a unique address");
1848
1849 generic_opt_check(p->command, cs->options);
1850
1851 if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
1852 xtables_error(PARAMETER_PROBLEM,
1853 "chain name `%s' too long (must be under %u chars)",
1854 p->chain, XT_EXTENSION_MAXNAMELEN);
1855
1856 if (p->command == CMD_APPEND ||
1857 p->command == CMD_DELETE ||
1858 p->command == CMD_DELETE_NUM ||
1859 p->command == CMD_CHECK ||
1860 p->command == CMD_INSERT ||
1861 p->command == CMD_REPLACE) {
1862 if (strcmp(p->chain, "PREROUTING") == 0
1863 || strcmp(p->chain, "INPUT") == 0) {
1864 /* -o not valid with incoming packets. */
1865 if (cs->options & OPT_VIANAMEOUT)
1866 xtables_error(PARAMETER_PROBLEM,
1867 "Can't use -%c with %s\n",
1868 opt2char(OPT_VIANAMEOUT),
1869 p->chain);
1870 }
1871
1872 if (strcmp(p->chain, "POSTROUTING") == 0
1873 || strcmp(p->chain, "OUTPUT") == 0) {
1874 /* -i not valid with outgoing packets */
1875 if (cs->options & OPT_VIANAMEIN)
1876 xtables_error(PARAMETER_PROBLEM,
1877 "Can't use -%c with %s\n",
1878 opt2char(OPT_VIANAMEIN),
1879 p->chain);
1880 }
1881 }
1882 }
1883
ipv4_proto_parse(struct iptables_command_state * cs,struct xtables_args * args)1884 void ipv4_proto_parse(struct iptables_command_state *cs,
1885 struct xtables_args *args)
1886 {
1887 cs->fw.ip.proto = args->proto;
1888 cs->fw.ip.invflags = args->invflags;
1889 }
1890
1891 /* These are invalid numbers as upper layer protocol */
is_exthdr(uint16_t proto)1892 static int is_exthdr(uint16_t proto)
1893 {
1894 return (proto == IPPROTO_ROUTING ||
1895 proto == IPPROTO_FRAGMENT ||
1896 proto == IPPROTO_AH ||
1897 proto == IPPROTO_DSTOPTS);
1898 }
1899
ipv6_proto_parse(struct iptables_command_state * cs,struct xtables_args * args)1900 void ipv6_proto_parse(struct iptables_command_state *cs,
1901 struct xtables_args *args)
1902 {
1903 cs->fw6.ipv6.proto = args->proto;
1904 cs->fw6.ipv6.invflags = args->invflags;
1905
1906 /* this is needed for ip6tables-legacy only */
1907 args->flags |= IP6T_F_PROTO;
1908 cs->fw6.ipv6.flags |= IP6T_F_PROTO;
1909
1910 if (is_exthdr(cs->fw6.ipv6.proto)
1911 && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0)
1912 fprintf(stderr,
1913 "Warning: never matched protocol: %s. "
1914 "use extension match instead.\n",
1915 cs->protocol);
1916 }
1917
ipv4_post_parse(int command,struct iptables_command_state * cs,struct xtables_args * args)1918 void ipv4_post_parse(int command, struct iptables_command_state *cs,
1919 struct xtables_args *args)
1920 {
1921 cs->fw.ip.flags = args->flags;
1922 /* We already set invflags in proto_parse, but we need to refresh it
1923 * to include new parsed options.
1924 */
1925 cs->fw.ip.invflags = args->invflags;
1926
1927 memcpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ);
1928 memcpy(cs->fw.ip.iniface_mask,
1929 args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
1930
1931 memcpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ);
1932 memcpy(cs->fw.ip.outiface_mask,
1933 args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
1934
1935 if (args->goto_set)
1936 cs->fw.ip.flags |= IPT_F_GOTO;
1937
1938 /* nft-variants use cs->counters, legacy uses cs->fw.counters */
1939 cs->counters.pcnt = args->pcnt_cnt;
1940 cs->counters.bcnt = args->bcnt_cnt;
1941 cs->fw.counters.pcnt = args->pcnt_cnt;
1942 cs->fw.counters.bcnt = args->bcnt_cnt;
1943
1944 if (command & (CMD_REPLACE | CMD_INSERT |
1945 CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
1946 if (!(cs->options & OPT_DESTINATION))
1947 args->dhostnetworkmask = "0.0.0.0/0";
1948 if (!(cs->options & OPT_SOURCE))
1949 args->shostnetworkmask = "0.0.0.0/0";
1950 }
1951
1952 if (args->shostnetworkmask)
1953 xtables_ipparse_multiple(args->shostnetworkmask,
1954 &args->s.addr.v4, &args->s.mask.v4,
1955 &args->s.naddrs);
1956 if (args->dhostnetworkmask)
1957 xtables_ipparse_multiple(args->dhostnetworkmask,
1958 &args->d.addr.v4, &args->d.mask.v4,
1959 &args->d.naddrs);
1960
1961 if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
1962 (cs->fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
1963 xtables_error(PARAMETER_PROBLEM,
1964 "! not allowed with multiple"
1965 " source or destination IP addresses");
1966 }
1967
ipv6_post_parse(int command,struct iptables_command_state * cs,struct xtables_args * args)1968 void ipv6_post_parse(int command, struct iptables_command_state *cs,
1969 struct xtables_args *args)
1970 {
1971 cs->fw6.ipv6.flags = args->flags;
1972 /* We already set invflags in proto_parse, but we need to refresh it
1973 * to include new parsed options.
1974 */
1975 cs->fw6.ipv6.invflags = args->invflags;
1976
1977 memcpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ);
1978 memcpy(cs->fw6.ipv6.iniface_mask,
1979 args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
1980
1981 memcpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ);
1982 memcpy(cs->fw6.ipv6.outiface_mask,
1983 args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
1984
1985 if (args->goto_set)
1986 cs->fw6.ipv6.flags |= IP6T_F_GOTO;
1987
1988 /* nft-variants use cs->counters, legacy uses cs->fw6.counters */
1989 cs->counters.pcnt = args->pcnt_cnt;
1990 cs->counters.bcnt = args->bcnt_cnt;
1991 cs->fw6.counters.pcnt = args->pcnt_cnt;
1992 cs->fw6.counters.bcnt = args->bcnt_cnt;
1993
1994 if (command & (CMD_REPLACE | CMD_INSERT |
1995 CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
1996 if (!(cs->options & OPT_DESTINATION))
1997 args->dhostnetworkmask = "::0/0";
1998 if (!(cs->options & OPT_SOURCE))
1999 args->shostnetworkmask = "::0/0";
2000 }
2001
2002 if (args->shostnetworkmask)
2003 xtables_ip6parse_multiple(args->shostnetworkmask,
2004 &args->s.addr.v6,
2005 &args->s.mask.v6,
2006 &args->s.naddrs);
2007 if (args->dhostnetworkmask)
2008 xtables_ip6parse_multiple(args->dhostnetworkmask,
2009 &args->d.addr.v6,
2010 &args->d.mask.v6,
2011 &args->d.naddrs);
2012
2013 if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
2014 (cs->fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
2015 xtables_error(PARAMETER_PROBLEM,
2016 "! not allowed with multiple"
2017 " source or destination IP addresses");
2018 }
2019
2020 unsigned char *
make_delete_mask(const struct xtables_rule_match * matches,const struct xtables_target * target,size_t entry_size)2021 make_delete_mask(const struct xtables_rule_match *matches,
2022 const struct xtables_target *target,
2023 size_t entry_size)
2024 {
2025 /* Establish mask for comparison */
2026 unsigned int size = entry_size;
2027 const struct xtables_rule_match *matchp;
2028 unsigned char *mask, *mptr;
2029
2030 for (matchp = matches; matchp; matchp = matchp->next)
2031 size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
2032
2033 mask = xtables_calloc(1, size
2034 + XT_ALIGN(sizeof(struct xt_entry_target))
2035 + target->size);
2036
2037 memset(mask, 0xFF, entry_size);
2038 mptr = mask + entry_size;
2039
2040 for (matchp = matches; matchp; matchp = matchp->next) {
2041 memset(mptr, 0xFF,
2042 XT_ALIGN(sizeof(struct xt_entry_match))
2043 + matchp->match->userspacesize);
2044 mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
2045 }
2046
2047 memset(mptr, 0xFF,
2048 XT_ALIGN(sizeof(struct xt_entry_target))
2049 + target->userspacesize);
2050
2051 return mask;
2052 }
2053