From 44c884e1346556724e7a2298f527d96f118a890b Mon Sep 17 00:00:00 2001 From: Luigi Rizzo Date: Sun, 22 Jun 2003 17:33:19 +0000 Subject: [PATCH] Add support for multiple values and ranges for the "iplen", "ipttl", "ipid" options. This feature has been requested by several users. On passing, fix some minor bugs in the parser. This change is fully backward compatible so if you have an old /sbin/ipfw and a new kernel you are not in trouble (but you need to update /sbin/ipfw if you want to use the new features). Document the changes in the manpage. Now you can write things like ipfw add skipto 1000 iplen 0-500 which some people were asking to give preferential treatment to short packets. The 'MFC after' is just set as a reminder, because I still need to merge the Alpha/Sparc64 fixes for ipfw2 (which unfortunately change the size of certain kernel structures; not that it matters a lot since ipfw2 is entirely optional and not the default...) PR: bin/48015 MFC after: 1 week --- sbin/ipfw/ipfw.8 | 50 +++++++++++++++++++------------ sbin/ipfw/ipfw2.c | 70 +++++++++++++++++++++++++++++++++++++------- sys/netinet/ip_fw2.c | 41 ++++++++++++++++++-------- 3 files changed, 120 insertions(+), 41 deletions(-) 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 */