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
This commit is contained in:
luigi 2003-06-22 17:33:19 +00:00
parent b2922be00d
commit 52ba467ddf
3 changed files with 120 additions and 41 deletions

View File

@ -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 .

View File

@ -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;

View File

@ -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 */