Re: kern/80642: [patch] IPFW small patch - new RULE OPTION

From: Andrey V. Elsukov (bu7cher_at_yandex.ru)
Date: 06/17/05

  • Next message: GMane: "rebooting problem"
    Date: Fri, 17 Jun 2005 14:45:35 +0400
    To: FreeBSD Mailing List <freebsd-stable@freebsd.org>, freebsd-current@freebsd.org
    
    
    

    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 "freebsd-stable-unsubscribe@freebsd.org"


  • Next message: GMane: "rebooting problem"

    Relevant Pages

    • Re: kern/80642: [patch] IPFW small patch - new RULE OPTION
      ... > This patch breaks the ABI by inserting a new type into an implicitly ... # ipfw add allow ip from any to 10.0.0.20 in recv internet bound 10MB ... * This is used to store 64-bit bound value. ...
      (freebsd-current)
    • Re: kern/80642: [patch] IPFW small patch - new RULE OPTION
      ... > This patch breaks the ABI by inserting a new type into an implicitly ... # ipfw add allow ip from any to 10.0.0.20 in recv internet bound 10MB ... * This is used to store 64-bit bound value. ...
      (freebsd-hackers)
    • Re: traffic counting
      ... > ipfw count ... ... > How to collect and store these counters? ... To unsubscribe, ...
      (freebsd-questions)