Articles‎ > ‎

Secure Remote Access with Dymamic Iptables

posted May 15, 2011 10:03 AM by Victor Simone   [ updated May 21, 2011 10:29 AM ]
I recently purchased a Foscam FI8918W on the cheap. It connects to my wireless network and includes remote pan and tilt functionality. With my Android phone I downloaded IPCam Viewer by Robert Chou on the market place to view and control the thing. The paid version even includes the ability to use the camera's built in microphone and speakers, but I haven't purchased it yet to test this.

This was all very exciting stuff, but I didn't trust the camera's built-in web browser or security enough to feel comfortable hanging it out on the Internet. The solution? Write a script to dynamically change my firewall rules to only allow my phone access to view the camera!

To do this, I first needed to know what my phone's IP address is. I already have a DynDNS account with a few hosts. For the uninitiated, DynDNS provides a means to link a dynamic IP address to a DNS entry. I added a new host entry for my phone and downloaded DynDNS by Neil Boyd from the Android market place. Setup was very straight-forward, but because the app supports multiple dynamic domain services you must provide the Update Domain -- the address to send update requests to. I used members.dyndns.org which I found digging around in my Linux firewall's DynDNS update script. If you own a real domain name you can add a CNAME record pointing to the DynDNS record to keep all your hosts accessible through one domain name. CNAME or Canonical Name records are DNS records which point to another DNS record (as opposed to an A record pointing to an IP address). I used mobile.osquat.com to point back to my DynDNS entry.

Now we can find our mobile phone on the internet by querying mobile.osquat.com. Unfortunately, iptables doesn't support filtering by domain name, so we can't just write a rule stating that mobile.osquat.com is allowed through. This is where things get interesting.

The easiest way to dynamically update a firewall script is to create a user-defined iptables chain. A user-defined chain will limit the number of rules we have to write each time we update our firewall minimizing maintenance. I won't provide my entire firewall script, and instead only provide the necessary commands which can be incorporated into a firewall script to create the user-defined chain called webcam-allow, a default rule for this user-defined chain, and the routing into that chain.

# Delete, and create a user-defined iptable chain
$IPTABLES -X webcam-allow
$IPTABLES -N webcam-allow

# Add a default rule for the webcam-allow chain
$IPTABLES -A webcam-allow -J DROP

# In your prerouting chain, add a rule to send external traffic to the web cam. I used a lot of variables here to handle port forwarding; mangle to your needs

$IPTABLES -t nat -A PREROUTING -p TCP -i $EXTERNAL_IFACE --dport $DESTINATION_PORT -j DNAT --to-destination $INTERNAL_WEBCAM:80

# Instead of ALLOW or DROP when traffic is destined for our webcam, jump to our user-specified chain for processing

$IPTABLES -A FORWARD -p tcp -i $EXTERNAL_IFACE -d INTERNAL_WEBCAM --dport 80 --syn -m state --state NEW -j webcam-allow

If we were to run our newly modified firewall script we would have everything in place except for the fact that our only rule in the webcam-allow chain is to drop all requests to our IP camera. We can prove this by taking a peek at that chain. At the command prompt, issue the following command:

firewall@example.com:~$ sudo /usr/sbin/iptables -L webcam-allow -v 
Chain webcam-allow (0 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       tcp  --  any    any     anywhere             anywhere

After modifying the firewall script, we can focus on dynamically updating our user-defined iptables chain, webcam-allow. The default rule that we created when running our firewall script for the first time is to drop all traffic. This is just a safety rule which will be overwritten by our cron script shown below. Get our mobile devices IP address into a variable using dig. Then use iptables -R to replace rule number 1 in webcam-allow.

#!/bin/bash
#
#

IPTABLES=/usr/sbin/iptables

# Get the IP address of our mobile device
MOBILE_IP=`dig +short mobiledevice.example.com|tail -n 1`

# Allow access access from our mobile device
$IPTABLES -R webcam-allow 1 -p tcp -s $MOBILE_IP -j ACCEPT

Huzzah! Taking another look at the webcam-allow chain would reveal that our only rule is to allow access when the device's source IP is that of our mobile phone. Move the script to a cron directory and I can now check on my cameras anytime through my phone without worrying that the whole world can see into my home or that my camera's web server might get compromised. This could easily be expanded to support more services with a few simple tweaks.