ipfw's "via" rule option/match pattern

andreas scherrer ascherrer at gmail.com
Mon Aug 24 21:29:24 UTC 2015


> In freebsd-questions Digest, Vol 585, Issue 3, Message: 9
> On Wed, 19 Aug 2015 00:41:35 +0200 andreas scherrer <ascherrer at gmail.com> wrote:

<snip>

>   > When I run a quick test, sending one ICMP echo request from
>   > 192.168.32.10 to 192.168.38.17 (two devices communicating via the box
>   > that has the "count" rules listed below configured), I get the following
>   > result:
>
> A good set of tests for all combinations.  Something else I saw recently
> made me doubt that my own understanding of this was correct, and your
> tests seem to confirm that I've been misadvising people for, oh, the
> best part of 10 years .. here's the code, which I've checked hasn't
> functionally changed at all since 2012, and little from 2002 with
> Luigi's first ip_fw2.c (tabs lost):
>
>                  case O_RECV:
>                          match = iface_match(m->m_pkthdr.rcvif,
>                              (ipfw_insn_if *)cmd, chain, &tablearg);
>                          break;
>
>                  case O_XMIT:
>                          match = iface_match(oif, (ipfw_insn_if *)cmd,
>                              chain, &tablearg);
>                          break;
>
>                  case O_VIA:
>                          match = iface_match(oif ? oif :
>                              m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd,
>                              chain, &tablearg);
>                          break;
>
> iface_match() (qv) does the test vs iface name or IP address, returning
> 1 on a match, but begins by returning 0 if the passed interface is NULL.
> In the case of O_VIA, if the outside iface is specified then that iface
> (only) is tested; the rcvif is only checked if there's NO out iface.
>
> This directly contradicts what I've been telling myself and others for
> years :( I guess what's amazing is that nobody who'd know better ever
> pulled me up on such statements, increasing confidence in wrongness :)
>
>   > -----
>   > When 192.168.38.17 does not answer the ping:
>   > 00350     2     168 count icmp from 192.168.32.10 to 192.168.38.17 recv re0.32
>   > 00350     0       0 count icmp from 192.168.38.17 to 192.168.32.10 recv re0.38
>   > 00351     1      84 count icmp from 192.168.32.10 to 192.168.38.17 in recv re0.32
>   > 00351     0       0 count icmp from 192.168.38.17 to 192.168.32.10 in recv re0.38
>   > 00352     1      84 count icmp from 192.168.32.10 to 192.168.38.17 out recv re0.32
>   > 00352     0       0 count icmp from 192.168.38.17 to 192.168.32.10 out recv re0.38
>   > 00355     1      84 count icmp from 192.168.32.10 to 192.168.38.17 via re0.32
>   > 00355     0       0 count icmp from 192.168.38.17 to 192.168.32.10 via re0.38
>   > 00356     1      84 count icmp from 192.168.32.10 to 192.168.38.17 in via re0.32
>   > 00356     0       0 count icmp from 192.168.38.17 to 192.168.32.10 in via re0.38
>   > 00357     0       0 count icmp from 192.168.32.10 to 192.168.38.17 out via re0.32
>   > 00357     0       0 count icmp from 192.168.38.17 to 192.168.32.10 out via re0.38
>   > 00358     1      84 count icmp from 192.168.32.10 to 192.168.38.17 out recv re0.32 xmit re0.38
>   > 00358     0       0 count icmp from 192.168.38.17 to 192.168.32.10 out recv re0.38 xmit re0.32
>   >
>   > When 192.168.38.17 does answer the ping:
>   > 00350     2     168 count icmp from 192.168.32.10 to 192.168.38.17 recv re0.32
>   > 00350     2     168 count icmp from 192.168.38.17 to 192.168.32.10 recv re0.38
>   > 00351     1      84 count icmp from 192.168.32.10 to 192.168.38.17 in recv re0.32
>   > 00351     1      84 count icmp from 192.168.38.17 to 192.168.32.10 in recv re0.38
>   > 00352     1      84 count icmp from 192.168.32.10 to 192.168.38.17 out recv re0.32
>   > 00352     1      84 count icmp from 192.168.38.17 to 192.168.32.10 out recv re0.38
>   > 00355     1      84 count icmp from 192.168.32.10 to 192.168.38.17 via re0.32
>   > 00355     1      84 count icmp from 192.168.38.17 to 192.168.32.10 via re0.38
>   > 00356     1      84 count icmp from 192.168.32.10 to 192.168.38.17 in via re0.32
>   > 00356     1      84 count icmp from 192.168.38.17 to 192.168.32.10 in via re0.38
>   > 00357     0       0 count icmp from 192.168.32.10 to 192.168.38.17 out via re0.32
>   > 00357     0       0 count icmp from 192.168.38.17 to 192.168.32.10 out via re0.38
>   > 00358     1      84 count icmp from 192.168.32.10 to 192.168.38.17 out recv re0.32 xmit re0.38
>   > 00358     1      84 count icmp from 192.168.38.17 to 192.168.32.10 out recv re0.38 xmit re0.32
>   > -----
>   >
>   > According to the statement in [4] I would expect rule 357 to match...
>
> Yes; [4] is clearly wrong in this respect.  'out via' does NOT check the
> receive interface if the transmit interface is known.

Thank you for your effort! I finally understand what I am doing here! 
Awesome!
To be honest I was looking for the code you pasted but was not able to 
find it. Now I know where to look.

In summary I think it would be reasonable to advise people to *not* use 
"via" in combination with "in" or "out".

"in via $if" => "in recv $if"
"out via $if" => "out xmit $if"

Unless there can be outgoing packets without an xmit interface; but I 
don't see what those would be good for.

Still looking for a use case for "via" (there must be a reason it 
exists, right?) "via" seems to make more sense when used *without* 
"in"/"out".

"via $if" matches packets that are either incoming on $if or outgoing on 
$if. The most prominent use case that comes to my mind for that would be 
NAT (hiding an RFC 1918 network):

nat X ip4 from any to any via $if

Assuming the above is correct and that I wanted to tackle the issue of 
rewriting the ipfw handbook section: how would I do that (i.e. how to 
submit a new version)?


Best regards
andreas


More information about the freebsd-ipfw mailing list