1 /* Code to take an iptables-style command line and do it. */
2
3 /*
4 * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
5 *
6 * (C) 2000-2002 by the netfilter coreteam <coreteam@netfilter.org>:
7 * Paul 'Rusty' Russell <rusty@rustcorp.com.au>
8 * Marc Boucher <marc+nf@mbsi.ca>
9 * James Morris <jmorris@intercode.com.au>
10 * Harald Welte <laforge@gnumonks.org>
11 * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27 #include "config.h"
28 #include <getopt.h>
29 #include <string.h>
30 #include <netdb.h>
31 #include <errno.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <limits.h>
38 #include <unistd.h>
39 #include <iptables.h>
40 #include <xtables.h>
41 #include <fcntl.h>
42 #include "xshared.h"
43
44 static const char unsupported_rev[] = " [unsupported revision]";
45
46 static struct option original_opts[] = {
47 {.name = "append", .has_arg = 1, .val = 'A'},
48 {.name = "delete", .has_arg = 1, .val = 'D'},
49 {.name = "check", .has_arg = 1, .val = 'C'},
50 {.name = "insert", .has_arg = 1, .val = 'I'},
51 {.name = "replace", .has_arg = 1, .val = 'R'},
52 {.name = "list", .has_arg = 2, .val = 'L'},
53 {.name = "list-rules", .has_arg = 2, .val = 'S'},
54 {.name = "flush", .has_arg = 2, .val = 'F'},
55 {.name = "zero", .has_arg = 2, .val = 'Z'},
56 {.name = "new-chain", .has_arg = 1, .val = 'N'},
57 {.name = "delete-chain", .has_arg = 2, .val = 'X'},
58 {.name = "rename-chain", .has_arg = 1, .val = 'E'},
59 {.name = "policy", .has_arg = 1, .val = 'P'},
60 {.name = "source", .has_arg = 1, .val = 's'},
61 {.name = "destination", .has_arg = 1, .val = 'd'},
62 {.name = "src", .has_arg = 1, .val = 's'}, /* synonym */
63 {.name = "dst", .has_arg = 1, .val = 'd'}, /* synonym */
64 {.name = "protocol", .has_arg = 1, .val = 'p'},
65 {.name = "in-interface", .has_arg = 1, .val = 'i'},
66 {.name = "jump", .has_arg = 1, .val = 'j'},
67 {.name = "table", .has_arg = 1, .val = 't'},
68 {.name = "match", .has_arg = 1, .val = 'm'},
69 {.name = "numeric", .has_arg = 0, .val = 'n'},
70 {.name = "out-interface", .has_arg = 1, .val = 'o'},
71 {.name = "verbose", .has_arg = 0, .val = 'v'},
72 {.name = "wait", .has_arg = 2, .val = 'w'},
73 {.name = "wait-interval", .has_arg = 2, .val = 'W'},
74 {.name = "exact", .has_arg = 0, .val = 'x'},
75 {.name = "fragments", .has_arg = 0, .val = 'f'},
76 {.name = "version", .has_arg = 0, .val = 'V'},
77 {.name = "help", .has_arg = 2, .val = 'h'},
78 {.name = "line-numbers", .has_arg = 0, .val = '0'},
79 {.name = "modprobe", .has_arg = 1, .val = 'M'},
80 {.name = "set-counters", .has_arg = 1, .val = 'c'},
81 {.name = "goto", .has_arg = 1, .val = 'g'},
82 {.name = "ipv4", .has_arg = 0, .val = '4'},
83 {.name = "ipv6", .has_arg = 0, .val = '6'},
84 {NULL},
85 };
86
87 void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
88
89 struct xtables_globals iptables_globals = {
90 .option_offset = 0,
91 .program_version = PACKAGE_VERSION,
92 .orig_opts = original_opts,
93 .exit_err = iptables_exit_error,
94 .compat_rev = xtables_compatible_revision,
95 };
96
97 static const int inverse_for_options[NUMBER_OF_OPT] =
98 {
99 /* -n */ 0,
100 /* -s */ IPT_INV_SRCIP,
101 /* -d */ IPT_INV_DSTIP,
102 /* -p */ XT_INV_PROTO,
103 /* -j */ 0,
104 /* -v */ 0,
105 /* -x */ 0,
106 /* -i */ IPT_INV_VIA_IN,
107 /* -o */ IPT_INV_VIA_OUT,
108 /*--line*/ 0,
109 /* -c */ 0,
110 /* -f */ IPT_INV_FRAG,
111 };
112
113 #define opts iptables_globals.opts
114 #define prog_name iptables_globals.program_name
115 #define prog_vers iptables_globals.program_version
116
117 static void __attribute__((noreturn))
exit_tryhelp(int status)118 exit_tryhelp(int status)
119 {
120 if (line != -1)
121 fprintf(stderr, "Error occurred at line: %d\n", line);
122 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
123 prog_name, prog_name);
124 xtables_free_opts(1);
125 exit(status);
126 }
127
128 static void
exit_printhelp(const struct xtables_rule_match * matches)129 exit_printhelp(const struct xtables_rule_match *matches)
130 {
131 printf("%s v%s\n\n"
132 "Usage: %s -[ACD] chain rule-specification [options]\n"
133 " %s -I chain [rulenum] rule-specification [options]\n"
134 " %s -R chain rulenum rule-specification [options]\n"
135 " %s -D chain rulenum [options]\n"
136 " %s -[LS] [chain [rulenum]] [options]\n"
137 " %s -[FZ] [chain] [options]\n"
138 " %s -[NX] chain\n"
139 " %s -E old-chain-name new-chain-name\n"
140 " %s -P chain target [options]\n"
141 " %s -h (print this help information)\n\n",
142 prog_name, prog_vers, prog_name, prog_name,
143 prog_name, prog_name, prog_name, prog_name,
144 prog_name, prog_name, prog_name, prog_name);
145
146 printf(
147 "Commands:\n"
148 "Either long or short options are allowed.\n"
149 " --append -A chain Append to chain\n"
150 " --check -C chain Check for the existence of a rule\n"
151 " --delete -D chain Delete matching rule from chain\n"
152 " --delete -D chain rulenum\n"
153 " Delete rule rulenum (1 = first) from chain\n"
154 " --insert -I chain [rulenum]\n"
155 " Insert in chain as rulenum (default 1=first)\n"
156 " --replace -R chain rulenum\n"
157 " Replace rule rulenum (1 = first) in chain\n"
158 " --list -L [chain [rulenum]]\n"
159 " List the rules in a chain or all chains\n"
160 " --list-rules -S [chain [rulenum]]\n"
161 " Print the rules in a chain or all chains\n"
162 " --flush -F [chain] Delete all rules in chain or all chains\n"
163 " --zero -Z [chain [rulenum]]\n"
164 " Zero counters in chain or all chains\n"
165 " --new -N chain Create a new user-defined chain\n"
166 " --delete-chain\n"
167 " -X [chain] Delete a user-defined chain\n"
168 " --policy -P chain target\n"
169 " Change policy on chain to target\n"
170 " --rename-chain\n"
171 " -E old-chain new-chain\n"
172 " Change chain name, (moving any references)\n"
173
174 "Options:\n"
175 " --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n"
176 " --ipv6 -6 Error (line is ignored by iptables-restore)\n"
177 "[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n"
178 "[!] --source -s address[/mask][...]\n"
179 " source specification\n"
180 "[!] --destination -d address[/mask][...]\n"
181 " destination specification\n"
182 "[!] --in-interface -i input name[+]\n"
183 " network interface name ([+] for wildcard)\n"
184 " --jump -j target\n"
185 " target for rule (may load target extension)\n"
186 #ifdef IPT_F_GOTO
187 " --goto -g chain\n"
188 " jump to chain with no return\n"
189 #endif
190 " --match -m match\n"
191 " extended match (may load extension)\n"
192 " --numeric -n numeric output of addresses and ports\n"
193 "[!] --out-interface -o output name[+]\n"
194 " network interface name ([+] for wildcard)\n"
195 " --table -t table table to manipulate (default: `filter')\n"
196 " --verbose -v verbose mode\n"
197 " --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
198 " --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
199 " default is 1 second\n"
200 " --line-numbers print line numbers when listing\n"
201 " --exact -x expand numbers (display exact values)\n"
202 "[!] --fragment -f match second or further fragments only\n"
203 " --modprobe=<command> try to insert modules using this command\n"
204 " --set-counters PKTS BYTES set the counter during insert/append\n"
205 "[!] --version -V print package version.\n");
206
207 print_extension_helps(xtables_targets, matches);
208 exit(0);
209 }
210
211 void
iptables_exit_error(enum xtables_exittype status,const char * msg,...)212 iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
213 {
214 va_list args;
215
216 va_start(args, msg);
217 fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers);
218 vfprintf(stderr, msg, args);
219 va_end(args);
220 fprintf(stderr, "\n");
221 if (status == PARAMETER_PROBLEM)
222 exit_tryhelp(status);
223 if (status == VERSION_PROBLEM)
224 fprintf(stderr,
225 "Perhaps iptables or your kernel needs to be upgraded.\n");
226 /* On error paths, make sure that we don't leak memory */
227 xtables_free_opts(1);
228 exit(status);
229 }
230
231 /*
232 * All functions starting with "parse" should succeed, otherwise
233 * the program fails.
234 * Most routines return pointers to static data that may change
235 * between calls to the same or other routines with a few exceptions:
236 * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
237 * return global static data.
238 */
239
240 /* Christophe Burki wants `-p 6' to imply `-m tcp'. */
241
242 static void
parse_chain(const char * chainname)243 parse_chain(const char *chainname)
244 {
245 const char *ptr;
246
247 if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
248 xtables_error(PARAMETER_PROBLEM,
249 "chain name `%s' too long (must be under %u chars)",
250 chainname, XT_EXTENSION_MAXNAMELEN);
251
252 if (*chainname == '-' || *chainname == '!')
253 xtables_error(PARAMETER_PROBLEM,
254 "chain name not allowed to start "
255 "with `%c'\n", *chainname);
256
257 if (xtables_find_target(chainname, XTF_TRY_LOAD))
258 xtables_error(PARAMETER_PROBLEM,
259 "chain name may not clash "
260 "with target name\n");
261
262 for (ptr = chainname; *ptr; ptr++)
263 if (isspace(*ptr))
264 xtables_error(PARAMETER_PROBLEM,
265 "Invalid chain name `%s'", chainname);
266 }
267
268 static void
set_option(unsigned int * options,unsigned int option,uint8_t * invflg,int invert)269 set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
270 int invert)
271 {
272 if (*options & option)
273 xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
274 opt2char(option));
275 *options |= option;
276
277 if (invert) {
278 unsigned int i;
279 for (i = 0; 1 << i != option; i++);
280
281 if (!inverse_for_options[i])
282 xtables_error(PARAMETER_PROBLEM,
283 "cannot have ! before -%c",
284 opt2char(option));
285 *invflg |= inverse_for_options[i];
286 }
287 }
288
289 static void
print_header(unsigned int format,const char * chain,struct xtc_handle * handle)290 print_header(unsigned int format, const char *chain, struct xtc_handle *handle)
291 {
292 struct xt_counters counters;
293 const char *pol = iptc_get_policy(chain, &counters, handle);
294 printf("Chain %s", chain);
295 if (pol) {
296 printf(" (policy %s", pol);
297 if (!(format & FMT_NOCOUNTS)) {
298 fputc(' ', stdout);
299 xtables_print_num(counters.pcnt, (format|FMT_NOTABLE));
300 fputs("packets, ", stdout);
301 xtables_print_num(counters.bcnt, (format|FMT_NOTABLE));
302 fputs("bytes", stdout);
303 }
304 printf(")\n");
305 } else {
306 unsigned int refs;
307 if (!iptc_get_references(&refs, chain, handle))
308 printf(" (ERROR obtaining refs)\n");
309 else
310 printf(" (%u references)\n", refs);
311 }
312
313 if (format & FMT_LINENUMBERS)
314 printf(FMT("%-4s ", "%s "), "num");
315 if (!(format & FMT_NOCOUNTS)) {
316 if (format & FMT_KILOMEGAGIGA) {
317 printf(FMT("%5s ","%s "), "pkts");
318 printf(FMT("%5s ","%s "), "bytes");
319 } else {
320 printf(FMT("%8s ","%s "), "pkts");
321 printf(FMT("%10s ","%s "), "bytes");
322 }
323 }
324 if (!(format & FMT_NOTARGET))
325 printf(FMT("%-9s ","%s "), "target");
326 fputs(" prot ", stdout);
327 if (format & FMT_OPTIONS)
328 fputs("opt", stdout);
329 if (format & FMT_VIA) {
330 printf(FMT(" %-6s ","%s "), "in");
331 printf(FMT("%-6s ","%s "), "out");
332 }
333 printf(FMT(" %-19s ","%s "), "source");
334 printf(FMT(" %-19s "," %s "), "destination");
335 printf("\n");
336 }
337
338
339 static int
print_match(const struct xt_entry_match * m,const struct ipt_ip * ip,int numeric)340 print_match(const struct xt_entry_match *m,
341 const struct ipt_ip *ip,
342 int numeric)
343 {
344 const char *name = m->u.user.name;
345 const int revision = m->u.user.revision;
346 struct xtables_match *match, *mt;
347
348 match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
349 if (match) {
350 mt = xtables_find_match_revision(name, XTF_TRY_LOAD,
351 match, revision);
352 if (mt && mt->print)
353 mt->print(ip, m, numeric);
354 else if (match->print)
355 printf("%s%s ", match->name, unsupported_rev);
356 else
357 printf("%s ", match->name);
358 } else {
359 if (name[0])
360 printf("UNKNOWN match `%s' ", name);
361 }
362 /* Don't stop iterating. */
363 return 0;
364 }
365
366 /* e is called `fw' here for historical reasons */
367 static void
print_firewall(const struct ipt_entry * fw,const char * targname,unsigned int num,unsigned int format,struct xtc_handle * const handle)368 print_firewall(const struct ipt_entry *fw,
369 const char *targname,
370 unsigned int num,
371 unsigned int format,
372 struct xtc_handle *const handle)
373 {
374 struct xtables_target *target, *tg;
375 const struct xt_entry_target *t;
376 uint8_t flags;
377
378 if (!iptc_is_chain(targname, handle))
379 target = xtables_find_target(targname, XTF_TRY_LOAD);
380 else
381 target = xtables_find_target(XT_STANDARD_TARGET,
382 XTF_LOAD_MUST_SUCCEED);
383
384 t = ipt_get_target((struct ipt_entry *)fw);
385 flags = fw->ip.flags;
386
387 if (format & FMT_LINENUMBERS)
388 printf(FMT("%-4u ", "%u "), num);
389
390 if (!(format & FMT_NOCOUNTS)) {
391 xtables_print_num(fw->counters.pcnt, format);
392 xtables_print_num(fw->counters.bcnt, format);
393 }
394
395 if (!(format & FMT_NOTARGET))
396 printf(FMT("%-9s ", "%s "), targname);
397
398 fputc(fw->ip.invflags & XT_INV_PROTO ? '!' : ' ', stdout);
399 {
400 const char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC);
401 if (pname)
402 printf(FMT("%-5s", "%s "), pname);
403 else
404 printf(FMT("%-5hu", "%hu "), fw->ip.proto);
405 }
406
407 if (format & FMT_OPTIONS) {
408 if (format & FMT_NOTABLE)
409 fputs("opt ", stdout);
410 fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
411 fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
412 fputc(' ', stdout);
413 }
414
415 print_ifaces(fw->ip.iniface, fw->ip.outiface, fw->ip.invflags, format);
416
417 print_ipv4_addresses(fw, format);
418
419 if (format & FMT_NOTABLE)
420 fputs(" ", stdout);
421
422 #ifdef IPT_F_GOTO
423 if(fw->ip.flags & IPT_F_GOTO)
424 printf("[goto] ");
425 #endif
426
427 IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
428
429 if (target) {
430 const int revision = t->u.user.revision;
431
432 tg = xtables_find_target_revision(targname, XTF_TRY_LOAD,
433 target, revision);
434 if (tg && tg->print)
435 /* Print the target information. */
436 tg->print(&fw->ip, t, format & FMT_NUMERIC);
437 else if (target->print)
438 printf(" %s%s", target->name, unsupported_rev);
439 } else if (t->u.target_size != sizeof(*t))
440 printf("[%u bytes of unknown target data] ",
441 (unsigned int)(t->u.target_size - sizeof(*t)));
442
443 if (!(format & FMT_NONEWLINE))
444 fputc('\n', stdout);
445 }
446
447 static void
print_firewall_line(const struct ipt_entry * fw,struct xtc_handle * const h)448 print_firewall_line(const struct ipt_entry *fw,
449 struct xtc_handle *const h)
450 {
451 struct xt_entry_target *t;
452
453 t = ipt_get_target((struct ipt_entry *)fw);
454 print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h);
455 }
456
457 static int
append_entry(const xt_chainlabel chain,struct ipt_entry * fw,unsigned int nsaddrs,const struct in_addr saddrs[],const struct in_addr smasks[],unsigned int ndaddrs,const struct in_addr daddrs[],const struct in_addr dmasks[],int verbose,struct xtc_handle * handle)458 append_entry(const xt_chainlabel chain,
459 struct ipt_entry *fw,
460 unsigned int nsaddrs,
461 const struct in_addr saddrs[],
462 const struct in_addr smasks[],
463 unsigned int ndaddrs,
464 const struct in_addr daddrs[],
465 const struct in_addr dmasks[],
466 int verbose,
467 struct xtc_handle *handle)
468 {
469 unsigned int i, j;
470 int ret = 1;
471
472 for (i = 0; i < nsaddrs; i++) {
473 fw->ip.src.s_addr = saddrs[i].s_addr;
474 fw->ip.smsk.s_addr = smasks[i].s_addr;
475 for (j = 0; j < ndaddrs; j++) {
476 fw->ip.dst.s_addr = daddrs[j].s_addr;
477 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
478 if (verbose)
479 print_firewall_line(fw, handle);
480 ret &= iptc_append_entry(chain, fw, handle);
481 }
482 }
483
484 return ret;
485 }
486
487 static int
replace_entry(const xt_chainlabel chain,struct ipt_entry * fw,unsigned int rulenum,const struct in_addr * saddr,const struct in_addr * smask,const struct in_addr * daddr,const struct in_addr * dmask,int verbose,struct xtc_handle * handle)488 replace_entry(const xt_chainlabel chain,
489 struct ipt_entry *fw,
490 unsigned int rulenum,
491 const struct in_addr *saddr, const struct in_addr *smask,
492 const struct in_addr *daddr, const struct in_addr *dmask,
493 int verbose,
494 struct xtc_handle *handle)
495 {
496 fw->ip.src.s_addr = saddr->s_addr;
497 fw->ip.dst.s_addr = daddr->s_addr;
498 fw->ip.smsk.s_addr = smask->s_addr;
499 fw->ip.dmsk.s_addr = dmask->s_addr;
500
501 if (verbose)
502 print_firewall_line(fw, handle);
503 return iptc_replace_entry(chain, fw, rulenum, handle);
504 }
505
506 static int
insert_entry(const xt_chainlabel chain,struct ipt_entry * fw,unsigned int rulenum,unsigned int nsaddrs,const struct in_addr saddrs[],const struct in_addr smasks[],unsigned int ndaddrs,const struct in_addr daddrs[],const struct in_addr dmasks[],int verbose,struct xtc_handle * handle)507 insert_entry(const xt_chainlabel chain,
508 struct ipt_entry *fw,
509 unsigned int rulenum,
510 unsigned int nsaddrs,
511 const struct in_addr saddrs[],
512 const struct in_addr smasks[],
513 unsigned int ndaddrs,
514 const struct in_addr daddrs[],
515 const struct in_addr dmasks[],
516 int verbose,
517 struct xtc_handle *handle)
518 {
519 unsigned int i, j;
520 int ret = 1;
521
522 for (i = 0; i < nsaddrs; i++) {
523 fw->ip.src.s_addr = saddrs[i].s_addr;
524 fw->ip.smsk.s_addr = smasks[i].s_addr;
525 for (j = 0; j < ndaddrs; j++) {
526 fw->ip.dst.s_addr = daddrs[j].s_addr;
527 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
528 if (verbose)
529 print_firewall_line(fw, handle);
530 ret &= iptc_insert_entry(chain, fw, rulenum, handle);
531 }
532 }
533
534 return ret;
535 }
536
537 static unsigned char *
make_delete_mask(const struct xtables_rule_match * matches,const struct xtables_target * target)538 make_delete_mask(const struct xtables_rule_match *matches,
539 const struct xtables_target *target)
540 {
541 /* Establish mask for comparison */
542 unsigned int size;
543 const struct xtables_rule_match *matchp;
544 unsigned char *mask, *mptr;
545
546 size = sizeof(struct ipt_entry);
547 for (matchp = matches; matchp; matchp = matchp->next)
548 size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
549
550 mask = xtables_calloc(1, size
551 + XT_ALIGN(sizeof(struct xt_entry_target))
552 + target->size);
553
554 memset(mask, 0xFF, sizeof(struct ipt_entry));
555 mptr = mask + sizeof(struct ipt_entry);
556
557 for (matchp = matches; matchp; matchp = matchp->next) {
558 memset(mptr, 0xFF,
559 XT_ALIGN(sizeof(struct xt_entry_match))
560 + matchp->match->userspacesize);
561 mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
562 }
563
564 memset(mptr, 0xFF,
565 XT_ALIGN(sizeof(struct xt_entry_target))
566 + target->userspacesize);
567
568 return mask;
569 }
570
571 static int
delete_entry(const xt_chainlabel chain,struct ipt_entry * fw,unsigned int nsaddrs,const struct in_addr saddrs[],const struct in_addr smasks[],unsigned int ndaddrs,const struct in_addr daddrs[],const struct in_addr dmasks[],int verbose,struct xtc_handle * handle,struct xtables_rule_match * matches,const struct xtables_target * target)572 delete_entry(const xt_chainlabel chain,
573 struct ipt_entry *fw,
574 unsigned int nsaddrs,
575 const struct in_addr saddrs[],
576 const struct in_addr smasks[],
577 unsigned int ndaddrs,
578 const struct in_addr daddrs[],
579 const struct in_addr dmasks[],
580 int verbose,
581 struct xtc_handle *handle,
582 struct xtables_rule_match *matches,
583 const struct xtables_target *target)
584 {
585 unsigned int i, j;
586 int ret = 1;
587 unsigned char *mask;
588
589 mask = make_delete_mask(matches, target);
590 for (i = 0; i < nsaddrs; i++) {
591 fw->ip.src.s_addr = saddrs[i].s_addr;
592 fw->ip.smsk.s_addr = smasks[i].s_addr;
593 for (j = 0; j < ndaddrs; j++) {
594 fw->ip.dst.s_addr = daddrs[j].s_addr;
595 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
596 if (verbose)
597 print_firewall_line(fw, handle);
598 ret &= iptc_delete_entry(chain, fw, mask, handle);
599 }
600 }
601 free(mask);
602
603 return ret;
604 }
605
606 static int
check_entry(const xt_chainlabel chain,struct ipt_entry * fw,unsigned int nsaddrs,const struct in_addr * saddrs,const struct in_addr * smasks,unsigned int ndaddrs,const struct in_addr * daddrs,const struct in_addr * dmasks,bool verbose,struct xtc_handle * handle,struct xtables_rule_match * matches,const struct xtables_target * target)607 check_entry(const xt_chainlabel chain, struct ipt_entry *fw,
608 unsigned int nsaddrs, const struct in_addr *saddrs,
609 const struct in_addr *smasks, unsigned int ndaddrs,
610 const struct in_addr *daddrs, const struct in_addr *dmasks,
611 bool verbose, struct xtc_handle *handle,
612 struct xtables_rule_match *matches,
613 const struct xtables_target *target)
614 {
615 unsigned int i, j;
616 int ret = 1;
617 unsigned char *mask;
618
619 mask = make_delete_mask(matches, target);
620 for (i = 0; i < nsaddrs; i++) {
621 fw->ip.src.s_addr = saddrs[i].s_addr;
622 fw->ip.smsk.s_addr = smasks[i].s_addr;
623 for (j = 0; j < ndaddrs; j++) {
624 fw->ip.dst.s_addr = daddrs[j].s_addr;
625 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
626 if (verbose)
627 print_firewall_line(fw, handle);
628 ret &= iptc_check_entry(chain, fw, mask, handle);
629 }
630 }
631
632 free(mask);
633 return ret;
634 }
635
636 int
for_each_chain4(int (* fn)(const xt_chainlabel,int,struct xtc_handle *),int verbose,int builtinstoo,struct xtc_handle * handle)637 for_each_chain4(int (*fn)(const xt_chainlabel, int, struct xtc_handle *),
638 int verbose, int builtinstoo, struct xtc_handle *handle)
639 {
640 int ret = 1;
641 const char *chain;
642 char *chains;
643 unsigned int i, chaincount = 0;
644
645 chain = iptc_first_chain(handle);
646 while (chain) {
647 chaincount++;
648 chain = iptc_next_chain(handle);
649 }
650
651 chains = xtables_malloc(sizeof(xt_chainlabel) * chaincount);
652 i = 0;
653 chain = iptc_first_chain(handle);
654 while (chain) {
655 strcpy(chains + i*sizeof(xt_chainlabel), chain);
656 i++;
657 chain = iptc_next_chain(handle);
658 }
659
660 for (i = 0; i < chaincount; i++) {
661 if (!builtinstoo
662 && iptc_builtin(chains + i*sizeof(xt_chainlabel),
663 handle) == 1)
664 continue;
665 ret &= fn(chains + i*sizeof(xt_chainlabel), verbose, handle);
666 }
667
668 free(chains);
669 return ret;
670 }
671
672 int
flush_entries4(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)673 flush_entries4(const xt_chainlabel chain, int verbose,
674 struct xtc_handle *handle)
675 {
676 if (!chain)
677 return for_each_chain4(flush_entries4, verbose, 1, handle);
678
679 if (verbose)
680 fprintf(stdout, "Flushing chain `%s'\n", chain);
681 return iptc_flush_entries(chain, handle);
682 }
683
684 static int
zero_entries(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)685 zero_entries(const xt_chainlabel chain, int verbose,
686 struct xtc_handle *handle)
687 {
688 if (!chain)
689 return for_each_chain4(zero_entries, verbose, 1, handle);
690
691 if (verbose)
692 fprintf(stdout, "Zeroing chain `%s'\n", chain);
693 return iptc_zero_entries(chain, handle);
694 }
695
696 int
delete_chain4(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)697 delete_chain4(const xt_chainlabel chain, int verbose,
698 struct xtc_handle *handle)
699 {
700 if (!chain)
701 return for_each_chain4(delete_chain4, verbose, 0, handle);
702
703 if (verbose)
704 fprintf(stdout, "Deleting chain `%s'\n", chain);
705 return iptc_delete_chain(chain, handle);
706 }
707
708 static int
list_entries(const xt_chainlabel chain,int rulenum,int verbose,int numeric,int expanded,int linenumbers,struct xtc_handle * handle)709 list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
710 int expanded, int linenumbers, struct xtc_handle *handle)
711 {
712 int found = 0;
713 unsigned int format;
714 const char *this;
715
716 format = FMT_OPTIONS;
717 if (!verbose)
718 format |= FMT_NOCOUNTS;
719 else
720 format |= FMT_VIA;
721
722 if (numeric)
723 format |= FMT_NUMERIC;
724
725 if (!expanded)
726 format |= FMT_KILOMEGAGIGA;
727
728 if (linenumbers)
729 format |= FMT_LINENUMBERS;
730
731 for (this = iptc_first_chain(handle);
732 this;
733 this = iptc_next_chain(handle)) {
734 const struct ipt_entry *i;
735 unsigned int num;
736
737 if (chain && strcmp(chain, this) != 0)
738 continue;
739
740 if (found) printf("\n");
741
742 if (!rulenum)
743 print_header(format, this, handle);
744 i = iptc_first_rule(this, handle);
745
746 num = 0;
747 while (i) {
748 num++;
749 if (!rulenum || num == rulenum)
750 print_firewall(i,
751 iptc_get_target(i, handle),
752 num,
753 format,
754 handle);
755 i = iptc_next_rule(i, handle);
756 }
757 found = 1;
758 }
759
760 errno = ENOENT;
761 return found;
762 }
763
print_proto(uint16_t proto,int invert)764 static void print_proto(uint16_t proto, int invert)
765 {
766 if (proto) {
767 unsigned int i;
768 const char *invertstr = invert ? " !" : "";
769
770 const struct protoent *pent = getprotobynumber(proto);
771 if (pent) {
772 printf("%s -p %s", invertstr, pent->p_name);
773 return;
774 }
775
776 for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
777 if (xtables_chain_protos[i].num == proto) {
778 printf("%s -p %s",
779 invertstr, xtables_chain_protos[i].name);
780 return;
781 }
782
783 printf("%s -p %u", invertstr, proto);
784 }
785 }
786
787 #define IP_PARTS_NATIVE(n) \
788 (unsigned int)((n)>>24)&0xFF, \
789 (unsigned int)((n)>>16)&0xFF, \
790 (unsigned int)((n)>>8)&0xFF, \
791 (unsigned int)((n)&0xFF)
792
793 #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
794
795 /* This assumes that mask is contiguous, and byte-bounded. */
796 static void
print_iface(char letter,const char * iface,const unsigned char * mask,int invert)797 print_iface(char letter, const char *iface, const unsigned char *mask,
798 int invert)
799 {
800 unsigned int i;
801
802 if (mask[0] == 0)
803 return;
804
805 printf("%s -%c ", invert ? " !" : "", letter);
806
807 for (i = 0; i < IFNAMSIZ; i++) {
808 if (mask[i] != 0) {
809 if (iface[i] != '\0')
810 printf("%c", iface[i]);
811 } else {
812 /* we can access iface[i-1] here, because
813 * a few lines above we make sure that mask[0] != 0 */
814 if (iface[i-1] != '\0')
815 printf("+");
816 break;
817 }
818 }
819 }
820
print_match_save(const struct xt_entry_match * e,const struct ipt_ip * ip)821 static int print_match_save(const struct xt_entry_match *e,
822 const struct ipt_ip *ip)
823 {
824 const char *name = e->u.user.name;
825 const int revision = e->u.user.revision;
826 struct xtables_match *match, *mt, *mt2;
827
828 match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
829 if (match) {
830 mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
831 match, revision);
832 if (!mt2)
833 mt2 = match;
834 printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
835
836 /* some matches don't provide a save function */
837 if (mt && mt->save)
838 mt->save(ip, e);
839 else if (match->save)
840 printf(unsupported_rev);
841 } else {
842 if (e->u.match_size) {
843 fprintf(stderr,
844 "Can't find library for match `%s'\n",
845 name);
846 exit(1);
847 }
848 }
849 return 0;
850 }
851
852 /* Print a given ip including mask if necessary. */
print_ip(const char * prefix,uint32_t ip,uint32_t mask,int invert)853 static void print_ip(const char *prefix, uint32_t ip,
854 uint32_t mask, int invert)
855 {
856 uint32_t bits, hmask = ntohl(mask);
857 int i;
858
859 if (!mask && !ip && !invert)
860 return;
861
862 printf("%s %s %u.%u.%u.%u",
863 invert ? " !" : "",
864 prefix,
865 IP_PARTS(ip));
866
867 if (mask == 0xFFFFFFFFU) {
868 printf("/32");
869 return;
870 }
871
872 i = 32;
873 bits = 0xFFFFFFFEU;
874 while (--i >= 0 && hmask != bits)
875 bits <<= 1;
876 if (i >= 0)
877 printf("/%u", i);
878 else
879 printf("/%u.%u.%u.%u", IP_PARTS(mask));
880 }
881
882 /* We want this to be readable, so only print out necessary fields.
883 * Because that's the kind of world I want to live in.
884 */
print_rule4(const struct ipt_entry * e,struct xtc_handle * h,const char * chain,int counters)885 void print_rule4(const struct ipt_entry *e,
886 struct xtc_handle *h, const char *chain, int counters)
887 {
888 const struct xt_entry_target *t;
889 const char *target_name;
890
891 /* print counters for iptables-save */
892 if (counters > 0)
893 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
894
895 /* print chain name */
896 printf("-A %s", chain);
897
898 /* Print IP part. */
899 print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
900 e->ip.invflags & IPT_INV_SRCIP);
901
902 print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
903 e->ip.invflags & IPT_INV_DSTIP);
904
905 print_iface('i', e->ip.iniface, e->ip.iniface_mask,
906 e->ip.invflags & IPT_INV_VIA_IN);
907
908 print_iface('o', e->ip.outiface, e->ip.outiface_mask,
909 e->ip.invflags & IPT_INV_VIA_OUT);
910
911 print_proto(e->ip.proto, e->ip.invflags & XT_INV_PROTO);
912
913 if (e->ip.flags & IPT_F_FRAG)
914 printf("%s -f",
915 e->ip.invflags & IPT_INV_FRAG ? " !" : "");
916
917 /* Print matchinfo part */
918 if (e->target_offset)
919 IPT_MATCH_ITERATE(e, print_match_save, &e->ip);
920
921 /* print counters for iptables -R */
922 if (counters < 0)
923 printf(" -c %llu %llu", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
924
925 /* Print target name and targinfo part */
926 target_name = iptc_get_target(e, h);
927 t = ipt_get_target((struct ipt_entry *)e);
928 if (t->u.user.name[0]) {
929 const char *name = t->u.user.name;
930 const int revision = t->u.user.revision;
931 struct xtables_target *target, *tg, *tg2;
932
933 target = xtables_find_target(name, XTF_TRY_LOAD);
934 if (!target) {
935 fprintf(stderr, "Can't find library for target `%s'\n",
936 name);
937 exit(1);
938 }
939
940 tg = tg2 = xtables_find_target_revision(name, XTF_TRY_LOAD,
941 target, revision);
942 if (!tg2)
943 tg2 = target;
944 printf(" -j %s", tg2->alias ? tg2->alias(t) : target_name);
945
946 if (tg && tg->save)
947 tg->save(&e->ip, t);
948 else if (target->save)
949 printf(unsupported_rev);
950 else {
951 /* If the target size is greater than xt_entry_target
952 * there is something to be saved, we just don't know
953 * how to print it */
954 if (t->u.target_size !=
955 sizeof(struct xt_entry_target)) {
956 fprintf(stderr, "Target `%s' is missing "
957 "save function\n",
958 name);
959 exit(1);
960 }
961 }
962 } else if (target_name && (*target_name != '\0'))
963 #ifdef IPT_F_GOTO
964 printf(" -%c %s", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
965 #else
966 printf(" -j %s", target_name);
967 #endif
968
969 printf("\n");
970 }
971
972 static int
list_rules(const xt_chainlabel chain,int rulenum,int counters,struct xtc_handle * handle)973 list_rules(const xt_chainlabel chain, int rulenum, int counters,
974 struct xtc_handle *handle)
975 {
976 const char *this = NULL;
977 int found = 0;
978
979 if (counters)
980 counters = -1; /* iptables -c format */
981
982 /* Dump out chain names first,
983 * thereby preventing dependency conflicts */
984 if (!rulenum) for (this = iptc_first_chain(handle);
985 this;
986 this = iptc_next_chain(handle)) {
987 if (chain && strcmp(this, chain) != 0)
988 continue;
989
990 if (iptc_builtin(this, handle)) {
991 struct xt_counters count;
992 printf("-P %s %s", this, iptc_get_policy(this, &count, handle));
993 if (counters)
994 printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
995 printf("\n");
996 } else {
997 printf("-N %s\n", this);
998 }
999 }
1000
1001 for (this = iptc_first_chain(handle);
1002 this;
1003 this = iptc_next_chain(handle)) {
1004 const struct ipt_entry *e;
1005 int num = 0;
1006
1007 if (chain && strcmp(this, chain) != 0)
1008 continue;
1009
1010 /* Dump out rules */
1011 e = iptc_first_rule(this, handle);
1012 while(e) {
1013 num++;
1014 if (!rulenum || num == rulenum)
1015 print_rule4(e, handle, this, counters);
1016 e = iptc_next_rule(e, handle);
1017 }
1018 found = 1;
1019 }
1020
1021 errno = ENOENT;
1022 return found;
1023 }
1024
1025 static struct ipt_entry *
generate_entry(const struct ipt_entry * fw,struct xtables_rule_match * matches,struct xt_entry_target * target)1026 generate_entry(const struct ipt_entry *fw,
1027 struct xtables_rule_match *matches,
1028 struct xt_entry_target *target)
1029 {
1030 unsigned int size;
1031 struct xtables_rule_match *matchp;
1032 struct ipt_entry *e;
1033
1034 size = sizeof(struct ipt_entry);
1035 for (matchp = matches; matchp; matchp = matchp->next)
1036 size += matchp->match->m->u.match_size;
1037
1038 e = xtables_malloc(size + target->u.target_size);
1039 *e = *fw;
1040 e->target_offset = size;
1041 e->next_offset = size + target->u.target_size;
1042
1043 size = 0;
1044 for (matchp = matches; matchp; matchp = matchp->next) {
1045 memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
1046 size += matchp->match->m->u.match_size;
1047 }
1048 memcpy(e->elems + size, target, target->u.target_size);
1049
1050 return e;
1051 }
1052
do_command4(int argc,char * argv[],char ** table,struct xtc_handle ** handle,bool restore)1053 int do_command4(int argc, char *argv[], char **table,
1054 struct xtc_handle **handle, bool restore)
1055 {
1056 struct iptables_command_state cs = {
1057 .jumpto = "",
1058 .argv = argv,
1059 };
1060 struct ipt_entry *e = NULL;
1061 unsigned int nsaddrs = 0, ndaddrs = 0;
1062 struct in_addr *saddrs = NULL, *smasks = NULL;
1063 struct in_addr *daddrs = NULL, *dmasks = NULL;
1064 struct timeval wait_interval = {
1065 .tv_sec = 1,
1066 };
1067 bool wait_interval_set = false;
1068 int verbose = 0;
1069 int wait = 0;
1070 const char *chain = NULL;
1071 const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
1072 const char *policy = NULL, *newname = NULL;
1073 unsigned int rulenum = 0, command = 0;
1074 const char *pcnt = NULL, *bcnt = NULL;
1075 int ret = 1;
1076 struct xtables_match *m;
1077 struct xtables_rule_match *matchp;
1078 struct xtables_target *t;
1079 unsigned long long cnt;
1080 bool table_set = false;
1081
1082 /* re-set optind to 0 in case do_command4 gets called
1083 * a second time */
1084 optind = 0;
1085
1086 /* clear mflags in case do_command4 gets called a second time
1087 * (we clear the global list of all matches for security)*/
1088 for (m = xtables_matches; m; m = m->next)
1089 m->mflags = 0;
1090
1091 for (t = xtables_targets; t; t = t->next) {
1092 t->tflags = 0;
1093 t->used = 0;
1094 }
1095
1096 /* Suppress error messages: we may add new options if we
1097 demand-load a protocol. */
1098 opterr = 0;
1099 opts = xt_params->orig_opts;
1100 while ((cs.c = getopt_long(argc, argv,
1101 "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
1102 opts, NULL)) != -1) {
1103 switch (cs.c) {
1104 /*
1105 * Command selection
1106 */
1107 case 'A':
1108 add_command(&command, CMD_APPEND, CMD_NONE,
1109 cs.invert);
1110 chain = optarg;
1111 break;
1112
1113 case 'C':
1114 add_command(&command, CMD_CHECK, CMD_NONE,
1115 cs.invert);
1116 chain = optarg;
1117 break;
1118
1119 case 'D':
1120 add_command(&command, CMD_DELETE, CMD_NONE,
1121 cs.invert);
1122 chain = optarg;
1123 if (xs_has_arg(argc, argv)) {
1124 rulenum = parse_rulenumber(argv[optind++]);
1125 command = CMD_DELETE_NUM;
1126 }
1127 break;
1128
1129 case 'R':
1130 add_command(&command, CMD_REPLACE, CMD_NONE,
1131 cs.invert);
1132 chain = optarg;
1133 if (xs_has_arg(argc, argv))
1134 rulenum = parse_rulenumber(argv[optind++]);
1135 else
1136 xtables_error(PARAMETER_PROBLEM,
1137 "-%c requires a rule number",
1138 cmd2char(CMD_REPLACE));
1139 break;
1140
1141 case 'I':
1142 add_command(&command, CMD_INSERT, CMD_NONE,
1143 cs.invert);
1144 chain = optarg;
1145 if (xs_has_arg(argc, argv))
1146 rulenum = parse_rulenumber(argv[optind++]);
1147 else rulenum = 1;
1148 break;
1149
1150 case 'L':
1151 add_command(&command, CMD_LIST,
1152 CMD_ZERO | CMD_ZERO_NUM, cs.invert);
1153 if (optarg) chain = optarg;
1154 else if (xs_has_arg(argc, argv))
1155 chain = argv[optind++];
1156 if (xs_has_arg(argc, argv))
1157 rulenum = parse_rulenumber(argv[optind++]);
1158 break;
1159
1160 case 'S':
1161 add_command(&command, CMD_LIST_RULES,
1162 CMD_ZERO|CMD_ZERO_NUM, cs.invert);
1163 if (optarg) chain = optarg;
1164 else if (xs_has_arg(argc, argv))
1165 chain = argv[optind++];
1166 if (xs_has_arg(argc, argv))
1167 rulenum = parse_rulenumber(argv[optind++]);
1168 break;
1169
1170 case 'F':
1171 add_command(&command, CMD_FLUSH, CMD_NONE,
1172 cs.invert);
1173 if (optarg) chain = optarg;
1174 else if (xs_has_arg(argc, argv))
1175 chain = argv[optind++];
1176 break;
1177
1178 case 'Z':
1179 add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
1180 cs.invert);
1181 if (optarg) chain = optarg;
1182 else if (xs_has_arg(argc, argv))
1183 chain = argv[optind++];
1184 if (xs_has_arg(argc, argv)) {
1185 rulenum = parse_rulenumber(argv[optind++]);
1186 command = CMD_ZERO_NUM;
1187 }
1188 break;
1189
1190 case 'N':
1191 parse_chain(optarg);
1192 add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
1193 cs.invert);
1194 chain = optarg;
1195 break;
1196
1197 case 'X':
1198 add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
1199 cs.invert);
1200 if (optarg) chain = optarg;
1201 else if (xs_has_arg(argc, argv))
1202 chain = argv[optind++];
1203 break;
1204
1205 case 'E':
1206 add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
1207 cs.invert);
1208 chain = optarg;
1209 if (xs_has_arg(argc, argv))
1210 newname = argv[optind++];
1211 else
1212 xtables_error(PARAMETER_PROBLEM,
1213 "-%c requires old-chain-name and "
1214 "new-chain-name",
1215 cmd2char(CMD_RENAME_CHAIN));
1216 break;
1217
1218 case 'P':
1219 add_command(&command, CMD_SET_POLICY, CMD_NONE,
1220 cs.invert);
1221 chain = optarg;
1222 if (xs_has_arg(argc, argv))
1223 policy = argv[optind++];
1224 else
1225 xtables_error(PARAMETER_PROBLEM,
1226 "-%c requires a chain and a policy",
1227 cmd2char(CMD_SET_POLICY));
1228 break;
1229
1230 case 'h':
1231 if (!optarg)
1232 optarg = argv[optind];
1233
1234 /* iptables -p icmp -h */
1235 if (!cs.matches && cs.protocol)
1236 xtables_find_match(cs.protocol,
1237 XTF_TRY_LOAD, &cs.matches);
1238
1239 exit_printhelp(cs.matches);
1240
1241 /*
1242 * Option selection
1243 */
1244 case 'p':
1245 set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags,
1246 cs.invert);
1247
1248 /* Canonicalize into lower case */
1249 for (cs.protocol = optarg; *cs.protocol; cs.protocol++)
1250 *cs.protocol = tolower(*cs.protocol);
1251
1252 cs.protocol = optarg;
1253 cs.fw.ip.proto = xtables_parse_protocol(cs.protocol);
1254
1255 if (cs.fw.ip.proto == 0
1256 && (cs.fw.ip.invflags & XT_INV_PROTO))
1257 xtables_error(PARAMETER_PROBLEM,
1258 "rule would never match protocol");
1259 break;
1260
1261 case 's':
1262 set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags,
1263 cs.invert);
1264 shostnetworkmask = optarg;
1265 break;
1266
1267 case 'd':
1268 set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags,
1269 cs.invert);
1270 dhostnetworkmask = optarg;
1271 break;
1272
1273 #ifdef IPT_F_GOTO
1274 case 'g':
1275 set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
1276 cs.invert);
1277 cs.fw.ip.flags |= IPT_F_GOTO;
1278 cs.jumpto = xt_parse_target(optarg);
1279 break;
1280 #endif
1281
1282 case 'j':
1283 set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
1284 cs.invert);
1285 command_jump(&cs, optarg);
1286 break;
1287
1288
1289 case 'i':
1290 if (*optarg == '\0')
1291 xtables_error(PARAMETER_PROBLEM,
1292 "Empty interface is likely to be "
1293 "undesired");
1294 set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags,
1295 cs.invert);
1296 xtables_parse_interface(optarg,
1297 cs.fw.ip.iniface,
1298 cs.fw.ip.iniface_mask);
1299 break;
1300
1301 case 'o':
1302 if (*optarg == '\0')
1303 xtables_error(PARAMETER_PROBLEM,
1304 "Empty interface is likely to be "
1305 "undesired");
1306 set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags,
1307 cs.invert);
1308 xtables_parse_interface(optarg,
1309 cs.fw.ip.outiface,
1310 cs.fw.ip.outiface_mask);
1311 break;
1312
1313 case 'f':
1314 set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags,
1315 cs.invert);
1316 cs.fw.ip.flags |= IPT_F_FRAG;
1317 break;
1318
1319 case 'v':
1320 if (!verbose)
1321 set_option(&cs.options, OPT_VERBOSE,
1322 &cs.fw.ip.invflags, cs.invert);
1323 verbose++;
1324 break;
1325
1326 case 'w':
1327 if (restore) {
1328 xtables_error(PARAMETER_PROBLEM,
1329 "You cannot use `-w' from "
1330 "iptables-restore");
1331 }
1332 wait = parse_wait_time(argc, argv);
1333 break;
1334
1335 case 'W':
1336 if (restore) {
1337 xtables_error(PARAMETER_PROBLEM,
1338 "You cannot use `-W' from "
1339 "iptables-restore");
1340 }
1341 parse_wait_interval(argc, argv, &wait_interval);
1342 wait_interval_set = true;
1343 break;
1344
1345 case 'm':
1346 command_match(&cs);
1347 break;
1348
1349 case 'n':
1350 set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags,
1351 cs.invert);
1352 break;
1353
1354 case 't':
1355 if (cs.invert)
1356 xtables_error(PARAMETER_PROBLEM,
1357 "unexpected ! flag before --table");
1358 if (restore && table_set)
1359 xtables_error(PARAMETER_PROBLEM,
1360 "The -t option (seen in line %u) cannot be used in %s.\n",
1361 line, xt_params->program_name);
1362 *table = optarg;
1363 table_set = true;
1364 break;
1365
1366 case 'x':
1367 set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags,
1368 cs.invert);
1369 break;
1370
1371 case 'V':
1372 if (cs.invert)
1373 printf("Not %s ;-)\n", prog_vers);
1374 else
1375 printf("%s v%s (legacy)\n",
1376 prog_name, prog_vers);
1377 exit(0);
1378
1379 case '0':
1380 set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags,
1381 cs.invert);
1382 break;
1383
1384 case 'M':
1385 xtables_modprobe_program = optarg;
1386 break;
1387
1388 case 'c':
1389
1390 set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags,
1391 cs.invert);
1392 pcnt = optarg;
1393 bcnt = strchr(pcnt + 1, ',');
1394 if (bcnt)
1395 bcnt++;
1396 if (!bcnt && xs_has_arg(argc, argv))
1397 bcnt = argv[optind++];
1398 if (!bcnt)
1399 xtables_error(PARAMETER_PROBLEM,
1400 "-%c requires packet and byte counter",
1401 opt2char(OPT_COUNTERS));
1402
1403 if (sscanf(pcnt, "%llu", &cnt) != 1)
1404 xtables_error(PARAMETER_PROBLEM,
1405 "-%c packet counter not numeric",
1406 opt2char(OPT_COUNTERS));
1407 cs.fw.counters.pcnt = cnt;
1408
1409 if (sscanf(bcnt, "%llu", &cnt) != 1)
1410 xtables_error(PARAMETER_PROBLEM,
1411 "-%c byte counter not numeric",
1412 opt2char(OPT_COUNTERS));
1413 cs.fw.counters.bcnt = cnt;
1414 break;
1415
1416 case '4':
1417 /* This is indeed the IPv4 iptables */
1418 break;
1419
1420 case '6':
1421 /* This is not the IPv6 ip6tables */
1422 if (line != -1)
1423 return 1; /* success: line ignored */
1424 fprintf(stderr, "This is the IPv4 version of iptables.\n");
1425 exit_tryhelp(2);
1426
1427 case 1: /* non option */
1428 if (optarg[0] == '!' && optarg[1] == '\0') {
1429 if (cs.invert)
1430 xtables_error(PARAMETER_PROBLEM,
1431 "multiple consecutive ! not"
1432 " allowed");
1433 cs.invert = true;
1434 optarg[0] = '\0';
1435 continue;
1436 }
1437 fprintf(stderr, "Bad argument `%s'\n", optarg);
1438 exit_tryhelp(2);
1439
1440 default:
1441 if (command_default(&cs, &iptables_globals) == 1)
1442 /* cf. ip6tables.c */
1443 continue;
1444 break;
1445 }
1446 cs.invert = false;
1447 }
1448
1449 if (!wait && wait_interval_set)
1450 xtables_error(PARAMETER_PROBLEM,
1451 "--wait-interval only makes sense with --wait\n");
1452
1453 if (strcmp(*table, "nat") == 0 &&
1454 ((policy != NULL && strcmp(policy, "DROP") == 0) ||
1455 (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
1456 xtables_error(PARAMETER_PROBLEM,
1457 "\nThe \"nat\" table is not intended for filtering, "
1458 "the use of DROP is therefore inhibited.\n\n");
1459
1460 for (matchp = cs.matches; matchp; matchp = matchp->next)
1461 xtables_option_mfcall(matchp->match);
1462 if (cs.target != NULL)
1463 xtables_option_tfcall(cs.target);
1464
1465 /* Fix me: must put inverse options checking here --MN */
1466
1467 if (optind < argc)
1468 xtables_error(PARAMETER_PROBLEM,
1469 "unknown arguments found on commandline");
1470 if (!command)
1471 xtables_error(PARAMETER_PROBLEM, "no command specified");
1472 if (cs.invert)
1473 xtables_error(PARAMETER_PROBLEM,
1474 "nothing appropriate following !");
1475
1476 if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
1477 if (!(cs.options & OPT_DESTINATION))
1478 dhostnetworkmask = "0.0.0.0/0";
1479 if (!(cs.options & OPT_SOURCE))
1480 shostnetworkmask = "0.0.0.0/0";
1481 }
1482
1483 if (shostnetworkmask)
1484 xtables_ipparse_multiple(shostnetworkmask, &saddrs,
1485 &smasks, &nsaddrs);
1486
1487 if (dhostnetworkmask)
1488 xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
1489 &dmasks, &ndaddrs);
1490
1491 if ((nsaddrs > 1 || ndaddrs > 1) &&
1492 (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
1493 xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
1494 " source or destination IP addresses");
1495
1496 if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
1497 xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
1498 "specify a unique address");
1499
1500 generic_opt_check(command, cs.options);
1501
1502 /* Attempt to acquire the xtables lock */
1503 if (!restore)
1504 xtables_lock_or_exit(wait, &wait_interval);
1505
1506 /* only allocate handle if we weren't called with a handle */
1507 if (!*handle)
1508 *handle = iptc_init(*table);
1509
1510 /* try to insmod the module if iptc_init failed */
1511 if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1)
1512 *handle = iptc_init(*table);
1513
1514 if (!*handle)
1515 xtables_error(VERSION_PROBLEM,
1516 "can't initialize iptables table `%s': %s",
1517 *table, iptc_strerror(errno));
1518
1519 if (command == CMD_APPEND
1520 || command == CMD_DELETE
1521 || command == CMD_CHECK
1522 || command == CMD_INSERT
1523 || command == CMD_REPLACE) {
1524 if (strcmp(chain, "PREROUTING") == 0
1525 || strcmp(chain, "INPUT") == 0) {
1526 /* -o not valid with incoming packets. */
1527 if (cs.options & OPT_VIANAMEOUT)
1528 xtables_error(PARAMETER_PROBLEM,
1529 "Can't use -%c with %s\n",
1530 opt2char(OPT_VIANAMEOUT),
1531 chain);
1532 }
1533
1534 if (strcmp(chain, "POSTROUTING") == 0
1535 || strcmp(chain, "OUTPUT") == 0) {
1536 /* -i not valid with outgoing packets */
1537 if (cs.options & OPT_VIANAMEIN)
1538 xtables_error(PARAMETER_PROBLEM,
1539 "Can't use -%c with %s\n",
1540 opt2char(OPT_VIANAMEIN),
1541 chain);
1542 }
1543
1544 if (cs.target && iptc_is_chain(cs.jumpto, *handle)) {
1545 fprintf(stderr,
1546 "Warning: using chain %s, not extension\n",
1547 cs.jumpto);
1548
1549 if (cs.target->t)
1550 free(cs.target->t);
1551
1552 cs.target = NULL;
1553 }
1554
1555 /* If they didn't specify a target, or it's a chain
1556 name, use standard. */
1557 if (!cs.target
1558 && (strlen(cs.jumpto) == 0
1559 || iptc_is_chain(cs.jumpto, *handle))) {
1560 size_t size;
1561
1562 cs.target = xtables_find_target(XT_STANDARD_TARGET,
1563 XTF_LOAD_MUST_SUCCEED);
1564
1565 size = sizeof(struct xt_entry_target)
1566 + cs.target->size;
1567 cs.target->t = xtables_calloc(1, size);
1568 cs.target->t->u.target_size = size;
1569 strcpy(cs.target->t->u.user.name, cs.jumpto);
1570 if (!iptc_is_chain(cs.jumpto, *handle))
1571 cs.target->t->u.user.revision = cs.target->revision;
1572 xs_init_target(cs.target);
1573 }
1574
1575 if (!cs.target) {
1576 /* It is no chain, and we can't load a plugin.
1577 * We cannot know if the plugin is corrupt, non
1578 * existent OR if the user just misspelled a
1579 * chain.
1580 */
1581 #ifdef IPT_F_GOTO
1582 if (cs.fw.ip.flags & IPT_F_GOTO)
1583 xtables_error(PARAMETER_PROBLEM,
1584 "goto '%s' is not a chain\n",
1585 cs.jumpto);
1586 #endif
1587 xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED);
1588 } else {
1589 e = generate_entry(&cs.fw, cs.matches, cs.target->t);
1590 free(cs.target->t);
1591 }
1592 }
1593
1594 switch (command) {
1595 case CMD_APPEND:
1596 ret = append_entry(chain, e,
1597 nsaddrs, saddrs, smasks,
1598 ndaddrs, daddrs, dmasks,
1599 cs.options&OPT_VERBOSE,
1600 *handle);
1601 break;
1602 case CMD_DELETE:
1603 ret = delete_entry(chain, e,
1604 nsaddrs, saddrs, smasks,
1605 ndaddrs, daddrs, dmasks,
1606 cs.options&OPT_VERBOSE,
1607 *handle, cs.matches, cs.target);
1608 break;
1609 case CMD_DELETE_NUM:
1610 ret = iptc_delete_num_entry(chain, rulenum - 1, *handle);
1611 break;
1612 case CMD_CHECK:
1613 ret = check_entry(chain, e,
1614 nsaddrs, saddrs, smasks,
1615 ndaddrs, daddrs, dmasks,
1616 cs.options&OPT_VERBOSE,
1617 *handle, cs.matches, cs.target);
1618 break;
1619 case CMD_REPLACE:
1620 ret = replace_entry(chain, e, rulenum - 1,
1621 saddrs, smasks, daddrs, dmasks,
1622 cs.options&OPT_VERBOSE, *handle);
1623 break;
1624 case CMD_INSERT:
1625 ret = insert_entry(chain, e, rulenum - 1,
1626 nsaddrs, saddrs, smasks,
1627 ndaddrs, daddrs, dmasks,
1628 cs.options&OPT_VERBOSE,
1629 *handle);
1630 break;
1631 case CMD_FLUSH:
1632 ret = flush_entries4(chain, cs.options&OPT_VERBOSE, *handle);
1633 break;
1634 case CMD_ZERO:
1635 ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle);
1636 break;
1637 case CMD_ZERO_NUM:
1638 ret = iptc_zero_counter(chain, rulenum, *handle);
1639 break;
1640 case CMD_LIST:
1641 case CMD_LIST|CMD_ZERO:
1642 case CMD_LIST|CMD_ZERO_NUM:
1643 ret = list_entries(chain,
1644 rulenum,
1645 cs.options&OPT_VERBOSE,
1646 cs.options&OPT_NUMERIC,
1647 cs.options&OPT_EXPANDED,
1648 cs.options&OPT_LINENUMBERS,
1649 *handle);
1650 if (ret && (command & CMD_ZERO))
1651 ret = zero_entries(chain,
1652 cs.options&OPT_VERBOSE, *handle);
1653 if (ret && (command & CMD_ZERO_NUM))
1654 ret = iptc_zero_counter(chain, rulenum, *handle);
1655 break;
1656 case CMD_LIST_RULES:
1657 case CMD_LIST_RULES|CMD_ZERO:
1658 case CMD_LIST_RULES|CMD_ZERO_NUM:
1659 ret = list_rules(chain,
1660 rulenum,
1661 cs.options&OPT_VERBOSE,
1662 *handle);
1663 if (ret && (command & CMD_ZERO))
1664 ret = zero_entries(chain,
1665 cs.options&OPT_VERBOSE, *handle);
1666 if (ret && (command & CMD_ZERO_NUM))
1667 ret = iptc_zero_counter(chain, rulenum, *handle);
1668 break;
1669 case CMD_NEW_CHAIN:
1670 ret = iptc_create_chain(chain, *handle);
1671 break;
1672 case CMD_DELETE_CHAIN:
1673 ret = delete_chain4(chain, cs.options&OPT_VERBOSE, *handle);
1674 break;
1675 case CMD_RENAME_CHAIN:
1676 ret = iptc_rename_chain(chain, newname, *handle);
1677 break;
1678 case CMD_SET_POLICY:
1679 ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle);
1680 break;
1681 default:
1682 /* We should never reach this... */
1683 exit_tryhelp(2);
1684 }
1685
1686 if (verbose > 1)
1687 dump_entries(*handle);
1688
1689 xtables_rule_matches_free(&cs.matches);
1690
1691 if (e != NULL) {
1692 free(e);
1693 e = NULL;
1694 }
1695
1696 free(saddrs);
1697 free(smasks);
1698 free(daddrs);
1699 free(dmasks);
1700 xtables_free_opts(1);
1701
1702 return ret;
1703 }
1704