ipfw with nat - allowing by MAC address

Patrick Tracanelli eksffa at freebsdbrasil.com.br
Mon Apr 23 00:31:34 UTC 2007


I could not understand Joao's statement, so I tend to disagree that 
there is no layer2 traffic flowing on a NAT box. Makes no sense to me. I 
am sure it is possible to do all 2 sub-layer layer 2 filtering (MAC and 
LLC).

So I have just tried what you are willing to get working Lubomir, right 
now in the network I am.

My current enviroment is the simplest the possible:

[ 10.69.0.0/16 network ] <=> [ switch ] <=> [FreeBSD] <=> [Internet]

My external interface is vr0
My internal one is xl0

I have just allowed two stations to go to the DIVERT (natd) rules by 
using skipto approach, and all other machines are not skipped, so they 
tend to match an intermediary rule which does deny all traffic based on 
layer2. I kept only the relevant rules so it gets very clear to understand:

# ipfw show
00300   688   62538 skipto 1000 ip from any to any { MAC any 
08:00:46:bd:da:a3 or MAC any 00:17:31:df:bc:ab } layer2
00310   637   84252 skipto 1000 ip from any to any { MAC 
08:00:46:bd:da:a3 any or MAC 00:17:31:df:bc:ab any } layer2
00500   468   30071 deny log logamount 100 ip from any to any MAC any 
any layer2 via xl0
01000   527   50710 divert 8668 ip from 10.69.0.0/16 to any out via vr0
01100   556   68585 divert 8668 ip from any to me in via vr0
65535 14642 1214437 allow ip from any to any

In case ipfw list may be clearer:

# ipfw list
00300 skipto 1000 ip from any to any { MAC any 08:00:46:bd:da:a3 or MAC 
any 00:17:31:df:bc:ab } layer2
00310 skipto 1000 ip from any to any { MAC 08:00:46:bd:da:a3 any or MAC 
00:17:31:df:bc:ab any } layer2
00500 deny log logamount 100 ip from any to any MAC any any layer2 via xl0
01000 divert 8668 ip from 10.69.0.0/16 to any out via vr0
01100 divert 8668 ip from any to me in via vr0
65535 allow ip from any to any

Some relevant information: I am doing selective divert based on my 
network, on vr0 (external interface) while explicitly denying all layer2 
traffic based on mac, on rule 500, only on xl0 (internal network), 
because if I do it on all networks or on vr0, I will certainy deny my 
own outgoing packets.

So it worked perfectly, and right now while I send this message only the 
two MAC addresses are allowed to get diverted to natd (and go to internet).

As you can see, some traficc is still hitting rule # 500, so I want to 
know what it is:

# grep 500 /var/log/security | tail -5
Apr 22 19:54:32 HomerSimpson kernel: ipfw: 500 Deny UDP 
208.239.76.163:5060 10.69.69.39:5060 out via xl0
Apr 22 19:54:33 HomerSimpson kernel: ipfw: 500 Deny MAC in via xl0
Apr 22 19:54:36 HomerSimpson kernel: ipfw: 500 Deny UDP 
208.239.76.163:5060 10.69.69.39:5060 out via xl0
Apr 22 19:54:37 HomerSimpson kernel: ipfw: 500 Deny MAC in via xl0
Apr 22 19:54:50 HomerSimpson kernel: ipfw: limit 100 reached on entry 500

So, it is IP 10.69.69.39, which for sure has a different MAC address:

# arp 10.69.69.39
? (10.69.69.39) at 00:12:17:fb:ee:e7 on xl0 [ethernet]

You also said you wanted allow other stations to talk to the gateway, 
what in the above examples, I am not allowing, so for example if I add 
rule 400 like this:

# ipfw add 400 allow all from 10.69.0.0/16 to me via xl0 not layer2 
keep-state
00400 allow ip from 10.69.0.0/16 to me via xl0 not layer2 keep-state

I am certainly allowing any station on 10.69/16 network, regardless of 
its IP address (unless it is on 10.69/16 network) or MAC address (since 
I am not filtering on layer2):

# ipfw show
00300  2544  519800 skipto 1000 ip from any to any { MAC any 
08:00:46:bd:da:a3 or MAC any 00:17:31:df:bc:ab } layer2
00310  2415  601710 skipto 1000 ip from any to any { MAC 
08:00:46:bd:da:a3 any or MAC 00:17:31:df:bc:ab any } layer2
00400    29    2548 allow ip from 10.69.0.0/16 to me via xl0 not layer2 
keep-state
00500  1236   65813 deny log logamount 100 ip from any to any MAC any 
any layer2 via xl0
01000  1904  469946 divert 8668 ip from 10.69.0.0/16 to any out via vr0
01100  2049  525859 divert 8668 ip from any to me in via vr0
65535 42049 5911000 allow ip from any to any

Since ipfw is a first-match-based firewall you don't need to worry about 
this "allow from any to any" rule, because the hosts which get to this 
rule certainly were not skipped on the later rules, so they simply never 
get diverted, because they match on this "allow" and divert rules 
happens AFTER the allow.

Lets see who is matching rule # 400 (which is a keep-state rule, so it 
is generating dynamic state rules):

## Dynamic rules (2):
00400     1     100 (1s) STATE tcp 10.69.2.40 59235 <-> 10.69.2.1 22
00400     0       0 (0s) STATE udp 10.69.69.13 59577 <-> 10.69.69.1 53

Both 10.69.2.1 and 10.69.69.1 are "me" (the firewall itself). So just 
perfect, anyone can freely go through the private network, in the above 
dynamic we see an ssh session and an expired DNS query to the firewall 
which for sure is also the DNS server for the network).

Last thing, remember to enabled ethernet filtering on IPFW:

sysctl -w net.link.ether.ipfw=1

If not, no layer2 filtering will be processed at all.

Also, when doing layer2 filtering, remember that the default IPFW 
behavior is to filter layer3 and above layers, but when you set 
net.link.ether.ipfw to true, it does layer2 and above, so all traffic 
going via ether_demux() and ether_output_frame() gets filtered.

But the thing is that on the IP stack - /sys/net/if_ethersubr.c (where 
ether_demux() and ether_output_frame() happen) - layer2 traffic happen 
before the upper layers. So when doing ipfw layer firewall remember:

- layer2 rules will get processed first
- non layer specified rules will get processed two times, on layer2 and 
upper layers
- not layer2 (meaning all upper layers) will get processed only later

Hope this working example is a good start poing for your setup.



Lubomir Georgiev escreveu:
>  Thanks for the response but I have to disagree with you - I have read the
> responses time and time again with great attention, but to no avail. From
> what you said I understand that in order to utilize MAC address filtering I
> would need a managed switch or another box aside from the one that will be
> performing the NATing - is that right? Are you sure that there's no way to
> combine MAC filtering with NAT in a single box?
> 
>  Just to make things clear I'll give an example of what I want to do - I
> want a machine with say MAC-a to have internet connectivity regardless of
> its IP address - that is I can assign to it any of the
> 192.168.1.Xaddresses. But if a machine with say MAC-b comes into the
> network and tries
> any IP I want it to be excluded from the NATd  rule but still have
> connectivity with the FreeBSD box - so that I can open up a terminal and 
> add
> it to the rulelist if I want Inet connectivity on that machine.
> 
> 
> 
> P.S. I have heard of another way of filtering which uses the ARP tables -
> any comments on that? The thing that I don't think I'll be able to
> accomplish with the ARP tables is to use any of the 192.168.1.X IP
> addresses.
> 
> Once again thanks for all your help and I hope we can reach the final
> conclusion of this problem.
> 


-- 
Patrick Tracanelli

FreeBSD Brasil LTDA.
(31) 3281-9633 / 3281-3547
316601 at sip.freebsdbrasil.com.br
http://www.freebsdbrasil.com.br
"Long live Hanin Elias, Kim Deal!"



More information about the freebsd-ipfw mailing list