diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 2968109457bc..f63f78815801 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -707,7 +707,7 @@ The or .Cm all keywords mean any protocol will match. -.It Ar src No and Ar dst : ip-address | Cm { Ar ip-address Cm or ... } Op Ar ports +.It Ar src No and Ar dst : ip-address | Cm { Ar ip-address Cm or ... } Op Oo Cm not Oc Ar ports A single .Ar ip-address , or an @@ -776,7 +776,7 @@ masks, and resort to the format for contiguous masks, which is more compact and less error-prone. .El -.It Ar ports : Oo Cm not Oc Bro Ar port | port Ns \&- Ns Ar port Ns Brc Op , Ns Ar ... +.It Ar ports : Bro Ar port | port Ns \&- Ns Ar port Ns Brc Op , Ns Ar ports For protocols which support port numbers (such as TCP and UDP), optional .Cm ports may be specified as one or more ports or port ranges, separated @@ -827,10 +827,10 @@ The following match patterns can be used (listed in alphabetical order): .Bl -tag -width indent .It Cm bridged Matches only bridged packets. -.It Cm dst-ip Ar ip address +.It Cm dst-ip Ar ip-address Matches IP packets whose destination IP is one of the address(es) specified as argument. -.It Cm dst-port Ar source ports +.It Cm dst-port Ar ports Matches IP packets whose destination port is one of the port(s) specified as argument. .It Cm established @@ -892,15 +892,21 @@ are mutually exclusive (in fact, .Cm out is implemented as .Cm not in Ns No ). -.It Cm ipid Ar id +.It Cm ipid Ar id-list Matches IP packets whose .Cm ip_id -field has value -.Ar id . -.It Cm iplen Ar len +field has value included in +.Ar id-list , +which is either a single value or a list of values or ranges +specified in the same way as +.Ar ports . +.It Cm iplen Ar len-list Matches IP packets whose total length, including header and data, is -.Ar len -bytes. +in the set +.Ar len-list , +which is either a single value or a list of values or ranges +specified in the same way as +.Ar ports . .It Cm ipoptions Ar spec Matches packets whose IP header contains the comma separated list of options specified in @@ -942,9 +948,12 @@ The supported IP types of service are: The absence of a particular type may be denoted with a .Ql \&! . -.It Cm ipttl Ar ttl -Matches IP packets whose time to live is -.Ar ttl . +.It Cm ipttl Ar ttl-list +Matches IP packets whose time to live is included in +.Ar ttl-list , +which is either a single value or a list of values or ranges +specified in the same way as +.Ar ports . .It Cm ipversion Ar ver Matches IP packets whose IP version field is .Ar ver . @@ -1762,15 +1771,20 @@ The sysctl variable .Em net.link.ether.ipfw has no effect there. .It Options -The following options are not supported in -.Nm ipfw1 +In +.Nm ipfw1 , +the following options only accept a single value as an argument: +.Pp +.Cm ipid, iplen, ipttl +.Pp +The following options are not implemented by +.Nm ipfw1 : .Pp .Cm dst-ip, dst-port, layer2, mac, mac-type, src-ip, src-port. .Pp -Additionally, the following options are not supported in +Additionally, the RELENG_4 version of .Nm ipfw1 -(RELENG_4) -rules: +does not implement the following options: .Pp .Cm ipid, iplen, ipprecedence, iptos, ipttl, .Cm ipversion, tcpack, tcpseq, tcpwin . diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index f0a1030b147c..3a3ff3aac3a0 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -418,13 +418,37 @@ print_newports(ipfw_insn_u16 *cmd, int proto, int opcode) { u_int16_t *p = cmd->ports; int i; - char *sep= " "; + char *sep; if (cmd->o.len & F_NOT) printf(" not"); - if (opcode != 0) - printf ("%s", opcode == O_MAC_TYPE ? " mac-type" : - (opcode == O_IP_DSTPORT ? " dst-port" : " src-port")); + if (opcode != 0) { + switch (opcode) { + case O_IP_DSTPORT: + sep = "dst-port"; + break; + case O_IP_SRCPORT: + sep = "src-port"; + break; + case O_IPID: + sep = "ipid"; + break; + case O_IPLEN: + sep = "iplen"; + break; + case O_IPTTL: + sep = "ipttl"; + break; + case O_MAC_TYPE: + sep = "mac-type"; + break; + default: + sep = "???"; + break; + } + printf (" %s", sep); + } + sep = " "; for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { printf(sep); print_port(proto, p[0]); @@ -1096,11 +1120,19 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) break; case O_IPID: - printf(" ipid %u", cmd->arg1 ); + if (F_LEN(cmd) == 1) + printf(" ipid %u", cmd->arg1 ); + else + print_newports((ipfw_insn_u16 *)cmd, 0, + O_IPID); break; case O_IPTTL: - printf(" ipttl %u", cmd->arg1 ); + if (F_LEN(cmd) == 1) + printf(" ipttl %u", cmd->arg1 ); + else + print_newports((ipfw_insn_u16 *)cmd, 0, + O_IPTTL); break; case O_IPVER: @@ -1112,7 +1144,11 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) break; case O_IPLEN: - printf(" iplen %u", cmd->arg1 ); + if (F_LEN(cmd) == 1) + printf(" iplen %u", cmd->arg1 ); + else + print_newports((ipfw_insn_u16 *)cmd, 0, + O_IPLEN); break; case O_IPOPT: @@ -2971,19 +3007,31 @@ add(int ac, char *av[]) case TOK_IPTTL: NEED1("ipttl requires TTL"); - fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); + if (strpbrk(*av, "-,")) { + if (!add_ports(cmd, *av, 0, O_IPTTL)) + errx(EX_DATAERR, "invalid ipttl %s", *av); + } else + fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); ac--; av++; break; case TOK_IPID: - NEED1("ipid requires length"); - fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); + NEED1("ipid requires id"); + if (strpbrk(*av, "-,")) { + if (!add_ports(cmd, *av, 0, O_IPID)) + errx(EX_DATAERR, "invalid ipid %s", *av); + } else + fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); ac--; av++; break; case TOK_IPLEN: NEED1("iplen requires length"); - fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); + if (strpbrk(*av, "-,")) { + if (!add_ports(cmd, *av, 0, O_IPLEN)) + errx(EX_DATAERR, "invalid ip len %s", *av); + } else + fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); ac--; av++; break; diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 95a153ed6633..1af01da31e07 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -1730,17 +1730,30 @@ ipfw_chk(struct ip_fw_args *args) match = (hlen > 0 && cmd->arg1 == ip->ip_v); break; - case O_IPTTL: - match = (hlen > 0 && cmd->arg1 == ip->ip_ttl); - break; - case O_IPID: - match = (hlen > 0 && - cmd->arg1 == ntohs(ip->ip_id)); - break; - case O_IPLEN: - match = (hlen > 0 && cmd->arg1 == ip_len); + case O_IPTTL: + if (hlen > 0) { /* only for IP packets */ + uint16_t x; + uint16_t *p; + int i; + + if (cmd->opcode == O_IPLEN) + x = ip_len; + else if (cmd->opcode == O_IPTTL) + x = ip->ip_ttl; + else /* must be IPID */ + x = ntohs(ip->ip_id); + 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_IPPRECEDENCE: @@ -2371,11 +2384,8 @@ check_ipfw_struct(struct ip_fw *rule, int size) case O_IN: case O_FRAG: case O_IPOPT: - case O_IPLEN: - case O_IPID: case O_IPTOS: case O_IPPRECEDENCE: - case O_IPTTL: case O_IPVER: case O_TCPWIN: case O_TCPFLAGS: @@ -2440,6 +2450,13 @@ check_ipfw_struct(struct ip_fw *rule, int size) goto bad_size; break; + case O_IPID: + case O_IPTTL: + case O_IPLEN: + if (cmdlen < 1 || cmdlen > 31) + goto bad_size; + break; + case O_MAC_TYPE: case O_IP_SRCPORT: case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */