ipfw with nat - allowing by MAC address

Julian Elischer julian at elischer.org
Fri Apr 27 00:49:50 UTC 2007


Lubomir Georgiev wrote:
>  Yeah! People, we can congratulate ourselves! We've done it! With a few
> modifications I've finally found the smallest working MAC filtered NAT
> system. So here's what I ended up with - I'm including the queues just for
> the entirety of the ruleset, they have nothing to do with the filtering.

I presume xl0 is the inside interface?

here is how you should comment your script.

> 

# The following rules are applied at layer 2 and layer 3.
# Allow anything on the inside to talk to me directly if it wants to,
# * unless it wants to use port 8668  * (why 8668?)
ipfw add 00100 allow ip from any to me not dst-port 8668 via xl0
ipfw add 00101 allow ip from me not 8668 to any via xl0

#
# BTW also.. try not use the via keyword.. instead specify exactly what you want
# as it hides exactly what you are doing.. use in, out, recv and xmit
# (possibly in combination).

# Anything that is not to me directly is bound for the outside.
# At layer 2 we clobber any that are not 'blessed machines'.
 ipfw add 00300 "allow ip from any to any { MAC 00:19:d2:36:b8:48 any or MAC any 00:19:d2:36:b8:48 } layer2"
 ipfw add 00800 "deny log logamount 200 ip from any to any MAC any any layer2 via xl0"

# easier written as
# ipfw add 800 deny log logamount 200 ip from any to any layer2
 
# In layer 2 we have no more packets by this point.
# In layer 3, only packets that escaped layer 2 alive get diverted
 ipfw add 01203 divert 8668 ip from 192.168.1.0/24 to any out via fxp0
 ipfw add 01205 divert 8668 ip from any to me in via fxp0

# The rest is for conditionning the traffic on the external link


> 01250 queue 1 ip from any to any src-port 80 not layer2 via fxp0
> 01251 queue 1 ip from any to any dst-port 80 not layer2 via fxp0
> 01300 queue 2 ip from any to any not src-port 80 not layer2 via fxp0
> 01500 allow ip from any to any
> 65535 deny ip from any to any
> 
> 
>  Just one note - when I first reached this conclusion I had two very
> strange *blackouts*. As if the 100 and the 101 rule just suddenly stop
> working and I'm left out of the box e.g. I can't ssh in although the
> diverting still works - I can ping hosts on the Internet. It seems to be
> fine now and once I gain some knowledge I'm probably going to expand this
> ruleset, but for now I've accomplished my goal!
> 
>  I have all of you to thank for that! Even though it wasn't easy /mostly
> because of my ignorance I'm sure/ you pulled me through.
> 
> 
>  Respect.
> 
> 
> 
> 
>  One last request - if someone happens to have some free time and wishes to
> donate it to me I'd really like to better understand the whole *layer*
> thing. I have searched the Internet for answers on this as well as read the
> ipfw man page, but I can't really understand it.
> 
>  \/  Peace.


and here is how I would write it:
#!/bin/sh

INSIDE="xl0"
OUTSIDE="fxp0"
BLESSED_MAC="00:19:d2:36:b8:48"
OUTSIDE_IP="1.1.1.1"

#################################################
# START. ALL PACKETS FROM EVERYWHERE COME HERE. #
# A packet being routed comes here 4 times.     #
#################################################
# first split up the layer 2 packets and layer 3 packets
ipfw add 100 skipto 1000 ip from any to any not layer2

###############################################
# ###### START LAYER 2 PROCESSING #############
# this happens as the packet is traversing
# the ethernet driver.
# A routed packet comes here TWICE.
#
# In layer 2 just allow packets not traversing the inside 
# interface as we have no interest in other interfaces.
# Now split up incoming and outgoing.
ipfw add 110 skipto 120 ip from any to any in

######## PACKETS EXITING ${INSIDE} #############
# packet is exiting the INSIDE ethernet
# If it is not from us, and not to a blessed machine, kill it.
ipfw add 111 allow ip from any to any not xmit ${INSIDE}

#ipfw add 112 allow ip from me to any 
#ipfw add 113 allow ip from any to any MAC {$BLESSED_MAC} any
#ipfw add 114 deny ip from any to any

# this is actually pointless as there will be no such traffic,
# so in fact just allow everything.
ipfw add 112 allow ip from any to any

# ######## PACKETS COMING IN THROUGH ${INSIDE} ########
# If it is not to us, and not from a blessed machine, kill it.
ipfw add 120 allow ip from any to any not recv ${INSIDE}
ipfw add 122 allow ip from any to me
ipfw add 124 allow ip from any to any MAC any ${BLESSED_MAC}
ipfw add 126 deny log logamount 200 ip from any to any

######################################################
# END OF ALL LAYER 2 PROCESSING                      #
#                                                    #
# START LAYER 3 PROCESSING                           #
######################################################
# SPLIT FOR DIRECTION
ipfw add 1000 skipto 1500 ip from any to any in

# ########## OUTGOING PROCESSING ####################
# ignore everything not on "${OUTDSIDE}".. we just don't care.
# NAT anything that is not from my outside address.
ipfw add 1100 allow ip from any to any not xmit ${OUTSIDE}
ipfw add 1110 divert natd ip from not ${OUTSIDE_IP} to any

# Rate limit outgoing WEB packets to external servers (Mostly ACKS or POSTs)
ipfw add 1120 queue 1 tcp from any to any 80

# Rate limit outgoing WEB packets from INTERNAL servers to outside.
# (Assuming you have a server on this box, it would be real data).
ipfw add 1120 queue 2 tcp from any 80 to any

ipfw add 1130 allow ip from any to any

# ########### INCOMING PROCESSING ####################
#  Ignore anything not on ${OUTSIDE}
ipfw add 1500 allow ip from any to any not recv ${OUTSIDE}
# lets just be paranoid here.
ipfw add 1501 deny ip from any to not ${OUTSIDE_IP}

# anything remaining must be nat'd.
ipfw add 1510 divert natd ip from any to any

# rate limit incoming packets 
ipfw add 1520 queue 3 tcp from any to any 80 (POSTS and ACKS to your server)
ipfw add 1530 queue 4 tcp from any 80 to any (real download data)

# Protect your machine with more rules here
ipfw add 1550 allow ip from any to any

# end of ruleset

You may think that this is much more complicated than what you have, 
but it is MUCH more efficient. And, each rule is used for one and only one
thing. You can change a rule in one place and be sure you are not screwing up
what is going on somewhere else.
it only does processing on each packet that it has to.
Your rules are processing every rule for every packet for every interface 
for each direction..

I have not tested this however and I have a very small doubt about line 101..
it might have to be split to lines




More information about the freebsd-ipfw mailing list