Major cleanup of the parser and printing routines in an attempt to
render the syntax less ambiguous. Now rules can be in one of these two forms <action> <protocol> from <src> to <dst> [options] <action> MAC dst-mac src-mac mac-type [options] however you can now specify MAC and IP header fields as options e.g. ipfw add allow all from any to any mac-type arp ipfw add allow all from any to any { dst-ip me or src-ip me } which makes complex expressions a lot easier to write and parse. The "all from any to any" part is there just for backward compatibility. Manpage updated accordingly.
This commit is contained in:
parent
306fe283a1
commit
e706181ba6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=102087
165
sbin/ipfw/ipfw.8
165
sbin/ipfw/ipfw.8
@ -671,27 +671,29 @@ Only one level of parentheses is allowed.
|
|||||||
Beware that most shells have special meanings for parentheses
|
Beware that most shells have special meanings for parentheses
|
||||||
or braces, so it is advisable to put a \\ in front of them.
|
or braces, so it is advisable to put a \\ in front of them.
|
||||||
.Pp
|
.Pp
|
||||||
The body of a rule must in general comprise a source and destination
|
The body of a rule must in general include a source and destination
|
||||||
addres specifier.
|
addres specifier.
|
||||||
The keyword
|
The keyword
|
||||||
.Ar any
|
.Ar any
|
||||||
can be used in various places to specify that the content of
|
can be used in various places to specify that the content of
|
||||||
a required field is irrelevant.
|
a required field is irrelevant.
|
||||||
.Pp
|
.Pp
|
||||||
The general rule body format is one of the following:
|
The rule body format is one of the following:
|
||||||
.Bd -ragged -offset indent
|
.Bd -ragged -offset indent
|
||||||
.Ar proto
|
.Ar proto
|
||||||
.Cm from Ar src
|
.Cm from Ar src
|
||||||
.Cm to Ar dst
|
.Cm to Ar dst
|
||||||
.Op Ar options
|
.Op Ar options
|
||||||
.br
|
.Pp
|
||||||
.Cm MAC Ar dst-mac src-mac mac-type
|
.Cm MAC Ar dst-mac src-mac Op Cm not
|
||||||
.Op Cm from Ar src Cm to Ar dst
|
.Ar mac-type Op Ar options
|
||||||
.Op Ar options
|
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
where the second format allows you to specify MAC header fields
|
where the second format allows you to specify MAC header fields
|
||||||
instead (or in addition) of the IPv4 header fields.
|
instead of IPv4 header fields.
|
||||||
|
Note that in practice both formats are equivalent, because the
|
||||||
|
.Ar options
|
||||||
|
let you specify match patterns for all IP and MAC header fields.
|
||||||
.Pp
|
.Pp
|
||||||
Rule fields have the following meaning:
|
Rule fields have the following meaning:
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
@ -704,15 +706,16 @@ The
|
|||||||
or
|
or
|
||||||
.Cm all
|
.Cm all
|
||||||
keywords mean any protocol will match.
|
keywords mean any protocol will match.
|
||||||
.It Ar src No and Ar dst :
|
.It Ar src No and Ar dst : ip-address | { ip-address Cm or ... } Op Ar ports
|
||||||
A single
|
A single
|
||||||
.Ar ip address
|
.Ar ip-address
|
||||||
, or an
|
, or an
|
||||||
.Em or-block
|
.Em or-block
|
||||||
containing one or more of them,
|
containing one or more of them,
|
||||||
optionally followed by
|
optionally followed by
|
||||||
.Em port numbers.
|
.Ar ports
|
||||||
.It Ar ip address :
|
specifiers.
|
||||||
|
.It Ar ip-address :
|
||||||
An address (or set of addresses) specified in one of the following
|
An address (or set of addresses) specified in one of the following
|
||||||
ways, optionally preceded by a
|
ways, optionally preceded by a
|
||||||
.Cm not
|
.Cm not
|
||||||
@ -758,19 +761,13 @@ within a single rule. Because the matching occurs using a
|
|||||||
bitmask, it takes constant time and dramatically reduces
|
bitmask, it takes constant time and dramatically reduces
|
||||||
the complexity of rulesets.
|
the complexity of rulesets.
|
||||||
.El
|
.El
|
||||||
.It port numbers
|
.It Ar ports : Oo Cm not Oc Bro Ar port | port Ns \&- Ns Ar port Ns Brc Op , Ns Ar ...
|
||||||
With protocols which support port numbers (such as TCP and UDP), optional
|
For protocols which support port numbers (such as TCP and UDP), optional
|
||||||
.Cm ports
|
.Cm ports
|
||||||
may be specified as one or more ports or port ranges, separated
|
may be specified as one or more ports or port ranges, separated
|
||||||
by commas but no spaces, and an optional
|
by commas but no spaces, and an optional
|
||||||
.Cm not
|
.Cm not
|
||||||
operator:
|
operator.
|
||||||
.Bd -ragged -offset indent
|
|
||||||
.Op Cm not
|
|
||||||
.Brq Ar port | port Ns \&- Ns Ar port Ns
|
|
||||||
.Op , Ns Ar ...
|
|
||||||
.Ed
|
|
||||||
.Pp
|
|
||||||
The
|
The
|
||||||
.Ql \&-
|
.Ql \&-
|
||||||
notation specifies a range of ports (including boundaries).
|
notation specifies a range of ports (including boundaries).
|
||||||
@ -778,13 +775,12 @@ notation specifies a range of ports (including boundaries).
|
|||||||
Service names (from
|
Service names (from
|
||||||
.Pa /etc/services )
|
.Pa /etc/services )
|
||||||
may be used instead of numeric port values.
|
may be used instead of numeric port values.
|
||||||
The length of the port list is limited to 14 ports or ranges,
|
The length of the port list is limited to 30 ports or ranges,
|
||||||
though you can also use port ranges within an
|
though one can specify larger ranges by using an
|
||||||
.Em or-block
|
.Em or-block
|
||||||
to build essentially unlimited lists:
|
in the
|
||||||
.Pp
|
.Cm options
|
||||||
.Dl "ipfw add allow tcp from any { 1-20,30-50 or 500-600 } to any"
|
section of the rule.
|
||||||
.Pp
|
|
||||||
.Pp
|
.Pp
|
||||||
A backslash
|
A backslash
|
||||||
.Pq Ql \e
|
.Pq Ql \e
|
||||||
@ -800,7 +796,7 @@ specifications.
|
|||||||
See the
|
See the
|
||||||
.Cm frag
|
.Cm frag
|
||||||
option for details on matching fragmented packets.
|
option for details on matching fragmented packets.
|
||||||
.It dst-mac, src-mac
|
.It Ar dst-mac, src-mac
|
||||||
Destination and source MAC addresses, specified as
|
Destination and source MAC addresses, specified as
|
||||||
groups of hex digits separated by commas, and optionally
|
groups of hex digits separated by commas, and optionally
|
||||||
followed by a mask indicating how many bits are significant:
|
followed by a mask indicating how many bits are significant:
|
||||||
@ -811,7 +807,7 @@ Note that the order of MAC addresses (destination first,
|
|||||||
source second) is
|
source second) is
|
||||||
the same as on the wire, but the opposite of the one used for
|
the same as on the wire, but the opposite of the one used for
|
||||||
IP addresses.
|
IP addresses.
|
||||||
.It mac-type
|
.It Ar mac-type
|
||||||
The value of the Ethernet Type field, specified in the same way as
|
The value of the Ethernet Type field, specified in the same way as
|
||||||
.Cm port numbers
|
.Cm port numbers
|
||||||
(i.e. one or more comma-separated single values or ranges).
|
(i.e. one or more comma-separated single values or ranges).
|
||||||
@ -823,7 +819,7 @@ are always printed as hexadecimal (unless the
|
|||||||
option is used, in which case symbolic resolution will be
|
option is used, in which case symbolic resolution will be
|
||||||
attempted).
|
attempted).
|
||||||
.El
|
.El
|
||||||
.Ss RULE OPTIONS
|
.Ss RULE OPTIONS (MATCH PATTERNS)
|
||||||
Additional match patterns can be used within
|
Additional match patterns can be used within
|
||||||
rules. Zero or more of these so-called
|
rules. Zero or more of these so-called
|
||||||
.Em options
|
.Em options
|
||||||
@ -832,44 +828,31 @@ can be present in a rule, optionally prefixed by the
|
|||||||
operand, and possibly grouped into
|
operand, and possibly grouped into
|
||||||
.Em or-blocks .
|
.Em or-blocks .
|
||||||
.Pp
|
.Pp
|
||||||
Note that there is an ambiguity in the syntax: in a rule of
|
The following match patterns can be used (listed in alphabetical order):
|
||||||
the form
|
|
||||||
.Pp
|
|
||||||
.Dl "ipfw add allow ip from any to any { in or layer2 }"
|
|
||||||
.Pp
|
|
||||||
the or-block could contain either port lists or options.
|
|
||||||
To remove the ambiguity, one should specify a destination
|
|
||||||
port, which can be done by either using the keyword
|
|
||||||
.Cm any
|
|
||||||
or an empty or-block
|
|
||||||
.Cm { }
|
|
||||||
e.g.:
|
|
||||||
.Pp
|
|
||||||
.Dl "ipfw add allow ip from any to any any { in or layer2 }"
|
|
||||||
.Pp
|
|
||||||
The following options are available:
|
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
.It Cm bridged
|
.It Cm bridged
|
||||||
Matches only bridged packets.
|
Matches only bridged packets.
|
||||||
|
.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
|
||||||
|
Matches IP packets whose destination port is one of the port(s)
|
||||||
|
specified as argument.
|
||||||
.It Cm established
|
.It Cm established
|
||||||
TCP packets only.
|
Matches TCP packets that have the RST or ACK bits set.
|
||||||
Match packets that have the RST or ACK bits set.
|
|
||||||
.It Cm frag
|
.It Cm frag
|
||||||
Match if the packet is a fragment and this is not the first
|
Matches packets that are fragments and not the first
|
||||||
fragment of the datagram.
|
fragment of an IP datagram. Note that these packets will not have
|
||||||
.Cm frag
|
the next protocol header (e.g. TCP, UDP) so options that look into
|
||||||
may not be used in conjunction with either
|
these headers cannot match.
|
||||||
.Cm tcpflags
|
|
||||||
or TCP/UDP port specifications.
|
|
||||||
.It Cm gid Ar group
|
.It Cm gid Ar group
|
||||||
Match all TCP or UDP packets sent by or received for a
|
Matches all TCP or UDP packets sent by or received for a
|
||||||
.Ar group .
|
.Ar group .
|
||||||
A
|
A
|
||||||
.Ar group
|
.Ar group
|
||||||
may be matched by name or identification number.
|
may be specified by name or number.
|
||||||
.It Cm icmptypes Ar types
|
.It Cm icmptypes Ar types
|
||||||
ICMP packets only.
|
Matches ICMP packets whose ICMP type is in the list
|
||||||
Match if the ICMP type is in the list
|
|
||||||
.Ar types .
|
.Ar types .
|
||||||
The list may be specified as any combination of ranges or
|
The list may be specified as any combination of ranges or
|
||||||
individual types separated by commas.
|
individual types separated by commas.
|
||||||
@ -906,24 +889,25 @@ address mask request
|
|||||||
and address mask reply
|
and address mask reply
|
||||||
.Pq Cm 18 .
|
.Pq Cm 18 .
|
||||||
.It Cm in | out
|
.It Cm in | out
|
||||||
Only match incoming or outgoing packets, respectively.
|
Matches incoming or outgoing packets, respectively.
|
||||||
.Cm in
|
.Cm in
|
||||||
and
|
and
|
||||||
.Cm out
|
.Cm out
|
||||||
are mutually exclusive (in fact,
|
are mutually exclusive (in fact,
|
||||||
.Cm out
|
.Cm out
|
||||||
is implemented as
|
is implemented as
|
||||||
.Cm not in
|
.Cm not in Ns No ).
|
||||||
).
|
|
||||||
.It Cm ipid Ar id
|
.It Cm ipid Ar id
|
||||||
Match if the identification of IP datagram is
|
Matches IP packets whose
|
||||||
|
.Cm ip_id
|
||||||
|
field has value
|
||||||
.Ar id .
|
.Ar id .
|
||||||
.It Cm iplen Ar len
|
.It Cm iplen Ar len
|
||||||
Match if the total length of a packet, including header and data, is
|
Matches IP packets whose total length, including header and data, is
|
||||||
.Ar len
|
.Ar len
|
||||||
bytes.
|
bytes.
|
||||||
.It Cm ipoptions Ar spec
|
.It Cm ipoptions Ar spec
|
||||||
Match if the IP header contains the comma separated list of
|
Matches packets whose IP header contains the comma separated list of
|
||||||
options specified in
|
options specified in
|
||||||
.Ar spec .
|
.Ar spec .
|
||||||
The supported IP options are:
|
The supported IP options are:
|
||||||
@ -940,10 +924,12 @@ The absence of a particular option may be denoted
|
|||||||
with a
|
with a
|
||||||
.Ql \&! .
|
.Ql \&! .
|
||||||
.It Cm ipprecedence Ar precedence
|
.It Cm ipprecedence Ar precedence
|
||||||
Match if the numeric value of IP datagram's precedence is equal to
|
Matches IP packets whose precedence field is equal to
|
||||||
.Ar precedence .
|
.Ar precedence .
|
||||||
.It Cm iptos Ar spec
|
.It Cm iptos Ar spec
|
||||||
Match if the IP header contains the comma separated list of
|
Matches IP packets whose
|
||||||
|
.Cm tos
|
||||||
|
field contains the comma separated list of
|
||||||
service types specified in
|
service types specified in
|
||||||
.Ar spec .
|
.Ar spec .
|
||||||
The supported IP types of service are:
|
The supported IP types of service are:
|
||||||
@ -962,10 +948,10 @@ The absence of a particular type may be denoted
|
|||||||
with a
|
with a
|
||||||
.Ql \&! .
|
.Ql \&! .
|
||||||
.It Cm ipttl Ar ttl
|
.It Cm ipttl Ar ttl
|
||||||
Match if the time to live of IP datagram is
|
Matches IP packets whose time to live is
|
||||||
.Ar ttl .
|
.Ar ttl .
|
||||||
.It Cm ipversion Ar ver
|
.It Cm ipversion Ar ver
|
||||||
Match if the IP header version is
|
Matches IP packets whose IP version field is
|
||||||
.Ar ver .
|
.Ar ver .
|
||||||
.It Cm keep-state
|
.It Cm keep-state
|
||||||
Upon a match, the firewall will create a dynamic rule, whose
|
Upon a match, the firewall will create a dynamic rule, whose
|
||||||
@ -987,13 +973,22 @@ set of parameters as specified in the rule.
|
|||||||
One or more
|
One or more
|
||||||
of source and destination addresses and ports can be
|
of source and destination addresses and ports can be
|
||||||
specified.
|
specified.
|
||||||
|
.It Cm { MAC | mac } Ar dst-mac src-mac
|
||||||
|
Match packets with a given dst-mac and src-mac addresses, specified
|
||||||
|
in one of the forms described earlier.
|
||||||
|
.It Cm mac-type Ar mac-type
|
||||||
|
Matches packets whose
|
||||||
|
.Ar mac-type
|
||||||
|
corresponds to one of those specified as argument.
|
||||||
|
.It Cm proto Ar protocol
|
||||||
|
Matches packets with the corresponding IPv4 protocol.
|
||||||
.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar ipno | Ar any
|
.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar ipno | Ar any
|
||||||
Packet must be received, transmitted or be going through,
|
Matches packets received, transmitted or be going through,
|
||||||
respectively, the interface specified by exact name (
|
respectively, the interface specified by exact name
|
||||||
.Ar ifX
|
.Ns No ( Ar ifX Ns No ),
|
||||||
), by device name (
|
by device name
|
||||||
.Ar if Ns Cm *
|
.Ns No ( Ar if Ns Ar * Ns No ),
|
||||||
), by IP address, or through some interface.
|
by IP address, or through some interface.
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Cm via
|
.Cm via
|
||||||
@ -1030,10 +1025,15 @@ originating from the local host have no receive interface,
|
|||||||
while packets destined for the local host have no transmit
|
while packets destined for the local host have no transmit
|
||||||
interface.
|
interface.
|
||||||
.It Cm setup
|
.It Cm setup
|
||||||
TCP packets only.
|
Matches TCP packets that have the SYN bit set but no ACK bit.
|
||||||
Match packets that have the SYN bit set but no ACK bit.
|
|
||||||
This is the short form of
|
This is the short form of
|
||||||
.Dq Li tcpflags\ syn,!ack .
|
.Dq Li tcpflags\ syn,!ack .
|
||||||
|
.It Cm src-ip Ar ip-address
|
||||||
|
Matches IP packets whose source IP is one of the address(es)
|
||||||
|
specified as argument.
|
||||||
|
.It Cm src-port Ar ports
|
||||||
|
Matches IP packets whose source port is one of the port(s)
|
||||||
|
specified as argument.
|
||||||
.It Cm tcpack Ar ack
|
.It Cm tcpack Ar ack
|
||||||
TCP packets only.
|
TCP packets only.
|
||||||
Match if the TCP header acknowledgment number field is set to
|
Match if the TCP header acknowledgment number field is set to
|
||||||
@ -1601,6 +1601,21 @@ have in writing your rulesets.
|
|||||||
You might want to consider using these features in order to
|
You might want to consider using these features in order to
|
||||||
write your rulesets in a more efficient way.
|
write your rulesets in a more efficient way.
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
|
.It Handling of non-IPv4 packets
|
||||||
|
.Nm ipfw1
|
||||||
|
will silently accept all non-IPv4 packets (which
|
||||||
|
.Nm ipfw1
|
||||||
|
will only see when
|
||||||
|
.Em net.link.ether.bridge_ipfw=1 Ns
|
||||||
|
).
|
||||||
|
.Nm ipfw2
|
||||||
|
will filter all packets (including non-IPv4 ones) according to the ruleset.
|
||||||
|
To achieve the same behaviour as
|
||||||
|
.Nm ipfw1
|
||||||
|
you can use the following as the very first rule in your ruleset:
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw add 1 allow MAC any any not ip"
|
||||||
|
.Pp
|
||||||
.It Address sets
|
.It Address sets
|
||||||
.Nm ipfw1
|
.Nm ipfw1
|
||||||
does not supports address sets (those in the form
|
does not supports address sets (those in the form
|
||||||
|
@ -221,6 +221,8 @@ enum tokens {
|
|||||||
TOK_TCPACK,
|
TOK_TCPACK,
|
||||||
TOK_TCPWIN,
|
TOK_TCPWIN,
|
||||||
TOK_ICMPTYPES,
|
TOK_ICMPTYPES,
|
||||||
|
TOK_MAC,
|
||||||
|
TOK_MACTYPE,
|
||||||
|
|
||||||
TOK_PLR,
|
TOK_PLR,
|
||||||
TOK_NOERROR,
|
TOK_NOERROR,
|
||||||
@ -322,6 +324,14 @@ struct _s_x rule_options[] = {
|
|||||||
{ "tcpwin", TOK_TCPWIN },
|
{ "tcpwin", TOK_TCPWIN },
|
||||||
{ "icmptype", TOK_ICMPTYPES },
|
{ "icmptype", TOK_ICMPTYPES },
|
||||||
{ "icmptypes", TOK_ICMPTYPES },
|
{ "icmptypes", TOK_ICMPTYPES },
|
||||||
|
{ "dst-ip", TOK_DSTIP },
|
||||||
|
{ "src-ip", TOK_SRCIP },
|
||||||
|
{ "dst-port", TOK_DSTPORT },
|
||||||
|
{ "src-port", TOK_SRCPORT },
|
||||||
|
{ "proto", TOK_PROTO },
|
||||||
|
{ "MAC", TOK_MAC },
|
||||||
|
{ "mac", TOK_MAC },
|
||||||
|
{ "mac-type", TOK_MACTYPE },
|
||||||
|
|
||||||
{ "not", TOK_NOT }, /* pseudo option */
|
{ "not", TOK_NOT }, /* pseudo option */
|
||||||
{ "!", /* escape ? */ TOK_NOT }, /* pseudo option */
|
{ "!", /* escape ? */ TOK_NOT }, /* pseudo option */
|
||||||
@ -393,7 +403,7 @@ print_port(int proto, u_int16_t port)
|
|||||||
* XXX todo: add support for mask.
|
* XXX todo: add support for mask.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
print_newports(ipfw_insn_u16 *cmd, int proto)
|
print_newports(ipfw_insn_u16 *cmd, int proto, int opcode)
|
||||||
{
|
{
|
||||||
u_int16_t *p = cmd->ports;
|
u_int16_t *p = cmd->ports;
|
||||||
int i;
|
int i;
|
||||||
@ -401,6 +411,9 @@ print_newports(ipfw_insn_u16 *cmd, int proto)
|
|||||||
|
|
||||||
if (cmd->o.len & F_NOT)
|
if (cmd->o.len & F_NOT)
|
||||||
printf(" not");
|
printf(" not");
|
||||||
|
if (opcode != 0)
|
||||||
|
printf ("%s", opcode == O_MAC_TYPE ? " mac-type" :
|
||||||
|
(opcode == O_IP_DSTPORT ? " dst-port" : " src-port"));
|
||||||
for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
|
for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
|
||||||
printf(sep);
|
printf(sep);
|
||||||
print_port(proto, p[0]);
|
print_port(proto, p[0]);
|
||||||
@ -487,10 +500,10 @@ fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
|
|||||||
{
|
{
|
||||||
u_int16_t *p = cmd->ports;
|
u_int16_t *p = cmd->ports;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
char *s = av;
|
||||||
|
|
||||||
for (; *av ; i++, p +=2 ) {
|
while (*s) {
|
||||||
u_int16_t a, b;
|
u_int16_t a, b;
|
||||||
char *s;
|
|
||||||
|
|
||||||
a = strtoport(av, &s, 0, proto);
|
a = strtoport(av, &s, 0, proto);
|
||||||
if (s == av) /* no parameter */
|
if (s == av) /* no parameter */
|
||||||
@ -508,11 +521,13 @@ fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
|
|||||||
errx(EX_DATAERR, "invalid separator <%c> in <%s>\n",
|
errx(EX_DATAERR, "invalid separator <%c> in <%s>\n",
|
||||||
*s, av);
|
*s, av);
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
|
p += 2;
|
||||||
av = s+1;
|
av = s+1;
|
||||||
}
|
}
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
if (i+1 > F_LEN_MASK)
|
if (i+1 > F_LEN_MASK)
|
||||||
errx(EX_DATAERR, "too many port range\n");
|
errx(EX_DATAERR, "too many ports/ranges\n");
|
||||||
cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */
|
cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
@ -547,7 +562,7 @@ fill_reject_code(u_short *codep, char *str)
|
|||||||
val = strtoul(str, &s, 0);
|
val = strtoul(str, &s, 0);
|
||||||
if (s == str || *s != '\0' || val >= 0x100)
|
if (s == str || *s != '\0' || val >= 0x100)
|
||||||
val = match_token(icmpcodes, str);
|
val = match_token(icmpcodes, str);
|
||||||
if (val <= 0)
|
if (val < 0)
|
||||||
errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
|
errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
|
||||||
*codep = val;
|
*codep = val;
|
||||||
return;
|
return;
|
||||||
@ -624,12 +639,12 @@ print_flags(char *name, ipfw_insn *cmd, struct _s_x *list)
|
|||||||
* Print the ip address contained in a command.
|
* Print the ip address contained in a command.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
print_ip(ipfw_insn_ip *cmd)
|
print_ip(ipfw_insn_ip *cmd, char *s)
|
||||||
{
|
{
|
||||||
struct hostent *he = NULL;
|
struct hostent *he = NULL;
|
||||||
int mb;
|
int mb;
|
||||||
|
|
||||||
printf("%s ", cmd->o.len & F_NOT ? " not": "");
|
printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
|
||||||
|
|
||||||
if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
|
if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
|
||||||
printf("me");
|
printf("me");
|
||||||
@ -741,33 +756,47 @@ print_icmptypes(ipfw_insn_u32 *cmd)
|
|||||||
* show_ipfw() prints the body of an ipfw rule.
|
* show_ipfw() prints the body of an ipfw rule.
|
||||||
* Because the standard rule has at least proto src_ip dst_ip, we use
|
* Because the standard rule has at least proto src_ip dst_ip, we use
|
||||||
* a helper function to produce these entries if not provided explicitly.
|
* a helper function to produce these entries if not provided explicitly.
|
||||||
|
* The first argument is the list of fields we have, the second is
|
||||||
|
* the list of fields we want to be printed.
|
||||||
*
|
*
|
||||||
* Special case: if we have provided a MAC header, and no IP specs,
|
* Special cases if we have provided a MAC header:
|
||||||
* just leave it alone.
|
* + if the rule does not contain IP addresses/ports, do not print them;
|
||||||
* Also, if we have providea a MAC header and no IP protocol, print it
|
* + if the rule does not contain an IP proto, print "all" instead of "ip";
|
||||||
* as "all" instead of "ip".
|
*
|
||||||
|
* Once we have 'have_options', IP header fields are printed as options.
|
||||||
*/
|
*/
|
||||||
#define HAVE_PROTO 0x0001
|
#define HAVE_PROTO 0x0001
|
||||||
#define HAVE_SRCIP 0x0002
|
#define HAVE_SRCIP 0x0002
|
||||||
#define HAVE_DSTIP 0x0004
|
#define HAVE_DSTIP 0x0004
|
||||||
#define HAVE_MAC 0x0008
|
#define HAVE_MAC 0x0008
|
||||||
#define HAVE_MACTYPE 0x0010
|
#define HAVE_MACTYPE 0x0010
|
||||||
|
#define HAVE_OPTIONS 0x8000
|
||||||
|
|
||||||
#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
|
#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
|
||||||
static void
|
static void
|
||||||
show_prerequisites(int *flags, int want)
|
show_prerequisites(int *flags, int want, int cmd)
|
||||||
{
|
{
|
||||||
if ( (*flags & (HAVE_MAC | HAVE_MACTYPE)) == HAVE_MAC) {
|
if ( (*flags & HAVE_IP) == HAVE_IP)
|
||||||
printf(" any"); /* MAC type */
|
*flags |= HAVE_OPTIONS;
|
||||||
*flags |= HAVE_MACTYPE;
|
|
||||||
|
if ( (*flags & (HAVE_MAC|HAVE_MACTYPE|HAVE_OPTIONS)) == HAVE_MAC &&
|
||||||
|
cmd != O_MAC_TYPE) {
|
||||||
|
/*
|
||||||
|
* mac-type was optimized out by the compiler,
|
||||||
|
* restore it
|
||||||
|
*/
|
||||||
|
printf(" any");
|
||||||
|
*flags |= HAVE_MACTYPE | HAVE_OPTIONS;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( !(*flags & HAVE_OPTIONS)) {
|
||||||
|
if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
|
||||||
|
printf(" ip");
|
||||||
|
if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
|
||||||
|
printf(" from any");
|
||||||
|
if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP))
|
||||||
|
printf(" to any");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
|
|
||||||
printf( (*flags & HAVE_MAC) ? " all" : " ip");
|
|
||||||
if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
|
|
||||||
printf(" from any");
|
|
||||||
if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP))
|
|
||||||
printf(" to any");
|
|
||||||
*flags |= want;
|
*flags |= want;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,8 +847,7 @@ show_ipfw(struct ip_fw *rule)
|
|||||||
switch(cmd->opcode) {
|
switch(cmd->opcode) {
|
||||||
case O_CHECK_STATE:
|
case O_CHECK_STATE:
|
||||||
printf("check-state");
|
printf("check-state");
|
||||||
/* avoid printing anything else */
|
flags = HAVE_IP; /* avoid printing anything else */
|
||||||
flags = HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_PROB:
|
case O_PROB:
|
||||||
@ -898,47 +926,59 @@ show_ipfw(struct ip_fw *rule)
|
|||||||
else
|
else
|
||||||
printf(" log");
|
printf(" log");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* then print the body
|
* then print the body.
|
||||||
*/
|
*/
|
||||||
|
if (rule->_pad & 1) { /* empty rules before options */
|
||||||
|
printf (" all from any to any");
|
||||||
|
flags |= HAVE_IP | HAVE_OPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
for (l = rule->act_ofs, cmd = rule->cmd ;
|
for (l = rule->act_ofs, cmd = rule->cmd ;
|
||||||
l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
|
l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
|
||||||
/* useful alias */
|
/* useful alias */
|
||||||
ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
|
ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
|
||||||
|
|
||||||
|
show_prerequisites(&flags, 0, cmd->opcode);
|
||||||
|
|
||||||
switch(cmd->opcode) {
|
switch(cmd->opcode) {
|
||||||
case O_PROBE_STATE:
|
case O_PROBE_STATE:
|
||||||
break; /* no need to print anything here */
|
break; /* no need to print anything here */
|
||||||
|
|
||||||
case O_MACADDR2: {
|
case O_MACADDR2: {
|
||||||
ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
|
ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
|
||||||
if ( (flags & HAVE_MAC) == 0)
|
|
||||||
printf(" MAC");
|
if ((cmd->len & F_OR) && !or_block)
|
||||||
flags |= HAVE_MAC;
|
printf(" {");
|
||||||
if (cmd->len & F_NOT)
|
if (cmd->len & F_NOT)
|
||||||
printf(" not");
|
printf(" not");
|
||||||
|
printf(" MAC");
|
||||||
|
flags |= HAVE_MAC;
|
||||||
print_mac( m->addr, m->mask);
|
print_mac( m->addr, m->mask);
|
||||||
print_mac( m->addr + 6, m->mask + 6);
|
print_mac( m->addr + 6, m->mask + 6);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_MAC_TYPE:
|
case O_MAC_TYPE:
|
||||||
if ( (flags & HAVE_MAC) == 0)
|
if ((cmd->len & F_OR) && !or_block)
|
||||||
printf(" MAC");
|
printf(" {");
|
||||||
flags |= (HAVE_MAC | HAVE_MACTYPE);
|
print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE,
|
||||||
print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE);
|
(flags & HAVE_OPTIONS) ? cmd->opcode : 0);
|
||||||
|
flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_IP_SRC:
|
case O_IP_SRC:
|
||||||
case O_IP_SRC_MASK:
|
case O_IP_SRC_MASK:
|
||||||
case O_IP_SRC_ME:
|
case O_IP_SRC_ME:
|
||||||
case O_IP_SRC_SET:
|
case O_IP_SRC_SET:
|
||||||
show_prerequisites(&flags, HAVE_PROTO);
|
show_prerequisites(&flags, HAVE_PROTO, 0);
|
||||||
if (!(flags & HAVE_SRCIP))
|
if (!(flags & HAVE_SRCIP))
|
||||||
printf(" from");
|
printf(" from");
|
||||||
if ((cmd->len & F_OR) && !or_block)
|
if ((cmd->len & F_OR) && !or_block)
|
||||||
printf(" {");
|
printf(" {");
|
||||||
print_ip((ipfw_insn_ip *)cmd);
|
print_ip((ipfw_insn_ip *)cmd,
|
||||||
|
(flags & HAVE_OPTIONS) ? " src-ip" : "");
|
||||||
flags |= HAVE_SRCIP;
|
flags |= HAVE_SRCIP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -946,23 +986,24 @@ show_ipfw(struct ip_fw *rule)
|
|||||||
case O_IP_DST_MASK:
|
case O_IP_DST_MASK:
|
||||||
case O_IP_DST_ME:
|
case O_IP_DST_ME:
|
||||||
case O_IP_DST_SET:
|
case O_IP_DST_SET:
|
||||||
show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP);
|
show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
|
||||||
if (!(flags & HAVE_DSTIP))
|
if (!(flags & HAVE_DSTIP))
|
||||||
printf(" to");
|
printf(" to");
|
||||||
if ((cmd->len & F_OR) && !or_block)
|
if ((cmd->len & F_OR) && !or_block)
|
||||||
printf(" {");
|
printf(" {");
|
||||||
print_ip((ipfw_insn_ip *)cmd);
|
print_ip((ipfw_insn_ip *)cmd,
|
||||||
|
(flags & HAVE_OPTIONS) ? " dst-ip" : "");
|
||||||
flags |= HAVE_DSTIP;
|
flags |= HAVE_DSTIP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_IP_DSTPORT:
|
case O_IP_DSTPORT:
|
||||||
show_prerequisites(&flags,
|
show_prerequisites(&flags, HAVE_IP, 0);
|
||||||
HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP);
|
|
||||||
case O_IP_SRCPORT:
|
case O_IP_SRCPORT:
|
||||||
show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP);
|
show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
|
||||||
if ((cmd->len & F_OR) && !or_block)
|
if ((cmd->len & F_OR) && !or_block)
|
||||||
printf(" {");
|
printf(" {");
|
||||||
print_newports((ipfw_insn_u16 *)cmd, proto);
|
print_newports((ipfw_insn_u16 *)cmd, proto,
|
||||||
|
(flags & HAVE_OPTIONS) ? cmd->opcode : 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_PROTO: {
|
case O_PROTO: {
|
||||||
@ -974,6 +1015,8 @@ show_ipfw(struct ip_fw *rule)
|
|||||||
printf(" not");
|
printf(" not");
|
||||||
proto = cmd->arg1;
|
proto = cmd->arg1;
|
||||||
pe = getprotobynumber(cmd->arg1);
|
pe = getprotobynumber(cmd->arg1);
|
||||||
|
if (flags & HAVE_OPTIONS)
|
||||||
|
printf(" proto");
|
||||||
if (pe)
|
if (pe)
|
||||||
printf(" %s", pe->p_name);
|
printf(" %s", pe->p_name);
|
||||||
else
|
else
|
||||||
@ -983,8 +1026,7 @@ show_ipfw(struct ip_fw *rule)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default: /*options ... */
|
default: /*options ... */
|
||||||
show_prerequisites(&flags,
|
show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0);
|
||||||
HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP);
|
|
||||||
if ((cmd->len & F_OR) && !or_block)
|
if ((cmd->len & F_OR) && !or_block)
|
||||||
printf(" {");
|
printf(" {");
|
||||||
if (cmd->len & F_NOT && cmd->opcode != O_IN)
|
if (cmd->len & F_NOT && cmd->opcode != O_IN)
|
||||||
@ -1137,7 +1179,7 @@ show_ipfw(struct ip_fw *rule)
|
|||||||
or_block = 0;
|
or_block = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP);
|
show_prerequisites(&flags, HAVE_IP, 0);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
@ -2280,10 +2322,10 @@ fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, u_int16_t arg)
|
|||||||
static ipfw_insn *
|
static ipfw_insn *
|
||||||
add_mac(ipfw_insn *cmd, int ac, char *av[])
|
add_mac(ipfw_insn *cmd, int ac, char *av[])
|
||||||
{
|
{
|
||||||
ipfw_insn_mac *mac; /* also *src */
|
ipfw_insn_mac *mac;
|
||||||
|
|
||||||
if (ac <2)
|
if (ac < 2)
|
||||||
errx(EX_DATAERR, "MAC dst src [type]");
|
errx(EX_DATAERR, "MAC dst src [not] type");
|
||||||
|
|
||||||
cmd->opcode = O_MACADDR2;
|
cmd->opcode = O_MACADDR2;
|
||||||
cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac);
|
cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac);
|
||||||
@ -2291,17 +2333,84 @@ add_mac(ipfw_insn *cmd, int ac, char *av[])
|
|||||||
mac = (ipfw_insn_mac *)cmd;
|
mac = (ipfw_insn_mac *)cmd;
|
||||||
get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */
|
get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */
|
||||||
get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */
|
get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */
|
||||||
|
|
||||||
if (ac>2 && strcmp(av[2], "any") != 0) { /* we have a non-null type */
|
|
||||||
cmd += F_LEN(cmd);
|
|
||||||
|
|
||||||
fill_newports((ipfw_insn_u16 *)cmd, av[2], IPPROTO_ETHERTYPE);
|
|
||||||
cmd->opcode = O_MAC_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ipfw_insn *
|
||||||
|
add_mactype(ipfw_insn *cmd, int ac, char *av)
|
||||||
|
{
|
||||||
|
if (ac < 1)
|
||||||
|
errx(EX_DATAERR, "missing MAC type");
|
||||||
|
if (strcmp(av, "any") != 0) { /* we have a non-null type */
|
||||||
|
fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);
|
||||||
|
cmd->opcode = O_MAC_TYPE;
|
||||||
|
return cmd;
|
||||||
|
} else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ipfw_insn *
|
||||||
|
add_proto(ipfw_insn *cmd, char *av)
|
||||||
|
{
|
||||||
|
struct protoent *pe;
|
||||||
|
u_char proto = 0;
|
||||||
|
|
||||||
|
if (!strncmp(av, "all", strlen(av)))
|
||||||
|
; /* same as "ip" */
|
||||||
|
else if ((proto = atoi(av)) > 0)
|
||||||
|
; /* all done! */
|
||||||
|
else if ((pe = getprotobyname(av)) != NULL)
|
||||||
|
proto = pe->p_proto;
|
||||||
|
else
|
||||||
|
errx(EX_DATAERR, "invalid protocol ``%s''", av);
|
||||||
|
if (proto != IPPROTO_IP)
|
||||||
|
fill_cmd(cmd, O_PROTO, 0, proto);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ipfw_insn *
|
||||||
|
add_srcip(ipfw_insn *cmd, char *av)
|
||||||
|
{
|
||||||
|
fill_ip((ipfw_insn_ip *)cmd, av);
|
||||||
|
if (cmd->opcode == O_IP_DST_SET) /* set */
|
||||||
|
cmd->opcode = O_IP_SRC_SET;
|
||||||
|
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */
|
||||||
|
cmd->opcode = O_IP_SRC_ME;
|
||||||
|
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */
|
||||||
|
cmd->opcode = O_IP_SRC;
|
||||||
|
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_ip)) /* addr/mask */
|
||||||
|
cmd->opcode = O_IP_SRC_MASK;
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ipfw_insn *
|
||||||
|
add_dstip(ipfw_insn *cmd, char *av)
|
||||||
|
{
|
||||||
|
fill_ip((ipfw_insn_ip *)cmd, av);
|
||||||
|
if (cmd->opcode == O_IP_DST_SET) /* set */
|
||||||
|
;
|
||||||
|
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */
|
||||||
|
cmd->opcode = O_IP_DST_ME;
|
||||||
|
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */
|
||||||
|
cmd->opcode = O_IP_DST;
|
||||||
|
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_ip)) /* addr/mask */
|
||||||
|
cmd->opcode = O_IP_DST_MASK;
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ipfw_insn *
|
||||||
|
add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
|
||||||
|
{
|
||||||
|
if (!strncmp(av, "any", strlen(av))) {
|
||||||
|
return NULL;
|
||||||
|
} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
|
||||||
|
/* XXX todo: check that we have a protocol with ports */
|
||||||
|
cmd->opcode = opcode;
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse arguments and assemble the microinstructions which make up a rule.
|
* Parse arguments and assemble the microinstructions which make up a rule.
|
||||||
* Rules are added into the 'rulebuf' and then copied in the correct order
|
* Rules are added into the 'rulebuf' and then copied in the correct order
|
||||||
@ -2326,13 +2435,13 @@ add(int ac, char *av[])
|
|||||||
static u_int32_t rulebuf[255], actbuf[255], cmdbuf[255];
|
static u_int32_t rulebuf[255], actbuf[255], cmdbuf[255];
|
||||||
|
|
||||||
ipfw_insn *src, *dst, *cmd, *action, *prev;
|
ipfw_insn *src, *dst, *cmd, *action, *prev;
|
||||||
|
ipfw_insn *first_cmd; /* first match pattern */
|
||||||
|
|
||||||
struct ip_fw *rule;
|
struct ip_fw *rule;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* various flags used to record that we entered some fields.
|
* various flags used to record that we entered some fields.
|
||||||
*/
|
*/
|
||||||
int have_mac = 0; /* set if we have a MAC address */
|
|
||||||
ipfw_insn *have_state = NULL; /* check-state or keep-state */
|
ipfw_insn *have_state = NULL; /* check-state or keep-state */
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
@ -2489,7 +2598,7 @@ add(int ac, char *av[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errx(EX_DATAERR, "invalid action %s\n", *av);
|
errx(EX_DATAERR, "invalid action %s\n", av[-1]);
|
||||||
}
|
}
|
||||||
action = next_cmd(action);
|
action = next_cmd(action);
|
||||||
|
|
||||||
@ -2563,43 +2672,51 @@ add(int ac, char *av[])
|
|||||||
} \
|
} \
|
||||||
CLOSE_PAR;
|
CLOSE_PAR;
|
||||||
|
|
||||||
|
first_cmd = cmd;
|
||||||
|
/*
|
||||||
|
* MAC addresses, optional.
|
||||||
|
* If we have this, we skip the part "proto from src to dst"
|
||||||
|
* and jump straight to the option parsing.
|
||||||
|
*/
|
||||||
|
NOT_BLOCK;
|
||||||
|
NEED1("missing protocol");
|
||||||
|
if (!strncmp(*av, "MAC", strlen(*av)) ||
|
||||||
|
!strncmp(*av, "mac", strlen(*av))) {
|
||||||
|
ac--; av++; /* the "MAC" keyword */
|
||||||
|
add_mac(cmd, ac, av); /* exits in case of errors */
|
||||||
|
cmd = next_cmd(cmd);
|
||||||
|
ac -= 2; av += 2; /* dst-mac and src-mac */
|
||||||
|
NOT_BLOCK;
|
||||||
|
NEED1("missing mac type");
|
||||||
|
if (add_mactype(cmd, ac, av[0]))
|
||||||
|
cmd = next_cmd(cmd);
|
||||||
|
ac--; av++; /* any or mac-type */
|
||||||
|
goto read_options;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* protocol, mandatory
|
* protocol, mandatory
|
||||||
*/
|
*/
|
||||||
OR_START(get_proto);
|
OR_START(get_proto);
|
||||||
NOT_BLOCK;
|
NOT_BLOCK;
|
||||||
NEED1("missing protocol");
|
NEED1("missing protocol");
|
||||||
{
|
if (add_proto(cmd, *av)) {
|
||||||
struct protoent *pe;
|
av++; ac--;
|
||||||
|
if (F_LEN(cmd) == 0) /* plain IP */
|
||||||
if (!strncmp(*av, "all", strlen(*av)))
|
proto = 0;
|
||||||
; /* same as "ip" */
|
else {
|
||||||
else if (!strncmp(*av, "MAC", strlen(*av))) {
|
proto = cmd->arg1;
|
||||||
cmd = add_mac(cmd, ac-1, av+1); /* exits in case of errors */
|
prev = cmd;
|
||||||
av += 3;
|
cmd = next_cmd(cmd);
|
||||||
ac -= 3;
|
}
|
||||||
have_mac = 1;
|
|
||||||
} else if ((proto = atoi(*av)) > 0)
|
|
||||||
; /* all done! */
|
|
||||||
else if ((pe = getprotobyname(*av)) != NULL)
|
|
||||||
proto = pe->p_proto;
|
|
||||||
else
|
|
||||||
errx(EX_DATAERR, "invalid protocol ``%s''", *av);
|
|
||||||
av++; ac--;
|
|
||||||
if (proto != IPPROTO_IP)
|
|
||||||
fill_cmd(cmd, O_PROTO, 0, proto);
|
|
||||||
}
|
}
|
||||||
cmd = next_cmd(cmd);
|
|
||||||
OR_BLOCK(get_proto);
|
OR_BLOCK(get_proto);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "from", mandatory (unless we have a MAC address)
|
* "from", mandatory
|
||||||
*/
|
*/
|
||||||
if (!ac || strncmp(*av, "from", strlen(*av))) {
|
if (!ac || strncmp(*av, "from", strlen(*av)))
|
||||||
if (have_mac) /* we do not need a "to" address */
|
|
||||||
goto read_to;
|
|
||||||
errx(EX_USAGE, "missing ``from''");
|
errx(EX_USAGE, "missing ``from''");
|
||||||
}
|
|
||||||
ac--; av++;
|
ac--; av++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2608,51 +2725,33 @@ add(int ac, char *av[])
|
|||||||
OR_START(source_ip);
|
OR_START(source_ip);
|
||||||
NOT_BLOCK; /* optional "not" */
|
NOT_BLOCK; /* optional "not" */
|
||||||
NEED1("missing source address");
|
NEED1("missing source address");
|
||||||
|
if (add_srcip(cmd, *av)) {
|
||||||
/* source -- mandatory */
|
ac--; av++;
|
||||||
fill_ip((ipfw_insn_ip *)cmd, *av);
|
if (F_LEN(cmd) != 0) { /* ! any */
|
||||||
if (cmd->opcode == O_IP_DST_SET) /* set */
|
prev = cmd;
|
||||||
cmd->opcode = O_IP_SRC_SET;
|
cmd = next_cmd(cmd);
|
||||||
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */
|
}
|
||||||
cmd->opcode = O_IP_SRC_ME;
|
}
|
||||||
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */
|
|
||||||
cmd->opcode = O_IP_SRC;
|
|
||||||
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_ip)) /* addr/mask */
|
|
||||||
cmd->opcode = O_IP_SRC_MASK;
|
|
||||||
/* otherwise len will be zero and the command skipped */
|
|
||||||
ac--; av++;
|
|
||||||
prev = cmd; /* in case we need to backtrack */
|
|
||||||
cmd = next_cmd(cmd);
|
|
||||||
OR_BLOCK(source_ip);
|
OR_BLOCK(source_ip);
|
||||||
|
|
||||||
OR_START(source_port);
|
|
||||||
/*
|
/*
|
||||||
* source ports, optional
|
* source ports, optional
|
||||||
*/
|
*/
|
||||||
NOT_BLOCK; /* optional "not" */
|
NOT_BLOCK; /* optional "not" */
|
||||||
if (ac) {
|
if (ac) {
|
||||||
if (!strncmp(*av, "any", strlen(*av))) {
|
if (!strncmp(*av, "any", strlen(*av)) ||
|
||||||
ac--;
|
add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
|
||||||
av++;
|
ac--; av++;
|
||||||
} else if (fill_newports((ipfw_insn_u16 *)cmd, *av, proto)) {
|
if (F_LEN(cmd) != 0)
|
||||||
/* XXX todo: check that we have a protocol with ports */
|
cmd = next_cmd(cmd);
|
||||||
cmd->opcode = O_IP_SRCPORT;
|
|
||||||
ac--;
|
|
||||||
av++;
|
|
||||||
cmd = next_cmd(cmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OR_BLOCK(source_port);
|
|
||||||
|
|
||||||
read_to:
|
|
||||||
/*
|
/*
|
||||||
* "to", mandatory (unless we have a MAC address
|
* "to", mandatory
|
||||||
*/
|
*/
|
||||||
if (!ac || strncmp(*av, "to", strlen(*av))) {
|
if (!ac || strncmp(*av, "to", strlen(*av)))
|
||||||
if (have_mac)
|
|
||||||
goto read_options;
|
|
||||||
errx(EX_USAGE, "missing ``to''");
|
errx(EX_USAGE, "missing ``to''");
|
||||||
}
|
|
||||||
av++; ac--;
|
av++; ac--;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2661,41 +2760,36 @@ add(int ac, char *av[])
|
|||||||
OR_START(dest_ip);
|
OR_START(dest_ip);
|
||||||
NOT_BLOCK; /* optional "not" */
|
NOT_BLOCK; /* optional "not" */
|
||||||
NEED1("missing dst address");
|
NEED1("missing dst address");
|
||||||
fill_ip((ipfw_insn_ip *)cmd, *av);
|
if (add_dstip(cmd, *av)) {
|
||||||
if (cmd->opcode == O_IP_DST_SET) /* set */
|
ac--; av++;
|
||||||
;
|
if (F_LEN(cmd) != 0) { /* ! any */
|
||||||
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */
|
prev = cmd;
|
||||||
cmd->opcode = O_IP_DST_ME;
|
cmd = next_cmd(cmd);
|
||||||
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */
|
}
|
||||||
cmd->opcode = O_IP_DST;
|
}
|
||||||
else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_ip)) /* addr/mask */
|
|
||||||
cmd->opcode = O_IP_DST_MASK;
|
|
||||||
ac--;
|
|
||||||
av++;
|
|
||||||
prev = cmd;
|
|
||||||
cmd = next_cmd(cmd);
|
|
||||||
OR_BLOCK(dest_ip);
|
OR_BLOCK(dest_ip);
|
||||||
|
|
||||||
OR_START(dest_port);
|
|
||||||
/*
|
/*
|
||||||
* dest. ports, optional
|
* dest. ports, optional
|
||||||
*/
|
*/
|
||||||
NOT_BLOCK; /* optional "not" */
|
NOT_BLOCK; /* optional "not" */
|
||||||
if (ac) {
|
if (ac) {
|
||||||
if (!strncmp(*av, "any", strlen(*av))) {
|
if (!strncmp(*av, "any", strlen(*av)) ||
|
||||||
ac--;
|
add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
|
||||||
av++;
|
ac--; av++;
|
||||||
} else if (fill_newports((ipfw_insn_u16 *)cmd, *av, proto)) {
|
if (F_LEN(cmd) != 0)
|
||||||
/* XXX todo: check that we have a protocol with ports */
|
cmd = next_cmd(cmd);
|
||||||
cmd->opcode = O_IP_DSTPORT;
|
|
||||||
ac--;
|
|
||||||
av++;
|
|
||||||
cmd += F_LEN(cmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OR_BLOCK(dest_port);
|
|
||||||
|
|
||||||
read_options:
|
read_options:
|
||||||
|
if (ac && first_cmd == cmd) {
|
||||||
|
/*
|
||||||
|
* nothing specified so far, store in the rule to ease
|
||||||
|
* printout later.
|
||||||
|
*/
|
||||||
|
rule->_pad = 1;
|
||||||
|
}
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
while (ac) {
|
while (ac) {
|
||||||
char *s;
|
char *s;
|
||||||
@ -2735,6 +2829,7 @@ add(int ac, char *av[])
|
|||||||
if (!open_par)
|
if (!open_par)
|
||||||
errx(EX_USAGE, "+missing \")\"\n");
|
errx(EX_USAGE, "+missing \")\"\n");
|
||||||
open_par = 0;
|
open_par = 0;
|
||||||
|
prev = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_IN:
|
case TOK_IN:
|
||||||
@ -2940,6 +3035,62 @@ add(int ac, char *av[])
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_PROTO:
|
||||||
|
NEED1("missing protocol");
|
||||||
|
if (add_proto(cmd, *av)) {
|
||||||
|
proto = cmd->arg1;
|
||||||
|
ac--; av++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_SRCIP:
|
||||||
|
NEED1("missing source IP");
|
||||||
|
if (add_srcip(cmd, *av)) {
|
||||||
|
ac--; av++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_DSTIP:
|
||||||
|
NEED1("missing destination IP");
|
||||||
|
if (add_dstip(cmd, *av)) {
|
||||||
|
ac--; av++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_SRCPORT:
|
||||||
|
NEED1("missing source port");
|
||||||
|
if (!strncmp(*av, "any", strlen(*av)) ||
|
||||||
|
add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
|
||||||
|
ac--; av++;
|
||||||
|
} else
|
||||||
|
errx(EX_DATAERR, "invalid source port %s", *av);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_DSTPORT:
|
||||||
|
NEED1("missing destination port");
|
||||||
|
if (!strncmp(*av, "any", strlen(*av)) ||
|
||||||
|
add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
|
||||||
|
ac--; av++;
|
||||||
|
} else
|
||||||
|
errx(EX_DATAERR, "invalid destination port %s",
|
||||||
|
*av);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_MAC:
|
||||||
|
if (ac < 2)
|
||||||
|
errx(EX_USAGE, "MAC dst-mac src-mac");
|
||||||
|
if (add_mac(cmd, ac, av)) {
|
||||||
|
ac -= 2; av += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_MACTYPE:
|
||||||
|
NEED1("missing mac type");
|
||||||
|
if (!add_mactype(cmd, ac, *av))
|
||||||
|
errx(EX_DATAERR, "invalid mac type %s", av);
|
||||||
|
ac--; av++;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
|
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user