ipfw "bug" - recv any = not recv any
Jeff Kletsky
jeff+freebsd at wagsky.com
Tue Jul 29 16:01:14 UTC 2008
The "recv any" = "not recv any" = noop behavior got me this weekend,
even after careful reading of the man page.
My situation is attempting to use "not recv any" to discriminate
between packets generated by the host from those being routed through
the host. It is reasonably easy to confirm that, at least in
7.0-RELEASE-p3, "recv any" and "not recv any" are both behaving as
no-ops in the ipfw syntax.
This was discussed to some extent in the post and related thread:
<http://lists.freebsd.org/mailman/htdig/freebsd-ipfw/2005-August/001969.html>
Luigi Rizzo wrote:
> ok, so the problem is the following: when i implemented ipfw2
> i thought that 'recv any' or 'xmit any' were effectively NOPs
> so the parser erroneously removes them, together with any 'not' prefix
> (which is processed before).
>
> To fix this one should
> - patch the function ipfw2.c:fill_iface()
> so that an argument of 'any' puts some special pattern
> in the ipfw_insn_if (e.g. an * in the first char of name[]
> should suffice as i doubt it is a legal interface name).
>
> [...]
While there are ways to do this (e.g., tagging, or "[not] recv *"),
I would suggest at least clarification of the documentation.
At this point, I suspect that there are enough "overly cautious" rule
writers that have included "recv any" in their now-deployed rules that
(properly for them) match both externally and internally generated
packets that changing "recv any" to only match packets that were
received would break more things than it fixes. Changing the parsing
of "not recv any" to produce the code behind "not recv *" would be
"less dangerous" and might be considered at some time.
Let me preface this by saying that I don't know the internals of ipfw2
well enough to confirm that a doc change like this matches the
operation of the code, but something along the lines of:
recv | xmit | via {ifX | if* | ipno | * }
Matches packets received, transmitted or going through,
respec-
tively, the interface specified by exact name (ifX), by device
name (if*), by IP address, or through some interface (*).
The via keyword causes the interface to always be checked. If
recv or xmit is used instead of via, then only the receive or
transmit interface (respectively) is checked. By specifying
both, it is possible to match packets based on both receive and
transmit interface, e.g.:
ipfw add deny ip from any to any out recv ed0 xmit ed1
The recv interface can be tested on either incoming or outgoing
packets, while the xmit interface can only be tested on outgoing
packets. So out is required (and in is invalid) whenever xmit is
used.
A packet may not have a receive or transmit interface: packets
originating from the local host have no receive interface, while
packets destined for the local host have no transmit interface.
To match packets that have no receive interface, the construct
"not recv *" may be used.
The constructs "recv any" and "not recv any" are presently both
treated equivalently as a match-all condition and both are stripped
during parsing. This behavior, especially of the latter, is subject
to change in future releases, and is not suggested for new rule sets.
I hope this post at least helps the next person who trips across this.
I'm very open to ideas on how to clarify and/or improve the behavior.
I haven't looked into the other "any" matches to see if they have
similar behavior
that would benefit from additional documentation
Jeff
P.S. Thanks to Julian Elischer for suggesting "not recv *" as an approach.
More information about the freebsd-ipfw
mailing list