Robert Watson wrote:
 > This patch breaks the ABI by inserting a new type into an implicitly
 > numbered enumeration, renumbering all entries later in the enum.
 > O_BOUND, if added, should be appended to the end, and/or we should
 > number  the operations explicitly.

Ok. I have corrected this.
* ipfw_bound.diff - the patch with smallest changes, with only bound option.
* ipfw_bound2.diff - bound and check-bound option.

Examples:

We can limit incoming traffic (internet is external interface):
# ipfw add allow ip from any to 10.0.0.20 in recv internet bound 10MB
# ipfw add deny ip from any to 10.0.0.0/24 in recv internet

We can use traffic shaper after excess of a limit:
# ipfw add allow ip from any to 10.0.0.20 in recv internet bound 10MB
# ipfw add pipe 1 ip from any to 10.0.0.20 in recv internet
# ipfw pipe 1 config bw 5Kbit/s queue 10Kbytes

We can block any access after limit excess:
# ipfw add 100 allow ip from 10.0.0.20 to any out xmit internet \
check-bound 200
# ipfw add 200 allow ip from any to 10.0.0.20 in recv internet bound \ 10MB
# ipfw add 300 deny ip from any to any

More details you can read on http://butcher.heavennet.ru/
--
WBR, Andrey V. Elsukov
--- sbin/ipfw/ipfw2.c   Tue Jun  7 18:11:17 2005
+++ sbin/ipfw/ipfw2.c   Fri Jun 17 13:09:43 2005
@@ -277,6 +277,7 @@
        TOK_SRCIP6,
 
        TOK_IPV4,
+       TOK_BOUND,
 };
 
 struct _s_x dummynet_params[] = {
@@ -403,6 +404,7 @@
        { "dst-ip6",            TOK_DSTIP6},
        { "src-ipv6",           TOK_SRCIP6},
        { "src-ip6",            TOK_SRCIP6},
+       { "bound",              TOK_BOUND},
        { "//",                 TOK_COMMENT },
 
        { "not",                TOK_NOT },              /* pseudo option */
@@ -1858,6 +1860,10 @@
                                print_ext6hdr( (ipfw_insn *) cmd );
                                break;
 
+                       case O_BOUND:
+                               printf(" bound %u", ((ipfw_insn_u64 
*)cmd)->bound);
+                               break;
+
                        default:
                                printf(" [opcode %d len %d]",
                                    cmd->opcode, cmd->len);
@@ -2515,7 +2521,7 @@
 "      icmp6types LIST | ext6hdr LIST | flow-id N[,N] |\n"
 "      mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
 "      setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
-"      tcpdatalen LIST | verrevpath | versrcreach | antispoof\n"
+"      tcpdatalen LIST | verrevpath | versrcreach | antispoof | bound VALUE\n"
 );
 exit(0);
 }
@@ -3683,6 +3689,7 @@
        int i;
 
        int open_par = 0;       /* open parenthesis ( */
+       int have_bound = 0;
 
        /* proto is here because it is used to fetch ports */
        u_char proto = IPPROTO_IP;      /* default protocol */
@@ -4492,6 +4499,33 @@
                        fill_comment(cmd, ac, av);
                        av += ac;
                        ac = 0;
+                       break;
+
+               case TOK_BOUND:
+                       NEED1("bound requires numeric value");
+                       if (have_bound)
+                               errx(EX_USAGE, "only one of bound is allowed");
+                       if (open_par)
+                               errx(EX_USAGE, "bound cannot be part "
+                                               "of an or block"); 
+                       if (cmd->len & F_NOT)
+                               errx(EX_USAGE, 
+                               "\"not\" not allowed with bound option"); 
+                       {
+                               char *end = NULL;
+                               uint64_t bound = strtoull(*av, &end, 0);
+                               if (bound)
+                               switch (*end){
+                                       case 'G': bound *= 1024;
+                                       case 'M': bound *= 1024;
+                                       case 'K': bound *= 1024;
+                               };
+                               cmd->opcode = O_BOUND;
+                               ((ipfw_insn_u64 *)cmd)->bound = bound;
+                               cmd->len = F_INSN_SIZE(ipfw_insn_u64) & 
F_LEN_MASK;
+                               have_bound = 1;
+                               ac--; av++;
+                       } 
                        break;
 
                default:
--- sys/netinet/ip_fw.h Fri Jun  3 05:10:28 2005
+++ sys/netinet/ip_fw.h Fri Jun 17 11:30:30 2005
@@ -154,6 +154,7 @@
        O_NGTEE,                /* copy to ng_ipfw              */
 
        O_IP4,
+       O_BOUND,                /* u64 = bound in bytes */
 
        O_LAST_OPCODE           /* not an opcode!               */
 };
@@ -228,6 +229,14 @@
        ipfw_insn o;
        u_int32_t d[1]; /* one or more */
 } ipfw_insn_u32;
+
+/*
+ * This is used to store 64-bit bound value.
+ */
+typedef struct _ipfw_insn_u64 {
+       ipfw_insn o;
+       u_int64_t bound;
+} ipfw_insn_u64; 
 
 /*
  * This is used to store IP addr-mask pairs.
--- sys/netinet/ip_fw2.c        Thu Jun 16 18:55:58 2005
+++ sys/netinet/ip_fw2.c        Fri Jun 17 11:46:36 2005
@@ -2251,6 +2251,10 @@
                         * logic to deal with F_NOT and F_OR flags associated
                         * with the opcode.
                         */
+                       case O_BOUND:
+                               match = (f->bcnt < ((ipfw_insn_u64 
*)cmd)->bound);
+                               break;
+
                        case O_NOP:
                                match = 1;
                                break;
@@ -3387,6 +3391,11 @@
                case O_PROB:
                case O_ICMPTYPE:
                        if (cmdlen != F_INSN_SIZE(ipfw_insn_u32))
+                               goto bad_size;
+                       break;
+               
+               case O_BOUND:
+                       if (cmdlen != F_INSN_SIZE(ipfw_insn_u64))
                                goto bad_size;
                        break;
 

--- sbin/ipfw/ipfw2.c   Tue Jun  7 18:11:17 2005
+++ sbin/ipfw/ipfw2.c   Fri Jun 17 13:40:54 2005
@@ -277,6 +277,8 @@
        TOK_SRCIP6,
 
        TOK_IPV4,
+       TOK_BOUND,
+       TOK_CHECK_BOUND,
 };
 
 struct _s_x dummynet_params[] = {
@@ -403,6 +405,8 @@
        { "dst-ip6",            TOK_DSTIP6},
        { "src-ipv6",           TOK_SRCIP6},
        { "src-ip6",            TOK_SRCIP6},
+       { "bound",              TOK_BOUND},
+       { "check-bound",        TOK_CHECK_BOUND},
        { "//",                 TOK_COMMENT },
 
        { "not",                TOK_NOT },              /* pseudo option */
@@ -1636,6 +1640,9 @@
                        flags |= HAVE_PROTO;
                        break;
 
+               case O_BOUND:
+                       break;
+
                default: /*options ... */
                        if (!(cmd->len & (F_OR|F_NOT)))
                                if (((cmd->opcode == O_IP6) &&
@@ -1858,6 +1865,10 @@
                                print_ext6hdr( (ipfw_insn *) cmd );
                                break;
 
+                       case O_CHECK_BOUND:
+                               printf(" check-bound %d", cmd->arg1);
+                               break;
+
                        default:
                                printf(" [opcode %d len %d]",
                                    cmd->opcode, cmd->len);
@@ -1872,6 +1883,8 @@
                }
        }
        show_prerequisites(&flags, HAVE_IP, 0);
+       if (rule->cmd->opcode == O_BOUND) 
+               printf(" bound %u", ((ipfw_insn_u64 *)(rule->cmd))->bound);
        if (comment)
                printf(" // %s", comment);
        printf("\n");
@@ -2515,7 +2528,8 @@
 "      icmp6types LIST | ext6hdr LIST | flow-id N[,N] |\n"
 "      mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
 "      setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
-"      tcpdatalen LIST | verrevpath | versrcreach | antispoof\n"
+"      tcpdatalen LIST | verrevpath | versrcreach | antispoof | bound VALUE 
|\n"
+"      check-bound NUM\n"
 );
 exit(0);
 }
@@ -3677,7 +3691,8 @@
         * various flags used to record that we entered some fields.
         */
        ipfw_insn *have_state = NULL;   /* check-state or keep-state */
-       ipfw_insn *have_log = NULL, *have_altq = NULL;
+       ipfw_insn *have_log = NULL, *have_altq = NULL,
+                 *have_bound = NULL;
        size_t len;
 
        int i;
@@ -4494,6 +4509,39 @@
                        ac = 0;
                        break;
 
+               case TOK_BOUND:
+                       NEED1("bound requires numeric value");
+                       if (have_bound)
+                               errx(EX_USAGE, "only one of bound is allowed");
+                       if (open_par)
+                               errx(EX_USAGE, "bound cannot be part "
+                                               "of an or block"); 
+                       if (cmd->len & F_NOT)
+                               errx(EX_USAGE, 
+                               "\"not\" not allowed with bound option"); 
+                       {
+                               char *end = NULL;
+                               uint64_t bound = strtoull(*av, &end, 0);
+                               if (bound)
+                               switch (*end){
+                                       case 'G': bound *= 1024;
+                                       case 'M': bound *= 1024;
+                                       case 'K': bound *= 1024;
+                               };
+                               cmd->opcode = O_BOUND;
+                               ((ipfw_insn_u64 *)cmd)->bound = bound;
+                               cmd->len = F_INSN_SIZE(ipfw_insn_u64) & 
F_LEN_MASK;
+                               have_bound = cmd;
+                               ac--; av++;
+                       } 
+                       break;
+
+               case TOK_CHECK_BOUND:
+                       NEED1("check-bound requires rule number"); 
+                       fill_cmd(cmd, O_CHECK_BOUND, 0, strtoul(*av, NULL, 0));
+                       ac--; av++; 
+                       break;
+
                default:
                        errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
                }
@@ -4506,6 +4554,8 @@
 done:
        /*
         * Now copy stuff into the rule.
+        * If we have a bound option, the first instruction MUST BE 
+        * a O_BOUND.
         * If we have a keep-state option, the first instruction
         * must be a PROBE_STATE (which is generated here).
         * If we have a LOG option, it was stored as the first command,
@@ -4514,7 +4564,15 @@
        dst = (ipfw_insn *)rule->cmd;
 
        /*
-        * First thing to write into the command stream is the match 
probability.
+        * First write into the command stream bound instruction
+        */
+       if (have_bound) {
+               bcopy(have_bound, dst, F_LEN(have_bound) * sizeof(uint32_t));
+               dst = next_cmd(dst);
+       }
+
+       /*
+        * write the match probability  
         */
        if (match_prob != 1) { /* 1 means always match */
                dst->opcode = O_PROB;
@@ -4531,7 +4589,8 @@
                dst = next_cmd(dst);
        }
        /*
-        * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ
+        * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ,
+        * O_BOUND
         */
        for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
                i = F_LEN(src);
@@ -4541,6 +4600,7 @@
                case O_KEEP_STATE:
                case O_LIMIT:
                case O_ALTQ:
+               case O_BOUND:
                        break;
                default:
                        bcopy(src, dst, i * sizeof(uint32_t));
--- sys/netinet/ip_fw.h Fri Jun  3 05:10:28 2005
+++ sys/netinet/ip_fw.h Fri Jun 17 13:18:47 2005
@@ -154,6 +154,8 @@
        O_NGTEE,                /* copy to ng_ipfw              */
 
        O_IP4,
+       O_BOUND,                /* u64 = bound in bytes */
+       O_CHECK_BOUND,          /* u16 = rule number */
 
        O_LAST_OPCODE           /* not an opcode!               */
 };
@@ -230,6 +232,14 @@
 } ipfw_insn_u32;
 
 /*
+ * This is used to store 64-bit bound value.
+ */
+typedef struct _ipfw_insn_u64 {
+       ipfw_insn o;
+       u_int64_t bound;
+} ipfw_insn_u64; 
+
+/*
  * This is used to store IP addr-mask pairs.
  */
 typedef struct _ipfw_insn_ip {
@@ -351,11 +361,16 @@
  *
  * When assembling instruction, remember the following:
  *
+ *  + if a rule has a "bound" option, then the first instruction
+ *     (at r->cmd) MUST BE an O_BOUND
  *  + if a rule has a "keep-state" (or "limit") option, then the
  *     first instruction (at r->cmd) MUST BE an O_PROBE_STATE
  *  + if a rule has a "log" option, then the first action
  *     (at ACTION_PTR(r)) MUST be O_LOG
  *  + if a rule has an "altq" option, it comes after "log"
+ *
+ * NOTE: actually, O_PROB instruction may be first too. But O_BOUND 
+ *     MUST BE always first (at r->cmd). 
  *
  * NOTE: we use a simple linked list of rules because we never need
  *     to delete a rule without scanning the list. We do not use
--- sys/netinet/ip_fw2.c        Thu Jun 16 18:55:58 2005
+++ sys/netinet/ip_fw2.c        Fri Jun 17 13:26:19 2005
@@ -2251,6 +2251,26 @@
                         * logic to deal with F_NOT and F_OR flags associated
                         * with the opcode.
                         */
+                       case O_BOUND:
+                               match = (f->bcnt < ((ipfw_insn_u64 
*)cmd)->bound);
+                               break;
+
+                       case O_CHECK_BOUND:
+                               {
+                               struct ip_fw* rule;
+                               for (rule = f->next; 
+                                        rule && cmd->arg1 >= rule->rulenum; 
+                                        rule = rule->next) 
+                                       if (rule->rulenum == cmd->arg1 && 
+                                               rule->cmd->opcode == O_BOUND )
+                                       {
+                                               match = (rule->bcnt < 
+                                                       ((ipfw_insn_u64 
*)(rule->cmd))->bound);
+                                               break;
+                                       }
+                               }
+                               break;
+ 
                        case O_NOP:
                                match = 1;
                                break;
@@ -3373,6 +3393,7 @@
                case O_EXT_HDR:
                case O_IP6:
                case O_IP4:
+               case O_CHECK_BOUND:
                        if (cmdlen != F_INSN_SIZE(ipfw_insn))
                                goto bad_size;
                        break;
@@ -3388,6 +3409,16 @@
                case O_ICMPTYPE:
                        if (cmdlen != F_INSN_SIZE(ipfw_insn_u32))
                                goto bad_size;
+                       break;
+               
+               case O_BOUND:
+                       if (cmdlen != F_INSN_SIZE(ipfw_insn_u64))
+                               goto bad_size;
+                       if (cmd != rule->cmd) {
+                               printf("ipfw: bogus rule, opcode %d must be 
first\n",
+                                               cmd->opcode);
+                               return EINVAL;
+                       } 
                        break;
 
                case O_LIMIT:

_______________________________________________
freebsd-stable@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-stable
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to