Your home Internet router gives you some protection against direct attacks on your computer by keeping your home network safely encapsulated. Each of your home computers can access the Internet (this is called NAT), but no outsider can access your computers directly. Outsiders only see the router. However, sometimes you want your computer to be “fully” online. Enter the “DMZ” feature of your router. Your router’s DMZ allows one of your computers to be fully exposed to the Internet (for better or worse).
Reasons to enable your DMZ:
- Access your files while away from home.
- Serve web pages from your computer.
- Make BitTorrent transfers faster. BitTorrent transfers are usually faster when your computer is directly exposed to the Internet.
For my work at FamilyLink.com, I develop directly on my local machine. While working on our Facebook application, I need to allow Facebook servers to directly access my machine. (When you use a Facebook app, you’re accessing Facebook’s servers and Facebook servers are, in turn, accessing the developer’s server via a callback URL. While working on our Facebook app, Facebook directly accesses my local machine.) This requires me to open my machine to the DMZ.
Reasons not to enable your DMZ:
- Your computer is more likely to be hacked
- Your private data is more likely to be accessed
If you enable your DMZ, know which services are enabled on your machine and which files and data are being shared. There may be files you’re comfortable sharing on your local network that you wouldn’t want to share with the world. Only enable the DMZ as long as necessary.
Enabling the DMZ can be a pain — logging into your router and navigating to the correct setting — so I wrote the following Ruby scripts to make it easy. The first worked with the Linksys router I had. (I believe it was a WRT54G.) To use, fill in your router’s IP address and password, and your computer’s hardware address, then type “linksys_dmz.rb on” or “linksys_dmz.rb off” at the command-line. The script looks up your computer’s hardware address in the table of local IP addresses so the IP address can safely change from time to time.
#!/usr/bin/env ruby # linksys_dmz.rb router = '10.1.1.1' user = 'admin' pass = 'your_password' hardware_address = '00:23:6C:00:00:00' leases = `curl -su #{user}:#{pass} http://#{router}/DHCPTable.asp` leases.scan(%r{'([^']+)', hardware_address}) do |m| ip_address = m[0].strip.to_s last_digit = ip_address.split('.').last if $*[0] == 'open' || $*[0] == 'on' post_values = "submit_button=DMZ&change_action=&action=Apply&dmz_enable=1&dmz_ipaddr=#{last_digit}" print "Opening DMZ to #{ip_address}\n\n" else post_values = "submit_button=DMZ&change_action=&action=Apply&dmz_enable=0" print "Closing DMZ\n\n" end `curl -su #{user}:#{pass} -e http://#{router}/DMZ.asp -d '#{post_values}' http://#{router}/apply.cgi` end
Last year I switched to Verizon FIOS, which came with its own wireless router, so I had to write a new script. Again, fill in the password, then type “verizon_dmz.rb on” or “verizon_dmz.rb off” in Terminal. (This script assumes a 10.1.1.* network. Change it to 192.168.1.* if that’s what you have.)
As a side note, the Verizon router was a bit of beast to automate. It uses a hashed signature to try to enforce JavaScript-enabled browsers. Writing this script required using TamperData, Charles Proxy, and a lot of trial and error to discover which POST data were necessary.
I use this script to open the DMZ before working on our Facebook app, then I close it when I’m done for the day. Eventually, it’d be nice to find a way to enable the DMZ remotely — maybe via email or something.
#!/usr/bin/env ruby # verizon_dmz.rb require 'rubygems' require 'mechanize' require 'digest/md5' user = 'admin' pass = 'your_password' localhost = `ifconfig`.scan(/inet (\d+\.\d+\.\d+\.\d+).*broadcast 10.1.1.255/).join router = localhost.gsub(/\d+$/,'1') begin agent = Mechanize.new page = agent.get("http://#{router}:81") rescue Exception abort "Unable to connect to Verizon Router! Check the IP address." end form = page.forms[0] auth_key = form.fields.find {|f| f.name == 'auth_key'}.value form.fields.find {|f| f.name == 'user_name'}.value = user form.fields.find {|f| f.name == 'md5_pass'}.value = Digest::MD5.hexdigest(pass + auth_key) form.fields.find {|f| f.name == 'mimic_button_field'}.value = 'submit_button_login_submit%3A+..' form.method = "POST" form.submit post = { 'dmz_host_cb_watermark' => '1', 'dmz_host_ip0' => localhost.split('.')[0], 'dmz_host_ip1' => localhost.split('.')[1], 'dmz_host_ip2' => localhost.split('.')[2], 'dmz_host_ip3' => localhost.split('.')[3], 'active_page' => '9013', 'mimic_button_field' => 'submit_button_login_submit%3A+..', } if $*[0] == 'open' || $*[0] == 'on' post['dmz_host_cb'] = '1' puts "Opening DMZ to #{localhost}" else puts "Closing DMZ" end agent.post('/index.cgi', post)
3 replies on “Script to enable/disable DMZ on Linksys and Verizon routers”
DMZ on home routers is a misnomer and is more dangerous from a security standpoint. The actual term for it should be 1:1 NAT because it does not truly create a new zone for your node or appliance. So, if someone exploits a security loophole in the machine opened up to the outside world could have access to other machines on your network or tunnel through that machine.
At the very least make sure Enable NAT Loopback is disabled if you do not care for the machine to be accessible to the outside world. Otherwise, set up the “DMZ” to point to another router or subnet that cannot access the rest of your network, then you can connect to your actual zone for direct access. Or if you really want to kick it up a notch disable the firewall on the router and use pfSense, Smoothwall, or IPCop.
Nonetheless, an impressive script. Makes me want to become a better coder.
Good point, Michael. I think I used the DMZ setting because it was easier and then the script went that direction too. It would be a good project to modify the script to work with port forwarding instead.
The “DMZ” setting forwards all incoming traffic to that particular host. Using port forwarding is a more secure way to setup external access (as you can easily control specific ports to be forwarded)
Port forwarding also allows you to forward specific ports to different hosts which offers a more flexibility (e.g. port 22 goes to host1, port 23 goes to host2, etc…)