diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 027080237bb4..3badfa9a802c 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1652,10 +1652,12 @@ option for details on matching fragmented packets. TCP packets only. Match if the TCP header sequence number field is set to .Ar seq . -.It Cm tcpwin Ar win -TCP packets only. -Match if the TCP header window field is set to -.Ar win . +.It Cm tcpwin Ar tcpwin-list +Matches TCP packets whose header window field is set to +.Ar tcpwin-list , +which is either a single value or a list of values or ranges +specified in the same way as +.Ar ports . .It Cm tcpoptions Ar spec TCP packets only. Match if the TCP header contains the comma separated list of diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 6b0e0f0b54b8..ac0632e4aaa0 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -512,6 +512,7 @@ static struct _s_x _port_name[] = { {"ipttl", O_IPTTL}, {"mac-type", O_MAC_TYPE}, {"tcpdatalen", O_TCPDATALEN}, + {"tcpwin", O_TCPWIN}, {"tagged", O_TAGGED}, {NULL, 0} }; @@ -1480,7 +1481,11 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) break; case O_TCPWIN: - printf(" tcpwin %d", ntohs(cmd->arg1)); + if (F_LEN(cmd) == 1) + printf(" tcpwin %u", cmd->arg1); + else + print_newports((ipfw_insn_u16 *)cmd, 0, + O_TCPWIN); break; case O_TCPACK: @@ -3447,8 +3452,12 @@ read_options: case TOK_TCPWIN: NEED1("tcpwin requires length"); - fill_cmd(cmd, O_TCPWIN, 0, - htons(strtoul(*av, NULL, 0))); + if (strpbrk(*av, "-,")) { + if (!add_ports(cmd, *av, 0, O_TCPWIN)) + errx(EX_DATAERR, "invalid tcpwin len %s", *av); + } else + fill_cmd(cmd, O_TCPWIN, 0, + strtoul(*av, NULL, 0)); av++; break; diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c index 12a7fb9594c9..82ffb985b5ff 100644 --- a/sys/netinet/ipfw/ip_fw2.c +++ b/sys/netinet/ipfw/ip_fw2.c @@ -1650,8 +1650,22 @@ do { \ break; case O_TCPWIN: - match = (proto == IPPROTO_TCP && offset == 0 && - cmd->arg1 == TCP(ulp)->th_win); + if (proto == IPPROTO_TCP && offset == 0) { + uint16_t x; + uint16_t *p; + int i; + + x = ntohs(TCP(ulp)->th_win); + if (cmdlen == 1) { + match = (cmd->arg1 == x); + break; + } + /* Otherwise we have ranges. */ + p = ((ipfw_insn_u16 *)cmd)->ports; + i = cmdlen - 1; + for (; !match && i > 0; i--, p += 2) + match = (x >= p[0] && x <= p[1]); + } break; case O_ESTAB: diff --git a/sys/netinet/ipfw/ip_fw_sockopt.c b/sys/netinet/ipfw/ip_fw_sockopt.c index dce3fdc750ba..1302452c7216 100644 --- a/sys/netinet/ipfw/ip_fw_sockopt.c +++ b/sys/netinet/ipfw/ip_fw_sockopt.c @@ -569,7 +569,6 @@ check_ipfw_struct(struct ip_fw *rule, int size) case O_IPPRECEDENCE: case O_IPVER: case O_SOCKARG: - case O_TCPWIN: case O_TCPFLAGS: case O_TCPOPTS: case O_ESTAB: @@ -679,6 +678,7 @@ check_ipfw_struct(struct ip_fw *rule, int size) case O_IPTTL: case O_IPLEN: case O_TCPDATALEN: + case O_TCPWIN: case O_TAGGED: if (cmdlen < 1 || cmdlen > 31) goto bad_size;