]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
iptables --list-rules command
authorHenrik Nordstrom <henrik@henriknordstrom.net>
Tue, 13 May 2008 11:08:26 +0000 (13:08 +0200)
committerPatrick McHardy <kaber@trash.net>
Tue, 13 May 2008 11:08:26 +0000 (13:08 +0200)
Adds iptables --list-rules (-S) command, acting as a combination of
iptables --list and iptables-save.

The primary motivation behind this patch is to get iptables-save like
output capabilities in iptables-restore, allowing "iptables-restore -n"
to be used as a consistent API to iptables for all kind of operations,
not only blind updates..

As a bonus iptables also gets the capability of printing the rules
as-is.

This completely replaces the earlier patch which added the --rules
option.

Henrik Nordstrom <henrik@henriknordstrom.net>

include/ip6tables.h
include/iptables.h
ip6tables-save.c
ip6tables.8.in
ip6tables.c
iptables-save.c
iptables.8.in
iptables.c

index 0bed11f8b3b7ee98f2058fad7ea8eaf0bedb3ac0..077fee926952a021ef4ff4e0a0975e78b7e381de 100644 (file)
@@ -22,5 +22,6 @@ extern int do_command6(int argc, char *argv[], char **table,
 extern int for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), int verbose, int builtinstoo, ip6tc_handle_t *handle);
 extern int flush_entries(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle);
 extern int delete_chain(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle);
+void print_rule(const struct ip6t_entry *e, ip6tc_handle_t *h, const char *chain, int counters);
 
 #endif /*_IP6TABLES_USER_H*/
index e5f8b400d7e9a529c4d5e6ba3d68edcc33d8bbfb..ecc7168fdd3ed02c3df85cc2c9f94a44b1a6ddd1 100644 (file)
@@ -23,6 +23,8 @@ extern int flush_entries(const ipt_chainlabel chain, int verbose,
                        iptc_handle_t *handle);
 extern int for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
                int verbose, int builtinstoo, iptc_handle_t *handle);
+extern void print_rule(const struct ipt_entry *e,
+               iptc_handle_t *handle, const char *chain, int counters);
 
 /* kernel revision handling */
 extern int kernel_version;
index bd4ccbfe9576f3b6d798afdd48ffb3c28661922f..7b03d7c223aa2d8becb4c0627feb27ae34e5d76f 100644 (file)
@@ -33,199 +33,6 @@ static const struct option options[] = {
 };
 
 
-/* This assumes that mask is contiguous, and byte-bounded. */
-static void
-print_iface(char letter, const char *iface, const unsigned char *mask,
-           int invert)
-{
-       unsigned int i;
-
-       if (mask[0] == 0)
-               return;
-
-       printf("-%c %s", letter, invert ? "! " : "");
-
-       for (i = 0; i < IFNAMSIZ; i++) {
-               if (mask[i] != 0) {
-                       if (iface[i] != '\0')
-                               printf("%c", iface[i]);
-               } else {
-                       /* we can access iface[i-1] here, because
-                        * a few lines above we make sure that mask[0] != 0 */
-                       if (iface[i-1] != '\0')
-                               printf("+");
-                       break;
-               }
-       }
-
-       printf(" ");
-}
-
-/* These are hardcoded backups in ip6tables.c, so they are safe */
-struct pprot {
-       char *name;
-       u_int8_t num;
-};
-
-static const struct pprot chain_protos[] = {
-       { "tcp", IPPROTO_TCP },
-       { "udp", IPPROTO_UDP },
-       { "icmpv6", IPPROTO_ICMPV6 },
-       { "esp", IPPROTO_ESP },
-       { "ah", IPPROTO_AH },
-};
-
-/* The ip6tables looks up the /etc/protocols. */
-static void print_proto(u_int16_t proto, int invert)
-{
-       if (proto) {
-               unsigned int i;
-               const char *invertstr = invert ? "! " : "";
-
-               struct protoent *pent = getprotobynumber(proto);
-               if (pent) {
-                       printf("-p %s%s ",
-                              invertstr, pent->p_name);
-                       return;
-               }
-
-               for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
-                       if (chain_protos[i].num == proto) {
-                               printf("-p %s%s ",
-                                      invertstr, chain_protos[i].name);
-                               return;
-                       }
-
-               printf("-p %s%u ", invertstr, proto);
-       }
-}
-
-static int print_match(const struct ip6t_entry_match *e,
-                       const struct ip6t_ip6 *ip)
-{
-       struct xtables_match *match
-               = find_match(e->u.user.name, TRY_LOAD, NULL);
-
-       if (match) {
-               printf("-m %s ", e->u.user.name);
-
-               /* some matches don't provide a save function */
-               if (match->save)
-                       match->save(ip, e);
-       } else {
-               if (e->u.match_size) {
-                       fprintf(stderr,
-                               "Can't find library for match `%s'\n",
-                               e->u.user.name);
-                       exit(1);
-               }
-       }
-       return 0;
-}
-
-/* print a given ip including mask if neccessary */
-static void print_ip(char *prefix, const struct in6_addr *ip, const struct in6_addr *mask, int invert)
-{
-       char buf[51];
-       int l = ipv6_prefix_length(mask);
-
-       if (l == 0 && !invert)
-               return;
-
-       printf("%s %s%s",
-               prefix,
-               invert ? "! " : "",
-               inet_ntop(AF_INET6, ip, buf, sizeof buf));
-
-       if (l == -1)
-               printf("/%s ", inet_ntop(AF_INET6, mask, buf, sizeof buf));
-       else
-               printf("/%d ", l);
-}
-
-/* We want this to be readable, so only print out neccessary fields.
- * Because that's the kind of world I want to live in.  */
-static void print_rule(const struct ip6t_entry *e,
-                      ip6tc_handle_t *h, const char *chain, int counters)
-{
-       struct ip6t_entry_target *t;
-       const char *target_name;
-
-       /* print counters */
-       if (counters)
-               printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
-
-       /* print chain name */
-       printf("-A %s ", chain);
-
-       /* Print IP part. */
-       print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk),
-                       e->ipv6.invflags & IP6T_INV_SRCIP);
-
-       print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk),
-                       e->ipv6.invflags & IP6T_INV_DSTIP);
-
-       print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask,
-                   e->ipv6.invflags & IP6T_INV_VIA_IN);
-
-       print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask,
-                   e->ipv6.invflags & IP6T_INV_VIA_OUT);
-
-       print_proto(e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
-
-#if 0
-       /* not definied in ipv6
-        * FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? */
-       if (e->ipv6.flags & IPT_F_FRAG)
-               printf("%s-f ",
-                      e->ipv6.invflags & IP6T_INV_FRAG ? "! " : "");
-#endif
-
-       if (e->ipv6.flags & IP6T_F_TOS)
-               printf("%s-? %d ",
-                      e->ipv6.invflags & IP6T_INV_TOS ? "! " : "",
-                      e->ipv6.tos);
-
-       /* Print matchinfo part */
-       if (e->target_offset) {
-               IP6T_MATCH_ITERATE(e, print_match, &e->ipv6);
-       }
-
-       /* Print target name */
-       target_name = ip6tc_get_target(e, h);
-       if (target_name && (*target_name != '\0'))
-               printf("-j %s ", target_name);
-
-       /* Print targinfo part */
-       t = ip6t_get_target((struct ip6t_entry *)e);
-       if (t->u.user.name[0]) {
-               struct xtables_target *target
-                       = find_target(t->u.user.name, TRY_LOAD);
-
-               if (!target) {
-                       fprintf(stderr, "Can't find library for target `%s'\n",
-                               t->u.user.name);
-                       exit(1);
-               }
-
-               if (target->save)
-                       target->save(&e->ipv6, t);
-               else {
-                       /* If the target size is greater than ip6t_entry_target
-                        * there is something to be saved, we just don't know
-                        * how to print it */
-                       if (t->u.target_size !=
-                           sizeof(struct ip6t_entry_target)) {
-                               fprintf(stderr, "Target `%s' is missing "
-                                               "save function\n",
-                                       t->u.user.name);
-                               exit(1);
-                       }
-               }
-       }
-       printf("\n");
-}
-
 /* Debugging prototype. */
 static int for_each_table(int (*func)(const char *tablename))
 {
index f1033635b0815c22406cf66d9519237c1bf94dff..45b14dca5e2a39b5245b50270b4723d5b733b6ed 100644 (file)
@@ -197,6 +197,11 @@ arguments given. The exact rules are suppressed until you use
  ip6tables -L -v
 .fi
 .TP
+.BR "-S, --list-rules " "[\fIchain\fP]"
+Print all rules in the selected chain.  If no chain is selected, all
+chains are printed like iptables-save. Like every other iptables command,
+it applies to the specified table (filter is the default).
+.TP
 .BR "-F, --flush " "[\fIchain\fP]"
 Flush the selected chain (all the chains in the table if none is given).
 This is equivalent to deleting all the rules one by one.
index dc74bcbe0c1fab7859195877cebb84ecacdbf60c..606de3c990ff299e3a1e0d9a322412c082aabb43 100644 (file)
 #define CMD_DELETE_CHAIN       0x0200U
 #define CMD_SET_POLICY         0x0400U
 #define CMD_RENAME_CHAIN       0x0800U
-#define NUMBER_OF_CMD  13
+#define CMD_LIST_RULES         0x1000U
+#define NUMBER_OF_CMD  14
 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
-                                'N', 'X', 'P', 'E' };
+                                'N', 'X', 'P', 'E', 'S' };
 
 #define OPTION_OFFSET 256
 
@@ -106,6 +107,7 @@ static struct option original_opts[] = {
        {.name = "insert",        .has_arg = 1, .val = 'I'},
        {.name = "replace",       .has_arg = 1, .val = 'R'},
        {.name = "list",          .has_arg = 2, .val = 'L'},
+       {.name = "list-rules",    .has_arg = 2, .val = 'S'},
        {.name = "flush",         .has_arg = 2, .val = 'F'},
        {.name = "zero",          .has_arg = 2, .val = 'Z'},
        {.name = "new-chain",     .has_arg = 1, .val = 'N'},
@@ -154,7 +156,7 @@ static unsigned int global_option_offset = 0;
 static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
 /* Well, it's better than "Re: Linux vs FreeBSD" */
 {
-       /*     -n  -s  -d  -p  -j  -v  -x  -i  -o  --line -c */
+       /*     -n  -s  -d  -p  -j  -v  -x  -i  -o --line -c */
 /*INSERT*/    {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
 /*DELETE*/    {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'},
 /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'},
@@ -166,7 +168,8 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
 /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' '},
-/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x'}
+/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x'},
+/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x'}
 };
 
 static int inverse_for_options[NUMBER_OF_OPT] =
@@ -300,6 +303,8 @@ exit_printhelp(struct ip6tables_rule_match *matches)
 "  --replace -R chain rulenum\n"
 "                              Replace rule rulenum (1 = first) in chain\n"
 "  --list    -L [chain]                List the rules in a chain or all chains\n"
+"  --list-rules\n"
+"            -S [chain]         Print the rules in a chain or all chains\n"
 "  --flush   -F [chain]                Delete all rules in  chain or all chains\n"
 "  --zero    -Z [chain]                Zero counters in chain or all chains\n"
 "  --new     -N chain          Create a new user-defined chain\n"
@@ -1098,6 +1103,239 @@ list_entries(const ip6t_chainlabel chain, int verbose, int numeric,
        return found;
 }
 
+/* This assumes that mask is contiguous, and byte-bounded. */
+static void
+print_iface(char letter, const char *iface, const unsigned char *mask,
+           int invert)
+{
+       unsigned int i;
+
+       if (mask[0] == 0)
+               return;
+
+       printf("-%c %s", letter, invert ? "! " : "");
+
+       for (i = 0; i < IFNAMSIZ; i++) {
+               if (mask[i] != 0) {
+                       if (iface[i] != '\0')
+                               printf("%c", iface[i]);
+               } else {
+                       /* we can access iface[i-1] here, because
+                        * a few lines above we make sure that mask[0] != 0 */
+                       if (iface[i-1] != '\0')
+                               printf("+");
+                       break;
+               }
+       }
+
+       printf(" ");
+}
+
+/* The ip6tables looks up the /etc/protocols. */
+static void print_proto(u_int16_t proto, int invert)
+{
+       if (proto) {
+               unsigned int i;
+               const char *invertstr = invert ? "! " : "";
+
+               struct protoent *pent = getprotobynumber(proto);
+               if (pent) {
+                       printf("-p %s%s ",
+                              invertstr, pent->p_name);
+                       return;
+               }
+
+               for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
+                       if (chain_protos[i].num == proto) {
+                               printf("-p %s%s ",
+                                      invertstr, chain_protos[i].name);
+                               return;
+                       }
+
+               printf("-p %s%u ", invertstr, proto);
+       }
+}
+
+static int print_match_save(const struct ip6t_entry_match *e,
+                       const struct ip6t_ip6 *ip)
+{
+       struct xtables_match *match
+               = find_match(e->u.user.name, TRY_LOAD, NULL);
+
+       if (match) {
+               printf("-m %s ", e->u.user.name);
+
+               /* some matches don't provide a save function */
+               if (match->save)
+                       match->save(ip, e);
+       } else {
+               if (e->u.match_size) {
+                       fprintf(stderr,
+                               "Can't find library for match `%s'\n",
+                               e->u.user.name);
+                       exit(1);
+               }
+       }
+       return 0;
+}
+
+/* print a given ip including mask if neccessary */
+static void print_ip(char *prefix, const struct in6_addr *ip, const struct in6_addr *mask, int invert)
+{
+       char buf[51];
+       int l = ipv6_prefix_length(mask);
+
+       if (l == 0 && !invert)
+               return;
+
+       printf("%s %s%s",
+               prefix,
+               invert ? "! " : "",
+               inet_ntop(AF_INET6, ip, buf, sizeof buf));
+
+       if (l == -1)
+               printf("/%s ", inet_ntop(AF_INET6, mask, buf, sizeof buf));
+       else
+               printf("/%d ", l);
+}
+
+/* We want this to be readable, so only print out neccessary fields.
+ * Because that's the kind of world I want to live in.  */
+void print_rule(const struct ip6t_entry *e,
+                      ip6tc_handle_t *h, const char *chain, int counters)
+{
+       struct ip6t_entry_target *t;
+       const char *target_name;
+
+       /* print counters for iptables-save */
+       if (counters > 0)
+               printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
+
+       /* print chain name */
+       printf("-A %s ", chain);
+
+       /* Print IP part. */
+       print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk),
+                       e->ipv6.invflags & IP6T_INV_SRCIP);
+
+       print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk),
+                       e->ipv6.invflags & IP6T_INV_DSTIP);
+
+       print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask,
+                   e->ipv6.invflags & IP6T_INV_VIA_IN);
+
+       print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask,
+                   e->ipv6.invflags & IP6T_INV_VIA_OUT);
+
+       print_proto(e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
+
+#if 0
+       /* not definied in ipv6
+        * FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? */
+       if (e->ipv6.flags & IPT_F_FRAG)
+               printf("%s-f ",
+                      e->ipv6.invflags & IP6T_INV_FRAG ? "! " : "");
+#endif
+
+       if (e->ipv6.flags & IP6T_F_TOS)
+               printf("%s-? %d ",
+                      e->ipv6.invflags & IP6T_INV_TOS ? "! " : "",
+                      e->ipv6.tos);
+
+       /* Print matchinfo part */
+       if (e->target_offset) {
+               IP6T_MATCH_ITERATE(e, print_match_save, &e->ipv6);
+       }
+
+       /* print counters for iptables -R */
+       if (counters < 0)
+               printf("-c %llu %llu ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
+
+       /* Print target name */
+       target_name = ip6tc_get_target(e, h);
+       if (target_name && (*target_name != '\0'))
+               printf("-j %s ", target_name);
+
+       /* Print targinfo part */
+       t = ip6t_get_target((struct ip6t_entry *)e);
+       if (t->u.user.name[0]) {
+               struct xtables_target *target
+                       = find_target(t->u.user.name, TRY_LOAD);
+
+               if (!target) {
+                       fprintf(stderr, "Can't find library for target `%s'\n",
+                               t->u.user.name);
+                       exit(1);
+               }
+
+               if (target->save)
+                       target->save(&e->ipv6, t);
+               else {
+                       /* If the target size is greater than ip6t_entry_target
+                        * there is something to be saved, we just don't know
+                        * how to print it */
+                       if (t->u.target_size !=
+                           sizeof(struct ip6t_entry_target)) {
+                               fprintf(stderr, "Target `%s' is missing "
+                                               "save function\n",
+                                       t->u.user.name);
+                               exit(1);
+                       }
+               }
+       }
+       printf("\n");
+}
+
+static int
+list_rules(const ip6t_chainlabel chain, int counters,
+            ip6tc_handle_t *handle)
+{
+       const char *this = NULL;
+       int found = 0;
+
+       if (counters)
+           counters = -1;              /* iptables -c format */
+
+       /* Dump out chain names first,
+        * thereby preventing dependency conflicts */
+       for (this = ip6tc_first_chain(handle);
+            this;
+            this = ip6tc_next_chain(handle)) {
+               if (chain && strcmp(this, chain) != 0)
+                       continue;
+
+               if (ip6tc_builtin(this, *handle)) {
+                       struct ip6t_counters count;
+                       printf("-P %s %s", this, ip6tc_get_policy(this, &count, handle));
+                       if (counters)
+                           printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+                       printf("\n");
+               } else {
+                       printf("-N %s\n", this);
+               }
+       }
+
+       for (this = ip6tc_first_chain(handle);
+            this;
+            this = ip6tc_next_chain(handle)) {
+               const struct ip6t_entry *e;
+
+               if (chain && strcmp(this, chain) != 0)
+                       continue;
+
+               /* Dump out rules */
+               e = ip6tc_first_rule(this, handle);
+               while(e) {
+                       print_rule(e, handle, this, counters);
+                       e = ip6tc_next_rule(e, handle);
+               }
+               found = 1;
+       }
+
+       errno = ENOENT;
+       return found;
+}
+
 static struct ip6t_entry *
 generate_entry(const struct ip6t_entry *fw,
               struct ip6tables_rule_match *matches,
@@ -1201,7 +1439,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
        opterr = 0;
 
        while ((c = getopt_long(argc, argv,
-          "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:",
+          "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:",
                                           opts, NULL)) != -1) {
                switch (c) {
                        /*
@@ -1256,6 +1494,15 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
                                chain = argv[optind++];
                        break;
 
+               case 'S':
+                       add_command(&command, CMD_LIST_RULES, CMD_ZERO,
+                                   invert);
+                       if (optarg) chain = optarg;
+                       else if (optind < argc && argv[optind][0] != '-'
+                                && argv[optind][0] != '!')
+                               chain = argv[optind++];
+                       break;
+
                case 'F':
                        add_command(&command, CMD_FLUSH, CMD_NONE,
                                    invert);
@@ -1266,7 +1513,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
                        break;
 
                case 'Z':
-                       add_command(&command, CMD_ZERO, CMD_LIST,
+                       add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
                                    invert);
                        if (optarg) chain = optarg;
                        else if (optind < argc && argv[optind][0] != '-'
@@ -1515,7 +1762,6 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
 
                        break;
 
-
                case 1: /* non option */
                        if (optarg[0] == '!' && optarg[1] == '\0') {
                                if (invert)
@@ -1767,20 +2013,13 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
                                   options&OPT_VERBOSE,
                                   handle);
                break;
-       case CMD_LIST:
-               ret = list_entries(chain,
-                                  options&OPT_VERBOSE,
-                                  options&OPT_NUMERIC,
-                                  options&OPT_EXPANDED,
-                                  options&OPT_LINENUMBERS,
-                                  handle);
-               break;
        case CMD_FLUSH:
                ret = flush_entries(chain, options&OPT_VERBOSE, handle);
                break;
        case CMD_ZERO:
                ret = zero_entries(chain, options&OPT_VERBOSE, handle);
                break;
+       case CMD_LIST:
        case CMD_LIST|CMD_ZERO:
                ret = list_entries(chain,
                                   options&OPT_VERBOSE,
@@ -1788,7 +2027,16 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
                                   options&OPT_EXPANDED,
                                   options&OPT_LINENUMBERS,
                                   handle);
-               if (ret)
+               if (ret && (command & CMD_ZERO))
+                       ret = zero_entries(chain,
+                                          options&OPT_VERBOSE, handle);
+               break;
+       case CMD_LIST_RULES:
+       case CMD_LIST_RULES|CMD_ZERO:
+               ret = list_rules(chain,
+                                  options&OPT_VERBOSE,
+                                  handle);
+               if (ret && (command & CMD_ZERO))
                        ret = zero_entries(chain,
                                           options&OPT_VERBOSE, handle);
                break;
index e8bdda2b50377d0df5bb201fb476a0b33694c928..ecccac47bf47bd25b0ba2933af61d25d989e82b3 100644 (file)
@@ -31,211 +31,6 @@ static const struct option options[] = {
        {NULL},
 };
 
-#define IP_PARTS_NATIVE(n)                     \
-(unsigned int)((n)>>24)&0xFF,                  \
-(unsigned int)((n)>>16)&0xFF,                  \
-(unsigned int)((n)>>8)&0xFF,                   \
-(unsigned int)((n)&0xFF)
-
-#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
-
-/* This assumes that mask is contiguous, and byte-bounded. */
-static void
-print_iface(char letter, const char *iface, const unsigned char *mask,
-           int invert)
-{
-       unsigned int i;
-
-       if (mask[0] == 0)
-               return;
-
-       printf("-%c %s", letter, invert ? "! " : "");
-
-       for (i = 0; i < IFNAMSIZ; i++) {
-               if (mask[i] != 0) {
-                       if (iface[i] != '\0')
-                               printf("%c", iface[i]);
-               } else {
-                       /* we can access iface[i-1] here, because
-                        * a few lines above we make sure that mask[0] != 0 */
-                       if (iface[i-1] != '\0')
-                               printf("+");
-                       break;
-               }
-       }
-
-       printf(" ");
-}
-
-/* These are hardcoded backups in iptables.c, so they are safe */
-struct pprot {
-       char *name;
-       u_int8_t num;
-};
-
-/* FIXME: why don't we use /etc/protocols ? */
-static const struct pprot chain_protos[] = {
-       { "tcp", IPPROTO_TCP },
-       { "udp", IPPROTO_UDP },
-       { "icmp", IPPROTO_ICMP },
-       { "esp", IPPROTO_ESP },
-       { "ah", IPPROTO_AH },
-       { "sctp", IPPROTO_SCTP },
-};
-
-static void print_proto(u_int16_t proto, int invert)
-{
-       if (proto) {
-               unsigned int i;
-               const char *invertstr = invert ? "! " : "";
-
-               struct protoent *pent = getprotobynumber(proto);
-               if (pent) {
-                       printf("-p %s%s ", invertstr, pent->p_name);
-                       return;
-               }
-
-               for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
-                       if (chain_protos[i].num == proto) {
-                               printf("-p %s%s ",
-                                      invertstr, chain_protos[i].name);
-                               return;
-                       }
-
-               printf("-p %s%u ", invertstr, proto);
-       }
-}
-
-static int print_match(const struct ipt_entry_match *e,
-                       const struct ipt_ip *ip)
-{
-       struct xtables_match *match
-               = find_match(e->u.user.name, TRY_LOAD, NULL);
-
-       if (match) {
-               printf("-m %s ", e->u.user.name);
-
-               /* some matches don't provide a save function */
-               if (match->save)
-                       match->save(ip, e);
-       } else {
-               if (e->u.match_size) {
-                       fprintf(stderr,
-                               "Can't find library for match `%s'\n",
-                               e->u.user.name);
-                       exit(1);
-               }
-       }
-       return 0;
-}
-
-/* print a given ip including mask if neccessary */
-static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
-{
-       u_int32_t bits, hmask = ntohl(mask);
-       int i;
-
-       if (!mask && !ip && !invert)
-               return;
-
-       printf("%s %s%u.%u.%u.%u",
-               prefix,
-               invert ? "! " : "",
-               IP_PARTS(ip));
-
-       if (mask == 0xFFFFFFFFU) {
-               printf("/32 ");
-               return;
-       }
-
-       i    = 32;
-       bits = 0xFFFFFFFEU;
-       while (--i >= 0 && hmask != bits)
-               bits <<= 1;
-       if (i >= 0)
-               printf("/%u ", i);
-       else
-               printf("/%u.%u.%u.%u ", IP_PARTS(mask));
-}
-
-/* We want this to be readable, so only print out neccessary fields.
- * Because that's the kind of world I want to live in.  */
-static void print_rule(const struct ipt_entry *e,
-               iptc_handle_t *h, const char *chain, int counters)
-{
-       struct ipt_entry_target *t;
-       const char *target_name;
-
-       /* print counters */
-       if (counters)
-               printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
-
-       /* print chain name */
-       printf("-A %s ", chain);
-
-       /* Print IP part. */
-       print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
-                       e->ip.invflags & IPT_INV_SRCIP);
-
-       print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
-                       e->ip.invflags & IPT_INV_DSTIP);
-
-       print_iface('i', e->ip.iniface, e->ip.iniface_mask,
-                   e->ip.invflags & IPT_INV_VIA_IN);
-
-       print_iface('o', e->ip.outiface, e->ip.outiface_mask,
-                   e->ip.invflags & IPT_INV_VIA_OUT);
-
-       print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
-
-       if (e->ip.flags & IPT_F_FRAG)
-               printf("%s-f ",
-                      e->ip.invflags & IPT_INV_FRAG ? "! " : "");
-
-       /* Print matchinfo part */
-       if (e->target_offset) {
-               IPT_MATCH_ITERATE(e, print_match, &e->ip);
-       }
-
-       /* Print target name */
-       target_name = iptc_get_target(e, h);
-       if (target_name && (*target_name != '\0'))
-#ifdef IPT_F_GOTO
-               printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
-#else
-               printf("-j %s ", target_name);
-#endif
-
-       /* Print targinfo part */
-       t = ipt_get_target((struct ipt_entry *)e);
-       if (t->u.user.name[0]) {
-               struct xtables_target *target
-                       = find_target(t->u.user.name, TRY_LOAD);
-
-               if (!target) {
-                       fprintf(stderr, "Can't find library for target `%s'\n",
-                               t->u.user.name);
-                       exit(1);
-               }
-
-               if (target->save)
-                       target->save(&e->ip, t);
-               else {
-                       /* If the target size is greater than ipt_entry_target
-                        * there is something to be saved, we just don't know
-                        * how to print it */
-                       if (t->u.target_size !=
-                           sizeof(struct ipt_entry_target)) {
-                               fprintf(stderr, "Target `%s' is missing "
-                                               "save function\n",
-                                       t->u.user.name);
-                               exit(1);
-                       }
-               }
-       }
-       printf("\n");
-}
-
 /* Debugging prototype. */
 static int for_each_table(int (*func)(const char *tablename))
 {
index 8ebedb82b4138eae7ae351071a686d28da70a3c9..0b945cb76313113b847c9c7bfefe2f2837cbb81e 100644 (file)
@@ -205,6 +205,11 @@ arguments given. The exact rules are suppressed until you use
  iptables -L -v
 .fi
 .TP
+.BR "-S, --list-rules " "[\fIchain\fP]"
+Print all rules in the selected chain.  If no chain is selected, all
+chains are printed like iptables-save. Like every other iptables command,
+it applies to the specified table (filter is the default).
+.TP
 .BR "-F, --flush " "[\fIchain\fP]"
 Flush the selected chain (all the chains in the table if none is given).
 This is equivalent to deleting all the rules one by one.
index 8c876d2275835b274b27e3287edbe0f5295cacce..98db70fc9b973d64cf25491e283283f4363c753e 100644 (file)
 #define CMD_DELETE_CHAIN       0x0200U
 #define CMD_SET_POLICY         0x0400U
 #define CMD_RENAME_CHAIN       0x0800U
-#define NUMBER_OF_CMD  13
+#define CMD_LIST_RULES         0x1000U
+#define NUMBER_OF_CMD  14
 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
-                                'N', 'X', 'P', 'E' };
+                                'N', 'X', 'P', 'E', 'S' };
 
 #define OPTION_OFFSET 256
 
@@ -104,6 +105,7 @@ static struct option original_opts[] = {
        {.name = "insert",        .has_arg = 1, .val = 'I'},
        {.name = "replace",       .has_arg = 1, .val = 'R'},
        {.name = "list",          .has_arg = 2, .val = 'L'},
+       {.name = "list-rules",    .has_arg = 2, .val = 'S'},
        {.name = "flush",         .has_arg = 2, .val = 'F'},
        {.name = "zero",          .has_arg = 2, .val = 'Z'},
        {.name = "new-chain",     .has_arg = 1, .val = 'N'},
@@ -154,7 +156,7 @@ static unsigned int global_option_offset = 0;
 static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
 /* Well, it's better than "Re: Linux vs FreeBSD" */
 {
-       /*     -n  -s  -d  -p  -j  -v  -x  -i  -o  -f  --line -c */
+       /*     -n  -s  -d  -p  -j  -v  -x  -i  -o  -f --line -c */
 /*INSERT*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '},
 /*DELETE*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x','x'},
 /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
@@ -166,7 +168,8 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
 /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x',' '},
-/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'}
+/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'},
+/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}
 };
 
 static int inverse_for_options[NUMBER_OF_OPT] =
@@ -303,6 +306,8 @@ exit_printhelp(struct iptables_rule_match *matches)
 "  --replace -R chain rulenum\n"
 "                              Replace rule rulenum (1 = first) in chain\n"
 "  --list    -L [chain]                List the rules in a chain or all chains\n"
+"  --list-rules\n"
+"            -S [chain]         Print the rules in a chain or all chains\n"
 "  --flush   -F [chain]                Delete all rules in  chain or all chains\n"
 "  --zero    -Z [chain]                Zero counters in chain or all chains\n"
 "  --new     -N chain          Create a new user-defined chain\n"
@@ -1101,6 +1106,249 @@ list_entries(const ipt_chainlabel chain, int verbose, int numeric,
        return found;
 }
 
+static void print_proto(u_int16_t proto, int invert)
+{
+       if (proto) {
+               unsigned int i;
+               const char *invertstr = invert ? "! " : "";
+
+               struct protoent *pent = getprotobynumber(proto);
+               if (pent) {
+                       printf("-p %s%s ", invertstr, pent->p_name);
+                       return;
+               }
+
+               for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
+                       if (chain_protos[i].num == proto) {
+                               printf("-p %s%s ",
+                                      invertstr, chain_protos[i].name);
+                               return;
+                       }
+
+               printf("-p %s%u ", invertstr, proto);
+       }
+}
+
+#define IP_PARTS_NATIVE(n)                     \
+(unsigned int)((n)>>24)&0xFF,                  \
+(unsigned int)((n)>>16)&0xFF,                  \
+(unsigned int)((n)>>8)&0xFF,                   \
+(unsigned int)((n)&0xFF)
+
+#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
+
+/* This assumes that mask is contiguous, and byte-bounded. */
+static void
+print_iface(char letter, const char *iface, const unsigned char *mask,
+           int invert)
+{
+       unsigned int i;
+
+       if (mask[0] == 0)
+               return;
+
+       printf("-%c %s", letter, invert ? "! " : "");
+
+       for (i = 0; i < IFNAMSIZ; i++) {
+               if (mask[i] != 0) {
+                       if (iface[i] != '\0')
+                               printf("%c", iface[i]);
+               } else {
+                       /* we can access iface[i-1] here, because
+                        * a few lines above we make sure that mask[0] != 0 */
+                       if (iface[i-1] != '\0')
+                               printf("+");
+                       break;
+               }
+       }
+
+       printf(" ");
+}
+
+static int print_match_save(const struct ipt_entry_match *e,
+                       const struct ipt_ip *ip)
+{
+       struct xtables_match *match
+               = find_match(e->u.user.name, TRY_LOAD, NULL);
+
+       if (match) {
+               printf("-m %s ", e->u.user.name);
+
+               /* some matches don't provide a save function */
+               if (match->save)
+                       match->save(ip, e);
+       } else {
+               if (e->u.match_size) {
+                       fprintf(stderr,
+                               "Can't find library for match `%s'\n",
+                               e->u.user.name);
+                       exit(1);
+               }
+       }
+       return 0;
+}
+
+/* print a given ip including mask if neccessary */
+static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
+{
+       u_int32_t bits, hmask = ntohl(mask);
+       int i;
+
+       if (!mask && !ip && !invert)
+               return;
+
+       printf("%s %s%u.%u.%u.%u",
+               prefix,
+               invert ? "! " : "",
+               IP_PARTS(ip));
+
+       if (mask == 0xFFFFFFFFU) {
+               printf("/32 ");
+               return;
+       }
+
+       i    = 32;
+       bits = 0xFFFFFFFEU;
+       while (--i >= 0 && hmask != bits)
+               bits <<= 1;
+       if (i >= 0)
+               printf("/%u ", i);
+       else
+               printf("/%u.%u.%u.%u ", IP_PARTS(mask));
+}
+
+/* We want this to be readable, so only print out neccessary fields.
+ * Because that's the kind of world I want to live in.  */
+void print_rule(const struct ipt_entry *e,
+               iptc_handle_t *h, const char *chain, int counters)
+{
+       struct ipt_entry_target *t;
+       const char *target_name;
+
+       /* print counters for iptables-save */
+       if (counters > 0)
+               printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
+
+       /* print chain name */
+       printf("-A %s ", chain);
+
+       /* Print IP part. */
+       print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
+                       e->ip.invflags & IPT_INV_SRCIP);
+
+       print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
+                       e->ip.invflags & IPT_INV_DSTIP);
+
+       print_iface('i', e->ip.iniface, e->ip.iniface_mask,
+                   e->ip.invflags & IPT_INV_VIA_IN);
+
+       print_iface('o', e->ip.outiface, e->ip.outiface_mask,
+                   e->ip.invflags & IPT_INV_VIA_OUT);
+
+       print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
+
+       if (e->ip.flags & IPT_F_FRAG)
+               printf("%s-f ",
+                      e->ip.invflags & IPT_INV_FRAG ? "! " : "");
+
+       /* Print matchinfo part */
+       if (e->target_offset) {
+               IPT_MATCH_ITERATE(e, print_match_save, &e->ip);
+       }
+
+       /* print counters for iptables -R */
+       if (counters < 0)
+               printf("-c %llu %llu ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
+
+       /* Print target name */
+       target_name = iptc_get_target(e, h);
+       if (target_name && (*target_name != '\0'))
+#ifdef IPT_F_GOTO
+               printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
+#else
+               printf("-j %s ", target_name);
+#endif
+
+       /* Print targinfo part */
+       t = ipt_get_target((struct ipt_entry *)e);
+       if (t->u.user.name[0]) {
+               struct xtables_target *target
+                       = find_target(t->u.user.name, TRY_LOAD);
+
+               if (!target) {
+                       fprintf(stderr, "Can't find library for target `%s'\n",
+                               t->u.user.name);
+                       exit(1);
+               }
+
+               if (target->save)
+                       target->save(&e->ip, t);
+               else {
+                       /* If the target size is greater than ipt_entry_target
+                        * there is something to be saved, we just don't know
+                        * how to print it */
+                       if (t->u.target_size !=
+                           sizeof(struct ipt_entry_target)) {
+                               fprintf(stderr, "Target `%s' is missing "
+                                               "save function\n",
+                                       t->u.user.name);
+                               exit(1);
+                       }
+               }
+       }
+       printf("\n");
+}
+
+static int
+list_rules(const ipt_chainlabel chain, int counters,
+            iptc_handle_t *handle)
+{
+       const char *this = NULL;
+       int found = 0;
+
+       if (counters)
+           counters = -1;              /* iptables -c format */
+
+       /* Dump out chain names first,
+        * thereby preventing dependency conflicts */
+       for (this = iptc_first_chain(handle);
+            this;
+            this = iptc_next_chain(handle)) {
+               if (chain && strcmp(this, chain) != 0)
+                       continue;
+
+               if (iptc_builtin(this, *handle)) {
+                       struct ipt_counters count;
+                       printf("-P %s %s", this, iptc_get_policy(this, &count, handle));
+                       if (counters)
+                           printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+                       printf("\n");
+               } else {
+                       printf("-N %s\n", this);
+               }
+       }
+
+       for (this = iptc_first_chain(handle);
+            this;
+            this = iptc_next_chain(handle)) {
+               const struct ipt_entry *e;
+
+               if (chain && strcmp(this, chain) != 0)
+                       continue;
+
+               /* Dump out rules */
+               e = iptc_first_rule(this, handle);
+               while(e) {
+                       print_rule(e, handle, this, counters);
+                       e = iptc_next_rule(e, handle);
+               }
+               found = 1;
+       }
+
+       errno = ENOENT;
+       return found;
+}
+
 static struct ipt_entry *
 generate_entry(const struct ipt_entry *fw,
               struct iptables_rule_match *matches,
@@ -1218,7 +1466,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
        opterr = 0;
 
        while ((c = getopt_long(argc, argv,
-          "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
+          "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
                                           opts, NULL)) != -1) {
                switch (c) {
                        /*
@@ -1273,6 +1521,15 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                                chain = argv[optind++];
                        break;
 
+               case 'S':
+                       add_command(&command, CMD_LIST_RULES, CMD_ZERO,
+                                   invert);
+                       if (optarg) chain = optarg;
+                       else if (optind < argc && argv[optind][0] != '-'
+                                && argv[optind][0] != '!')
+                               chain = argv[optind++];
+                       break;
+
                case 'F':
                        add_command(&command, CMD_FLUSH, CMD_NONE,
                                    invert);
@@ -1283,7 +1540,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                        break;
 
                case 'Z':
-                       add_command(&command, CMD_ZERO, CMD_LIST,
+                       add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
                                    invert);
                        if (optarg) chain = optarg;
                        else if (optind < argc && argv[optind][0] != '-'
@@ -1807,20 +2064,13 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                                   options&OPT_VERBOSE,
                                   handle);
                break;
-       case CMD_LIST:
-               ret = list_entries(chain,
-                                  options&OPT_VERBOSE,
-                                  options&OPT_NUMERIC,
-                                  options&OPT_EXPANDED,
-                                  options&OPT_LINENUMBERS,
-                                  handle);
-               break;
        case CMD_FLUSH:
                ret = flush_entries(chain, options&OPT_VERBOSE, handle);
                break;
        case CMD_ZERO:
                ret = zero_entries(chain, options&OPT_VERBOSE, handle);
                break;
+       case CMD_LIST:
        case CMD_LIST|CMD_ZERO:
                ret = list_entries(chain,
                                   options&OPT_VERBOSE,
@@ -1828,7 +2078,16 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                                   options&OPT_EXPANDED,
                                   options&OPT_LINENUMBERS,
                                   handle);
-               if (ret)
+               if (ret && (command & CMD_ZERO))
+                       ret = zero_entries(chain,
+                                          options&OPT_VERBOSE, handle);
+               break;
+       case CMD_LIST_RULES:
+       case CMD_LIST_RULES|CMD_ZERO:
+               ret = list_rules(chain,
+                                  options&OPT_VERBOSE,
+                                  handle);
+               if (ret && (command & CMD_ZERO))
                        ret = zero_entries(chain,
                                           options&OPT_VERBOSE, handle);
                break;