1 /* Code to take an iptables-style command line and do it. */
2
3 /*
4 * Author: [email protected] and [email protected]
5 *
6 * (C) 2000-2002 by the netfilter coreteam <[email protected]>:
7 * Paul 'Rusty' Russell <[email protected]>
8 * Marc Boucher <[email protected]>
9 * James Morris <[email protected]>
10 * Harald Welte <[email protected]>
11 * Jozsef Kadlecsik <[email protected]>
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 struct xtables_globals iptables_globals = {
88 .option_offset = 0,
89 .program_version = PACKAGE_VERSION " (legacy)",
90 .orig_opts = original_opts,
91 .compat_rev = xtables_compatible_revision,
92 };
93
94 /*
95 * All functions starting with "parse" should succeed, otherwise
96 * the program fails.
97 * Most routines return pointers to static data that may change
98 * between calls to the same or other routines with a few exceptions:
99 * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
100 * return global static data.
101 */
102
103 /* Christophe Burki wants `-p 6' to imply `-m tcp'. */
104
105
106 static int
print_match(const struct xt_entry_match * m,const struct ipt_ip * ip,int numeric)107 print_match(const struct xt_entry_match *m,
108 const struct ipt_ip *ip,
109 int numeric)
110 {
111 const char *name = m->u.user.name;
112 const int revision = m->u.user.revision;
113 struct xtables_match *match, *mt;
114
115 match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
116 if (match) {
117 mt = xtables_find_match_revision(name, XTF_TRY_LOAD,
118 match, revision);
119 if (mt && mt->print)
120 mt->print(ip, m, numeric);
121 else if (match->print)
122 printf("%s%s ", match->name, unsupported_rev);
123 else
124 printf("%s ", match->name);
125
126 if (match->next == match)
127 free(match);
128 } else {
129 if (name[0])
130 printf("UNKNOWN match `%s' ", name);
131 }
132 /* Don't stop iterating. */
133 return 0;
134 }
135
136 /* e is called `fw' here for historical reasons */
137 static void
print_firewall(const struct ipt_entry * fw,const char * targname,unsigned int num,unsigned int format,struct xtc_handle * const handle)138 print_firewall(const struct ipt_entry *fw,
139 const char *targname,
140 unsigned int num,
141 unsigned int format,
142 struct xtc_handle *const handle)
143 {
144 struct xtables_target *target, *tg;
145 const struct xt_entry_target *t;
146
147 if (!iptc_is_chain(targname, handle))
148 target = xtables_find_target(targname, XTF_TRY_LOAD);
149 else
150 target = xtables_find_target(XT_STANDARD_TARGET,
151 XTF_LOAD_MUST_SUCCEED);
152
153 t = ipt_get_target((struct ipt_entry *)fw);
154
155 print_rule_details(num, &fw->counters, targname, fw->ip.proto,
156 fw->ip.flags, fw->ip.invflags, format);
157
158 print_fragment(fw->ip.flags, fw->ip.invflags, format, false);
159
160 print_ifaces(fw->ip.iniface, fw->ip.outiface, fw->ip.invflags, format);
161
162 print_ipv4_addresses(fw, format);
163
164 if (format & FMT_NOTABLE)
165 fputs(" ", stdout);
166
167 #ifdef IPT_F_GOTO
168 if(fw->ip.flags & IPT_F_GOTO)
169 printf("[goto] ");
170 #endif
171
172 IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
173
174 if (target) {
175 const int revision = t->u.user.revision;
176
177 tg = xtables_find_target_revision(targname, XTF_TRY_LOAD,
178 target, revision);
179 if (tg && tg->print)
180 /* Print the target information. */
181 tg->print(&fw->ip, t, format & FMT_NUMERIC);
182 else if (target->print)
183 printf(" %s%s", target->name, unsupported_rev);
184
185 if (target->next == target)
186 free(target);
187 } else if (t->u.target_size != sizeof(*t))
188 printf("[%u bytes of unknown target data] ",
189 (unsigned int)(t->u.target_size - sizeof(*t)));
190
191 if (!(format & FMT_NONEWLINE))
192 fputc('\n', stdout);
193 }
194
195 static void
print_firewall_line(const struct ipt_entry * fw,struct xtc_handle * const h)196 print_firewall_line(const struct ipt_entry *fw,
197 struct xtc_handle *const h)
198 {
199 struct xt_entry_target *t;
200
201 t = ipt_get_target((struct ipt_entry *)fw);
202 print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h);
203 }
204
205 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)206 append_entry(const xt_chainlabel chain,
207 struct ipt_entry *fw,
208 unsigned int nsaddrs,
209 const struct in_addr saddrs[],
210 const struct in_addr smasks[],
211 unsigned int ndaddrs,
212 const struct in_addr daddrs[],
213 const struct in_addr dmasks[],
214 int verbose,
215 struct xtc_handle *handle)
216 {
217 unsigned int i, j;
218 int ret = 1;
219
220 for (i = 0; i < nsaddrs; i++) {
221 fw->ip.src.s_addr = saddrs[i].s_addr;
222 fw->ip.smsk.s_addr = smasks[i].s_addr;
223 for (j = 0; j < ndaddrs; j++) {
224 fw->ip.dst.s_addr = daddrs[j].s_addr;
225 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
226 if (verbose)
227 print_firewall_line(fw, handle);
228 ret &= iptc_append_entry(chain, fw, handle);
229 }
230 }
231
232 return ret;
233 }
234
235 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)236 replace_entry(const xt_chainlabel chain,
237 struct ipt_entry *fw,
238 unsigned int rulenum,
239 const struct in_addr *saddr, const struct in_addr *smask,
240 const struct in_addr *daddr, const struct in_addr *dmask,
241 int verbose,
242 struct xtc_handle *handle)
243 {
244 fw->ip.src.s_addr = saddr->s_addr;
245 fw->ip.dst.s_addr = daddr->s_addr;
246 fw->ip.smsk.s_addr = smask->s_addr;
247 fw->ip.dmsk.s_addr = dmask->s_addr;
248
249 if (verbose)
250 print_firewall_line(fw, handle);
251 return iptc_replace_entry(chain, fw, rulenum, handle);
252 }
253
254 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)255 insert_entry(const xt_chainlabel chain,
256 struct ipt_entry *fw,
257 unsigned int rulenum,
258 unsigned int nsaddrs,
259 const struct in_addr saddrs[],
260 const struct in_addr smasks[],
261 unsigned int ndaddrs,
262 const struct in_addr daddrs[],
263 const struct in_addr dmasks[],
264 int verbose,
265 struct xtc_handle *handle)
266 {
267 unsigned int i, j;
268 int ret = 1;
269
270 for (i = 0; i < nsaddrs; i++) {
271 fw->ip.src.s_addr = saddrs[i].s_addr;
272 fw->ip.smsk.s_addr = smasks[i].s_addr;
273 for (j = 0; j < ndaddrs; j++) {
274 fw->ip.dst.s_addr = daddrs[j].s_addr;
275 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
276 if (verbose)
277 print_firewall_line(fw, handle);
278 ret &= iptc_insert_entry(chain, fw, rulenum, handle);
279 }
280 }
281
282 return ret;
283 }
284
285 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)286 delete_entry(const xt_chainlabel chain,
287 struct ipt_entry *fw,
288 unsigned int nsaddrs,
289 const struct in_addr saddrs[],
290 const struct in_addr smasks[],
291 unsigned int ndaddrs,
292 const struct in_addr daddrs[],
293 const struct in_addr dmasks[],
294 int verbose,
295 struct xtc_handle *handle,
296 struct xtables_rule_match *matches,
297 const struct xtables_target *target)
298 {
299 unsigned int i, j;
300 int ret = 1;
301 unsigned char *mask;
302
303 mask = make_delete_mask(matches, target, sizeof(*fw));
304 for (i = 0; i < nsaddrs; i++) {
305 fw->ip.src.s_addr = saddrs[i].s_addr;
306 fw->ip.smsk.s_addr = smasks[i].s_addr;
307 for (j = 0; j < ndaddrs; j++) {
308 fw->ip.dst.s_addr = daddrs[j].s_addr;
309 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
310 if (verbose)
311 print_firewall_line(fw, handle);
312 ret &= iptc_delete_entry(chain, fw, mask, handle);
313 }
314 }
315 free(mask);
316
317 return ret;
318 }
319
320 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)321 check_entry(const xt_chainlabel chain, struct ipt_entry *fw,
322 unsigned int nsaddrs, const struct in_addr *saddrs,
323 const struct in_addr *smasks, unsigned int ndaddrs,
324 const struct in_addr *daddrs, const struct in_addr *dmasks,
325 bool verbose, struct xtc_handle *handle,
326 struct xtables_rule_match *matches,
327 const struct xtables_target *target)
328 {
329 unsigned int i, j;
330 int ret = 1;
331 unsigned char *mask;
332
333 mask = make_delete_mask(matches, target, sizeof(*fw));
334 for (i = 0; i < nsaddrs; i++) {
335 fw->ip.src.s_addr = saddrs[i].s_addr;
336 fw->ip.smsk.s_addr = smasks[i].s_addr;
337 for (j = 0; j < ndaddrs; j++) {
338 fw->ip.dst.s_addr = daddrs[j].s_addr;
339 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
340 if (verbose)
341 print_firewall_line(fw, handle);
342 ret &= iptc_check_entry(chain, fw, mask, handle);
343 }
344 }
345
346 free(mask);
347 return ret;
348 }
349
350 int
for_each_chain4(int (* fn)(const xt_chainlabel,int,struct xtc_handle *),int verbose,int builtinstoo,struct xtc_handle * handle)351 for_each_chain4(int (*fn)(const xt_chainlabel, int, struct xtc_handle *),
352 int verbose, int builtinstoo, struct xtc_handle *handle)
353 {
354 int ret = 1;
355 const char *chain;
356 char *chains;
357 unsigned int i, chaincount = 0;
358
359 chain = iptc_first_chain(handle);
360 while (chain) {
361 chaincount++;
362 chain = iptc_next_chain(handle);
363 }
364
365 chains = xtables_malloc(sizeof(xt_chainlabel) * chaincount);
366 i = 0;
367 chain = iptc_first_chain(handle);
368 while (chain) {
369 strcpy(chains + i*sizeof(xt_chainlabel), chain);
370 i++;
371 chain = iptc_next_chain(handle);
372 }
373
374 for (i = 0; i < chaincount; i++) {
375 if (!builtinstoo
376 && iptc_builtin(chains + i*sizeof(xt_chainlabel),
377 handle) == 1)
378 continue;
379 ret &= fn(chains + i*sizeof(xt_chainlabel), verbose, handle);
380 }
381
382 free(chains);
383 return ret;
384 }
385
386 int
flush_entries4(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)387 flush_entries4(const xt_chainlabel chain, int verbose,
388 struct xtc_handle *handle)
389 {
390 if (!chain)
391 return for_each_chain4(flush_entries4, verbose, 1, handle);
392
393 if (verbose)
394 fprintf(stdout, "Flushing chain `%s'\n", chain);
395 return iptc_flush_entries(chain, handle);
396 }
397
398 static int
zero_entries(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)399 zero_entries(const xt_chainlabel chain, int verbose,
400 struct xtc_handle *handle)
401 {
402 if (!chain)
403 return for_each_chain4(zero_entries, verbose, 1, handle);
404
405 if (verbose)
406 fprintf(stdout, "Zeroing chain `%s'\n", chain);
407 return iptc_zero_entries(chain, handle);
408 }
409
410 int
delete_chain4(const xt_chainlabel chain,int verbose,struct xtc_handle * handle)411 delete_chain4(const xt_chainlabel chain, int verbose,
412 struct xtc_handle *handle)
413 {
414 if (!chain)
415 return for_each_chain4(delete_chain4, verbose, 0, handle);
416
417 if (verbose)
418 fprintf(stdout, "Deleting chain `%s'\n", chain);
419 return iptc_delete_chain(chain, handle);
420 }
421
422 static int
list_entries(const xt_chainlabel chain,int rulenum,int verbose,int numeric,int expanded,int linenumbers,struct xtc_handle * handle)423 list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
424 int expanded, int linenumbers, struct xtc_handle *handle)
425 {
426 int found = 0;
427 unsigned int format;
428 const char *this;
429
430 format = FMT_OPTIONS;
431 if (!verbose)
432 format |= FMT_NOCOUNTS;
433 else
434 format |= FMT_VIA;
435
436 if (numeric)
437 format |= FMT_NUMERIC;
438
439 if (!expanded)
440 format |= FMT_KILOMEGAGIGA;
441
442 if (linenumbers)
443 format |= FMT_LINENUMBERS;
444
445 for (this = iptc_first_chain(handle);
446 this;
447 this = iptc_next_chain(handle)) {
448 const struct ipt_entry *i;
449 unsigned int num;
450
451 if (chain && strcmp(chain, this) != 0)
452 continue;
453
454 if (found) printf("\n");
455
456 if (!rulenum) {
457 struct xt_counters counters;
458 unsigned int urefs;
459 const char *pol;
460 int refs = -1;
461
462 pol = iptc_get_policy(this, &counters, handle);
463 if (!pol && iptc_get_references(&urefs, this, handle))
464 refs = urefs;
465
466 print_header(format, this, pol, &counters, refs, 0);
467 }
468 i = iptc_first_rule(this, handle);
469
470 num = 0;
471 while (i) {
472 num++;
473 if (!rulenum || num == rulenum)
474 print_firewall(i,
475 iptc_get_target(i, handle),
476 num,
477 format,
478 handle);
479 i = iptc_next_rule(i, handle);
480 }
481 found = 1;
482 }
483
484 errno = ENOENT;
485 return found;
486 }
487
488 #define IP_PARTS_NATIVE(n) \
489 (unsigned int)((n)>>24)&0xFF, \
490 (unsigned int)((n)>>16)&0xFF, \
491 (unsigned int)((n)>>8)&0xFF, \
492 (unsigned int)((n)&0xFF)
493
494 #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
495
496 /* We want this to be readable, so only print out necessary fields.
497 * Because that's the kind of world I want to live in.
498 */
print_rule4(const struct ipt_entry * e,struct xtc_handle * h,const char * chain,int counters)499 void print_rule4(const struct ipt_entry *e,
500 struct xtc_handle *h, const char *chain, int counters)
501 {
502 const struct xt_entry_target *t;
503 const char *target_name;
504
505 /* print counters for iptables-save */
506 if (counters > 0)
507 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
508
509 /* print chain name */
510 printf("-A %s", chain);
511
512 /* Print IP part. */
513 save_ipv4_addr('s', &e->ip.src, &e->ip.smsk,
514 e->ip.invflags & IPT_INV_SRCIP);
515
516 save_ipv4_addr('d', &e->ip.dst, &e->ip.dmsk,
517 e->ip.invflags & IPT_INV_DSTIP);
518
519 save_rule_details(e->ip.iniface, e->ip.iniface_mask,
520 e->ip.outiface, e->ip.outiface_mask,
521 e->ip.proto, e->ip.flags & IPT_F_FRAG,
522 e->ip.invflags);
523
524 /* Print matchinfo part */
525 if (e->target_offset)
526 IPT_MATCH_ITERATE(e, print_match_save, &e->ip);
527
528 /* print counters for iptables -R */
529 if (counters < 0)
530 printf(" -c %llu %llu", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
531
532 /* Print target name and targinfo part */
533 target_name = iptc_get_target(e, h);
534 t = ipt_get_target((struct ipt_entry *)e);
535 if (t->u.user.name[0]) {
536 const char *name = t->u.user.name;
537 const int revision = t->u.user.revision;
538 struct xtables_target *target, *tg, *tg2;
539
540 target = xtables_find_target(name, XTF_TRY_LOAD);
541 if (!target) {
542 fprintf(stderr, "Can't find library for target `%s'\n",
543 name);
544 exit(1);
545 }
546
547 tg = tg2 = xtables_find_target_revision(name, XTF_TRY_LOAD,
548 target, revision);
549 if (!tg2)
550 tg2 = target;
551 printf(" -j %s", tg2->alias ? tg2->alias(t) : target_name);
552
553 if (tg && tg->save)
554 tg->save(&e->ip, t);
555 else if (target->save)
556 printf(unsupported_rev);
557 else {
558 /* If the target size is greater than xt_entry_target
559 * there is something to be saved, we just don't know
560 * how to print it */
561 if (t->u.target_size !=
562 sizeof(struct xt_entry_target)) {
563 fprintf(stderr, "Target `%s' is missing "
564 "save function\n",
565 name);
566 exit(1);
567 }
568 }
569 } else if (target_name && (*target_name != '\0'))
570 #ifdef IPT_F_GOTO
571 printf(" -%c %s", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
572 #else
573 printf(" -j %s", target_name);
574 #endif
575
576 printf("\n");
577 }
578
579 static int
list_rules(const xt_chainlabel chain,int rulenum,int counters,struct xtc_handle * handle)580 list_rules(const xt_chainlabel chain, int rulenum, int counters,
581 struct xtc_handle *handle)
582 {
583 const char *this = NULL;
584 int found = 0;
585
586 if (counters)
587 counters = -1; /* iptables -c format */
588
589 /* Dump out chain names first,
590 * thereby preventing dependency conflicts */
591 if (!rulenum) for (this = iptc_first_chain(handle);
592 this;
593 this = iptc_next_chain(handle)) {
594 if (chain && strcmp(this, chain) != 0)
595 continue;
596
597 if (iptc_builtin(this, handle)) {
598 struct xt_counters count;
599 printf("-P %s %s", this, iptc_get_policy(this, &count, handle));
600 if (counters)
601 printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
602 printf("\n");
603 } else {
604 printf("-N %s\n", this);
605 }
606 }
607
608 for (this = iptc_first_chain(handle);
609 this;
610 this = iptc_next_chain(handle)) {
611 const struct ipt_entry *e;
612 int num = 0;
613
614 if (chain && strcmp(this, chain) != 0)
615 continue;
616
617 /* Dump out rules */
618 e = iptc_first_rule(this, handle);
619 while(e) {
620 num++;
621 if (!rulenum || num == rulenum)
622 print_rule4(e, handle, this, counters);
623 e = iptc_next_rule(e, handle);
624 }
625 found = 1;
626 }
627
628 errno = ENOENT;
629 return found;
630 }
631
632 static struct ipt_entry *
generate_entry(const struct ipt_entry * fw,struct xtables_rule_match * matches,struct xt_entry_target * target)633 generate_entry(const struct ipt_entry *fw,
634 struct xtables_rule_match *matches,
635 struct xt_entry_target *target)
636 {
637 unsigned int size;
638 struct xtables_rule_match *matchp;
639 struct ipt_entry *e;
640
641 size = sizeof(struct ipt_entry);
642 for (matchp = matches; matchp; matchp = matchp->next)
643 size += matchp->match->m->u.match_size;
644
645 e = xtables_malloc(size + target->u.target_size);
646 *e = *fw;
647 e->target_offset = size;
648 e->next_offset = size + target->u.target_size;
649
650 size = 0;
651 for (matchp = matches; matchp; matchp = matchp->next) {
652 memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
653 size += matchp->match->m->u.match_size;
654 }
655 memcpy(e->elems + size, target, target->u.target_size);
656
657 return e;
658 }
659
do_command4(int argc,char * argv[],char ** table,struct xtc_handle ** handle,bool restore)660 int do_command4(int argc, char *argv[], char **table,
661 struct xtc_handle **handle, bool restore)
662 {
663 struct xt_cmd_parse_ops cmd_parse_ops = {
664 .proto_parse = ipv4_proto_parse,
665 .post_parse = ipv4_post_parse,
666 };
667 struct xt_cmd_parse p = {
668 .table = *table,
669 .restore = restore,
670 .line = line,
671 .ops = &cmd_parse_ops,
672 };
673 struct iptables_command_state cs = {
674 .jumpto = "",
675 .argv = argv,
676 };
677 struct xtables_args args = {
678 .family = AF_INET,
679 };
680 struct ipt_entry *e = NULL;
681 unsigned int nsaddrs = 0, ndaddrs = 0;
682 struct in_addr *saddrs = NULL, *smasks = NULL;
683 struct in_addr *daddrs = NULL, *dmasks = NULL;
684 int verbose = 0;
685 int wait = 0;
686 const char *chain = NULL;
687 const char *policy = NULL, *newname = NULL;
688 unsigned int rulenum = 0, command = 0;
689 int ret = 1;
690
691 do_parse(argc, argv, &p, &cs, &args);
692
693 command = p.command;
694 chain = p.chain;
695 *table = p.table;
696 rulenum = p.rulenum;
697 policy = p.policy;
698 newname = p.newname;
699 verbose = p.verbose;
700 wait = args.wait;
701 nsaddrs = args.s.naddrs;
702 ndaddrs = args.d.naddrs;
703 saddrs = args.s.addr.v4;
704 daddrs = args.d.addr.v4;
705 smasks = args.s.mask.v4;
706 dmasks = args.d.mask.v4;
707
708 /* Attempt to acquire the xtables lock */
709 if (!restore)
710 xtables_lock_or_exit(wait);
711
712 /* only allocate handle if we weren't called with a handle */
713 if (!*handle)
714 *handle = iptc_init(*table);
715
716 /* try to insmod the module if iptc_init failed */
717 if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1)
718 *handle = iptc_init(*table);
719
720 if (!*handle)
721 xtables_error(VERSION_PROBLEM,
722 "can't initialize iptables table `%s': %s",
723 *table, iptc_strerror(errno));
724
725 if (command == CMD_APPEND
726 || command == CMD_DELETE
727 || command == CMD_CHECK
728 || command == CMD_INSERT
729 || command == CMD_REPLACE) {
730 if (cs.target && iptc_is_chain(cs.jumpto, *handle)) {
731 fprintf(stderr,
732 "Warning: using chain %s, not extension\n",
733 cs.jumpto);
734
735 if (cs.target->t)
736 free(cs.target->t);
737
738 cs.target = NULL;
739 }
740
741 /* If they didn't specify a target, or it's a chain
742 name, use standard. */
743 if (!cs.target
744 && (strlen(cs.jumpto) == 0
745 || iptc_is_chain(cs.jumpto, *handle))) {
746 size_t size;
747
748 cs.target = xtables_find_target(XT_STANDARD_TARGET,
749 XTF_LOAD_MUST_SUCCEED);
750
751 size = sizeof(struct xt_entry_target)
752 + cs.target->size;
753 cs.target->t = xtables_calloc(1, size);
754 cs.target->t->u.target_size = size;
755 strcpy(cs.target->t->u.user.name, cs.jumpto);
756 if (!iptc_is_chain(cs.jumpto, *handle))
757 cs.target->t->u.user.revision = cs.target->revision;
758 xs_init_target(cs.target);
759 }
760
761 if (!cs.target) {
762 /* It is no chain, and we can't load a plugin.
763 * We cannot know if the plugin is corrupt, non
764 * existent OR if the user just misspelled a
765 * chain.
766 */
767 #ifdef IPT_F_GOTO
768 if (cs.fw.ip.flags & IPT_F_GOTO)
769 xtables_error(PARAMETER_PROBLEM,
770 "goto '%s' is not a chain",
771 cs.jumpto);
772 #endif
773 xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED);
774 } else {
775 e = generate_entry(&cs.fw, cs.matches, cs.target->t);
776 }
777 }
778
779 switch (command) {
780 case CMD_APPEND:
781 ret = append_entry(chain, e,
782 nsaddrs, saddrs, smasks,
783 ndaddrs, daddrs, dmasks,
784 cs.options&OPT_VERBOSE,
785 *handle);
786 break;
787 case CMD_DELETE:
788 ret = delete_entry(chain, e,
789 nsaddrs, saddrs, smasks,
790 ndaddrs, daddrs, dmasks,
791 cs.options&OPT_VERBOSE,
792 *handle, cs.matches, cs.target);
793 break;
794 case CMD_DELETE_NUM:
795 ret = iptc_delete_num_entry(chain, rulenum - 1, *handle);
796 break;
797 case CMD_CHECK:
798 ret = check_entry(chain, e,
799 nsaddrs, saddrs, smasks,
800 ndaddrs, daddrs, dmasks,
801 cs.options&OPT_VERBOSE,
802 *handle, cs.matches, cs.target);
803 break;
804 case CMD_REPLACE:
805 ret = replace_entry(chain, e, rulenum - 1,
806 saddrs, smasks, daddrs, dmasks,
807 cs.options&OPT_VERBOSE, *handle);
808 break;
809 case CMD_INSERT:
810 ret = insert_entry(chain, e, rulenum - 1,
811 nsaddrs, saddrs, smasks,
812 ndaddrs, daddrs, dmasks,
813 cs.options&OPT_VERBOSE,
814 *handle);
815 break;
816 case CMD_FLUSH:
817 ret = flush_entries4(chain, cs.options&OPT_VERBOSE, *handle);
818 break;
819 case CMD_ZERO:
820 ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle);
821 break;
822 case CMD_ZERO_NUM:
823 ret = iptc_zero_counter(chain, rulenum, *handle);
824 break;
825 case CMD_LIST:
826 case CMD_LIST|CMD_ZERO:
827 case CMD_LIST|CMD_ZERO_NUM:
828 ret = list_entries(chain,
829 rulenum,
830 cs.options&OPT_VERBOSE,
831 cs.options&OPT_NUMERIC,
832 cs.options&OPT_EXPANDED,
833 cs.options&OPT_LINENUMBERS,
834 *handle);
835 if (ret && (command & CMD_ZERO))
836 ret = zero_entries(chain,
837 cs.options&OPT_VERBOSE, *handle);
838 if (ret && (command & CMD_ZERO_NUM))
839 ret = iptc_zero_counter(chain, rulenum, *handle);
840 break;
841 case CMD_LIST_RULES:
842 case CMD_LIST_RULES|CMD_ZERO:
843 case CMD_LIST_RULES|CMD_ZERO_NUM:
844 ret = list_rules(chain,
845 rulenum,
846 cs.options&OPT_VERBOSE,
847 *handle);
848 if (ret && (command & CMD_ZERO))
849 ret = zero_entries(chain,
850 cs.options&OPT_VERBOSE, *handle);
851 if (ret && (command & CMD_ZERO_NUM))
852 ret = iptc_zero_counter(chain, rulenum, *handle);
853 break;
854 case CMD_NEW_CHAIN:
855 ret = iptc_create_chain(chain, *handle);
856 break;
857 case CMD_DELETE_CHAIN:
858 ret = delete_chain4(chain, cs.options&OPT_VERBOSE, *handle);
859 break;
860 case CMD_RENAME_CHAIN:
861 ret = iptc_rename_chain(chain, newname, *handle);
862 break;
863 case CMD_SET_POLICY:
864 ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle);
865 break;
866 case CMD_NONE:
867 /* do_parse ignored the line (eg: -4 with ip6tables-restore) */
868 break;
869 default:
870 /* We should never reach this... */
871 exit_tryhelp(2, line);
872 }
873
874 if (verbose > 1)
875 dump_entries(*handle);
876
877 xtables_clear_iptables_command_state(&cs);
878
879 if (e != NULL) {
880 free(e);
881 e = NULL;
882 }
883
884 free(saddrs);
885 free(smasks);
886 free(daddrs);
887 free(dmasks);
888 xtables_free_opts(1);
889
890 return ret;
891 }
892