OpenWrt Forum Archive

Topic: How to make DMZ work from within LAN?

The content of this topic has been archived on 8 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

OK, I've read the BFD (big fat disclaimer) in /etc/firewall.user.  -i $WAN ONLY matches packets that physically came from the $WAN interface, not from the LAN to the WAN address.  Accepted.  The question is, how can this be made to work without using -i $WAN?

Example scenario:
Web server on DMZ.  Configured iptables to use the DMZ rules provided by commented default in /etc/firewall.user.
Person on WAN asks for homepage.com, is directed to WAN IP, successfully sent to web server in LAN.  Good.
Person on LAN asks for homepage.com, is directed to WAN IP.  Router sees request coming from LAN, rules don't apply, unable to connect.  Bad.

So, this is what I tried, with no noticable effect.

WAN_IP=$(nvram get wan_ipaddr)
DMZ_IP=192.168.82.2

# Looking to allow requests from the LAN to the WAN IP to be forwarded just like the DMZ below...
iptables -t nat -A prerouting_rule -i $LAN -d $WAN_IP -j DNAT --to $DMZ_IP
iptables        -A forwarding_rule -i $LAN -d $DMZ_IP -j ACCEPT

### DMZ (should be placed after port forwarding / accept rules)
iptables -t nat -A prerouting_rule -i $WAN -j DNAT --to $DMZ_IP
iptables        -A forwarding_rule -i $WAN -d $DMZ_IP -j ACCEPT

Any ideas?  Thanks!!

One way is to just create a hosts file with an entry for homepage.com

- DL

I know this doesn't answer your exact question but I run shorewall and these lines in the rules file would give you what you want:

#
#       http access to the voidmain.is-a-geek.net
#
DNAT     net            dmz:172.16.210.2  tcp   80      -          $NET_IP
DNAT     loc            dmz:172.16.210.2  tcp   80      -          $NET_IP

My Server is in my dedicated DMZ on the 172.16.210.2 address and clients on my 192.168.x.x LAN network get to it via the public IP address along with WAN traffic.

If I look at my restore file I believe these are the actual iptables commands that set this up:

iptables -A loc2dmz -d 172.16.210.2 -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A net2dmz -d 172.16.210.2 -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -d 68.188.13.164 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.210.2
iptables -A loc_dnat -d 68.188.13.164 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.210.2
iptables -A net_dnat -d 68.188.13.164 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.210.2

Of course it's a little more complicated that because shorewall sets up special named filters for each zone and applies several other iptables rules to them so this isn't the entire picture in my case but I believe they are roughly the commands you need. In the above lines my public IP address is 68.188.13.164 and my web server in my DMZ is 172.16.210.2. Hopefully someone else can answer it fully with just iptables commands.

dl - Thanks, but I want it to work by IP, too - not just host name.

Void Main - I'll give this a try tomorrow - it looks promising.  (I'd do it now if it didn't involve so much translation.)  At first, it looked no different, but I see that you're not using the NAT tables at all, which was one of my suspicions.  What is that OUTPUT line for?

Misc note:  I was also interested in revslowmo's response at http://forum.openwrt.org/viewtopic.php?id=2460.  I hadn't considered that the request may also need to be post-routed.  However, after trying to add the postrouting entry, my requests still weren't going through from the LAN side.  Ideas??

Thanks for the quick responses!!

Actually the OUTPUT line should probably have not made it into this message. I also had a rule for fw2dmz that matched the loc2dmz and net2dmz and I believe it is associated with the fw2dmz. So you can probably ignore it. If you want the rest of my restore script to see all the rules I would be happy to send it to you but I would rather not post it here.

All you have to do is replace  "-i $WAN" with "-d x.x.x.x" and fill in the correct wan ip for x.x.x.x. The problem is this means that your ip can nolonger change; any time you get a new ip address you'd have to rerun the firewall.

Sorry, but the "-i $WAN" / "-d x.x.x.x" trick didn't work...  Still need to try Void Main's entries...

Oh .. right .. I suppose I should explain it better:

iptables -t nat -A prerouting_rule -d x.x.x.x -p tcp --dport 80 -j DNAT --to 10.0.0.2
iptables -A forwarding_rule -p tcp --dport 80 -d 10.0.0.2 -j ACCEPT
iptables -t nat -A postrouting_rule -s 10.0.0.0/24 -p tcp --dport 80 -d 10.0.0.2 -j MASQUERADE

x.x.x.x is my external IP address; I want it so when I connect to that IP address that it gets forwarded to my internal webserver which is 10.0.0.2. The problem is this:

request: 10.0.0.x (some random lan machine) -> x.x.x.x (external ip) -> 10.0.0.2 (websever)
response: 10.0.0.2 -> 10.0.0.x

I've connected to x.x.x.x but the response came from 10.0.0.2 .. oops. To correct this, a masquerade is done using the third rule. This has the unfortunate side effect of hiding the original source address, but it does correct the issue with the response. Since this only applies to machines on the lan subnet, I've added a -s; this allows proper logging of requests from outside the lan.

Well, as usual, mbm solved it.  (I'm trying to forward everything, not just tcp 80, so I removed those criteria.)

About "the unfortunate side effect of hiding the original source address", I did some testing on a Linksys router with the original firmware, with the same results - so they didn't do any better (not surprised).  If I understand your explanation correctly, the issue basically being that the "dmz box" was responding directly to the requestor, but the requestor was only expecting the response from the router (where it understood the request to be sent)?

Thanks!

(Last edited by ziesemer on 19 Jan 2006, 04:47)

ziesemer wrote:

About "the unfortunate side effect of hiding the original source address", I did some testing on a Linksys router with the original firmware, with the same results - so they didn't do any better (not surprised).  If I understand your explanation correctly, the issue basically being that the "dmz box" was responding directly to the requestor, but the requestor was only expecting the response from the router (where it understood the request to be sent)?

Yes, this is exactly the issue; when the webserver sees a request from the same subnet, the response is sent directly back to the source and not to the machine that did the redirect. So the MASQ rule is used to hide the original source address, replacing it with the address of the machine doing the redirect.

If you can force the webserver to send the response to the redirect then you don't need the MASQ rule and you'll see the proper source address. This can be done by either iptables commands on the webserver to dnat the respose, or by moving either the client or webserver to another subnet so direct communication between the webserver and client is impossible.

With the rules that shorewall uses there is no MASQ so you get the original source and not a masqueraded source.

Void Main wrote:

With the rules that shorewall uses there is no MASQ so you get the original source and not a masqueraded source.

I really doubt that, especially after looking at the rules you pasted earlier. If anything your network falls under the conditions of my previous post, not due to some magical shorewall rule;  but I suppose anything the end user finds sufficiently incomprehensible is indestinguishable from magic.

mbm wrote:
Void Main wrote:

With the rules that shorewall uses there is no MASQ so you get the original source and not a masqueraded source.

I really doubt that, especially after looking at the rules you pasted earlier. If anything your network falls under the conditions of my previous post, not due to some magical shorewall rule;  but I suppose anything the end user finds sufficiently incomprehensible is indestinguishable from magic.

What the heck is that supposed to mean? All I am saying is, from a machine on my LAN (192.168.0.x) I load up my web site in my browser (voidmain.is-a-geek.net) which has an external address of 68.188.13.164 which happens to be forwarded to my server in my DMZ on the 172.16.x.x network. Apache on that server logs hits from my internal address (192.168.0.x). There is nothing magical about it, that's how it works. "netstat -an" also shows connections from the LAN addresses.

I just want to say "thanks" to mbm for this solution.  This is exactly the information that I needed.

Now I just need to figure out how to forward TCP port 19 on the WAN to TCP port 22 on the linksys, while allowing WAN connections to TCP22 to pass through to my DMZ machine's TCP22.  A quick check with google says that I should use -j REDIRECT, but OpenWRT doesn't like REDIRECT (Unknown Arg).

(Last edited by mranak on 22 Jan 2006, 04:30)

An alternative solution is to add your box's hostname on your lan's dns server, i.e. /etc/hosts on your router if you haven't changed the default config. This has the benefits of not making all traffic go through the router (it's faster) and not hiding your source IP address (it's more convenient and more secure). Things are a bit more complicated if you have another dns server, like the very nice maradns; you'll need to declare the hostname (e.g. foo.stereo.lu) as a zone you are authoritative for. I'll post my maradns config if anyone wants it.

This is what it looks like here:

wanbox> host foo.stereo.lu
foo.stereo.lu has address 212.121.252.52

lanbox> host foo.stereo.lu
foo.stereo.lu has address 10.0.1.6

YMMV, etc.

Here's a solution for the PPPoE user, without a static IP:

Make a new file, name it whatever you like, in /etc/ppp/ip-up.d/, with these contents:

#!/bin/sh                                                 
WANIP=$(ifconfig ppp0 | grep addr | awk '{print $2}' | sed 's/addr://')
iptables -t nat -A prerouting_rule -d $WANIP -p tcp -j DNAT --to 192.168.1.2
iptables -A forwarding_rule -p tcp -d 192.168.1.2 -j ACCEPT
iptables -t nat -A postrouting_rule -s 192.168.0.0/12 -p tcp -d 192.168.1.2 -j MASQUERADE

chmod a+x it.

Of course, change IPs as necessary... This auto-detects the IP address assigned by pppoe and uses it for forwarding (all ports, not just 80; same behavior as stock linksys firmware's DMZ)

Here's a question for you guys; can domain names be used in the -d argument of the iptables? if they can, that means anyone can set up a DDNS and use it for forwarding...

[edit] whoops, sorry for bringing this back from the graveyard tongue

One thing I should note is that you need to do this forwarding bit per-port for any other special forwards and then the last one should be the DMZ (if you want that)

(Last edited by Legoguy on 27 Jan 2007, 18:25)

mbm wrote:

iptables -t nat -A prerouting_rule -d x.x.x.x -p tcp --dport 80 -j DNAT --to 10.0.0.2
iptables -A forwarding_rule -p tcp --dport 80 -d 10.0.0.2 -j ACCEPT
iptables -t nat -A postrouting_rule -s 10.0.0.0/24 -p tcp --dport 80 -d 10.0.0.2 -j MASQUERADE

The OpenWRT wiki and /etc/firewall.user says to configure a port to be forwarded use:

iptables -t nat -A prerouting_wan -p tcp --dport 8080 -j DNAT --to 10.0.0.2:80
iptables        -A forwarding_wan -p tcp --dport 80 -d 10.0.0.2 -j ACCEPT

Thus, if port forwarding is already in place, there will already be an entry in the forwarding_wan chain.

If so, what purpose does the additional entry in the forwarding_rule chain serve?

(The two rules are identical with the only difference that they are in different chains.)

This interesting thread in the wl500g forum suggests only a pre-routing and post-routing rule to the nat table is required.

I'm using:

iptables -t nat -A prerouting_rule  -d $wan_ip        -p tcp --dport 8080   -j DNAT --to 10.0.0.2:80
iptables -t nat -A postrouting_rule -s 10.0.0.0/24 -p tcp -d 10.0.0.2 -j MASQUERADE

which seems to work.

To all:

Without having the time at the moment to list all the details, just please consider the following:

If you're trying to poke a whole through the NAT/firewall to allow for an internal service to be accessed by the public IP address, do you really want that service working properly for the whole known world, EXCEPT for your small corner (on your local LAN, behind the router?)  I can see plenty of uses for the opposite, and many uses for making something publicly accessible, but a lot of the approaches people are taking towards this just seems backwards...

The "_wan" chains are predefined to mean anything that is actually coming from the WAN interface, regardless of address.  I'm guessing too many people misunderstood the BFD / "Big Fat Disclaimer" in the earlier firewall.user default files (I was one of them), and the "_wan" chains were added to try to make things easier.

Assume you have a local subnet of 192.168.0.1/24, and a WAN IP of 1.2.3.4.  Using the "_wan" chains to forward incoming requests on port 80 to your local web server running on 192.168.0.2 will allow the rest of the outside world to get to your web server.  But these rules won't match any requests to 1.2.3.4 coming from inside the LAN.  You'd have to know to use 192.168.0.2 instead, or utilize some of the other "work arounds" such as tweaking your DNS, using a hosts file, etc.

mbm helped to clarify this in his 2006-01-11 post on this thread.  Use the non-"_WAN" chains, and instead of keying to the interface, key to the destination address, e.g. "-d 1.2.3.4".  This will then match any requests for the public IP, whether from the WAN or the LAN interface.  The only tricky part is remembering to add the MASQUERADE rule to send the source address that will allow for responses.

Anyone, please correct me if I'm missing something obvious here.  (I've been using this approach on many networks for the past year+, without any real issues.)

quietdragon:
I'm confused about which "additional entry" and which "two rules" you are referring to, especially considering the 2 previous quotes and 5 total lines to choose from.

Given the 3 total quotes, I think that the "mbm wrote" is the best approach.

With the 3rd quote from the wl500g forum, you need to make sure that "$wan_ip" is initialized somewhere.  I've not jumped to Kamikaze yet, but as of the latest WR release, this was not defined by default.

Also, as I understand, by default all forwarded connections are dropped by default, unless accepted at some point with another rule.  I would think that the wl500g example is only working if there is another "-j ACCEPT" on the forwarding rule at some point in one of the configuration files.

My $0.02 for the day...

ziesemer wrote:

I'm confused about which "additional entry" and which "two rules" you are referring to, especially considering the 2 previous quotes and 5 total lines to choose from.

Given the 3 total quotes, I think that the "mbm wrote" is the best approach.

With the 3rd quote from the wl500g forum, you need to make sure that "$wan_ip" is initialized somewhere.  I've not jumped to Kamikaze yet, but as of the latest WR release, this was not defined by default.

Also, as I understand, by default all forwarded connections are dropped by default, unless accepted at some point with another rule.  I would think that the wl500g example is only working if there is another "-j ACCEPT" on the forwarding rule at some point in one of the configuration files.

Thanks for taking the time to compose such a detailed reply. I apologise for the lack of clarity in my post. Let me try to rephrase.

The OpenWRT wiki and /etc/firewall.user give guidance on punching a hole in the firewall to allow an external host to gain access to a service provided by an internal host. For each service, two lines are required:

iptables -t nat -A prerouting_wan -p tcp --dport 8080 -j DNAT --to 10.0.0.2:80
iptables        -A forwarding_wan -p tcp --dport 80 -d 10.0.0.2 -j ACCEPT     ## FWDING RULE #1

The post made by mbm that I was referring to was this one. In that post, mbm includes this set of rules:

iptables -t nat -A prerouting_rule -d x.x.x.x -p tcp --dport 80 -j DNAT --to 10.0.0.2
iptables -A forwarding_rule -p tcp --dport 80 -d 10.0.0.2 -j ACCEPT            ## FWDING RULE #2
iptables -t nat -A postrouting_rule -s 10.0.0.0/24 -p tcp --dport 80 -d 10.0.0.2 -j MASQUERADE

My question pertains to the difference between FWDING RULE #1 and FWDING RULE #2, and the necessity of FWDING RULE #2 in the presence of FWDING RULE #1.

FWDING RULE #1 is necessary to allow external hosts access. Internal loopback, at least in my case, appears to work fine in the absence of FWDING RULE #2.

I would think that mbm has inserted FWDING RULE #2 there for a good reason. My 0.9 White Russian configuration is working without that rule, and I'd like to understand why.

Just in case anyone is interested, a short and good description of the problem and a sollution can be found at:
http://www.netfilter.org/documentation/ … TO-10.html

I think it's better to use SNAT instead of MASQUERADE as is suggested there, since it'll perform (slightly) better smile

Cheers! smile

Let's see if I can give a late reply to quietdragon's question too smile
The difference between the two rules is, as you correctly stated, that they are set on different rulesets. Note the difference between those rulesets though:
forwarding_wan applies only to wan -> any traffic.
forwarding_rule applies to any -> any traffic.

I expect the second rule is added so that you can access the webserver from the lan.
Normally (stock/simple setup, and probably also your setup) you'd be able to get to the webserver from the rest of the lan anyways, in which case the second rule isn't needed.
I think the posted started with someone having the webserver on a DMZ though, and then the rule might make sense, cause the rest of the lan can't neccecarily get to the DMZ.

In most people's setups, I agree it's probably not needed though.

cranphin wrote:

Just in case anyone is interested, a short and good description of the problem and a sollution can be found at:
http://www.netfilter.org/documentation/ … TO-10.html

I think it's better to use SNAT instead of MASQUERADE as is suggested there, since it'll perform (slightly) better smile

Cheers! smile

Would you be able to distill this down to rules using SNAT then?
I'm using mbm's rules posted above to achieve fully working access between p2p clients behind the router, but am interested in anything that will increase efficiency.
I'm a FreeBSD admin (sorry :-) so I'm not really up on iptables, though I have a vague understanding.
Many thanks.

I haven't read the whole thread, but basically if you want to use SNAT instead of MASQUERADE, all you need to do is replace:

iptables -t nat [...] -j MASQUERADE

with

iptables -t nat [...] -j SNAT --to-source IPADDRESS

where IPADDRESS is the IP address of your WAN interface.

(There are a couple of slight variations.  See the iptables manpage for details.)

As noted in the manpage, for this to work, you have to know what IPADDRESS is.  i.e. it has to be static.  If you get your IP address via DHCP or PPPoE etc., you will have to use MASQUERADE.

Wodin wrote:

I haven't read the whole thread, but basically if you want to use SNAT instead of MASQUERADE, all you need to do is replace:

iptables -t nat [...] -j MASQUERADE

with

iptables -t nat [...] -j SNAT --to-source IPADDRESS

where IPADDRESS is the IP address of your WAN interface.

(There are a couple of slight variations.  See the iptables manpage for details.)

As noted in the manpage, for this to work, you have to know what IPADDRESS is.  i.e. it has to be static.  If you get your IP address via DHCP or PPPoE etc., you will have to use MASQUERADE.

Thanks for the reply.
Mbm's rules above are:

iptables -t nat -A prerouting_rule -d $WANIP -p tcp --dport 80 -j DNAT --to 10.0.0.2
iptables -A forwarding_rule -p tcp --dport 80 -d 10.0.0.2 -j ACCEPT
iptables -t nat -A postrouting_rule -s 10.0.0.0/24 -p tcp --dport 80 -d 10.0.0.2 -j MASQUERADE

You already have to know the WANIP to set this up. Therefore SNAT is perfectly acceptable?
So we can distill this down to:

iptables -t nat -A prerouting_rule -d $WANIP -p tcp --dport 80 -j DNAT --to 10.0.0.2
iptables -t nat -A postrouting_rule -s 10.0.0.0/24 -p tcp --dport 80 -d 10.0.0.2 -j SNAT --to $WANIP

I'm not using DMZ, so the 2nd rule (as noted above) is not necessary. It seems to all work.
Can the iptable gurus comment on what I've done is correct?

It would seem that this internal forwarding is actually what most people want in their setups?
I've hacked my /etc/firewall.user to add code to perform this 'full' forwarding by cating this to it:

WAN=eth0.1
WANIP=`ifconfig $WAN | awk '/inet addr:/ { sub(/addr:/, ""); print $2 }'`
WANIP=${WANIP:-`awk -F, '{ print $2 }' /usr/tmp/ez-ipupdate.cache`}

forward () {
  do_forward $1 $2 tcp
  do_forward $1 $2 udp
}

do_forward () {
  iptables -t nat -A prerouting_rule -d $WANIP -p $3 --dport $1 -j DNAT --to $2
  iptables -t nat -A postrouting_rule -s 192.168.1.0/24 -p $3 --dport $1 -d $2 -j SNAT --to $WANIP

  iptables -t nat -A prerouting_wan -p $3 -m multiport --dports $1 -j DNAT --to $2
  iptables        -A forwarding_wan    -d $2     -j ACCEPT
}

forward 27588 192.168.1.4
forward 31745 192.168.1.4
forward 59287 192.168.1.4

forward 27589 192.168.1.149
forward 31746 192.168.1.149
forward 59288 192.168.1.149

do_forward 80 192.168.1.2 tcp

I said 'hacked' smile
I added the last 2 rules, so I don't have to remember to setup the port forwards in /etc/config/firewall, as well as in here.
Shouldn't an extra option be added to /usr/lib/firewall.awk to allow this fuller forwarding? e.g. I'm assuming we don't want to change the current behaviour of 'forward' (though we could) so I suggest 'forwardrw' (anyone think of a better name) to allow the above in /etc/config/firewall:

forwardrw:dport=27588:192.168.1.4
forwardrw:proto=tcp dport=80:192.168.1.2

Comments?
Cheers.

(Last edited by gildenman on 18 Feb 2008, 16:00)

The discussion might have continued from here.