~ubuntu-branches/ubuntu/lucid/iptables/lucid

« back to all changes in this revision

Viewing changes to iptables.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen, Iain Lane, Soren Hansen
  • Date: 2008-11-15 01:27:37 UTC
  • mfrom: (5.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20081115012737-o3kdn2z1o9ercq10
Tags: 1.4.1.1-4ubuntu1
[ Iain Lane ]
* Merge from debian unstable (LP: #294220), remaining changes:
  - debian/patches/0901-build-libipq_pic.a.patch - Build libipq_pic.a with
    -fPIC. Upstream changed build system and patch modified accordingly.

[ Soren Hansen ]
* Revert changes between 1.4.1.1-3 and 1.4.1.1-4, thus bringing back
  the howtos.

Show diffs side-by-side

added added

removed removed

Lines of Context:
75
75
#define CMD_DELETE_CHAIN        0x0200U
76
76
#define CMD_SET_POLICY          0x0400U
77
77
#define CMD_RENAME_CHAIN        0x0800U
78
 
#define NUMBER_OF_CMD   13
 
78
#define CMD_LIST_RULES          0x1000U
 
79
#define NUMBER_OF_CMD   14
79
80
static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
80
 
                                 'N', 'X', 'P', 'E' };
 
81
                                 'N', 'X', 'P', 'E', 'S' };
81
82
 
82
83
#define OPTION_OFFSET 256
83
84
 
99
100
= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '0', 'c'};
100
101
 
101
102
static struct option original_opts[] = {
102
 
        { "append", 1, NULL, 'A' },
103
 
        { "delete", 1, NULL,  'D' },
104
 
        { "insert", 1, NULL,  'I' },
105
 
        { "replace", 1, NULL,  'R' },
106
 
        { "list", 2, NULL,  'L' },
107
 
        { "flush", 2, NULL,  'F' },
108
 
        { "zero", 2, NULL,  'Z' },
109
 
        { "new-chain", 1, NULL,  'N' },
110
 
        { "delete-chain", 2, NULL,  'X' },
111
 
        { "rename-chain", 1, NULL,  'E' },
112
 
        { "policy", 1, NULL,  'P' },
113
 
        { "source", 1, NULL, 's' },
114
 
        { "destination", 1, NULL,  'd' },
115
 
        { "src", 1, NULL,  's' }, /* synonym */
116
 
        { "dst", 1, NULL,  'd' }, /* synonym */
117
 
        { "protocol", 1, NULL,  'p' },
118
 
        { "in-interface", 1, NULL, 'i' },
119
 
        { "jump", 1, NULL, 'j' },
120
 
        { "table", 1, NULL, 't' },
121
 
        { "match", 1, NULL, 'm' },
122
 
        { "numeric", 0, NULL, 'n' },
123
 
        { "out-interface", 1, NULL, 'o' },
124
 
        { "verbose", 0, NULL, 'v' },
125
 
        { "exact", 0, NULL, 'x' },
126
 
        { "fragments", 0, NULL, 'f' },
127
 
        { "version", 0, NULL, 'V' },
128
 
        { "help", 2, NULL, 'h' },
129
 
        { "line-numbers", 0, NULL, '0' },
130
 
        { "modprobe", 1, NULL, 'M' },
131
 
        { "set-counters", 1, NULL, 'c' },
132
 
        { "goto", 1, NULL, 'g' },
133
 
        { }
 
103
        {.name = "append",        .has_arg = 1, .val = 'A'},
 
104
        {.name = "delete",        .has_arg = 1, .val = 'D'},
 
105
        {.name = "insert",        .has_arg = 1, .val = 'I'},
 
106
        {.name = "replace",       .has_arg = 1, .val = 'R'},
 
107
        {.name = "list",          .has_arg = 2, .val = 'L'},
 
108
        {.name = "list-rules",    .has_arg = 2, .val = 'S'},
 
109
        {.name = "flush",         .has_arg = 2, .val = 'F'},
 
110
        {.name = "zero",          .has_arg = 2, .val = 'Z'},
 
111
        {.name = "new-chain",     .has_arg = 1, .val = 'N'},
 
112
        {.name = "delete-chain",  .has_arg = 2, .val = 'X'},
 
113
        {.name = "rename-chain",  .has_arg = 1, .val = 'E'},
 
114
        {.name = "policy",        .has_arg = 1, .val = 'P'},
 
115
        {.name = "source",        .has_arg = 1, .val = 's'},
 
116
        {.name = "destination",   .has_arg = 1, .val = 'd'},
 
117
        {.name = "src",           .has_arg = 1, .val = 's'}, /* synonym */
 
118
        {.name = "dst",           .has_arg = 1, .val = 'd'}, /* synonym */
 
119
        {.name = "protocol",      .has_arg = 1, .val = 'p'},
 
120
        {.name = "in-interface",  .has_arg = 1, .val = 'i'},
 
121
        {.name = "jump",          .has_arg = 1, .val = 'j'},
 
122
        {.name = "table",         .has_arg = 1, .val = 't'},
 
123
        {.name = "match",         .has_arg = 1, .val = 'm'},
 
124
        {.name = "numeric",       .has_arg = 0, .val = 'n'},
 
125
        {.name = "out-interface", .has_arg = 1, .val = 'o'},
 
126
        {.name = "verbose",       .has_arg = 0, .val = 'v'},
 
127
        {.name = "exact",         .has_arg = 0, .val = 'x'},
 
128
        {.name = "fragments",     .has_arg = 0, .val = 'f'},
 
129
        {.name = "version",       .has_arg = 0, .val = 'V'},
 
130
        {.name = "help",          .has_arg = 2, .val = 'h'},
 
131
        {.name = "line-numbers",  .has_arg = 0, .val = '0'},
 
132
        {.name = "modprobe",      .has_arg = 1, .val = 'M'},
 
133
        {.name = "set-counters",  .has_arg = 1, .val = 'c'},
 
134
        {.name = "goto",          .has_arg = 1, .val = 'g'},
 
135
        {NULL},
134
136
};
135
137
 
136
138
/* we need this for iptables-restore.  iptables-restore.c sets line to the
154
156
static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
155
157
/* Well, it's better than "Re: Linux vs FreeBSD" */
156
158
{
157
 
        /*     -n  -s  -d  -p  -j  -v  -x  -i  -o  -f  --line -c */
 
159
        /*     -n  -s  -d  -p  -j  -v  -x  -i  -o  -f --line -c */
158
160
/*INSERT*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '},
159
161
/*DELETE*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x','x'},
160
162
/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
165
167
/*ZERO*/      {'x','x','x','x','x',' ','x','x','x','x','x','x'},
166
168
/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
167
169
/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
168
 
/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
169
 
/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'}
 
170
/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x',' '},
 
171
/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'},
 
172
/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}
170
173
};
171
174
 
172
175
static int inverse_for_options[NUMBER_OF_OPT] =
190
193
 
191
194
int kernel_version;
192
195
 
193
 
extern void dump_entries(const iptc_handle_t handle);
194
 
 
195
196
/* A few hardcoded protocols for 'all' and in case the user has no
196
197
   /etc/protocols */
197
198
struct pprot {
253
254
        IPT_DOTTED_MASK
254
255
};
255
256
 
256
 
static struct in_addr *
257
 
__dotted_to_addr(const char *dotted, int type)
258
 
{
259
 
        static struct in_addr addr;
260
 
        unsigned char *addrp;
261
 
        char *p, *q;
262
 
        unsigned int onebyte;
263
 
        int i;
264
 
        char buf[20];
265
 
 
266
 
        /* copy dotted string, because we need to modify it */
267
 
        strncpy(buf, dotted, sizeof(buf) - 1);
268
 
        buf[sizeof(buf) - 1] = '\0';
269
 
        addrp = (unsigned char *) &(addr.s_addr);
270
 
 
271
 
        p = buf;
272
 
        for (i = 0; i < 3; i++) {
273
 
                if ((q = strchr(p, '.')) == NULL) {
274
 
                        if (type == IPT_DOTTED_ADDR) {
275
 
                                /* autocomplete, this is a network address */
276
 
                                if (string_to_number(p, 0, 255, &onebyte) == -1)
277
 
                                        return (struct in_addr *) NULL;
278
 
 
279
 
                                addrp[i] = (unsigned char) onebyte;
280
 
                                while (i < 3)
281
 
                                        addrp[++i] = 0;
282
 
 
283
 
                                return &addr;
284
 
                        } else
285
 
                                return (struct in_addr *) NULL;
286
 
                }
287
 
 
288
 
                *q = '\0';
289
 
                if (string_to_number(p, 0, 255, &onebyte) == -1)
290
 
                        return (struct in_addr *) NULL;
291
 
 
292
 
                addrp[i] = (unsigned char) onebyte;
293
 
                p = q + 1;
294
 
        }
295
 
 
296
 
        /* we've checked 3 bytes, now we check the last one */
297
 
        if (string_to_number(p, 0, 255, &onebyte) == -1)
298
 
                return (struct in_addr *) NULL;
299
 
 
300
 
        addrp[3] = (unsigned char) onebyte;
301
 
 
302
 
        return &addr;
303
 
}
304
 
 
305
 
struct in_addr *
306
 
dotted_to_addr(const char *dotted)
307
 
{
308
 
        return __dotted_to_addr(dotted, IPT_DOTTED_ADDR);
309
 
}
310
 
 
311
 
struct in_addr *
312
 
dotted_to_mask(const char *dotted)
313
 
{
314
 
        return __dotted_to_addr(dotted, IPT_DOTTED_MASK);
315
 
}
316
 
 
317
 
static struct in_addr *
318
 
network_to_addr(const char *name)
319
 
{
320
 
        struct netent *net;
321
 
        static struct in_addr addr;
322
 
 
323
 
        if ((net = getnetbyname(name)) != NULL) {
324
 
                if (net->n_addrtype != AF_INET)
325
 
                        return (struct in_addr *) NULL;
326
 
                addr.s_addr = htonl((unsigned long) net->n_net);
327
 
                return &addr;
328
 
        }
329
 
 
330
 
        return (struct in_addr *) NULL;
331
 
}
332
 
 
333
 
static void
334
 
inaddrcpy(struct in_addr *dst, struct in_addr *src)
335
 
{
336
 
        /* memcpy(dst, src, sizeof(struct in_addr)); */
337
 
        dst->s_addr = src->s_addr;
338
 
}
339
 
 
340
257
static void free_opts(int reset_offset)
341
258
{
342
259
        if (opts != original_opts) {
362
279
exit_printhelp(struct iptables_rule_match *matches)
363
280
{
364
281
        struct iptables_rule_match *matchp = NULL;
365
 
        struct iptables_target *t = NULL;
 
282
        struct xtables_target *t = NULL;
366
283
 
367
284
        printf("%s v%s\n\n"
368
285
"Usage: %s -[AD] chain rule-specification [options]\n"
369
286
"       %s -[RI] chain rulenum rule-specification [options]\n"
370
287
"       %s -D chain rulenum [options]\n"
371
 
"       %s -[LFZ] [chain] [options]\n"
 
288
"       %s -[LS] [chain [rulenum]] [options]\n"
 
289
"       %s -[FZ] [chain] [options]\n"
372
290
"       %s -[NX] chain\n"
373
291
"       %s -E old-chain-name new-chain-name\n"
374
292
"       %s -P chain target [options]\n"
375
293
"       %s -h (print this help information)\n\n",
376
294
               program_name, program_version, program_name, program_name,
377
295
               program_name, program_name, program_name, program_name,
378
 
               program_name, program_name);
 
296
               program_name, program_name, program_name);
379
297
 
380
298
        printf(
381
299
"Commands:\n"
388
306
"                               Insert in chain as rulenum (default 1=first)\n"
389
307
"  --replace -R chain rulenum\n"
390
308
"                               Replace rule rulenum (1 = first) in chain\n"
391
 
"  --list    -L [chain]         List the rules in a chain or all chains\n"
 
309
"  --list    -L [chain [rulenum]]\n"
 
310
"                               List the rules in a chain or all chains\n"
 
311
"  --list-rules -S [chain [rulenum]]\n"
 
312
"                               Print the rules in a chain or all chains\n"
392
313
"  --flush   -F [chain]         Delete all rules in  chain or all chains\n"
393
314
"  --zero    -Z [chain]         Zero counters in chain or all chains\n"
394
315
"  --new     -N chain           Create a new user-defined chain\n"
531
452
}
532
453
 
533
454
int
534
 
check_inverse(const char option[], int *invert, int *optind, int argc)
 
455
check_inverse(const char option[], int *invert, int *my_optind, int argc)
535
456
{
536
457
        if (option && strcmp(option, "!") == 0) {
537
458
                if (*invert)
538
459
                        exit_error(PARAMETER_PROBLEM,
539
460
                                   "Multiple `!' flags not allowed");
540
461
                *invert = TRUE;
541
 
                if (optind) {
542
 
                        *optind = *optind+1;
543
 
                        if (argc && *optind > argc)
 
462
                if (my_optind != NULL) {
 
463
                        ++*my_optind;
 
464
                        if (argc && *my_optind > argc)
544
465
                                exit_error(PARAMETER_PROBLEM,
545
466
                                           "no argument following `!'");
546
467
                }
550
471
        return FALSE;
551
472
}
552
473
 
553
 
static struct in_addr *
554
 
host_to_addr(const char *name, unsigned int *naddr)
555
 
{
556
 
        struct hostent *host;
557
 
        struct in_addr *addr;
558
 
        unsigned int i;
559
 
 
560
 
        *naddr = 0;
561
 
        if ((host = gethostbyname(name)) != NULL) {
562
 
                if (host->h_addrtype != AF_INET ||
563
 
                    host->h_length != sizeof(struct in_addr))
564
 
                        return (struct in_addr *) NULL;
565
 
 
566
 
                while (host->h_addr_list[*naddr] != (char *) NULL)
567
 
                        (*naddr)++;
568
 
                addr = fw_calloc(*naddr, sizeof(struct in_addr) * *naddr);
569
 
                for (i = 0; i < *naddr; i++)
570
 
                        inaddrcpy(&(addr[i]),
571
 
                                  (struct in_addr *) host->h_addr_list[i]);
572
 
                return addr;
573
 
        }
574
 
 
575
 
        return (struct in_addr *) NULL;
576
 
}
577
 
 
578
 
static char *
579
 
addr_to_host(const struct in_addr *addr)
580
 
{
581
 
        struct hostent *host;
582
 
 
583
 
        if ((host = gethostbyaddr((char *) addr,
584
 
                                  sizeof(struct in_addr), AF_INET)) != NULL)
585
 
                return (char *) host->h_name;
586
 
 
587
 
        return (char *) NULL;
588
 
}
589
 
 
590
474
/*
591
475
 *      All functions starting with "parse" should succeed, otherwise
592
476
 *      the program fails.
596
480
 *      return global static data.
597
481
*/
598
482
 
599
 
static struct in_addr *
600
 
parse_hostnetwork(const char *name, unsigned int *naddrs)
601
 
{
602
 
        struct in_addr *addrp, *addrptmp;
603
 
 
604
 
        if ((addrptmp = dotted_to_addr(name)) != NULL ||
605
 
            (addrptmp = network_to_addr(name)) != NULL) {
606
 
                addrp = fw_malloc(sizeof(struct in_addr));
607
 
                inaddrcpy(addrp, addrptmp);
608
 
                *naddrs = 1;
609
 
                return addrp;
610
 
        }
611
 
        if ((addrp = host_to_addr(name, naddrs)) != NULL)
612
 
                return addrp;
613
 
 
614
 
        exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
615
 
}
616
 
 
617
 
static struct in_addr *
618
 
parse_mask(char *mask)
619
 
{
620
 
        static struct in_addr maskaddr;
621
 
        struct in_addr *addrp;
622
 
        unsigned int bits;
623
 
 
624
 
        if (mask == NULL) {
625
 
                /* no mask at all defaults to 32 bits */
626
 
                maskaddr.s_addr = 0xFFFFFFFF;
627
 
                return &maskaddr;
628
 
        }
629
 
        if ((addrp = dotted_to_mask(mask)) != NULL)
630
 
                /* dotted_to_addr already returns a network byte order addr */
631
 
                return addrp;
632
 
        if (string_to_number(mask, 0, 32, &bits) == -1)
633
 
                exit_error(PARAMETER_PROBLEM,
634
 
                           "invalid mask `%s' specified", mask);
635
 
        if (bits != 0) {
636
 
                maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
637
 
                return &maskaddr;
638
 
        }
639
 
 
640
 
        maskaddr.s_addr = 0L;
641
 
        return &maskaddr;
642
 
}
643
 
 
644
 
void
645
 
parse_hostnetworkmask(const char *name, struct in_addr **addrpp,
646
 
                      struct in_addr *maskp, unsigned int *naddrs)
647
 
{
648
 
        struct in_addr *addrp;
649
 
        char buf[256];
650
 
        char *p;
651
 
        int i, j, k, n;
652
 
 
653
 
        strncpy(buf, name, sizeof(buf) - 1);
654
 
        buf[sizeof(buf) - 1] = '\0';
655
 
        if ((p = strrchr(buf, '/')) != NULL) {
656
 
                *p = '\0';
657
 
                addrp = parse_mask(p + 1);
658
 
        } else
659
 
                addrp = parse_mask(NULL);
660
 
        inaddrcpy(maskp, addrp);
661
 
 
662
 
        /* if a null mask is given, the name is ignored, like in "any/0" */
663
 
        if (maskp->s_addr == 0L)
664
 
                strcpy(buf, "0.0.0.0");
665
 
 
666
 
        addrp = *addrpp = parse_hostnetwork(buf, naddrs);
667
 
        n = *naddrs;
668
 
        for (i = 0, j = 0; i < n; i++) {
669
 
                addrp[j++].s_addr &= maskp->s_addr;
670
 
                for (k = 0; k < j - 1; k++) {
671
 
                        if (addrp[k].s_addr == addrp[j - 1].s_addr) {
672
 
                                (*naddrs)--;
673
 
                                j--;
674
 
                                break;
675
 
                        }
676
 
                }
677
 
        }
678
 
}
679
 
 
680
483
/* Christophe Burki wants `-p 6' to imply `-m tcp'.  */
681
 
static struct iptables_match *
 
484
static struct xtables_match *
682
485
find_proto(const char *pname, enum ipt_tryload tryload, int nolookup, struct iptables_rule_match **matches)
683
486
{
684
487
        unsigned int proto;
765
568
        return targetname;
766
569
}
767
570
 
768
 
static char *
769
 
addr_to_network(const struct in_addr *addr)
770
 
{
771
 
        struct netent *net;
772
 
 
773
 
        if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
774
 
                return (char *) net->n_name;
775
 
 
776
 
        return (char *) NULL;
777
 
}
778
 
 
779
 
char *
780
 
addr_to_dotted(const struct in_addr *addrp)
781
 
{
782
 
        static char buf[20];
783
 
        const unsigned char *bytep;
784
 
 
785
 
        bytep = (const unsigned char *) &(addrp->s_addr);
786
 
        sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
787
 
        return buf;
788
 
}
789
 
 
790
 
char *
791
 
addr_to_anyname(const struct in_addr *addr)
792
 
{
793
 
        char *name;
794
 
 
795
 
        if ((name = addr_to_host(addr)) != NULL ||
796
 
            (name = addr_to_network(addr)) != NULL)
797
 
                return name;
798
 
 
799
 
        return addr_to_dotted(addr);
800
 
}
801
 
 
802
 
char *
803
 
mask_to_dotted(const struct in_addr *mask)
804
 
{
805
 
        int i;
806
 
        static char buf[20];
807
 
        u_int32_t maskaddr, bits;
808
 
 
809
 
        maskaddr = ntohl(mask->s_addr);
810
 
 
811
 
        if (maskaddr == 0xFFFFFFFFL)
812
 
                /* we don't want to see "/32" */
813
 
                return "";
814
 
 
815
 
        i = 32;
816
 
        bits = 0xFFFFFFFEL;
817
 
        while (--i >= 0 && maskaddr != bits)
818
 
                bits <<= 1;
819
 
        if (i >= 0)
820
 
                sprintf(buf, "/%d", i);
821
 
        else
822
 
                /* mask was not a decent combination of 1's and 0's */
823
 
                sprintf(buf, "/%s", addr_to_dotted(mask));
824
 
 
825
 
        return buf;
826
 
}
827
 
 
828
571
static void
829
572
set_option(unsigned int *options, unsigned int option, u_int8_t *invflg,
830
573
           int invert)
863
606
        *option_offset = global_option_offset;
864
607
 
865
608
        merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
 
609
        if (merge == NULL)
 
610
                return NULL;
866
611
        memcpy(merge, oldopts, num_old * sizeof(struct option));
867
612
        free_opts(0); /* Release previous options merged if any */
868
613
        for (i = 0; i < num_new; i++) {
874
619
        return merge;
875
620
}
876
621
 
877
 
void register_match(struct iptables_match *me)
878
 
{
879
 
        me->family = PF_INET;
880
 
        xtables_register_match(me);
881
 
}
882
 
 
883
 
void register_target(struct iptables_target *me)
884
 
{
885
 
        me->family = PF_INET;
886
 
        xtables_register_target(me);
887
 
}
888
 
 
889
622
static void
890
623
print_num(u_int64_t number, unsigned int format)
891
624
{
967
700
            const struct ipt_ip *ip,
968
701
            int numeric)
969
702
{
970
 
        struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD, NULL);
 
703
        struct xtables_match *match = find_match(m->u.user.name, TRY_LOAD, NULL);
971
704
 
972
705
        if (match) {
973
706
                if (match->print)
982
715
        return 0;
983
716
}
984
717
 
985
 
/* e is called `fw' here for hysterical raisins */
 
718
/* e is called `fw' here for historical reasons */
986
719
static void
987
720
print_firewall(const struct ipt_entry *fw,
988
721
               const char *targname,
990
723
               unsigned int format,
991
724
               const iptc_handle_t handle)
992
725
{
993
 
        struct iptables_target *target = NULL;
 
726
        struct xtables_target *target = NULL;
994
727
        const struct ipt_entry_target *t;
995
728
        u_int8_t flags;
996
729
        char buf[BUFSIZ];
1004
737
        flags = fw->ip.flags;
1005
738
 
1006
739
        if (format & FMT_LINENUMBERS)
1007
 
                printf(FMT("%-4u ", "%u "), num+1);
 
740
                printf(FMT("%-4u ", "%u "), num);
1008
741
 
1009
742
        if (!(format & FMT_NOCOUNTS)) {
1010
743
                print_num(fw->counters.pcnt, format);
1066
799
                printf(FMT("%-19s ","%s "), "anywhere");
1067
800
        else {
1068
801
                if (format & FMT_NUMERIC)
1069
 
                        sprintf(buf, "%s", addr_to_dotted(&(fw->ip.src)));
 
802
                        sprintf(buf, "%s", ipaddr_to_numeric(&fw->ip.src));
1070
803
                else
1071
 
                        sprintf(buf, "%s", addr_to_anyname(&(fw->ip.src)));
1072
 
                strcat(buf, mask_to_dotted(&(fw->ip.smsk)));
 
804
                        sprintf(buf, "%s", ipaddr_to_anyname(&fw->ip.src));
 
805
                strcat(buf, ipmask_to_numeric(&fw->ip.smsk));
1073
806
                printf(FMT("%-19s ","%s "), buf);
1074
807
        }
1075
808
 
1078
811
                printf(FMT("%-19s ","-> %s"), "anywhere");
1079
812
        else {
1080
813
                if (format & FMT_NUMERIC)
1081
 
                        sprintf(buf, "%s", addr_to_dotted(&(fw->ip.dst)));
 
814
                        sprintf(buf, "%s", ipaddr_to_numeric(&fw->ip.dst));
1082
815
                else
1083
 
                        sprintf(buf, "%s", addr_to_anyname(&(fw->ip.dst)));
1084
 
                strcat(buf, mask_to_dotted(&(fw->ip.dmsk)));
 
816
                        sprintf(buf, "%s", ipaddr_to_anyname(&fw->ip.dst));
 
817
                strcat(buf, ipmask_to_numeric(&fw->ip.dmsk));
1085
818
                printf(FMT("%-19s ","-> %s"), buf);
1086
819
        }
1087
820
 
1318
1051
                return for_each_chain(delete_chain, verbose, 0, handle);
1319
1052
 
1320
1053
        if (verbose)
1321
 
                fprintf(stdout, "Deleting chain `%s'\n", chain);
 
1054
                fprintf(stdout, "Deleting chain `%s'\n", chain);
1322
1055
        return iptc_delete_chain(chain, handle);
1323
1056
}
1324
1057
 
1325
1058
static int
1326
 
list_entries(const ipt_chainlabel chain, int verbose, int numeric,
 
1059
list_entries(const ipt_chainlabel chain, int rulenum, int verbose, int numeric,
1327
1060
             int expanded, int linenumbers, iptc_handle_t *handle)
1328
1061
{
1329
1062
        int found = 0;
1356
1089
 
1357
1090
                if (found) printf("\n");
1358
1091
 
1359
 
                print_header(format, this, handle);
 
1092
                if (!rulenum)
 
1093
                        print_header(format, this, handle);
1360
1094
                i = iptc_first_rule(this, handle);
1361
1095
 
1362
1096
                num = 0;
1363
1097
                while (i) {
1364
 
                        print_firewall(i,
1365
 
                                       iptc_get_target(i, handle),
1366
 
                                       num++,
1367
 
                                       format,
1368
 
                                       *handle);
 
1098
                        num++;
 
1099
                        if (!rulenum || num == rulenum)
 
1100
                                print_firewall(i,
 
1101
                                               iptc_get_target(i, handle),
 
1102
                                               num,
 
1103
                                               format,
 
1104
                                               *handle);
1369
1105
                        i = iptc_next_rule(i, handle);
1370
1106
                }
1371
1107
                found = 1;
1375
1111
        return found;
1376
1112
}
1377
1113
 
 
1114
static void print_proto(u_int16_t proto, int invert)
 
1115
{
 
1116
        if (proto) {
 
1117
                unsigned int i;
 
1118
                const char *invertstr = invert ? "! " : "";
 
1119
 
 
1120
                struct protoent *pent = getprotobynumber(proto);
 
1121
                if (pent) {
 
1122
                        printf("-p %s%s ", invertstr, pent->p_name);
 
1123
                        return;
 
1124
                }
 
1125
 
 
1126
                for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
 
1127
                        if (chain_protos[i].num == proto) {
 
1128
                                printf("-p %s%s ",
 
1129
                                       invertstr, chain_protos[i].name);
 
1130
                                return;
 
1131
                        }
 
1132
 
 
1133
                printf("-p %s%u ", invertstr, proto);
 
1134
        }
 
1135
}
 
1136
 
 
1137
#define IP_PARTS_NATIVE(n)                      \
 
1138
(unsigned int)((n)>>24)&0xFF,                   \
 
1139
(unsigned int)((n)>>16)&0xFF,                   \
 
1140
(unsigned int)((n)>>8)&0xFF,                    \
 
1141
(unsigned int)((n)&0xFF)
 
1142
 
 
1143
#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
 
1144
 
 
1145
/* This assumes that mask is contiguous, and byte-bounded. */
 
1146
static void
 
1147
print_iface(char letter, const char *iface, const unsigned char *mask,
 
1148
            int invert)
 
1149
{
 
1150
        unsigned int i;
 
1151
 
 
1152
        if (mask[0] == 0)
 
1153
                return;
 
1154
 
 
1155
        printf("-%c %s", letter, invert ? "! " : "");
 
1156
 
 
1157
        for (i = 0; i < IFNAMSIZ; i++) {
 
1158
                if (mask[i] != 0) {
 
1159
                        if (iface[i] != '\0')
 
1160
                                printf("%c", iface[i]);
 
1161
                } else {
 
1162
                        /* we can access iface[i-1] here, because
 
1163
                         * a few lines above we make sure that mask[0] != 0 */
 
1164
                        if (iface[i-1] != '\0')
 
1165
                                printf("+");
 
1166
                        break;
 
1167
                }
 
1168
        }
 
1169
 
 
1170
        printf(" ");
 
1171
}
 
1172
 
 
1173
static int print_match_save(const struct ipt_entry_match *e,
 
1174
                        const struct ipt_ip *ip)
 
1175
{
 
1176
        struct xtables_match *match
 
1177
                = find_match(e->u.user.name, TRY_LOAD, NULL);
 
1178
 
 
1179
        if (match) {
 
1180
                printf("-m %s ", e->u.user.name);
 
1181
 
 
1182
                /* some matches don't provide a save function */
 
1183
                if (match->save)
 
1184
                        match->save(ip, e);
 
1185
        } else {
 
1186
                if (e->u.match_size) {
 
1187
                        fprintf(stderr,
 
1188
                                "Can't find library for match `%s'\n",
 
1189
                                e->u.user.name);
 
1190
                        exit(1);
 
1191
                }
 
1192
        }
 
1193
        return 0;
 
1194
}
 
1195
 
 
1196
/* print a given ip including mask if neccessary */
 
1197
static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
 
1198
{
 
1199
        u_int32_t bits, hmask = ntohl(mask);
 
1200
        int i;
 
1201
 
 
1202
        if (!mask && !ip && !invert)
 
1203
                return;
 
1204
 
 
1205
        printf("%s %s%u.%u.%u.%u",
 
1206
                prefix,
 
1207
                invert ? "! " : "",
 
1208
                IP_PARTS(ip));
 
1209
 
 
1210
        if (mask == 0xFFFFFFFFU) {
 
1211
                printf("/32 ");
 
1212
                return;
 
1213
        }
 
1214
 
 
1215
        i    = 32;
 
1216
        bits = 0xFFFFFFFEU;
 
1217
        while (--i >= 0 && hmask != bits)
 
1218
                bits <<= 1;
 
1219
        if (i >= 0)
 
1220
                printf("/%u ", i);
 
1221
        else
 
1222
                printf("/%u.%u.%u.%u ", IP_PARTS(mask));
 
1223
}
 
1224
 
 
1225
/* We want this to be readable, so only print out neccessary fields.
 
1226
 * Because that's the kind of world I want to live in.  */
 
1227
void print_rule(const struct ipt_entry *e,
 
1228
                iptc_handle_t *h, const char *chain, int counters)
 
1229
{
 
1230
        struct ipt_entry_target *t;
 
1231
        const char *target_name;
 
1232
 
 
1233
        /* print counters for iptables-save */
 
1234
        if (counters > 0)
 
1235
                printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
 
1236
 
 
1237
        /* print chain name */
 
1238
        printf("-A %s ", chain);
 
1239
 
 
1240
        /* Print IP part. */
 
1241
        print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
 
1242
                        e->ip.invflags & IPT_INV_SRCIP);
 
1243
 
 
1244
        print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
 
1245
                        e->ip.invflags & IPT_INV_DSTIP);
 
1246
 
 
1247
        print_iface('i', e->ip.iniface, e->ip.iniface_mask,
 
1248
                    e->ip.invflags & IPT_INV_VIA_IN);
 
1249
 
 
1250
        print_iface('o', e->ip.outiface, e->ip.outiface_mask,
 
1251
                    e->ip.invflags & IPT_INV_VIA_OUT);
 
1252
 
 
1253
        print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
 
1254
 
 
1255
        if (e->ip.flags & IPT_F_FRAG)
 
1256
                printf("%s-f ",
 
1257
                       e->ip.invflags & IPT_INV_FRAG ? "! " : "");
 
1258
 
 
1259
        /* Print matchinfo part */
 
1260
        if (e->target_offset) {
 
1261
                IPT_MATCH_ITERATE(e, print_match_save, &e->ip);
 
1262
        }
 
1263
 
 
1264
        /* print counters for iptables -R */
 
1265
        if (counters < 0)
 
1266
                printf("-c %llu %llu ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
 
1267
 
 
1268
        /* Print target name */
 
1269
        target_name = iptc_get_target(e, h);
 
1270
        if (target_name && (*target_name != '\0'))
 
1271
#ifdef IPT_F_GOTO
 
1272
                printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
 
1273
#else
 
1274
                printf("-j %s ", target_name);
 
1275
#endif
 
1276
 
 
1277
        /* Print targinfo part */
 
1278
        t = ipt_get_target((struct ipt_entry *)e);
 
1279
        if (t->u.user.name[0]) {
 
1280
                struct xtables_target *target
 
1281
                        = find_target(t->u.user.name, TRY_LOAD);
 
1282
 
 
1283
                if (!target) {
 
1284
                        fprintf(stderr, "Can't find library for target `%s'\n",
 
1285
                                t->u.user.name);
 
1286
                        exit(1);
 
1287
                }
 
1288
 
 
1289
                if (target->save)
 
1290
                        target->save(&e->ip, t);
 
1291
                else {
 
1292
                        /* If the target size is greater than ipt_entry_target
 
1293
                         * there is something to be saved, we just don't know
 
1294
                         * how to print it */
 
1295
                        if (t->u.target_size !=
 
1296
                            sizeof(struct ipt_entry_target)) {
 
1297
                                fprintf(stderr, "Target `%s' is missing "
 
1298
                                                "save function\n",
 
1299
                                        t->u.user.name);
 
1300
                                exit(1);
 
1301
                        }
 
1302
                }
 
1303
        }
 
1304
        printf("\n");
 
1305
}
 
1306
 
 
1307
static int
 
1308
list_rules(const ipt_chainlabel chain, int rulenum, int counters,
 
1309
             iptc_handle_t *handle)
 
1310
{
 
1311
        const char *this = NULL;
 
1312
        int found = 0;
 
1313
 
 
1314
        if (counters)
 
1315
            counters = -1;              /* iptables -c format */
 
1316
 
 
1317
        /* Dump out chain names first,
 
1318
         * thereby preventing dependency conflicts */
 
1319
        if (!rulenum) for (this = iptc_first_chain(handle);
 
1320
             this;
 
1321
             this = iptc_next_chain(handle)) {
 
1322
                if (chain && strcmp(this, chain) != 0)
 
1323
                        continue;
 
1324
 
 
1325
                if (iptc_builtin(this, *handle)) {
 
1326
                        struct ipt_counters count;
 
1327
                        printf("-P %s %s", this, iptc_get_policy(this, &count, handle));
 
1328
                        if (counters)
 
1329
                            printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
 
1330
                        printf("\n");
 
1331
                } else {
 
1332
                        printf("-N %s\n", this);
 
1333
                }
 
1334
        }
 
1335
 
 
1336
        for (this = iptc_first_chain(handle);
 
1337
             this;
 
1338
             this = iptc_next_chain(handle)) {
 
1339
                const struct ipt_entry *e;
 
1340
                int num = 0;
 
1341
 
 
1342
                if (chain && strcmp(this, chain) != 0)
 
1343
                        continue;
 
1344
 
 
1345
                /* Dump out rules */
 
1346
                e = iptc_first_rule(this, handle);
 
1347
                while(e) {
 
1348
                        num++;
 
1349
                        if (!rulenum || num == rulenum)
 
1350
                            print_rule(e, handle, this, counters);
 
1351
                        e = iptc_next_rule(e, handle);
 
1352
                }
 
1353
                found = 1;
 
1354
        }
 
1355
 
 
1356
        errno = ENOENT;
 
1357
        return found;
 
1358
}
 
1359
 
1378
1360
static struct ipt_entry *
1379
1361
generate_entry(const struct ipt_entry *fw,
1380
1362
               struct iptables_rule_match *matches,
1403
1385
        return e;
1404
1386
}
1405
1387
 
1406
 
void clear_rule_matches(struct iptables_rule_match **matches)
 
1388
static void clear_rule_matches(struct iptables_rule_match **matches)
1407
1389
{
1408
1390
        struct iptables_rule_match *matchp, *tmp;
1409
1391
 
1440
1422
        if (uname(&uts) == -1) {
1441
1423
                fprintf(stderr, "Unable to retrieve kernel version.\n");
1442
1424
                free_opts(1);
1443
 
                exit(1); 
 
1425
                exit(1);
1444
1426
        }
1445
1427
 
1446
1428
        sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
1461
1443
        unsigned int rulenum = 0, options = 0, command = 0;
1462
1444
        const char *pcnt = NULL, *bcnt = NULL;
1463
1445
        int ret = 1;
1464
 
        struct iptables_match *m;
 
1446
        struct xtables_match *m;
1465
1447
        struct iptables_rule_match *matches = NULL;
1466
1448
        struct iptables_rule_match *matchp;
1467
 
        struct iptables_target *target = NULL;
1468
 
        struct iptables_target *t;
 
1449
        struct xtables_target *target = NULL;
 
1450
        struct xtables_target *t;
1469
1451
        const char *jumpto = "";
1470
1452
        char *protocol = NULL;
1471
1453
        int proto_used = 0;
1492
1474
        opterr = 0;
1493
1475
 
1494
1476
        while ((c = getopt_long(argc, argv,
1495
 
           "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
 
1477
           "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
1496
1478
                                           opts, NULL)) != -1) {
1497
1479
                switch (c) {
1498
1480
                        /*
1545
1527
                        else if (optind < argc && argv[optind][0] != '-'
1546
1528
                                 && argv[optind][0] != '!')
1547
1529
                                chain = argv[optind++];
 
1530
                        if (optind < argc && argv[optind][0] != '-'
 
1531
                            && argv[optind][0] != '!')
 
1532
                                rulenum = parse_rulenumber(argv[optind++]);
 
1533
                        break;
 
1534
 
 
1535
                case 'S':
 
1536
                        add_command(&command, CMD_LIST_RULES, CMD_ZERO,
 
1537
                                    invert);
 
1538
                        if (optarg) chain = optarg;
 
1539
                        else if (optind < argc && argv[optind][0] != '-'
 
1540
                                 && argv[optind][0] != '!')
 
1541
                                chain = argv[optind++];
 
1542
                        if (optind < argc && argv[optind][0] != '-'
 
1543
                            && argv[optind][0] != '!')
 
1544
                                rulenum = parse_rulenumber(argv[optind++]);
1548
1545
                        break;
1549
1546
 
1550
1547
                case 'F':
1557
1554
                        break;
1558
1555
 
1559
1556
                case 'Z':
1560
 
                        add_command(&command, CMD_ZERO, CMD_LIST,
 
1557
                        add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
1561
1558
                                    invert);
1562
1559
                        if (optarg) chain = optarg;
1563
1560
                        else if (optind < argc && argv[optind][0] != '-'
1597
1594
                                newname = argv[optind++];
1598
1595
                        else
1599
1596
                                exit_error(PARAMETER_PROBLEM,
1600
 
                                           "-%c requires old-chain-name and "
 
1597
                                           "-%c requires old-chain-name and "
1601
1598
                                           "new-chain-name",
1602
1599
                                            cmd2char(CMD_RENAME_CHAIN));
1603
1600
                        break;
1689
1686
                                             target->revision);
1690
1687
                                if (target->init != NULL)
1691
1688
                                        target->init(target->t);
1692
 
                                opts = merge_options(opts, target->extra_opts, &target->option_offset);
 
1689
                                opts = merge_options(opts,
 
1690
                                                     target->extra_opts,
 
1691
                                                     &target->option_offset);
 
1692
                                if (opts == NULL)
 
1693
                                        exit_error(OTHER_PROBLEM,
 
1694
                                                   "can't alloc memory!");
1693
1695
                        }
1694
1696
                        break;
1695
1697
 
1741
1743
                        set_revision(m->m->u.user.name, m->revision);
1742
1744
                        if (m->init != NULL)
1743
1745
                                m->init(m->m);
1744
 
                        if (m != m->next)
 
1746
                        if (m != m->next) {
1745
1747
                                /* Merge options for non-cloned matches */
1746
 
                                opts = merge_options(opts, m->extra_opts, &m->option_offset);
 
1748
                                opts = merge_options(opts,
 
1749
                                                     m->extra_opts,
 
1750
                                                     &m->option_offset);
 
1751
                                if (opts == NULL)
 
1752
                                        exit_error(OTHER_PROBLEM,
 
1753
                                                   "can't alloc memory!");
 
1754
                        }
1747
1755
                }
1748
1756
                break;
1749
1757
 
1778
1786
                        break;
1779
1787
 
1780
1788
                case 'M':
1781
 
                        modprobe = optarg;
 
1789
                        modprobe_program = optarg;
1782
1790
                        break;
1783
1791
 
1784
1792
                case 'c':
1786
1794
                        set_option(&options, OPT_COUNTERS, &fw.ip.invflags,
1787
1795
                                   invert);
1788
1796
                        pcnt = optarg;
1789
 
                        if (optind < argc && argv[optind][0] != '-'
 
1797
                        bcnt = strchr(pcnt + 1, ',');
 
1798
                        if (bcnt)
 
1799
                            bcnt++;
 
1800
                        if (!bcnt && optind < argc && argv[optind][0] != '-'
1790
1801
                            && argv[optind][0] != '!')
1791
1802
                                bcnt = argv[optind++];
1792
 
                        else
 
1803
                        if (!bcnt)
1793
1804
                                exit_error(PARAMETER_PROBLEM,
1794
1805
                                        "-%c requires packet and byte counter",
1795
1806
                                        opt2char(OPT_COUNTERS));
1796
1807
 
1797
 
                        if (sscanf(pcnt, "%llu", (unsigned long long *)&cnt) != 1)
 
1808
                        if (sscanf(pcnt, "%llu", &cnt) != 1)
1798
1809
                                exit_error(PARAMETER_PROBLEM,
1799
1810
                                        "-%c packet counter not numeric",
1800
1811
                                        opt2char(OPT_COUNTERS));
1801
1812
                        fw.counters.pcnt = cnt;
1802
1813
 
1803
 
                        if (sscanf(bcnt, "%llu", (unsigned long long *)&cnt) != 1)
 
1814
                        if (sscanf(bcnt, "%llu", &cnt) != 1)
1804
1815
                                exit_error(PARAMETER_PROBLEM,
1805
1816
                                        "-%c byte counter not numeric",
1806
1817
                                        opt2char(OPT_COUNTERS));
1828
1839
                                               &target->tflags,
1829
1840
                                               &fw, &target->t))) {
1830
1841
                                for (matchp = matches; matchp; matchp = matchp->next) {
1831
 
                                        if (matchp->completed) 
 
1842
                                        if (matchp->completed)
1832
1843
                                                continue;
1833
1844
                                        if (matchp->match->parse(c - matchp->match->option_offset,
1834
1845
                                                     argv, invert,
1865
1876
                                if (m == NULL
1866
1877
                                    && protocol
1867
1878
                                    && (!find_proto(protocol, DONT_LOAD,
1868
 
                                                   options&OPT_NUMERIC, NULL) 
 
1879
                                                   options&OPT_NUMERIC, NULL)
1869
1880
                                        || (find_proto(protocol, DONT_LOAD,
1870
1881
                                                        options&OPT_NUMERIC, NULL)
1871
1882
                                            && (proto_used == 0))
1874
1885
                                                       options&OPT_NUMERIC, &matches))) {
1875
1886
                                        /* Try loading protocol */
1876
1887
                                        size_t size;
1877
 
                                        
 
1888
 
1878
1889
                                        proto_used = 1;
1879
1890
 
1880
1891
                                        size = IPT_ALIGN(sizeof(struct ipt_entry_match))
1889
1900
                                                m->init(m->m);
1890
1901
 
1891
1902
                                        opts = merge_options(opts,
1892
 
                                            m->extra_opts, &m->option_offset);
 
1903
                                                             m->extra_opts,
 
1904
                                                             &m->option_offset);
 
1905
                                        if (opts == NULL)
 
1906
                                                exit_error(OTHER_PROBLEM,
 
1907
                                                        "can't alloc memory!");
1893
1908
 
1894
1909
                                        optind--;
1895
1910
                                        continue;
1929
1944
        }
1930
1945
 
1931
1946
        if (shostnetworkmask)
1932
 
                parse_hostnetworkmask(shostnetworkmask, &saddrs,
1933
 
                                      &(fw.ip.smsk), &nsaddrs);
 
1947
                ipparse_hostnetworkmask(shostnetworkmask, &saddrs,
 
1948
                                        &fw.ip.smsk, &nsaddrs);
1934
1949
 
1935
1950
        if (dhostnetworkmask)
1936
 
                parse_hostnetworkmask(dhostnetworkmask, &daddrs,
1937
 
                                      &(fw.ip.dmsk), &ndaddrs);
 
1951
                ipparse_hostnetworkmask(dhostnetworkmask, &daddrs,
 
1952
                                        &fw.ip.dmsk, &ndaddrs);
1938
1953
 
1939
1954
        if ((nsaddrs > 1 || ndaddrs > 1) &&
1940
1955
            (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
1957
1972
                *handle = iptc_init(*table);
1958
1973
 
1959
1974
        /* try to insmod the module if iptc_init failed */
1960
 
        if (!*handle && load_xtables_ko(modprobe, 0) != -1)
 
1975
        if (!*handle && load_xtables_ko(modprobe_program, 0) != -1)
1961
1976
                *handle = iptc_init(*table);
1962
1977
 
1963
1978
        if (!*handle)
2066
2081
                                   options&OPT_VERBOSE,
2067
2082
                                   handle);
2068
2083
                break;
2069
 
        case CMD_LIST:
2070
 
                ret = list_entries(chain,
2071
 
                                   options&OPT_VERBOSE,
2072
 
                                   options&OPT_NUMERIC,
2073
 
                                   options&OPT_EXPANDED,
2074
 
                                   options&OPT_LINENUMBERS,
2075
 
                                   handle);
2076
 
                break;
2077
2084
        case CMD_FLUSH:
2078
2085
                ret = flush_entries(chain, options&OPT_VERBOSE, handle);
2079
2086
                break;
2080
2087
        case CMD_ZERO:
2081
2088
                ret = zero_entries(chain, options&OPT_VERBOSE, handle);
2082
2089
                break;
 
2090
        case CMD_LIST:
2083
2091
        case CMD_LIST|CMD_ZERO:
2084
2092
                ret = list_entries(chain,
 
2093
                                   rulenum,
2085
2094
                                   options&OPT_VERBOSE,
2086
2095
                                   options&OPT_NUMERIC,
2087
2096
                                   options&OPT_EXPANDED,
2088
2097
                                   options&OPT_LINENUMBERS,
2089
2098
                                   handle);
2090
 
                if (ret)
 
2099
                if (ret && (command & CMD_ZERO))
 
2100
                        ret = zero_entries(chain,
 
2101
                                           options&OPT_VERBOSE, handle);
 
2102
                break;
 
2103
        case CMD_LIST_RULES:
 
2104
        case CMD_LIST_RULES|CMD_ZERO:
 
2105
                ret = list_rules(chain,
 
2106
                                   rulenum,
 
2107
                                   options&OPT_VERBOSE,
 
2108
                                   handle);
 
2109
                if (ret && (command & CMD_ZERO))
2091
2110
                        ret = zero_entries(chain,
2092
2111
                                           options&OPT_VERBOSE, handle);
2093
2112
                break;
2101
2120
                ret = iptc_rename_chain(chain, newname, handle);
2102
2121
                break;
2103
2122
        case CMD_SET_POLICY:
2104
 
                ret = iptc_set_policy(chain, policy, NULL, handle);
 
2123
                ret = iptc_set_policy(chain, policy, options&OPT_COUNTERS ? &fw.counters : NULL, handle);
2105
2124
                break;
2106
2125
        default:
2107
2126
                /* We should never reach this... */