in via or in recv

Jeremie Le Hen jeremie at le-hen.org
Mon Sep 19 06:07:19 PDT 2005


Hi Martin,

> >This rule will apply on the outgoing path (because of "xmit") and will
> >let through all packets that arrived on fxp0 and then leave through sis0.
>
> Yep, but the rule is only executed on the outgoing phase because at
> the incoming phase, the xmit interfaces is unknown and as such,
> the rule does not match.
> 
> FreeBSD does have an IPFW option for single pass or regular handling
> of the packets. Single pass means: Only once through the firewall rules,
> done at arrival of the packet.
> 
> The regular handling is to call the firewall rules for each packet when the
> packet enters the computer and once when the packet is send out.
> The words "in" and "out" in the Firewall rules are intended to give the rule
> designer the opportunity to let a rule work on incoming or outgoing packets.
> 
> When a packet enters the PC, the outgoing interface is not known yet, so 
> the following rules do the same:
> 
> ipfw add allow ip from any to any in recv fxp0
> ipfw add allow ip from any to any in via fxp0

Until there, I agree.

> The following two rules do NOT (in general) behave the same:
> ipfw add allow ip from any to any out recv fxp0
> ipfw add allow ip from any to any out via fxp0
> 
> The second rule will also match packets coming in through (read "via") fxp0.

This is what I read numerous times on the archives indeed.  But I
checked the code myself :

http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet/ip_fw2.c?annotate=1.111

Here is a snap from line 2480 :
%	case O_RECV:
%		match = iface_match(m->m_pkthdr.rcvif,
%		    (ipfw_insn_if *)cmd);
%		break;
%
%	case O_XMIT:
%		match = iface_match(oif, (ipfw_insn_if *)cmd);
%		break;
%
%	case O_VIA:
%		match = iface_match(oif ? oif :
%		    m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd);
%		break;

What I understand for the "via" keyword is that when the output
interface is known, then it is matched against it, and nothing more.

The two rules you have used above are _not_ equivalent.  In the first
case we will match on the outgoing path, whatever the output interface
is, but when the input one was fxp0.

In the second rule, the "out" (== "not in") keyword make the rule apply
only on the outgoing path [1].  Therefore `oif' will be defined and
the output interface will be checked, whereas in the first rule this
was the input interface.

[1] "in" is implemented as :
%	case O_IN:	/* "out" is "not in" */
%		match = (oif == NULL);
%		break;

> Things get more complicated when the packet is "created" in the PC itself.

Still reading the implementation, I would say that packets generated
on the machine itself will have a NULL input interface, thus the
iface_match() function will never match (first statement in the function).

For what I understand, I would say that if you want to only match
packet generated locally, you should use something like this (although
it's quite tricky and does not perform very well due to the use of strings
function) :
% ipfw add allow all from any to any out not recv *

"recv *" will match every input interface, except when it's NULL.


Please, correct me if I'm wrong.
-- 
Jeremie Le Hen
< jeremie at le-hen dot org >< ttz at chchile dot org >


More information about the freebsd-ipfw mailing list