upload tizen1.0 source
[external/iptables.git] / iptables.c
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
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 <sys/utsname.h>
43 #include "xshared.h"
44
45 #ifndef TRUE
46 #define TRUE 1
47 #endif
48 #ifndef FALSE
49 #define FALSE 0
50 #endif
51
52 #define FMT_NUMERIC     0x0001
53 #define FMT_NOCOUNTS    0x0002
54 #define FMT_KILOMEGAGIGA 0x0004
55 #define FMT_OPTIONS     0x0008
56 #define FMT_NOTABLE     0x0010
57 #define FMT_NOTARGET    0x0020
58 #define FMT_VIA         0x0040
59 #define FMT_NONEWLINE   0x0080
60 #define FMT_LINENUMBERS 0x0100
61
62 #define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \
63                         | FMT_NUMERIC | FMT_NOTABLE)
64 #define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
65
66
67 #define CMD_NONE                0x0000U
68 #define CMD_INSERT              0x0001U
69 #define CMD_DELETE              0x0002U
70 #define CMD_DELETE_NUM          0x0004U
71 #define CMD_REPLACE             0x0008U
72 #define CMD_APPEND              0x0010U
73 #define CMD_LIST                0x0020U
74 #define CMD_FLUSH               0x0040U
75 #define CMD_ZERO                0x0080U
76 #define CMD_NEW_CHAIN           0x0100U
77 #define CMD_DELETE_CHAIN        0x0200U
78 #define CMD_SET_POLICY          0x0400U
79 #define CMD_RENAME_CHAIN        0x0800U
80 #define CMD_LIST_RULES          0x1000U
81 #define CMD_ZERO_NUM            0x2000U
82 #define NUMBER_OF_CMD   15
83 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
84                                  'Z', 'N', 'X', 'P', 'E', 'S' };
85
86 #define OPT_NONE        0x00000U
87 #define OPT_NUMERIC     0x00001U
88 #define OPT_SOURCE      0x00002U
89 #define OPT_DESTINATION 0x00004U
90 #define OPT_PROTOCOL    0x00008U
91 #define OPT_JUMP        0x00010U
92 #define OPT_VERBOSE     0x00020U
93 #define OPT_EXPANDED    0x00040U
94 #define OPT_VIANAMEIN   0x00080U
95 #define OPT_VIANAMEOUT  0x00100U
96 #define OPT_FRAGMENT    0x00200U
97 #define OPT_LINENUMBERS 0x00400U
98 #define OPT_COUNTERS    0x00800U
99 #define NUMBER_OF_OPT   12
100 static const char optflags[NUMBER_OF_OPT]
101 = { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '0', 'c'};
102
103 static struct option original_opts[] = {
104         {.name = "append",        .has_arg = 1, .val = 'A'},
105         {.name = "delete",        .has_arg = 1, .val = 'D'},
106         {.name = "insert",        .has_arg = 1, .val = 'I'},
107         {.name = "replace",       .has_arg = 1, .val = 'R'},
108         {.name = "list",          .has_arg = 2, .val = 'L'},
109         {.name = "list-rules",    .has_arg = 2, .val = 'S'},
110         {.name = "flush",         .has_arg = 2, .val = 'F'},
111         {.name = "zero",          .has_arg = 2, .val = 'Z'},
112         {.name = "new-chain",     .has_arg = 1, .val = 'N'},
113         {.name = "delete-chain",  .has_arg = 2, .val = 'X'},
114         {.name = "rename-chain",  .has_arg = 1, .val = 'E'},
115         {.name = "policy",        .has_arg = 1, .val = 'P'},
116         {.name = "source",        .has_arg = 1, .val = 's'},
117         {.name = "destination",   .has_arg = 1, .val = 'd'},
118         {.name = "src",           .has_arg = 1, .val = 's'}, /* synonym */
119         {.name = "dst",           .has_arg = 1, .val = 'd'}, /* synonym */
120         {.name = "protocol",      .has_arg = 1, .val = 'p'},
121         {.name = "in-interface",  .has_arg = 1, .val = 'i'},
122         {.name = "jump",          .has_arg = 1, .val = 'j'},
123         {.name = "table",         .has_arg = 1, .val = 't'},
124         {.name = "match",         .has_arg = 1, .val = 'm'},
125         {.name = "numeric",       .has_arg = 0, .val = 'n'},
126         {.name = "out-interface", .has_arg = 1, .val = 'o'},
127         {.name = "verbose",       .has_arg = 0, .val = 'v'},
128         {.name = "exact",         .has_arg = 0, .val = 'x'},
129         {.name = "fragments",     .has_arg = 0, .val = 'f'},
130         {.name = "version",       .has_arg = 0, .val = 'V'},
131         {.name = "help",          .has_arg = 2, .val = 'h'},
132         {.name = "line-numbers",  .has_arg = 0, .val = '0'},
133         {.name = "modprobe",      .has_arg = 1, .val = 'M'},
134         {.name = "set-counters",  .has_arg = 1, .val = 'c'},
135         {.name = "goto",          .has_arg = 1, .val = 'g'},
136         {NULL},
137 };
138
139 /* we need this for iptables-restore.  iptables-restore.c sets line to the
140  * current line of the input file, in order  to give a more precise error
141  * message.  iptables itself doesn't need this, so it is initialized to the
142  * magic number of -1 */
143 int line = -1;
144
145 void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
146
147 struct xtables_globals iptables_globals = {
148         .option_offset = 0,
149         .program_version = IPTABLES_VERSION,
150         .opts = original_opts,
151         .orig_opts = original_opts,
152         .exit_err = iptables_exit_error,
153 };
154
155 /* Table of legal combinations of commands and options.  If any of the
156  * given commands make an option legal, that option is legal (applies to
157  * CMD_LIST and CMD_ZERO only).
158  * Key:
159  *  +  compulsory
160  *  x  illegal
161  *     optional
162  */
163
164 static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
165 /* Well, it's better than "Re: Linux vs FreeBSD" */
166 {
167         /*     -n  -s  -d  -p  -j  -v  -x  -i  -o  -f --line -c */
168 /*INSERT*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '},
169 /*DELETE*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x','x'},
170 /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
171 /*REPLACE*/   {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '},
172 /*APPEND*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '},
173 /*LIST*/      {' ','x','x','x','x',' ',' ','x','x','x',' ','x'},
174 /*FLUSH*/     {'x','x','x','x','x',' ','x','x','x','x','x','x'},
175 /*ZERO*/      {'x','x','x','x','x',' ','x','x','x','x','x','x'},
176 /*ZERO_NUM*/  {'x','x','x','x','x',' ','x','x','x','x','x','x'},
177 /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
178 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
179 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x',' '},
180 /*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'},
181 /*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}
182 };
183
184 static int inverse_for_options[NUMBER_OF_OPT] =
185 {
186 /* -n */ 0,
187 /* -s */ IPT_INV_SRCIP,
188 /* -d */ IPT_INV_DSTIP,
189 /* -p */ IPT_INV_PROTO,
190 /* -j */ 0,
191 /* -v */ 0,
192 /* -x */ 0,
193 /* -i */ IPT_INV_VIA_IN,
194 /* -o */ IPT_INV_VIA_OUT,
195 /* -f */ IPT_INV_FRAG,
196 /*--line*/ 0,
197 /* -c */ 0,
198 };
199
200 #define opts iptables_globals.opts
201 #define prog_name iptables_globals.program_name
202 #define prog_vers iptables_globals.program_version
203
204 int kernel_version;
205
206 /* Primitive headers... */
207 /* defined in netinet/in.h */
208 #if 0
209 #ifndef IPPROTO_ESP
210 #define IPPROTO_ESP 50
211 #endif
212 #ifndef IPPROTO_AH
213 #define IPPROTO_AH 51
214 #endif
215 #endif
216
217 static const char *
218 proto_to_name(u_int8_t proto, int nolookup)
219 {
220         unsigned int i;
221
222         if (proto && !nolookup) {
223                 struct protoent *pent = getprotobynumber(proto);
224                 if (pent)
225                         return pent->p_name;
226         }
227
228         for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
229                 if (xtables_chain_protos[i].num == proto)
230                         return xtables_chain_protos[i].name;
231
232         return NULL;
233 }
234
235 enum {
236         IPT_DOTTED_ADDR = 0,
237         IPT_DOTTED_MASK
238 };
239
240 static void __attribute__((noreturn))
241 exit_tryhelp(int status)
242 {
243         if (line != -1)
244                 fprintf(stderr, "Error occurred at line: %d\n", line);
245         fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
246                         prog_name, prog_name);
247         xtables_free_opts(1);
248         exit(status);
249 }
250
251 static void
252 exit_printhelp(struct xtables_rule_match *matches)
253 {
254         printf("%s v%s\n\n"
255 "Usage: %s -[AD] chain rule-specification [options]\n"
256 "       %s -I chain [rulenum] rule-specification [options]\n"
257 "       %s -R chain rulenum rule-specification [options]\n"
258 "       %s -D chain rulenum [options]\n"
259 "       %s -[LS] [chain [rulenum]] [options]\n"
260 "       %s -[FZ] [chain] [options]\n"
261 "       %s -[NX] chain\n"
262 "       %s -E old-chain-name new-chain-name\n"
263 "       %s -P chain target [options]\n"
264 "       %s -h (print this help information)\n\n",
265                prog_name, prog_vers, prog_name, prog_name,
266                prog_name, prog_name, prog_name, prog_name,
267                prog_name, prog_name, prog_name, prog_name);
268
269         printf(
270 "Commands:\n"
271 "Either long or short options are allowed.\n"
272 "  --append  -A chain           Append to chain\n"
273 "  --delete  -D chain           Delete matching rule from chain\n"
274 "  --delete  -D chain rulenum\n"
275 "                               Delete rule rulenum (1 = first) from chain\n"
276 "  --insert  -I chain [rulenum]\n"
277 "                               Insert in chain as rulenum (default 1=first)\n"
278 "  --replace -R chain rulenum\n"
279 "                               Replace rule rulenum (1 = first) in chain\n"
280 "  --list    -L [chain [rulenum]]\n"
281 "                               List the rules in a chain or all chains\n"
282 "  --list-rules -S [chain [rulenum]]\n"
283 "                               Print the rules in a chain or all chains\n"
284 "  --flush   -F [chain]         Delete all rules in  chain or all chains\n"
285 "  --zero    -Z [chain [rulenum]]\n"
286 "                               Zero counters in chain or all chains\n"
287 "  --new     -N chain           Create a new user-defined chain\n"
288 "  --delete-chain\n"
289 "            -X [chain]         Delete a user-defined chain\n"
290 "  --policy  -P chain target\n"
291 "                               Change policy on chain to target\n"
292 "  --rename-chain\n"
293 "            -E old-chain new-chain\n"
294 "                               Change chain name, (moving any references)\n"
295
296 "Options:\n"
297 "[!] --proto    -p proto        protocol: by number or name, eg. `tcp'\n"
298 "[!] --source   -s address[/mask][...]\n"
299 "                               source specification\n"
300 "[!] --destination -d address[/mask][...]\n"
301 "                               destination specification\n"
302 "[!] --in-interface -i input name[+]\n"
303 "                               network interface name ([+] for wildcard)\n"
304 " --jump        -j target\n"
305 "                               target for rule (may load target extension)\n"
306 #ifdef IPT_F_GOTO
307 "  --goto      -g chain\n"
308 "                              jump to chain with no return\n"
309 #endif
310 "  --match      -m match\n"
311 "                               extended match (may load extension)\n"
312 "  --numeric    -n              numeric output of addresses and ports\n"
313 "[!] --out-interface -o output name[+]\n"
314 "                               network interface name ([+] for wildcard)\n"
315 "  --table      -t table        table to manipulate (default: `filter')\n"
316 "  --verbose    -v              verbose mode\n"
317 "  --line-numbers               print line numbers when listing\n"
318 "  --exact      -x              expand numbers (display exact values)\n"
319 "[!] --fragment -f              match second or further fragments only\n"
320 "  --modprobe=<command>         try to insert modules using this command\n"
321 "  --set-counters PKTS BYTES    set the counter during insert/append\n"
322 "[!] --version  -V              print package version.\n");
323
324         print_extension_helps(xtables_targets, matches);
325         exit(0);
326 }
327
328 void
329 iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
330 {
331         va_list args;
332
333         va_start(args, msg);
334         fprintf(stderr, "%s v%s: ", prog_name, prog_vers);
335         vfprintf(stderr, msg, args);
336         va_end(args);
337         fprintf(stderr, "\n");
338         if (status == PARAMETER_PROBLEM)
339                 exit_tryhelp(status);
340         if (status == VERSION_PROBLEM)
341                 fprintf(stderr,
342                         "Perhaps iptables or your kernel needs to be upgraded.\n");
343         /* On error paths, make sure that we don't leak memory */
344         xtables_free_opts(1);
345         exit(status);
346 }
347
348 static void
349 generic_opt_check(int command, int options)
350 {
351         int i, j, legal = 0;
352
353         /* Check that commands are valid with options.  Complicated by the
354          * fact that if an option is legal with *any* command given, it is
355          * legal overall (ie. -z and -l).
356          */
357         for (i = 0; i < NUMBER_OF_OPT; i++) {
358                 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
359
360                 for (j = 0; j < NUMBER_OF_CMD; j++) {
361                         if (!(command & (1<<j)))
362                                 continue;
363
364                         if (!(options & (1<<i))) {
365                                 if (commands_v_options[j][i] == '+')
366                                         xtables_error(PARAMETER_PROBLEM,
367                                                    "You need to supply the `-%c' "
368                                                    "option for this command\n",
369                                                    optflags[i]);
370                         } else {
371                                 if (commands_v_options[j][i] != 'x')
372                                         legal = 1;
373                                 else if (legal == 0)
374                                         legal = -1;
375                         }
376                 }
377                 if (legal == -1)
378                         xtables_error(PARAMETER_PROBLEM,
379                                    "Illegal option `-%c' with this command\n",
380                                    optflags[i]);
381         }
382 }
383
384 static char
385 opt2char(int option)
386 {
387         const char *ptr;
388         for (ptr = optflags; option > 1; option >>= 1, ptr++);
389
390         return *ptr;
391 }
392
393 static char
394 cmd2char(int option)
395 {
396         const char *ptr;
397         for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
398
399         return *ptr;
400 }
401
402 static void
403 add_command(unsigned int *cmd, const int newcmd, const int othercmds, 
404             int invert)
405 {
406         if (invert)
407                 xtables_error(PARAMETER_PROBLEM, "unexpected ! flag");
408         if (*cmd & (~othercmds))
409                 xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
410                            cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
411         *cmd |= newcmd;
412 }
413
414 /*
415  *      All functions starting with "parse" should succeed, otherwise
416  *      the program fails.
417  *      Most routines return pointers to static data that may change
418  *      between calls to the same or other routines with a few exceptions:
419  *      "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
420  *      return global static data.
421 */
422
423 /* Christophe Burki wants `-p 6' to imply `-m tcp'.  */
424 static struct xtables_match *
425 find_proto(const char *pname, enum xtables_tryload tryload,
426            int nolookup, struct xtables_rule_match **matches)
427 {
428         unsigned int proto;
429
430         if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) {
431                 const char *protoname = proto_to_name(proto, nolookup);
432
433                 if (protoname)
434                         return xtables_find_match(protoname, tryload, matches);
435         } else
436                 return xtables_find_match(pname, tryload, matches);
437
438         return NULL;
439 }
440
441 /* Can't be zero. */
442 static int
443 parse_rulenumber(const char *rule)
444 {
445         unsigned int rulenum;
446
447         if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
448                 xtables_error(PARAMETER_PROBLEM,
449                            "Invalid rule number `%s'", rule);
450
451         return rulenum;
452 }
453
454 static const char *
455 parse_target(const char *targetname)
456 {
457         const char *ptr;
458
459         if (strlen(targetname) < 1)
460                 xtables_error(PARAMETER_PROBLEM,
461                            "Invalid target name (too short)");
462
463         if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN)
464                 xtables_error(PARAMETER_PROBLEM,
465                            "Invalid target name `%s' (%u chars max)",
466                            targetname, XT_EXTENSION_MAXNAMELEN - 1);
467
468         for (ptr = targetname; *ptr; ptr++)
469                 if (isspace(*ptr))
470                         xtables_error(PARAMETER_PROBLEM,
471                                    "Invalid target name `%s'", targetname);
472         return targetname;
473 }
474
475 static void
476 set_option(unsigned int *options, unsigned int option, u_int8_t *invflg,
477            int invert)
478 {
479         if (*options & option)
480                 xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
481                            opt2char(option));
482         *options |= option;
483
484         if (invert) {
485                 unsigned int i;
486                 for (i = 0; 1 << i != option; i++);
487
488                 if (!inverse_for_options[i])
489                         xtables_error(PARAMETER_PROBLEM,
490                                    "cannot have ! before -%c",
491                                    opt2char(option));
492                 *invflg |= inverse_for_options[i];
493         }
494 }
495
496 static void
497 print_num(u_int64_t number, unsigned int format)
498 {
499         if (format & FMT_KILOMEGAGIGA) {
500                 if (number > 99999) {
501                         number = (number + 500) / 1000;
502                         if (number > 9999) {
503                                 number = (number + 500) / 1000;
504                                 if (number > 9999) {
505                                         number = (number + 500) / 1000;
506                                         if (number > 9999) {
507                                                 number = (number + 500) / 1000;
508                                                 printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
509                                         }
510                                         else printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
511                                 }
512                                 else printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
513                         } else
514                                 printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
515                 } else
516                         printf(FMT("%5llu ","%llu "), (unsigned long long)number);
517         } else
518                 printf(FMT("%8llu ","%llu "), (unsigned long long)number);
519 }
520
521
522 static void
523 print_header(unsigned int format, const char *chain, struct iptc_handle *handle)
524 {
525         struct ipt_counters counters;
526         const char *pol = iptc_get_policy(chain, &counters, handle);
527         printf("Chain %s", chain);
528         if (pol) {
529                 printf(" (policy %s", pol);
530                 if (!(format & FMT_NOCOUNTS)) {
531                         fputc(' ', stdout);
532                         print_num(counters.pcnt, (format|FMT_NOTABLE));
533                         fputs("packets, ", stdout);
534                         print_num(counters.bcnt, (format|FMT_NOTABLE));
535                         fputs("bytes", stdout);
536                 }
537                 printf(")\n");
538         } else {
539                 unsigned int refs;
540                 if (!iptc_get_references(&refs, chain, handle))
541                         printf(" (ERROR obtaining refs)\n");
542                 else
543                         printf(" (%u references)\n", refs);
544         }
545
546         if (format & FMT_LINENUMBERS)
547                 printf(FMT("%-4s ", "%s "), "num");
548         if (!(format & FMT_NOCOUNTS)) {
549                 if (format & FMT_KILOMEGAGIGA) {
550                         printf(FMT("%5s ","%s "), "pkts");
551                         printf(FMT("%5s ","%s "), "bytes");
552                 } else {
553                         printf(FMT("%8s ","%s "), "pkts");
554                         printf(FMT("%10s ","%s "), "bytes");
555                 }
556         }
557         if (!(format & FMT_NOTARGET))
558                 printf(FMT("%-9s ","%s "), "target");
559         fputs(" prot ", stdout);
560         if (format & FMT_OPTIONS)
561                 fputs("opt", stdout);
562         if (format & FMT_VIA) {
563                 printf(FMT(" %-6s ","%s "), "in");
564                 printf(FMT("%-6s ","%s "), "out");
565         }
566         printf(FMT(" %-19s ","%s "), "source");
567         printf(FMT(" %-19s "," %s "), "destination");
568         printf("\n");
569 }
570
571
572 static int
573 print_match(const struct ipt_entry_match *m,
574             const struct ipt_ip *ip,
575             int numeric)
576 {
577         struct xtables_match *match =
578                 xtables_find_match(m->u.user.name, XTF_TRY_LOAD, NULL);
579
580         if (match) {
581                 if (match->print)
582                         match->print(ip, m, numeric);
583                 else
584                         printf("%s ", match->name);
585         } else {
586                 if (m->u.user.name[0])
587                         printf("UNKNOWN match `%s' ", m->u.user.name);
588         }
589         /* Don't stop iterating. */
590         return 0;
591 }
592
593 /* e is called `fw' here for historical reasons */
594 static void
595 print_firewall(const struct ipt_entry *fw,
596                const char *targname,
597                unsigned int num,
598                unsigned int format,
599                struct iptc_handle *const handle)
600 {
601         struct xtables_target *target = NULL;
602         const struct ipt_entry_target *t;
603         u_int8_t flags;
604         char buf[BUFSIZ];
605
606         if (!iptc_is_chain(targname, handle))
607                 target = xtables_find_target(targname, XTF_TRY_LOAD);
608         else
609                 target = xtables_find_target(IPT_STANDARD_TARGET,
610                          XTF_LOAD_MUST_SUCCEED);
611
612         t = ipt_get_target((struct ipt_entry *)fw);
613         flags = fw->ip.flags;
614
615         if (format & FMT_LINENUMBERS)
616                 printf(FMT("%-4u ", "%u "), num);
617
618         if (!(format & FMT_NOCOUNTS)) {
619                 print_num(fw->counters.pcnt, format);
620                 print_num(fw->counters.bcnt, format);
621         }
622
623         if (!(format & FMT_NOTARGET))
624                 printf(FMT("%-9s ", "%s "), targname);
625
626         fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout);
627         {
628                 const char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC);
629                 if (pname)
630                         printf(FMT("%-5s", "%s "), pname);
631                 else
632                         printf(FMT("%-5hu", "%hu "), fw->ip.proto);
633         }
634
635         if (format & FMT_OPTIONS) {
636                 if (format & FMT_NOTABLE)
637                         fputs("opt ", stdout);
638                 fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
639                 fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
640                 fputc(' ', stdout);
641         }
642
643         if (format & FMT_VIA) {
644                 char iface[IFNAMSIZ+2];
645
646                 if (fw->ip.invflags & IPT_INV_VIA_IN) {
647                         iface[0] = '!';
648                         iface[1] = '\0';
649                 }
650                 else iface[0] = '\0';
651
652                 if (fw->ip.iniface[0] != '\0') {
653                         strcat(iface, fw->ip.iniface);
654                 }
655                 else if (format & FMT_NUMERIC) strcat(iface, "*");
656                 else strcat(iface, "any");
657                 printf(FMT(" %-6s ","in %s "), iface);
658
659                 if (fw->ip.invflags & IPT_INV_VIA_OUT) {
660                         iface[0] = '!';
661                         iface[1] = '\0';
662                 }
663                 else iface[0] = '\0';
664
665                 if (fw->ip.outiface[0] != '\0') {
666                         strcat(iface, fw->ip.outiface);
667                 }
668                 else if (format & FMT_NUMERIC) strcat(iface, "*");
669                 else strcat(iface, "any");
670                 printf(FMT("%-6s ","out %s "), iface);
671         }
672
673         fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
674         if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC))
675                 printf(FMT("%-19s ","%s "), "anywhere");
676         else {
677                 if (format & FMT_NUMERIC)
678                         strcpy(buf, xtables_ipaddr_to_numeric(&fw->ip.src));
679                 else
680                         strcpy(buf, xtables_ipaddr_to_anyname(&fw->ip.src));
681                 strcat(buf, xtables_ipmask_to_numeric(&fw->ip.smsk));
682                 printf(FMT("%-19s ","%s "), buf);
683         }
684
685         fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
686         if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
687                 printf(FMT("%-19s ","-> %s"), "anywhere");
688         else {
689                 if (format & FMT_NUMERIC)
690                         strcpy(buf, xtables_ipaddr_to_numeric(&fw->ip.dst));
691                 else
692                         strcpy(buf, xtables_ipaddr_to_anyname(&fw->ip.dst));
693                 strcat(buf, xtables_ipmask_to_numeric(&fw->ip.dmsk));
694                 printf(FMT("%-19s ","-> %s"), buf);
695         }
696
697         if (format & FMT_NOTABLE)
698                 fputs("  ", stdout);
699
700 #ifdef IPT_F_GOTO
701         if(fw->ip.flags & IPT_F_GOTO)
702                 printf("[goto] ");
703 #endif
704
705         IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
706
707         if (target) {
708                 if (target->print)
709                         /* Print the target information. */
710                         target->print(&fw->ip, t, format & FMT_NUMERIC);
711         } else if (t->u.target_size != sizeof(*t))
712                 printf("[%u bytes of unknown target data] ",
713                        (unsigned int)(t->u.target_size - sizeof(*t)));
714
715         if (!(format & FMT_NONEWLINE))
716                 fputc('\n', stdout);
717 }
718
719 static void
720 print_firewall_line(const struct ipt_entry *fw,
721                     struct iptc_handle *const h)
722 {
723         struct ipt_entry_target *t;
724
725         t = ipt_get_target((struct ipt_entry *)fw);
726         print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h);
727 }
728
729 static int
730 append_entry(const ipt_chainlabel chain,
731              struct ipt_entry *fw,
732              unsigned int nsaddrs,
733              const struct in_addr saddrs[],
734              const struct in_addr smasks[],
735              unsigned int ndaddrs,
736              const struct in_addr daddrs[],
737              const struct in_addr dmasks[],
738              int verbose,
739              struct iptc_handle *handle)
740 {
741         unsigned int i, j;
742         int ret = 1;
743
744         for (i = 0; i < nsaddrs; i++) {
745                 fw->ip.src.s_addr = saddrs[i].s_addr;
746                 fw->ip.smsk.s_addr = smasks[i].s_addr;
747                 for (j = 0; j < ndaddrs; j++) {
748                         fw->ip.dst.s_addr = daddrs[j].s_addr;
749                         fw->ip.dmsk.s_addr = dmasks[j].s_addr;
750                         if (verbose)
751                                 print_firewall_line(fw, handle);
752                         ret &= iptc_append_entry(chain, fw, handle);
753                 }
754         }
755
756         return ret;
757 }
758
759 static int
760 replace_entry(const ipt_chainlabel chain,
761               struct ipt_entry *fw,
762               unsigned int rulenum,
763               const struct in_addr *saddr, const struct in_addr *smask,
764               const struct in_addr *daddr, const struct in_addr *dmask,
765               int verbose,
766               struct iptc_handle *handle)
767 {
768         fw->ip.src.s_addr = saddr->s_addr;
769         fw->ip.dst.s_addr = daddr->s_addr;
770         fw->ip.smsk.s_addr = smask->s_addr;
771         fw->ip.dmsk.s_addr = dmask->s_addr;
772
773         if (verbose)
774                 print_firewall_line(fw, handle);
775         return iptc_replace_entry(chain, fw, rulenum, handle);
776 }
777
778 static int
779 insert_entry(const ipt_chainlabel chain,
780              struct ipt_entry *fw,
781              unsigned int rulenum,
782              unsigned int nsaddrs,
783              const struct in_addr saddrs[],
784              const struct in_addr smasks[],
785              unsigned int ndaddrs,
786              const struct in_addr daddrs[],
787              const struct in_addr dmasks[],
788              int verbose,
789              struct iptc_handle *handle)
790 {
791         unsigned int i, j;
792         int ret = 1;
793
794         for (i = 0; i < nsaddrs; i++) {
795                 fw->ip.src.s_addr = saddrs[i].s_addr;
796                 fw->ip.smsk.s_addr = smasks[i].s_addr;
797                 for (j = 0; j < ndaddrs; j++) {
798                         fw->ip.dst.s_addr = daddrs[j].s_addr;
799                         fw->ip.dmsk.s_addr = dmasks[j].s_addr;
800                         if (verbose)
801                                 print_firewall_line(fw, handle);
802                         ret &= iptc_insert_entry(chain, fw, rulenum, handle);
803                 }
804         }
805
806         return ret;
807 }
808
809 static unsigned char *
810 make_delete_mask(struct xtables_rule_match *matches,
811                  const struct xtables_target *target)
812 {
813         /* Establish mask for comparison */
814         unsigned int size;
815         struct xtables_rule_match *matchp;
816         unsigned char *mask, *mptr;
817
818         size = sizeof(struct ipt_entry);
819         for (matchp = matches; matchp; matchp = matchp->next)
820                 size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
821
822         mask = xtables_calloc(1, size
823                          + IPT_ALIGN(sizeof(struct ipt_entry_target))
824                          + target->size);
825
826         memset(mask, 0xFF, sizeof(struct ipt_entry));
827         mptr = mask + sizeof(struct ipt_entry);
828
829         for (matchp = matches; matchp; matchp = matchp->next) {
830                 memset(mptr, 0xFF,
831                        IPT_ALIGN(sizeof(struct ipt_entry_match))
832                        + matchp->match->userspacesize);
833                 mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
834         }
835
836         memset(mptr, 0xFF,
837                IPT_ALIGN(sizeof(struct ipt_entry_target))
838                + target->userspacesize);
839
840         return mask;
841 }
842
843 static int
844 delete_entry(const ipt_chainlabel chain,
845              struct ipt_entry *fw,
846              unsigned int nsaddrs,
847              const struct in_addr saddrs[],
848              const struct in_addr smasks[],
849              unsigned int ndaddrs,
850              const struct in_addr daddrs[],
851              const struct in_addr dmasks[],
852              int verbose,
853              struct iptc_handle *handle,
854              struct xtables_rule_match *matches,
855              const struct xtables_target *target)
856 {
857         unsigned int i, j;
858         int ret = 1;
859         unsigned char *mask;
860
861         mask = make_delete_mask(matches, target);
862         for (i = 0; i < nsaddrs; i++) {
863                 fw->ip.src.s_addr = saddrs[i].s_addr;
864                 fw->ip.smsk.s_addr = smasks[i].s_addr;
865                 for (j = 0; j < ndaddrs; j++) {
866                         fw->ip.dst.s_addr = daddrs[j].s_addr;
867                         fw->ip.dmsk.s_addr = dmasks[j].s_addr;
868                         if (verbose)
869                                 print_firewall_line(fw, handle);
870                         ret &= iptc_delete_entry(chain, fw, mask, handle);
871                 }
872         }
873         free(mask);
874
875         return ret;
876 }
877
878 int
879 for_each_chain(int (*fn)(const ipt_chainlabel, int, struct iptc_handle *),
880                int verbose, int builtinstoo, struct iptc_handle *handle)
881 {
882         int ret = 1;
883         const char *chain;
884         char *chains;
885         unsigned int i, chaincount = 0;
886
887         chain = iptc_first_chain(handle);
888         while (chain) {
889                 chaincount++;
890                 chain = iptc_next_chain(handle);
891         }
892
893         chains = xtables_malloc(sizeof(ipt_chainlabel) * chaincount);
894         i = 0;
895         chain = iptc_first_chain(handle);
896         while (chain) {
897                 strcpy(chains + i*sizeof(ipt_chainlabel), chain);
898                 i++;
899                 chain = iptc_next_chain(handle);
900         }
901
902         for (i = 0; i < chaincount; i++) {
903                 if (!builtinstoo
904                     && iptc_builtin(chains + i*sizeof(ipt_chainlabel),
905                                     handle) == 1)
906                         continue;
907                 ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle);
908         }
909
910         free(chains);
911         return ret;
912 }
913
914 int
915 flush_entries(const ipt_chainlabel chain, int verbose,
916               struct iptc_handle *handle)
917 {
918         if (!chain)
919                 return for_each_chain(flush_entries, verbose, 1, handle);
920
921         if (verbose)
922                 fprintf(stdout, "Flushing chain `%s'\n", chain);
923         return iptc_flush_entries(chain, handle);
924 }
925
926 static int
927 zero_entries(const ipt_chainlabel chain, int verbose,
928              struct iptc_handle *handle)
929 {
930         if (!chain)
931                 return for_each_chain(zero_entries, verbose, 1, handle);
932
933         if (verbose)
934                 fprintf(stdout, "Zeroing chain `%s'\n", chain);
935         return iptc_zero_entries(chain, handle);
936 }
937
938 int
939 delete_chain(const ipt_chainlabel chain, int verbose,
940              struct iptc_handle *handle)
941 {
942         if (!chain)
943                 return for_each_chain(delete_chain, verbose, 0, handle);
944
945         if (verbose)
946                 fprintf(stdout, "Deleting chain `%s'\n", chain);
947         return iptc_delete_chain(chain, handle);
948 }
949
950 static int
951 list_entries(const ipt_chainlabel chain, int rulenum, int verbose, int numeric,
952              int expanded, int linenumbers, struct iptc_handle *handle)
953 {
954         int found = 0;
955         unsigned int format;
956         const char *this;
957
958         format = FMT_OPTIONS;
959         if (!verbose)
960                 format |= FMT_NOCOUNTS;
961         else
962                 format |= FMT_VIA;
963
964         if (numeric)
965                 format |= FMT_NUMERIC;
966
967         if (!expanded)
968                 format |= FMT_KILOMEGAGIGA;
969
970         if (linenumbers)
971                 format |= FMT_LINENUMBERS;
972
973         for (this = iptc_first_chain(handle);
974              this;
975              this = iptc_next_chain(handle)) {
976                 const struct ipt_entry *i;
977                 unsigned int num;
978
979                 if (chain && strcmp(chain, this) != 0)
980                         continue;
981
982                 if (found) printf("\n");
983
984                 if (!rulenum)
985                         print_header(format, this, handle);
986                 i = iptc_first_rule(this, handle);
987
988                 num = 0;
989                 while (i) {
990                         num++;
991                         if (!rulenum || num == rulenum)
992                                 print_firewall(i,
993                                                iptc_get_target(i, handle),
994                                                num,
995                                                format,
996                                                handle);
997                         i = iptc_next_rule(i, handle);
998                 }
999                 found = 1;
1000         }
1001
1002         errno = ENOENT;
1003         return found;
1004 }
1005
1006 static void print_proto(u_int16_t proto, int invert)
1007 {
1008         if (proto) {
1009                 unsigned int i;
1010                 const char *invertstr = invert ? "! " : "";
1011
1012                 struct protoent *pent = getprotobynumber(proto);
1013                 if (pent) {
1014                         printf("%s-p %s ", invertstr, pent->p_name);
1015                         return;
1016                 }
1017
1018                 for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
1019                         if (xtables_chain_protos[i].num == proto) {
1020                                 printf("%s-p %s ",
1021                                        invertstr, xtables_chain_protos[i].name);
1022                                 return;
1023                         }
1024
1025                 printf("%s-p %u ", invertstr, proto);
1026         }
1027 }
1028
1029 #define IP_PARTS_NATIVE(n)                      \
1030 (unsigned int)((n)>>24)&0xFF,                   \
1031 (unsigned int)((n)>>16)&0xFF,                   \
1032 (unsigned int)((n)>>8)&0xFF,                    \
1033 (unsigned int)((n)&0xFF)
1034
1035 #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
1036
1037 /* This assumes that mask is contiguous, and byte-bounded. */
1038 static void
1039 print_iface(char letter, const char *iface, const unsigned char *mask,
1040             int invert)
1041 {
1042         unsigned int i;
1043
1044         if (mask[0] == 0)
1045                 return;
1046
1047         printf("%s-%c ", invert ? "! " : "", letter);
1048
1049         for (i = 0; i < IFNAMSIZ; i++) {
1050                 if (mask[i] != 0) {
1051                         if (iface[i] != '\0')
1052                                 printf("%c", iface[i]);
1053                 } else {
1054                         /* we can access iface[i-1] here, because
1055                          * a few lines above we make sure that mask[0] != 0 */
1056                         if (iface[i-1] != '\0')
1057                                 printf("+");
1058                         break;
1059                 }
1060         }
1061
1062         printf(" ");
1063 }
1064
1065 static int print_match_save(const struct ipt_entry_match *e,
1066                         const struct ipt_ip *ip)
1067 {
1068         struct xtables_match *match =
1069                 xtables_find_match(e->u.user.name, XTF_TRY_LOAD, NULL);
1070
1071         if (match) {
1072                 printf("-m %s ", e->u.user.name);
1073
1074                 /* some matches don't provide a save function */
1075                 if (match->save)
1076                         match->save(ip, e);
1077         } else {
1078                 if (e->u.match_size) {
1079                         fprintf(stderr,
1080                                 "Can't find library for match `%s'\n",
1081                                 e->u.user.name);
1082                         exit(1);
1083                 }
1084         }
1085         return 0;
1086 }
1087
1088 /* print a given ip including mask if neccessary */
1089 static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
1090 {
1091         u_int32_t bits, hmask = ntohl(mask);
1092         int i;
1093
1094         if (!mask && !ip && !invert)
1095                 return;
1096
1097         printf("%s%s %u.%u.%u.%u",
1098                 invert ? "! " : "",
1099                 prefix,
1100                 IP_PARTS(ip));
1101
1102         if (mask == 0xFFFFFFFFU) {
1103                 printf("/32 ");
1104                 return;
1105         }
1106
1107         i    = 32;
1108         bits = 0xFFFFFFFEU;
1109         while (--i >= 0 && hmask != bits)
1110                 bits <<= 1;
1111         if (i >= 0)
1112                 printf("/%u ", i);
1113         else
1114                 printf("/%u.%u.%u.%u ", IP_PARTS(mask));
1115 }
1116
1117 /* We want this to be readable, so only print out neccessary fields.
1118  * Because that's the kind of world I want to live in.  */
1119 void print_rule(const struct ipt_entry *e,
1120                 struct iptc_handle *h, const char *chain, int counters)
1121 {
1122         struct ipt_entry_target *t;
1123         const char *target_name;
1124
1125         /* print counters for iptables-save */
1126         if (counters > 0)
1127                 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
1128
1129         /* print chain name */
1130         printf("-A %s ", chain);
1131
1132         /* Print IP part. */
1133         print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
1134                         e->ip.invflags & IPT_INV_SRCIP);
1135
1136         print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
1137                         e->ip.invflags & IPT_INV_DSTIP);
1138
1139         print_iface('i', e->ip.iniface, e->ip.iniface_mask,
1140                     e->ip.invflags & IPT_INV_VIA_IN);
1141
1142         print_iface('o', e->ip.outiface, e->ip.outiface_mask,
1143                     e->ip.invflags & IPT_INV_VIA_OUT);
1144
1145         print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
1146
1147         if (e->ip.flags & IPT_F_FRAG)
1148                 printf("%s-f ",
1149                        e->ip.invflags & IPT_INV_FRAG ? "! " : "");
1150
1151         /* Print matchinfo part */
1152         if (e->target_offset) {
1153                 IPT_MATCH_ITERATE(e, print_match_save, &e->ip);
1154         }
1155
1156         /* print counters for iptables -R */
1157         if (counters < 0)
1158                 printf("-c %llu %llu ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
1159
1160         /* Print target name */
1161         target_name = iptc_get_target(e, h);
1162         if (target_name && (*target_name != '\0'))
1163 #ifdef IPT_F_GOTO
1164                 printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
1165 #else
1166                 printf("-j %s ", target_name);
1167 #endif
1168
1169         /* Print targinfo part */
1170         t = ipt_get_target((struct ipt_entry *)e);
1171         if (t->u.user.name[0]) {
1172                 struct xtables_target *target =
1173                         xtables_find_target(t->u.user.name, XTF_TRY_LOAD);
1174
1175                 if (!target) {
1176                         fprintf(stderr, "Can't find library for target `%s'\n",
1177                                 t->u.user.name);
1178                         exit(1);
1179                 }
1180
1181                 if (target->save)
1182                         target->save(&e->ip, t);
1183                 else {
1184                         /* If the target size is greater than ipt_entry_target
1185                          * there is something to be saved, we just don't know
1186                          * how to print it */
1187                         if (t->u.target_size !=
1188                             sizeof(struct ipt_entry_target)) {
1189                                 fprintf(stderr, "Target `%s' is missing "
1190                                                 "save function\n",
1191                                         t->u.user.name);
1192                                 exit(1);
1193                         }
1194                 }
1195         }
1196         printf("\n");
1197 }
1198
1199 static int
1200 list_rules(const ipt_chainlabel chain, int rulenum, int counters,
1201              struct iptc_handle *handle)
1202 {
1203         const char *this = NULL;
1204         int found = 0;
1205
1206         if (counters)
1207             counters = -1;              /* iptables -c format */
1208
1209         /* Dump out chain names first,
1210          * thereby preventing dependency conflicts */
1211         if (!rulenum) for (this = iptc_first_chain(handle);
1212              this;
1213              this = iptc_next_chain(handle)) {
1214                 if (chain && strcmp(this, chain) != 0)
1215                         continue;
1216
1217                 if (iptc_builtin(this, handle)) {
1218                         struct ipt_counters count;
1219                         printf("-P %s %s", this, iptc_get_policy(this, &count, handle));
1220                         if (counters)
1221                             printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
1222                         printf("\n");
1223                 } else {
1224                         printf("-N %s\n", this);
1225                 }
1226         }
1227
1228         for (this = iptc_first_chain(handle);
1229              this;
1230              this = iptc_next_chain(handle)) {
1231                 const struct ipt_entry *e;
1232                 int num = 0;
1233
1234                 if (chain && strcmp(this, chain) != 0)
1235                         continue;
1236
1237                 /* Dump out rules */
1238                 e = iptc_first_rule(this, handle);
1239                 while(e) {
1240                         num++;
1241                         if (!rulenum || num == rulenum)
1242                             print_rule(e, handle, this, counters);
1243                         e = iptc_next_rule(e, handle);
1244                 }
1245                 found = 1;
1246         }
1247
1248         errno = ENOENT;
1249         return found;
1250 }
1251
1252 static struct ipt_entry *
1253 generate_entry(const struct ipt_entry *fw,
1254                struct xtables_rule_match *matches,
1255                struct ipt_entry_target *target)
1256 {
1257         unsigned int size;
1258         struct xtables_rule_match *matchp;
1259         struct ipt_entry *e;
1260
1261         size = sizeof(struct ipt_entry);
1262         for (matchp = matches; matchp; matchp = matchp->next)
1263                 size += matchp->match->m->u.match_size;
1264
1265         e = xtables_malloc(size + target->u.target_size);
1266         *e = *fw;
1267         e->target_offset = size;
1268         e->next_offset = size + target->u.target_size;
1269
1270         size = 0;
1271         for (matchp = matches; matchp; matchp = matchp->next) {
1272                 memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
1273                 size += matchp->match->m->u.match_size;
1274         }
1275         memcpy(e->elems + size, target, target->u.target_size);
1276
1277         return e;
1278 }
1279
1280 static void clear_rule_matches(struct xtables_rule_match **matches)
1281 {
1282         struct xtables_rule_match *matchp, *tmp;
1283
1284         for (matchp = *matches; matchp;) {
1285                 tmp = matchp->next;
1286                 if (matchp->match->m) {
1287                         free(matchp->match->m);
1288                         matchp->match->m = NULL;
1289                 }
1290                 if (matchp->match == matchp->match->next) {
1291                         free(matchp->match);
1292                         matchp->match = NULL;
1293                 }
1294                 free(matchp);
1295                 matchp = tmp;
1296         }
1297
1298         *matches = NULL;
1299 }
1300
1301 void
1302 get_kernel_version(void) {
1303         static struct utsname uts;
1304         int x = 0, y = 0, z = 0;
1305
1306         if (uname(&uts) == -1) {
1307                 fprintf(stderr, "Unable to retrieve kernel version.\n");
1308                 xtables_free_opts(1);
1309                 exit(1);
1310         }
1311
1312         sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
1313         kernel_version = LINUX_VERSION(x, y, z);
1314 }
1315
1316 int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle)
1317 {
1318         struct ipt_entry fw, *e = NULL;
1319         int invert = 0;
1320         unsigned int nsaddrs = 0, ndaddrs = 0;
1321         struct in_addr *saddrs = NULL, *smasks = NULL;
1322         struct in_addr *daddrs = NULL, *dmasks = NULL;
1323
1324         int c, verbose = 0;
1325         const char *chain = NULL;
1326         const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
1327         const char *policy = NULL, *newname = NULL;
1328         unsigned int rulenum = 0, options = 0, command = 0;
1329         const char *pcnt = NULL, *bcnt = NULL;
1330         int ret = 1;
1331         struct xtables_match *m;
1332         struct xtables_rule_match *matches = NULL;
1333         struct xtables_rule_match *matchp;
1334         struct xtables_target *target = NULL;
1335         struct xtables_target *t;
1336         const char *jumpto = "";
1337         char *protocol = NULL;
1338         int proto_used = 0;
1339         unsigned long long cnt;
1340
1341         memset(&fw, 0, sizeof(fw));
1342
1343         /* re-set optind to 0 in case do_command gets called
1344          * a second time */
1345         optind = 0;
1346
1347         /* clear mflags in case do_command gets called a second time
1348          * (we clear the global list of all matches for security)*/
1349         for (m = xtables_matches; m; m = m->next)
1350                 m->mflags = 0;
1351
1352         for (t = xtables_targets; t; t = t->next) {
1353                 t->tflags = 0;
1354                 t->used = 0;
1355         }
1356
1357         /* Suppress error messages: we may add new options if we
1358            demand-load a protocol. */
1359         opterr = 0;
1360
1361         while ((c = getopt_long(argc, argv,
1362            "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
1363                                            opts, NULL)) != -1) {
1364                 switch (c) {
1365                         /*
1366                          * Command selection
1367                          */
1368                 case 'A':
1369                         add_command(&command, CMD_APPEND, CMD_NONE,
1370                                     invert);
1371                         chain = optarg;
1372                         break;
1373
1374                 case 'D':
1375                         add_command(&command, CMD_DELETE, CMD_NONE,
1376                                     invert);
1377                         chain = optarg;
1378                         if (optind < argc && argv[optind][0] != '-'
1379                             && argv[optind][0] != '!') {
1380                                 rulenum = parse_rulenumber(argv[optind++]);
1381                                 command = CMD_DELETE_NUM;
1382                         }
1383                         break;
1384
1385                 case 'R':
1386                         add_command(&command, CMD_REPLACE, CMD_NONE,
1387                                     invert);
1388                         chain = optarg;
1389                         if (optind < argc && argv[optind][0] != '-'
1390                             && argv[optind][0] != '!')
1391                                 rulenum = parse_rulenumber(argv[optind++]);
1392                         else
1393                                 xtables_error(PARAMETER_PROBLEM,
1394                                            "-%c requires a rule number",
1395                                            cmd2char(CMD_REPLACE));
1396                         break;
1397
1398                 case 'I':
1399                         add_command(&command, CMD_INSERT, CMD_NONE,
1400                                     invert);
1401                         chain = optarg;
1402                         if (optind < argc && argv[optind][0] != '-'
1403                             && argv[optind][0] != '!')
1404                                 rulenum = parse_rulenumber(argv[optind++]);
1405                         else rulenum = 1;
1406                         break;
1407
1408                 case 'L':
1409                         add_command(&command, CMD_LIST,
1410                                     CMD_ZERO | CMD_ZERO_NUM, invert);
1411                         if (optarg) chain = optarg;
1412                         else if (optind < argc && argv[optind][0] != '-'
1413                                  && argv[optind][0] != '!')
1414                                 chain = argv[optind++];
1415                         if (optind < argc && argv[optind][0] != '-'
1416                             && argv[optind][0] != '!')
1417                                 rulenum = parse_rulenumber(argv[optind++]);
1418                         break;
1419
1420                 case 'S':
1421                         add_command(&command, CMD_LIST_RULES,
1422                                     CMD_ZERO|CMD_ZERO_NUM, invert);
1423                         if (optarg) chain = optarg;
1424                         else if (optind < argc && argv[optind][0] != '-'
1425                                  && argv[optind][0] != '!')
1426                                 chain = argv[optind++];
1427                         if (optind < argc && argv[optind][0] != '-'
1428                             && argv[optind][0] != '!')
1429                                 rulenum = parse_rulenumber(argv[optind++]);
1430                         break;
1431
1432                 case 'F':
1433                         add_command(&command, CMD_FLUSH, CMD_NONE,
1434                                     invert);
1435                         if (optarg) chain = optarg;
1436                         else if (optind < argc && argv[optind][0] != '-'
1437                                  && argv[optind][0] != '!')
1438                                 chain = argv[optind++];
1439                         break;
1440
1441                 case 'Z':
1442                         add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
1443                                     invert);
1444                         if (optarg) chain = optarg;
1445                         else if (optind < argc && argv[optind][0] != '-'
1446                                 && argv[optind][0] != '!')
1447                                 chain = argv[optind++];
1448                         if (optind < argc && argv[optind][0] != '-'
1449                                 && argv[optind][0] != '!') {
1450                                 rulenum = parse_rulenumber(argv[optind++]);
1451                                 command = CMD_ZERO_NUM;
1452                         }
1453                         break;
1454
1455                 case 'N':
1456                         if (optarg && (*optarg == '-' || *optarg == '!'))
1457                                 xtables_error(PARAMETER_PROBLEM,
1458                                            "chain name not allowed to start "
1459                                            "with `%c'\n", *optarg);
1460                         if (xtables_find_target(optarg, XTF_TRY_LOAD))
1461                                 xtables_error(PARAMETER_PROBLEM,
1462                                            "chain name may not clash "
1463                                            "with target name\n");
1464                         add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
1465                                     invert);
1466                         chain = optarg;
1467                         break;
1468
1469                 case 'X':
1470                         add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
1471                                     invert);
1472                         if (optarg) chain = optarg;
1473                         else if (optind < argc && argv[optind][0] != '-'
1474                                  && argv[optind][0] != '!')
1475                                 chain = argv[optind++];
1476                         break;
1477
1478                 case 'E':
1479                         add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
1480                                     invert);
1481                         chain = optarg;
1482                         if (optind < argc && argv[optind][0] != '-'
1483                             && argv[optind][0] != '!')
1484                                 newname = argv[optind++];
1485                         else
1486                                 xtables_error(PARAMETER_PROBLEM,
1487                                            "-%c requires old-chain-name and "
1488                                            "new-chain-name",
1489                                             cmd2char(CMD_RENAME_CHAIN));
1490                         break;
1491
1492                 case 'P':
1493                         add_command(&command, CMD_SET_POLICY, CMD_NONE,
1494                                     invert);
1495                         chain = optarg;
1496                         if (optind < argc && argv[optind][0] != '-'
1497                             && argv[optind][0] != '!')
1498                                 policy = argv[optind++];
1499                         else
1500                                 xtables_error(PARAMETER_PROBLEM,
1501                                            "-%c requires a chain and a policy",
1502                                            cmd2char(CMD_SET_POLICY));
1503                         break;
1504
1505                 case 'h':
1506                         if (!optarg)
1507                                 optarg = argv[optind];
1508
1509                         /* iptables -p icmp -h */
1510                         if (!matches && protocol)
1511                                 xtables_find_match(protocol,
1512                                         XTF_TRY_LOAD, &matches);
1513
1514                         exit_printhelp(matches);
1515
1516                         /*
1517                          * Option selection
1518                          */
1519                 case 'p':
1520                         xtables_check_inverse(optarg, &invert, &optind, argc, argv);
1521                         set_option(&options, OPT_PROTOCOL, &fw.ip.invflags,
1522                                    invert);
1523
1524                         /* Canonicalize into lower case */
1525                         for (protocol = optarg; *protocol; protocol++)
1526                                 *protocol = tolower(*protocol);
1527
1528                         protocol = optarg;
1529                         fw.ip.proto = xtables_parse_protocol(protocol);
1530
1531                         if (fw.ip.proto == 0
1532                             && (fw.ip.invflags & IPT_INV_PROTO))
1533                                 xtables_error(PARAMETER_PROBLEM,
1534                                            "rule would never match protocol");
1535                         break;
1536
1537                 case 's':
1538                         xtables_check_inverse(optarg, &invert, &optind, argc, argv);
1539                         set_option(&options, OPT_SOURCE, &fw.ip.invflags,
1540                                    invert);
1541                         shostnetworkmask = optarg;
1542                         break;
1543
1544                 case 'd':
1545                         xtables_check_inverse(optarg, &invert, &optind, argc, argv);
1546                         set_option(&options, OPT_DESTINATION, &fw.ip.invflags,
1547                                    invert);
1548                         dhostnetworkmask = optarg;
1549                         break;
1550
1551 #ifdef IPT_F_GOTO
1552                 case 'g':
1553                         set_option(&options, OPT_JUMP, &fw.ip.invflags,
1554                                    invert);
1555                         fw.ip.flags |= IPT_F_GOTO;
1556                         jumpto = parse_target(optarg);
1557                         break;
1558 #endif
1559
1560                 case 'j':
1561                         set_option(&options, OPT_JUMP, &fw.ip.invflags,
1562                                    invert);
1563                         jumpto = parse_target(optarg);
1564                         /* TRY_LOAD (may be chain name) */
1565                         target = xtables_find_target(jumpto, XTF_TRY_LOAD);
1566
1567                         if (target) {
1568                                 size_t size;
1569
1570                                 size = IPT_ALIGN(sizeof(struct ipt_entry_target))
1571                                         + target->size;
1572
1573                                 target->t = xtables_calloc(1, size);
1574                                 target->t->u.target_size = size;
1575                                 strcpy(target->t->u.user.name, jumpto);
1576                                 target->t->u.user.revision = target->revision;
1577                                 if (target->init != NULL)
1578                                         target->init(target->t);
1579                                 opts = xtables_merge_options(opts,
1580                                                      target->extra_opts,
1581                                                      &target->option_offset);
1582                                 if (opts == NULL)
1583                                         xtables_error(OTHER_PROBLEM,
1584                                                    "can't alloc memory!");
1585                         }
1586                         break;
1587
1588
1589                 case 'i':
1590                         xtables_check_inverse(optarg, &invert, &optind, argc, argv);
1591                         set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags,
1592                                    invert);
1593                         xtables_parse_interface(optarg,
1594                                         fw.ip.iniface,
1595                                         fw.ip.iniface_mask);
1596                         break;
1597
1598                 case 'o':
1599                         xtables_check_inverse(optarg, &invert, &optind, argc, argv);
1600                         set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags,
1601                                    invert);
1602                         xtables_parse_interface(optarg,
1603                                         fw.ip.outiface,
1604                                         fw.ip.outiface_mask);
1605                         break;
1606
1607                 case 'f':
1608                         set_option(&options, OPT_FRAGMENT, &fw.ip.invflags,
1609                                    invert);
1610                         fw.ip.flags |= IPT_F_FRAG;
1611                         break;
1612
1613                 case 'v':
1614                         if (!verbose)
1615                                 set_option(&options, OPT_VERBOSE,
1616                                            &fw.ip.invflags, invert);
1617                         verbose++;
1618                         break;
1619
1620                 case 'm': {
1621                         size_t size;
1622
1623                         if (invert)
1624                                 xtables_error(PARAMETER_PROBLEM,
1625                                            "unexpected ! flag before --match");
1626
1627                         m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED,
1628                             &matches);
1629                         size = IPT_ALIGN(sizeof(struct ipt_entry_match))
1630                                          + m->size;
1631                         m->m = xtables_calloc(1, size);
1632                         m->m->u.match_size = size;
1633                         strcpy(m->m->u.user.name, m->name);
1634                         m->m->u.user.revision = m->revision;
1635                         if (m->init != NULL)
1636                                 m->init(m->m);
1637                         if (m != m->next) {
1638                                 /* Merge options for non-cloned matches */
1639                                 opts = xtables_merge_options(opts,
1640                                                      m->extra_opts,
1641                                                      &m->option_offset);
1642                                 if (opts == NULL)
1643                                         xtables_error(OTHER_PROBLEM,
1644                                                    "can't alloc memory!");
1645                         }
1646                 }
1647                 break;
1648
1649                 case 'n':
1650                         set_option(&options, OPT_NUMERIC, &fw.ip.invflags,
1651                                    invert);
1652                         break;
1653
1654                 case 't':
1655                         if (invert)
1656                                 xtables_error(PARAMETER_PROBLEM,
1657                                            "unexpected ! flag before --table");
1658                         *table = optarg;
1659                         break;
1660
1661                 case 'x':
1662                         set_option(&options, OPT_EXPANDED, &fw.ip.invflags,
1663                                    invert);
1664                         break;
1665
1666                 case 'V':
1667                         if (invert)
1668                                 printf("Not %s ;-)\n", prog_vers);
1669                         else
1670                                 printf("%s v%s\n",
1671                                        prog_name, prog_vers);
1672                         exit(0);
1673
1674                 case '0':
1675                         set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags,
1676                                    invert);
1677                         break;
1678
1679                 case 'M':
1680                         xtables_modprobe_program = optarg;
1681                         break;
1682
1683                 case 'c':
1684
1685                         set_option(&options, OPT_COUNTERS, &fw.ip.invflags,
1686                                    invert);
1687                         pcnt = optarg;
1688                         bcnt = strchr(pcnt + 1, ',');
1689                         if (bcnt)
1690                             bcnt++;
1691                         if (!bcnt && optind < argc && argv[optind][0] != '-'
1692                             && argv[optind][0] != '!')
1693                                 bcnt = argv[optind++];
1694                         if (!bcnt)
1695                                 xtables_error(PARAMETER_PROBLEM,
1696                                         "-%c requires packet and byte counter",
1697                                         opt2char(OPT_COUNTERS));
1698
1699                         if (sscanf(pcnt, "%llu", &cnt) != 1)
1700                                 xtables_error(PARAMETER_PROBLEM,
1701                                         "-%c packet counter not numeric",
1702                                         opt2char(OPT_COUNTERS));
1703                         fw.counters.pcnt = cnt;
1704
1705                         if (sscanf(bcnt, "%llu", &cnt) != 1)
1706                                 xtables_error(PARAMETER_PROBLEM,
1707                                         "-%c byte counter not numeric",
1708                                         opt2char(OPT_COUNTERS));
1709                         fw.counters.bcnt = cnt;
1710                         break;
1711
1712
1713                 case 1: /* non option */
1714                         if (optarg[0] == '!' && optarg[1] == '\0') {
1715                                 if (invert)
1716                                         xtables_error(PARAMETER_PROBLEM,
1717                                                    "multiple consecutive ! not"
1718                                                    " allowed");
1719                                 invert = TRUE;
1720                                 optarg[0] = '\0';
1721                                 continue;
1722                         }
1723                         fprintf(stderr, "Bad argument `%s'\n", optarg);
1724                         exit_tryhelp(2);
1725
1726                 default:
1727                         if (target == NULL || target->parse == NULL ||
1728                             !target->parse(c - target->option_offset,
1729                                                argv, invert,
1730                                                &target->tflags,
1731                                                &fw, &target->t)) {
1732                                 for (matchp = matches; matchp; matchp = matchp->next) {
1733                                         if (matchp->completed ||
1734                                             matchp->match->parse == NULL)
1735                                                 continue;
1736                                         if (matchp->match->parse(c - matchp->match->option_offset,
1737                                                      argv, invert,
1738                                                      &matchp->match->mflags,
1739                                                      &fw,
1740                                                      &matchp->match->m))
1741                                                 break;
1742                                 }
1743                                 m = matchp ? matchp->match : NULL;
1744
1745                                 /* If you listen carefully, you can
1746                                    actually hear this code suck. */
1747
1748                                 /* some explanations (after four different bugs
1749                                  * in 3 different releases): If we encounter a
1750                                  * parameter, that has not been parsed yet,
1751                                  * it's not an option of an explicitly loaded
1752                                  * match or a target.  However, we support
1753                                  * implicit loading of the protocol match
1754                                  * extension.  '-p tcp' means 'l4 proto 6' and
1755                                  * at the same time 'load tcp protocol match on
1756                                  * demand if we specify --dport'.
1757                                  *
1758                                  * To make this work, we need to make sure:
1759                                  * - the parameter has not been parsed by
1760                                  *   a match (m above)
1761                                  * - a protocol has been specified
1762                                  * - the protocol extension has not been
1763                                  *   loaded yet, or is loaded and unused
1764                                  *   [think of iptables-restore!]
1765                                  * - the protocol extension can be successively
1766                                  *   loaded
1767                                  */
1768                                 if (m == NULL
1769                                     && protocol
1770                                     && (!find_proto(protocol, XTF_DONT_LOAD,
1771                                                    options&OPT_NUMERIC, NULL)
1772                                         || (find_proto(protocol, XTF_DONT_LOAD,
1773                                                         options&OPT_NUMERIC, NULL)
1774                                             && (proto_used == 0))
1775                                        )
1776                                     && (m = find_proto(protocol, XTF_TRY_LOAD,
1777                                                        options&OPT_NUMERIC, &matches))) {
1778                                         /* Try loading protocol */
1779                                         size_t size;
1780
1781                                         proto_used = 1;
1782
1783                                         size = IPT_ALIGN(sizeof(struct ipt_entry_match))
1784                                                          + m->size;
1785
1786                                         m->m = xtables_calloc(1, size);
1787                                         m->m->u.match_size = size;
1788                                         strcpy(m->m->u.user.name, m->name);
1789                                         m->m->u.user.revision = m->revision;
1790                                         if (m->init != NULL)
1791                                                 m->init(m->m);
1792
1793                                         opts = xtables_merge_options(opts,
1794                                                              m->extra_opts,
1795                                                              &m->option_offset);
1796                                         if (opts == NULL)
1797                                                 xtables_error(OTHER_PROBLEM,
1798                                                         "can't alloc memory!");
1799
1800                                         optind--;
1801                                         continue;
1802                                 }
1803                                 if (!m) {
1804                                         if (c == '?') {
1805                                                 if (optopt) {
1806                                                         xtables_error(
1807                                                            PARAMETER_PROBLEM,
1808                                                            "option `%s' "
1809                                                            "requires an "
1810                                                            "argument",
1811                                                            argv[optind-1]);
1812                                                 } else {
1813                                                         xtables_error(
1814                                                            PARAMETER_PROBLEM,
1815                                                            "unknown option "
1816                                                            "`%s'",
1817                                                            argv[optind-1]);
1818                                                 }
1819                                         }
1820                                         xtables_error(PARAMETER_PROBLEM,
1821                                                    "Unknown arg `%s'", optarg);
1822                                 }
1823                         }
1824                 }
1825                 invert = FALSE;
1826         }
1827
1828         if (strcmp(*table, "nat") == 0 &&
1829             ((policy != NULL && strcmp(policy, "DROP") == 0) ||
1830             (jumpto != NULL && strcmp(jumpto, "DROP") == 0)))
1831                 xtables_error(PARAMETER_PROBLEM,
1832                         "\nThe \"nat\" table is not intended for filtering, "
1833                         "the use of DROP is therefore inhibited.\n\n");
1834
1835         for (matchp = matches; matchp; matchp = matchp->next)
1836                 if (matchp->match->final_check != NULL)
1837                         matchp->match->final_check(matchp->match->mflags);
1838
1839         if (target != NULL && target->final_check != NULL)
1840                 target->final_check(target->tflags);
1841
1842         /* Fix me: must put inverse options checking here --MN */
1843
1844         if (optind < argc)
1845                 xtables_error(PARAMETER_PROBLEM,
1846                            "unknown arguments found on commandline");
1847         if (!command)
1848                 xtables_error(PARAMETER_PROBLEM, "no command specified");
1849         if (invert)
1850                 xtables_error(PARAMETER_PROBLEM,
1851                            "nothing appropriate following !");
1852
1853         if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
1854                 if (!(options & OPT_DESTINATION))
1855                         dhostnetworkmask = "0.0.0.0/0";
1856                 if (!(options & OPT_SOURCE))
1857                         shostnetworkmask = "0.0.0.0/0";
1858         }
1859
1860         if (shostnetworkmask)
1861                 xtables_ipparse_multiple(shostnetworkmask, &saddrs,
1862                                          &smasks, &nsaddrs);
1863
1864         if (dhostnetworkmask)
1865                 xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
1866                                          &dmasks, &ndaddrs);
1867
1868         if ((nsaddrs > 1 || ndaddrs > 1) &&
1869             (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
1870                 xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
1871                            " source or destination IP addresses");
1872
1873         if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
1874                 xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
1875                            "specify a unique address");
1876
1877         generic_opt_check(command, options);
1878
1879         if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN)
1880                 xtables_error(PARAMETER_PROBLEM,
1881                            "chain name `%s' too long (must be under %i chars)",
1882                            chain, IPT_FUNCTION_MAXNAMELEN);
1883
1884         /* only allocate handle if we weren't called with a handle */
1885         if (!*handle)
1886                 *handle = iptc_init(*table);
1887
1888         /* try to insmod the module if iptc_init failed */
1889         if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1)
1890                 *handle = iptc_init(*table);
1891
1892         if (!*handle)
1893                 xtables_error(VERSION_PROBLEM,
1894                            "can't initialize iptables table `%s': %s",
1895                            *table, iptc_strerror(errno));
1896
1897         if (command == CMD_APPEND
1898             || command == CMD_DELETE
1899             || command == CMD_INSERT
1900             || command == CMD_REPLACE) {
1901                 if (strcmp(chain, "PREROUTING") == 0
1902                     || strcmp(chain, "INPUT") == 0) {
1903                         /* -o not valid with incoming packets. */
1904                         if (options & OPT_VIANAMEOUT)
1905                                 xtables_error(PARAMETER_PROBLEM,
1906                                            "Can't use -%c with %s\n",
1907                                            opt2char(OPT_VIANAMEOUT),
1908                                            chain);
1909                 }
1910
1911                 if (strcmp(chain, "POSTROUTING") == 0
1912                     || strcmp(chain, "OUTPUT") == 0) {
1913                         /* -i not valid with outgoing packets */
1914                         if (options & OPT_VIANAMEIN)
1915                                 xtables_error(PARAMETER_PROBLEM,
1916                                            "Can't use -%c with %s\n",
1917                                            opt2char(OPT_VIANAMEIN),
1918                                            chain);
1919                 }
1920
1921                 if (target && iptc_is_chain(jumpto, *handle)) {
1922                         fprintf(stderr,
1923                                 "Warning: using chain %s, not extension\n",
1924                                 jumpto);
1925
1926                         if (target->t)
1927                                 free(target->t);
1928
1929                         target = NULL;
1930                 }
1931
1932                 /* If they didn't specify a target, or it's a chain
1933                    name, use standard. */
1934                 if (!target
1935                     && (strlen(jumpto) == 0
1936                         || iptc_is_chain(jumpto, *handle))) {
1937                         size_t size;
1938
1939                         target = xtables_find_target(IPT_STANDARD_TARGET,
1940                                          XTF_LOAD_MUST_SUCCEED);
1941
1942                         size = sizeof(struct ipt_entry_target)
1943                                 + target->size;
1944                         target->t = xtables_calloc(1, size);
1945                         target->t->u.target_size = size;
1946                         strcpy(target->t->u.user.name, jumpto);
1947                         if (!iptc_is_chain(jumpto, *handle))
1948                                 target->t->u.user.revision = target->revision;
1949                         if (target->init != NULL)
1950                                 target->init(target->t);
1951                 }
1952
1953                 if (!target) {
1954                         /* it is no chain, and we can't load a plugin.
1955                          * We cannot know if the plugin is corrupt, non
1956                          * existant OR if the user just misspelled a
1957                          * chain. */
1958 #ifdef IPT_F_GOTO
1959                         if (fw.ip.flags & IPT_F_GOTO)
1960                                 xtables_error(PARAMETER_PROBLEM,
1961                                            "goto '%s' is not a chain\n", jumpto);
1962 #endif
1963                         xtables_find_target(jumpto, XTF_LOAD_MUST_SUCCEED);
1964                 } else {
1965                         e = generate_entry(&fw, matches, target->t);
1966                         free(target->t);
1967                 }
1968         }
1969
1970         switch (command) {
1971         case CMD_APPEND:
1972                 ret = append_entry(chain, e,
1973                                    nsaddrs, saddrs, smasks,
1974                                    ndaddrs, daddrs, dmasks,
1975                                    options&OPT_VERBOSE,
1976                                    *handle);
1977                 break;
1978         case CMD_DELETE:
1979                 ret = delete_entry(chain, e,
1980                                    nsaddrs, saddrs, smasks,
1981                                    ndaddrs, daddrs, dmasks,
1982                                    options&OPT_VERBOSE,
1983                                    *handle, matches, target);
1984                 break;
1985         case CMD_DELETE_NUM:
1986                 ret = iptc_delete_num_entry(chain, rulenum - 1, *handle);
1987                 break;
1988         case CMD_REPLACE:
1989                 ret = replace_entry(chain, e, rulenum - 1,
1990                                     saddrs, smasks, daddrs, dmasks,
1991                                     options&OPT_VERBOSE, *handle);
1992                 break;
1993         case CMD_INSERT:
1994                 ret = insert_entry(chain, e, rulenum - 1,
1995                                    nsaddrs, saddrs, smasks,
1996                                    ndaddrs, daddrs, dmasks,
1997                                    options&OPT_VERBOSE,
1998                                    *handle);
1999                 break;
2000         case CMD_FLUSH:
2001                 ret = flush_entries(chain, options&OPT_VERBOSE, *handle);
2002                 break;
2003         case CMD_ZERO:
2004                 ret = zero_entries(chain, options&OPT_VERBOSE, *handle);
2005                 break;
2006         case CMD_ZERO_NUM:
2007                 ret = iptc_zero_counter(chain, rulenum, *handle);
2008                 break;
2009         case CMD_LIST:
2010         case CMD_LIST|CMD_ZERO:
2011         case CMD_LIST|CMD_ZERO_NUM:
2012                 ret = list_entries(chain,
2013                                    rulenum,
2014                                    options&OPT_VERBOSE,
2015                                    options&OPT_NUMERIC,
2016                                    options&OPT_EXPANDED,
2017                                    options&OPT_LINENUMBERS,
2018                                    *handle);
2019                 if (ret && (command & CMD_ZERO))
2020                         ret = zero_entries(chain,
2021                                            options&OPT_VERBOSE, *handle);
2022                 if (ret && (command & CMD_ZERO_NUM))
2023                         ret = iptc_zero_counter(chain, rulenum, *handle);
2024                 break;
2025         case CMD_LIST_RULES:
2026         case CMD_LIST_RULES|CMD_ZERO:
2027         case CMD_LIST_RULES|CMD_ZERO_NUM:
2028                 ret = list_rules(chain,
2029                                    rulenum,
2030                                    options&OPT_VERBOSE,
2031                                    *handle);
2032                 if (ret && (command & CMD_ZERO))
2033                         ret = zero_entries(chain,
2034                                            options&OPT_VERBOSE, *handle);
2035                 if (ret && (command & CMD_ZERO_NUM))
2036                         ret = iptc_zero_counter(chain, rulenum, *handle);
2037                 break;
2038         case CMD_NEW_CHAIN:
2039                 ret = iptc_create_chain(chain, *handle);
2040                 break;
2041         case CMD_DELETE_CHAIN:
2042                 ret = delete_chain(chain, options&OPT_VERBOSE, *handle);
2043                 break;
2044         case CMD_RENAME_CHAIN:
2045                 ret = iptc_rename_chain(chain, newname, *handle);
2046                 break;
2047         case CMD_SET_POLICY:
2048                 ret = iptc_set_policy(chain, policy, options&OPT_COUNTERS ? &fw.counters : NULL, *handle);
2049                 break;
2050         default:
2051                 /* We should never reach this... */
2052                 exit_tryhelp(2);
2053         }
2054
2055         if (verbose > 1)
2056                 dump_entries(*handle);
2057
2058         clear_rule_matches(&matches);
2059
2060         if (e != NULL) {
2061                 free(e);
2062                 e = NULL;
2063         }
2064
2065         free(saddrs);
2066         free(smasks);
2067         free(daddrs);
2068         free(dmasks);
2069         xtables_free_opts(1);
2070
2071         return ret;
2072 }