Maxim Konovalov wrote:
Synopsis: [ipfw] ipfw core (crash)
http://www.freebsd.org/cgi/query-pr.cgi?pr=60154

I have updated patch and make the perl script for testing.

--
WBR, Andrey V. Elsukov
#!/usr/local/bin/perl -w
#===============================================================================
#
#         FILE:  test.pl
#  DESCRIPTION:  ipfw parser test
#       AUTHOR:  (c) Andrey V. Elsukov, <[EMAIL PROTECTED]>
#      CREATED:  16.12.2005 06:05:09 UTC
#===============================================================================

use strict;

sub result
{
        if ($? == -1) {
                print "ipfw failed to execute: $!\n";
        } elsif ($? & 127) {
                printf "ipfw died with signal %d, %s coredump\n",
                        ($? & 127), ($? & 128) ? 'with':'without';
        } else {
                printf "ipfw exited with value %d\n", $? >> 8;
        }
}

sub ip($$)
{
        my $dig = shift;
        my $separator = shift;
        my $str;
        $str .= "10.0.0.$_$separator" foreach(1..$dig-1);
        $str .= "10.0.0.$dig";
        return $str;
}
sub port($$)
{
        my $dig = shift;
        my $separator = shift;
        my $str;
        $str .= "$_$separator" foreach(1..$dig-1);
        $str .= $dig;
        return $str;
}

my $rule;
my @cnt = (5, 10, 25, 50, 100, 250, 500);
my @tests = (
        {       description => "protocols",
                rule => "allow {\$ } from any to any",
                func => \&port, separator => ' or ' },
        {       description => "source addresses (or block)",
                rule => "allow ip from { \$ } to any",
                func => \&ip, separator => ' or ' },
        {       description => "source addresses (list)",
                rule => "allow ip from { \$ } to any",
                func => \&ip,
                separator => ',' },
        {       description => "source addresses (sets)",
                rule => "allow ip from 10.0.0.0/24{\$} to any",
                func => \&port,
                separator => ',' },
        {       description => "source ports (list)",
                rule => "allow ip from 10.0.0.1 \$ to any",
                func => \&port,
                separator => ',' },
        {       description => "destination addresses (or block)",
                rule => "allow ip from any to { \$ }",
                func => \&ip,
                separator => ' or ' },
        {       description => "destination addresses (lists)",
                rule => "allow ip from any to { \$ }",
                func => \&ip,
                separator => ',' }
);
foreach my $test (@tests) {
        print "Check with multiple ", $test->{description}, ":\n";
        foreach my $c (@cnt) {
                print "try $c count ... ";
                my $rule = $test->{rule};
                my $substr = $test->{func}($c, $test->{separator});
                $rule =~ s/\$/$substr/;
#               print "ipfw -q add $rule\n";
                system("ipfw -q add $rule");
                &result();
        }
}
--- ipfw2.c.orig        Tue Dec 13 12:16:02 2005
+++ ipfw2.c     Fri Dec 16 11:39:44 2005
@@ -83,6 +83,26 @@
 #define NEED1(msg)      {if (!ac) errx(EX_USAGE, msg);}
 
 /*
+ * Some functions here get as argumet an ipfw_insn pointer
+ * and fills him. This pointer typically stored in statical
+ * buffer with fixed size. And some ipfw_insn can have a 
+ * variable size (for example, ipfw_insn_u16, ipfw_insn_u32,..).
+ * Free left space of this buffers do not controlled.
+ * As result we have some stange core dumps when user try 
+ * add rules. To fix this errors we add the "size_left"
+ * paramter to thises functions. size_left indicates which
+ * size we can write into buffer. Before any writes we
+ * must check this size and update him after each write.
+ * 
+ */
+#define CHECK_SIZE(size) \
+       { \
+               if ((int)(size_left - (size)) < 0) \
+                       errx(EX_DATAERR, "too big rule size\n"); \
+       }
+#define UPDATE_SIZE(size)      size_left -= (size)
+
+/*
  * _s_x is a structure that stores a string <-> token pairs, used in
  * various places in the parser. Entries are stored in arrays,
  * with an entry with s=NULL as terminator.
@@ -777,12 +797,14 @@
  * Fill the body of the command with the list of port ranges.
  */
 static int
-fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
+fill_newports(ipfw_insn_u16 *cmd, char *av, int proto, int size_left)
 {
        uint16_t a, b, *p = cmd->ports;
        int i = 0;
        char *s = av;
 
+       CHECK_SIZE(F_INSN_SIZE(*cmd));
+       UPDATE_SIZE(F_INSN_SIZE(ipfw_insn));
        while (*s) {
                a = strtoport(av, &s, 0, proto);
                if (s == av) /* no parameter */
@@ -802,12 +824,14 @@
                i++;
                p += 2;
                av = s+1;
-       }
-       if (i > 0) {
+               /* sizeof(u_int16_t[2]) = sizeof(u_int32_t) */
+               UPDATE_SIZE(F_INSN_SIZE(u_int32_t)); 
+               CHECK_SIZE(F_INSN_SIZE(u_int32_t));
                if (i+1 > F_LEN_MASK)
                        errx(EX_DATAERR, "too many ports/ranges\n");
-               cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */
        }
+       if (i > 0)
+               cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */
        return i;
 }
 
@@ -1055,10 +1079,11 @@
 }
 
 static void
-fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
+fill_icmptypes(ipfw_insn_u32 *cmd, char *av, int size_left)
 {
        uint8_t type;
 
+       CHECK_SIZE(F_INSN_SIZE(*cmd));
        cmd->d[0] = 0;
        while (*av) {
                if (*av == ',')
@@ -1148,10 +1173,11 @@
 }
 
 static void
-fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)
+fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int size_left)
 {
        uint8_t type;
 
+          CHECK_SIZE(F_INSN_SIZE(*cmd));
        cmd->d[0] = 0;
        while (*av) {
            if (*av == ',')
@@ -1217,11 +1243,12 @@
 
 /* fills command for the extension header filtering */
 int
-fill_ext6hdr( ipfw_insn *cmd, char *av)
+fill_ext6hdr( ipfw_insn *cmd, char *av, int size_left)
 {
        int tok;
        char *s = av;
 
+          CHECK_SIZE(F_INSN_SIZE(*cmd));
        cmd->arg1 = 0;
 
        while(s) {
@@ -2595,11 +2622,12 @@
  * We can have multiple comma-separated address/mask entries.
  */
 static void
-fill_ip(ipfw_insn_ip *cmd, char *av)
+fill_ip(ipfw_insn_ip *cmd, char *av, int size_left)
 {
        int len = 0;
        uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
 
+       CHECK_SIZE(F_INSN_SIZE(ipfw_insn));
        cmd->o.len &= ~F_LEN_MASK;      /* zero len */
 
        if (_substrcmp(av, "any") == 0)
@@ -2610,6 +2638,7 @@
                return;
        }
 
+       CHECK_SIZE(F_INSN_SIZE(ipfw_insn_u32));
        if (strncmp(av, "table(", 6) == 0) {
                char *p = strchr(av + 6, ',');
 
@@ -2625,6 +2654,7 @@
                return;
        }
 
+       UPDATE_SIZE(F_INSN_SIZE(ipfw_insn));
     while (av) {
        /*
         * After the address we can have '/' or ':' indicating a mask,
@@ -2695,6 +2725,7 @@
                d[0] = ntohl(d[0]);             /* base addr in host format */
                cmd->o.opcode = O_IP_DST_SET;   /* default */
                cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32;
+               CHECK_SIZE(cmd->o.len);
                for (i = 0; i < (cmd->o.arg1+31)/32 ; i++)
                        map[i] = 0;     /* clear map */
 
@@ -2766,8 +2797,16 @@
                cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
                return;
        }
-       len += 2;       /* two words... */
-       d += 2;
+       len += F_INSN_SIZE(u_int32_t)*2;        /* two words... */
+       d += F_INSN_SIZE(u_int32_t)*2;
+       UPDATE_SIZE(F_INSN_SIZE(u_int32_t)*2);
+       CHECK_SIZE(F_INSN_SIZE(u_int32_t)*2);
+       /* 
+        * O_IP_SRC_MASK and O_IP_DST_MASK can not have length
+        * greater that 31
+        */
+       if (len > 30)
+               errx(EX_DATAERR, "too many addresses\n");
     } /* end while */
     cmd->o.len |= len+1;
 }
@@ -2824,7 +2863,7 @@
  * Return 1 on success, 0 on failure.
  */
 static int
-fill_ip6(ipfw_insn_ip6 *cmd, char *av)
+fill_ip6(ipfw_insn_ip6 *cmd, char *av, int size_left)
 {
        int len = 0;
        struct in6_addr *d = &(cmd->addr6);
@@ -2833,6 +2872,7 @@
         * Note d[1] points to struct in6_add r mask6 of cmd
         */
 
+       CHECK_SIZE(F_INSN_SIZE(ipfw_insn));
        cmd->o.len &= ~F_LEN_MASK;      /* zero len */
 
        if (strcmp(av, "any") == 0)
@@ -2850,6 +2890,9 @@
        }
 
        av = strdup(av);
+
+          CHECK_SIZE(F_INSN_SIZE(ipfw_insn_ip6));
+          UPDATE_SIZE(F_INSN_SIZE(ipfw_insn));
        while (av) {
                /*
                 * After the address we can have '/' indicating a mask,
@@ -2914,6 +2957,10 @@
                /* Update length and pointer to arguments */
                len += F_INSN_SIZE(struct in6_addr)*2;
                d += 2;
+               UPDATE_SIZE(F_INSN_SIZE(struct in6_addr)*2);
+               CHECK_SIZE(F_INSN_SIZE(struct in6_addr)*2);
+               if (len + 1 > F_LEN_MASK)
+                       errx(EX_DATAERR, "too many addresses\n");
        } /* end while */
 
        /*
@@ -2932,13 +2979,15 @@
  * additional flow-id we want to filter, the basic is 1
  */
 void
-fill_flow6( ipfw_insn_u32 *cmd, char *av )
+fill_flow6(ipfw_insn_u32 *cmd, char *av, int size_left)
 {
        u_int32_t type;  /* Current flow number */
        u_int16_t nflow = 0;    /* Current flow index */
        char *s = av;
-       cmd->d[0] = 0;    /* Initializing the base number*/
 
+       CHECK_SIZE(F_INSN_SIZE(ipfw_insn_u32));
+       UPDATE_SIZE(F_INSN_SIZE(ipfw_insn));
+       cmd->d[0] = 0;    /* Initializing the base number*/
        while (s) {
                av = strsep( &s, ",") ;
                type = strtoul(av, &av, 0);
@@ -2947,6 +2996,8 @@
                if (type > 0xfffff)
                        errx(EX_DATAERR, "flow number out of range %s", av);
                cmd->d[nflow] |= type;
+               UPDATE_SIZE(F_INSN_SIZE(u_int32_t));
+               CHECK_SIZE(F_INSN_SIZE(u_int32_t));
                nflow++;
        }
        if( nflow > 0 ) {
@@ -2960,10 +3011,10 @@
 }
 
 static ipfw_insn *
-add_srcip6(ipfw_insn *cmd, char *av)
+add_srcip6(ipfw_insn *cmd, char *av, int size_left)
 {
 
-       fill_ip6((ipfw_insn_ip6 *)cmd, av);
+       fill_ip6((ipfw_insn_ip6 *)cmd, av, size_left);
        if (F_LEN(cmd) == 0)                            /* any */
                ;
        if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) {     /* "me" */
@@ -2979,10 +3030,10 @@
 }
 
 static ipfw_insn *
-add_dstip6(ipfw_insn *cmd, char *av)
+add_dstip6(ipfw_insn *cmd, char *av, int size_left)
 {
 
-       fill_ip6((ipfw_insn_ip6 *)cmd, av);
+       fill_ip6((ipfw_insn_ip6 *)cmd, av, size_left);
        if (F_LEN(cmd) == 0)                            /* any */
                ;
        if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) {     /* "me" */
@@ -3088,8 +3139,9 @@
  * patterns which match interfaces.
  */
 static void
-fill_iface(ipfw_insn_if *cmd, char *arg)
+fill_iface(ipfw_insn_if *cmd, char *arg, int size_left)
 {
+       CHECK_SIZE(F_INSN_SIZE(*cmd));
        cmd->name[0] = '\0';
        cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
 
@@ -3511,11 +3563,12 @@
  * Takes arguments and copies them into a comment
  */
 static void
-fill_comment(ipfw_insn *cmd, int ac, char **av)
+fill_comment(ipfw_insn *cmd, int ac, char **av, int size_left)
 {
        int i, l;
        char *p = (char *)(cmd + 1);
 
+       CHECK_SIZE(F_INSN_SIZE(*cmd))
        cmd->opcode = O_NOP;
        cmd->len =  (cmd->len & (F_NOT | F_OR));
 
@@ -3528,6 +3581,7 @@
                errx(EX_DATAERR,
                    "comment too long (max 80 chars)");
        l = 1 + (l+3)/4;
+       CHECK_SIZE(l);
        cmd->len =  (cmd->len & (F_NOT | F_OR)) | l;
        for (i = 0; i < ac; i++) {
                strcpy(p, av[i]);
@@ -3554,10 +3608,11 @@
  * two microinstructions, and returns the pointer to the last one.
  */
 static ipfw_insn *
-add_mac(ipfw_insn *cmd, int ac, char *av[])
+add_mac(ipfw_insn *cmd, int ac, char *av[], int size_left)
 {
        ipfw_insn_mac *mac;
 
+       CHECK_SIZE(F_INSN_SIZE(ipfw_insn_mac));
        if (ac < 2)
                errx(EX_DATAERR, "MAC dst src");
 
@@ -3571,12 +3626,14 @@
 }
 
 static ipfw_insn *
-add_mactype(ipfw_insn *cmd, int ac, char *av)
+add_mactype(ipfw_insn *cmd, int ac, char *av, int size_left)
 {
        if (ac < 1)
                errx(EX_DATAERR, "missing MAC type");
        if (strcmp(av, "any") != 0) { /* we have a non-null type */
-               fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);
+               fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE, 
size_left);
+               if (F_LEN(cmd) > 31)
+                       errx(EX_DATAERR, "too many MAC types\n");
                cmd->opcode = O_MAC_TYPE;
                return cmd;
        } else
@@ -3645,9 +3702,9 @@
 }
 
 static ipfw_insn *
-add_srcip(ipfw_insn *cmd, char *av)
+add_srcip(ipfw_insn *cmd, char *av, int size_left)
 {
-       fill_ip((ipfw_insn_ip *)cmd, av);
+       fill_ip((ipfw_insn_ip *)cmd, av, size_left);
        if (cmd->opcode == O_IP_DST_SET)                        /* set */
                cmd->opcode = O_IP_SRC_SET;
        else if (cmd->opcode == O_IP_DST_LOOKUP)                /* table */
@@ -3662,9 +3719,9 @@
 }
 
 static ipfw_insn *
-add_dstip(ipfw_insn *cmd, char *av)
+add_dstip(ipfw_insn *cmd, char *av, int size_left)
 {
-       fill_ip((ipfw_insn_ip *)cmd, av);
+       fill_ip((ipfw_insn_ip *)cmd, av, size_left);
        if (cmd->opcode == O_IP_DST_SET)                        /* set */
                ;
        else if (cmd->opcode == O_IP_DST_LOOKUP)                /* table */
@@ -3679,30 +3736,42 @@
 }
 
 static ipfw_insn *
-add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
+add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int size_left)
 {
-       if (_substrcmp(av, "any") == 0) {
+       if (_substrcmp(av, "any") == 0)
                return NULL;
-       } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
+
+       if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, size_left)) {
                /* XXX todo: check that we have a protocol with ports */
                cmd->opcode = opcode;
+               if(F_LEN(cmd) > 31)
+                       switch(opcode) {
+                               case O_IPID:
+                               case O_IPTTL:
+                               case O_IPLEN:
+                               case O_TCPDATALEN:
+                                       errx(EX_DATAERR, "too many options\n");
+                               case O_IP_SRCPORT:
+                               case O_IP_DSTPORT:
+                                       errx(EX_DATAERR, "too many ports\n");
+                       };
                return cmd;
        }
        return NULL;
 }
 
 static ipfw_insn *
-add_src(ipfw_insn *cmd, char *av, u_char proto)
+add_src(ipfw_insn *cmd, char *av, u_char proto, int size_left)
 {
        struct in6_addr a;
 
        if (proto == IPPROTO_IPV6  || strcmp(av, "me6") == 0 ||
            inet_pton(AF_INET6, av, &a))
-               return add_srcip6(cmd, av);
+               return add_srcip6(cmd, av, size_left);
        /* XXX: should check for IPv4, not !IPv6 */
        if (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
            !inet_pton(AF_INET6, av, &a))
-               return add_srcip(cmd, av);
+               return add_srcip(cmd, av, size_left);
        if (strcmp(av, "any") != 0)
                return cmd;
 
@@ -3710,17 +3779,17 @@
 }
 
 static ipfw_insn *
-add_dst(ipfw_insn *cmd, char *av, u_char proto)
+add_dst(ipfw_insn *cmd, char *av, u_char proto, int size_left)
 {
        struct in6_addr a;
 
        if (proto == IPPROTO_IPV6  || strcmp(av, "me6") == 0 ||
            inet_pton(AF_INET6, av, &a))
-               return add_dstip6(cmd, av);
+               return add_dstip6(cmd, av, size_left);
        /* XXX: should check for IPv4, not !IPv6 */
        if (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
            !inet_pton(AF_INET6, av, &a))
-               return add_dstip(cmd, av);
+               return add_dstip(cmd, av, size_left);
        if (strcmp(av, "any") != 0)
                return cmd;
 
@@ -3748,7 +3817,11 @@
         * Some things that need to go out of order (prob, action etc.)
         * go into actbuf[].
         */
-       static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
+
+#define MAX_INSN       255
+       static uint32_t rulebuf[MAX_INSN], actbuf[MAX_INSN], cmdbuf[MAX_INSN];
+       int size_left = MAX_INSN;
+       int off;        /* av offset */
 
        ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
        ipfw_insn *first_cmd;   /* first match pattern */
@@ -3780,6 +3853,7 @@
        action = (ipfw_insn *)actbuf;
 
        av++; ac--;
+       CHECK_SIZE(F_INSN_SIZE(struct ip_fw));
 
        /* [rule N]     -- Rule number optional */
        if (ac && isdigit(**av)) {
@@ -3797,12 +3871,15 @@
                av += 2; ac -= 2;
        }
 
+       UPDATE_SIZE(F_INSN_SIZE(struct ip_fw) - F_INSN_SIZE(ipfw_insn));
        /* [prob D]     -- match probability, optional */
        if (ac > 1 && _substrcmp(*av, "prob") == 0) {
                match_prob = strtod(av[1], NULL);
 
                if (match_prob <= 0 || match_prob > 1)
                        errx(EX_DATAERR, "illegal match prob. %s", av[1]);
+               /* reserve size for O_PROB */
+               UPDATE_SIZE(F_INSN_SIZE(ipfw_insn_u32));
                av += 2; ac -= 2;
        }
 
@@ -3810,7 +3887,8 @@
        NEED1("missing action");
        i = match_token(rule_actions, *av);
        ac--; av++;
-       action->len = 1;        /* default */
+       CHECK_SIZE(F_INSN_SIZE(ipfw_insn));
+       action->len = F_INSN_SIZE(ipfw_insn);   /* default */
        switch(i) {
        case TOK_CHECKSTATE:
                have_state = action;
@@ -3907,6 +3985,7 @@
                char *s, *end;
 
                NEED1("missing forward address[:port]");
+               CHECK_SIZE(F_INSN_SIZE(ipfw_insn_sa));
 
                action->opcode = O_FORWARD_IP;
                action->len = F_INSN_SIZE(ipfw_insn_sa);
@@ -3942,6 +4021,8 @@
        default:
                errx(EX_DATAERR, "invalid action %s\n", av[-1]);
        }
+       UPDATE_SIZE(action->len);
+       CHECK_SIZE(F_INSN_SIZE(ipfw_insn));
        action = next_cmd(action);
 
        /*
@@ -3962,6 +4043,7 @@
                        if (have_log)
                                errx(EX_DATAERR,
                                    "log cannot be specified more than once");
+                       CHECK_SIZE(F_INSN_SIZE(ipfw_insn_log));
                        have_log = (ipfw_insn *)c;
                        cmd->len = F_INSN_SIZE(ipfw_insn_log);
                        cmd->opcode = O_LOG;
@@ -3992,6 +4074,7 @@
                        if (have_altq)
                                errx(EX_DATAERR,
                                    "altq cannot be specified more than once");
+                       CHECK_SIZE(F_INSN_SIZE(ipfw_insn_altq));
                        have_altq = (ipfw_insn *)a;
                        cmd->len = F_INSN_SIZE(ipfw_insn_altq);
                        cmd->opcode = O_ALTQ;
@@ -4003,6 +4086,7 @@
                default:
                        abort();
                }
+               UPDATE_SIZE(F_LEN(cmd));
                cmd = next_cmd(cmd);
        }
 
@@ -4016,9 +4100,9 @@
                prev = NULL;                                    \
                open_par = 1;                                   \
                if ( (av[0])[1] == '\0') {                      \
-                       ac--; av++;                             \
+                       ac--; av++; off = 0;            \
                } else                                          \
-                       (*av)++;                                \
+                       off = 1;                                \
        }                                                       \
        target:                                                 \
 
@@ -4044,6 +4128,7 @@
        }
 
 #define OR_BLOCK(target)                                       \
+       off = 0; \
        if (ac && _substrcmp(*av, "or") == 0) {         \
                if (prev == NULL || open_par == 0)              \
                        errx(EX_DATAERR, "invalid OR block");   \
@@ -4084,9 +4169,11 @@
     OR_START(get_proto);
        NOT_BLOCK;
        NEED1("missing protocol");
-       if (add_proto_compat(cmd, *av, &proto)) {
+       CHECK_SIZE(F_INSN_SIZE(ipfw_insn));
+       if (add_proto_compat(cmd, *av + off, &proto)) {
                av++; ac--;
                if (F_LEN(cmd) != 0) {
+                       UPDATE_SIZE(F_LEN(cmd));
                        prev = cmd;
                        cmd = next_cmd(cmd);
                }
@@ -4109,9 +4196,10 @@
     OR_START(source_ip);
        NOT_BLOCK;      /* optional "not" */
        NEED1("missing source address");
-       if (add_src(cmd, *av, proto)) {
+       if (add_src(cmd, *av + off, proto, size_left)) {
                ac--; av++;
                if (F_LEN(cmd) != 0) {  /* ! any */
+                       UPDATE_SIZE(F_LEN(cmd));
                        prev = cmd;
                        cmd = next_cmd(cmd);
                }
@@ -4125,12 +4213,14 @@
        NOT_BLOCK;      /* optional "not" */
        if (ac) {
                if (_substrcmp(*av, "any") == 0 ||
-                   add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
+                   add_ports(cmd, *av, proto, O_IP_SRCPORT, size_left)) {
                        ac--; av++;
-                       if (F_LEN(cmd) != 0)
+                       if (F_LEN(cmd) != 0) {
+                               UPDATE_SIZE(F_LEN(cmd));
                                cmd = next_cmd(cmd);
                }
        }
+       }
 
        /*
         * "to", mandatory
@@ -4145,9 +4235,10 @@
     OR_START(dest_ip);
        NOT_BLOCK;      /* optional "not" */
        NEED1("missing dst address");
-       if (add_dst(cmd, *av, proto)) {
+       if (add_dst(cmd, *av + off, proto, size_left)) {
                ac--; av++;
                if (F_LEN(cmd) != 0) {  /* ! any */
+                       UPDATE_SIZE(F_LEN(cmd));
                        prev = cmd;
                        cmd = next_cmd(cmd);
                }
@@ -4161,12 +4252,14 @@
        NOT_BLOCK;      /* optional "not" */
        if (ac) {
                if (_substrcmp(*av, "any") == 0 ||
-                   add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
+                   add_ports(cmd, *av, proto, O_IP_DSTPORT, size_left)) {
                        ac--; av++;
-                       if (F_LEN(cmd) != 0)
+                       if (F_LEN(cmd) != 0) {
+                               UPDATE_SIZE(F_LEN(cmd));
                                cmd = next_cmd(cmd);
                }
        }
+       }
 
 read_options:
        if (ac && first_cmd == cmd) {
@@ -4184,6 +4277,8 @@
                s = *av;
                cmd32 = (ipfw_insn_u32 *)cmd;
 
+               CHECK_SIZE(F_INSN_SIZE(ipfw_insn_u32));
+
                if (*s == '!') {        /* alternate syntax for NOT */
                        if (cmd->len & F_NOT)
                                errx(EX_USAGE, "double \"not\" not allowed\n");
@@ -4252,7 +4347,7 @@
                case TOK_VIA:
                        NEED1("recv, xmit, via require interface name"
                                " or address");
-                       fill_iface((ipfw_insn_if *)cmd, av[0]);
+                       fill_iface((ipfw_insn_if *)cmd, av[0], size_left);
                        ac--; av++;
                        if (F_LEN(cmd) == 0)    /* not a valid address */
                                break;
@@ -4266,20 +4361,20 @@
 
                case TOK_ICMPTYPES:
                        NEED1("icmptypes requires list of types");
-                       fill_icmptypes((ipfw_insn_u32 *)cmd, *av);
+                       fill_icmptypes((ipfw_insn_u32 *)cmd, *av, size_left);
                        av++; ac--;
                        break;
                
                case TOK_ICMP6TYPES:
                        NEED1("icmptypes requires list of types");
-                       fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
+                       fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av, size_left);
                        av++; ac--;
                        break;
 
                case TOK_IPTTL:
                        NEED1("ipttl requires TTL");
                        if (strpbrk(*av, "-,")) {
-                           if (!add_ports(cmd, *av, 0, O_IPTTL))
+                           if (!add_ports(cmd, *av, 0, O_IPTTL, size_left))
                                errx(EX_DATAERR, "invalid ipttl %s", *av);
                        } else
                            fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0));
@@ -4289,7 +4384,7 @@
                case TOK_IPID:
                        NEED1("ipid requires id");
                        if (strpbrk(*av, "-,")) {
-                           if (!add_ports(cmd, *av, 0, O_IPID))
+                           if (!add_ports(cmd, *av, 0, O_IPID, size_left))
                                errx(EX_DATAERR, "invalid ipid %s", *av);
                        } else
                            fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0));
@@ -4299,7 +4394,7 @@
                case TOK_IPLEN:
                        NEED1("iplen requires length");
                        if (strpbrk(*av, "-,")) {
-                           if (!add_ports(cmd, *av, 0, O_IPLEN))
+                           if (!add_ports(cmd, *av, 0, O_IPLEN, size_left))
                                errx(EX_DATAERR, "invalid ip len %s", *av);
                        } else
                            fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));
@@ -4395,7 +4490,7 @@
                case TOK_TCPDATALEN:
                        NEED1("tcpdatalen requires length");
                        if (strpbrk(*av, "-,")) {
-                           if (!add_ports(cmd, *av, 0, O_TCPDATALEN))
+                           if (!add_ports(cmd, *av, 0, O_TCPDATALEN, 
size_left))
                                errx(EX_DATAERR, "invalid tcpdata len %s", *av);
                        } else
                            fill_cmd(cmd, O_TCPDATALEN, 0,
@@ -4451,6 +4546,7 @@
                                errx(EX_USAGE, "only one of keep-state "
                                        "and limit is allowed");
                        NEED1("limit needs mask and # of connections");
+                       CHECK_SIZE(F_INSN_SIZE(ipfw_insn_limit));
                        have_state = cmd;
                    {
                        ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
@@ -4488,28 +4584,28 @@
 
                case TOK_SRCIP:
                        NEED1("missing source IP");
-                       if (add_srcip(cmd, *av)) {
+                       if (add_srcip(cmd, *av, size_left)) {
                                ac--; av++;
                        }
                        break;
 
                case TOK_DSTIP:
                        NEED1("missing destination IP");
-                       if (add_dstip(cmd, *av)) {
+                       if (add_dstip(cmd, *av, size_left)) {
                                ac--; av++;
                        }
                        break;
 
                case TOK_SRCIP6:
                        NEED1("missing source IP6");
-                       if (add_srcip6(cmd, *av)) {
+                       if (add_srcip6(cmd, *av, size_left)) {
                                ac--; av++;
                        }
                        break;
                                
                case TOK_DSTIP6:
                        NEED1("missing destination IP6");
-                       if (add_dstip6(cmd, *av)) {
+                       if (add_dstip6(cmd, *av, size_left)) {
                                ac--; av++;
                        }
                        break;
@@ -4517,7 +4613,7 @@
                case TOK_SRCPORT:
                        NEED1("missing source port");
                        if (_substrcmp(*av, "any") == 0 ||
-                           add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
+                           add_ports(cmd, *av, proto, O_IP_SRCPORT, 
size_left)) {
                                ac--; av++;
                        } else
                                errx(EX_DATAERR, "invalid source port %s", *av);
@@ -4526,7 +4622,7 @@
                case TOK_DSTPORT:
                        NEED1("missing destination port");
                        if (_substrcmp(*av, "any") == 0 ||
-                           add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
+                           add_ports(cmd, *av, proto, O_IP_DSTPORT, 
size_left)) {
                                ac--; av++;
                        } else
                                errx(EX_DATAERR, "invalid destination port %s",
@@ -4534,14 +4630,14 @@
                        break;
 
                case TOK_MAC:
-                       if (add_mac(cmd, ac, av)) {
+                       if (add_mac(cmd, ac, av, size_left)) {
                                ac -= 2; av += 2;
                        }
                        break;
 
                case TOK_MACTYPE:
                        NEED1("missing mac type");
-                       if (!add_mactype(cmd, ac, *av))
+                       if (!add_mactype(cmd, ac, *av, size_left))
                                errx(EX_DATAERR, "invalid mac type %s", *av);
                        ac--; av++;
                        break;
@@ -4571,7 +4667,7 @@
                        break;
 
                case TOK_EXT6HDR:
-                       fill_ext6hdr( cmd, *av );
+                       fill_ext6hdr(cmd, *av, size_left);
                        ac--; av++;
                        break;
 
@@ -4579,12 +4675,12 @@
                        if (proto != IPPROTO_IPV6 )
                                errx( EX_USAGE, "flow-id filter is active "
                                    "only for ipv6 protocol\n");
-                       fill_flow6( (ipfw_insn_u32 *) cmd, *av );
+                       fill_flow6((ipfw_insn_u32 *)cmd, *av, size_left);
                        ac--; av++;
                        break;
 
                case TOK_COMMENT:
-                       fill_comment(cmd, ac, av);
+                       fill_comment(cmd, ac, av, size_left);
                        av += ac;
                        ac = 0;
                        break;
@@ -4593,6 +4689,7 @@
                        errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
                }
                if (F_LEN(cmd) > 0) {   /* prepare to advance */
+                       UPDATE_SIZE(F_LEN(cmd));
                        prev = cmd;
                        cmd = next_cmd(cmd);
                }
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-ipfw
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to