***************************************************************************** ***************************************************************************** **************** BANANA PI GATEWAY ***************************************************************************** ***************************************************************************** http://www.awasu.com/weblog/bpi-gateway/ ***************************************************************************** ***************************************************************************** First, activate the WiFi module: sudo modprobe bcmdhd Second, connect to WiFi network With interative commands: sudo ip link set wlan0 up sudo -s wpa_passphrase > /etc/wpa_supplicant.conf (write the password and push enter) wpa_supplicant -i wlan0 -c /etc/wpa_supplicant.conf sudo dhclient wlan0 sudo ip route change default via dev wlan0 Connect at boot: nano /etc/network/interfaces delete '#' fron auto wlan 0 =============================== Setting up the Gateway ======================== We now have our Banana Pi up and running with a clean installation of Bananian Linux. To get it working as a gateway, we need to do 3 things: set up a DHCP server, so that computers can join the network. set up a DNS server, so that domain names can be resolved. set up NAT, so that internet requests can be made on behalf of other computers on the network. Once you've set up these 3 things, you will have a basic gateway up and running, and other computers on the internal network should have internet access. The diagram below shows how it all fits together: When a new computer[1] joins the network, it will contact the DHCP server running on the bPi to get an IP address. As part of this assignment, the bPi will tell the new computer that it also handles DNS requests, as well as any other internet activity. If someone wants to go to a web site, they will ask the DNS server to look-up the domain name, to get the web site's IP address. Finally, NAT ensures that internet requests go out, and replies come back in, transparently. =============================== Setting up DHCP =============================== Every computer on a network has a unique ID, known as an IP address, which might look something like 72.249.26.4. Back in the day, a network administrator would have to go around and configure these manually for every single computer on a network, but with the advent of DHCP[1], this can now be done automatically. When a computer is turned on, and has been configured to use DHCP, it checks the network to see if a DHCP server is available and if so, asks it for an IP address. The DHCP server has a pool of IP addresses it can use, and if one is available, assigns it to the new computer, which can then use it to identify itself and communicate with other computers on the network. When the computer is turned off, its IP address is released and becomes available for use by another computer. Installing and configuring the DHCP server So, we need to install a DHCP server on our gateway, so that computers on our internal network can get IP addresses[2]. This is very simple: sudo apt-get install isc-dhcp-server It will probably fail when it tries to start up, because it hasn't been configured yet, but we can ignore this, since we will configure it now. First, edit /etc/default/isc-dhcp-server and set the INTERFACES parameter. For example, in my home network, I connect to the internet via wifi (i.e. the wlan0 network interface), and use the wired network for my LAN, so I would set this to eth0[3]. Then edit /etc/dhcp/dhcpd.conf: Set the domain-name option to what you would like to call your network e.g. gateway. Set the domain-name-servers option to the IP address of the bPi[4]. Add a line to set the routers option, that configures the IP address of the gateway[5]. Un-comment the authoritative statement. Configure the lease addresses[6] e.g. subnet 10.0.0.0 netmask 255.255.255.0 { range 10.0.0.100 10.0.0.199 ; } It is also possible to assign specific computers a fixed IP address, according to their MAC address e.g. host mycomputer { hardware ethernet XX:XX:XX:XX:XX:XX ; fixed-address 10.0.0.2 ; } Restart the service: sudo service isc-dhcp-server restart We also want it to start up when the system is booted: sudo update-rc.d isc-dhcp-server start Finally, to check what IP addresses have been assigned, take a look inside /var/lib/dhcp/dhcpd.leases. =============================== Setting up DNS ================================ Every computer is uniquely identified by an IP address, but these are inconvenient, and it's much easier to refer to them by name. The Domain Name System is a network's white pages, but instead of looking up somebody's name in order to get their telephone number, you can look up a domain name (e.g. awasu.com) and get its corresponding IP address (e.g. 72.249.26.4). Installing and configuring the DNS server We need to install a DNS server on our gateway, so that computers on the internal network can do domain name lookups[1]. First, we need to install the DNS server: sudo apt-get install bind9 We can also install some useful tools that let us do DNS lookups from the command line (e.g. dig and nsupdate): sudo apt-get install dnsutils Now, computers on my internal network will have their DNS lookups done by the DNS server running on our gateway[2]. However, the gateway DNS server itself needs to do DNS lookups, and this is configured in /etc/resolv.conf. In the case of my home network, I get given the address of a DNS server when I connect via wifi, but you might want to use something else e.g. 8.8.8.8, if you want to use Google's DNS servers. =============================== Setting up NAT ================================ Network Address Translation allows the gateway to send requests out to the internet on behalf of computers on the internal network. When the gateway receives an internet request, it tweaks it slightly to make it look like it was sending the request itself, and then forwards it on to the intended recipient on the internet. When the reply comes back, they gateway tweaks it again to make it look like nothing happened i.e. the computer on the internal network thinks it was communicating directly with the remote computer on the internet. To set this up, we first need to enable IP forwarding in the kernel. Edit /etc/sysctl.conf and uncomment the net.ipv4.ip_forward=1 line. To reload these settings: sudo sysctl -p /etc/sysctl.conf We also need to enable IP masquerading: sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE This command tells the gateway to forward any internet requests to the wlan0 interface i.e. my wifi connection, which is how I connect to the internet. Since we need this to always happen, the above command should be added to /etc/rc.local. =============================== Setting up a WiFi access point ================ Installing the WiFi adapter The Banana/Raspberry Pi's are very finicky when it comes to WiFi adapters 🙁 so you need to do some research before buying one. A list of wifi adapters known to work with a Raspberry Pi can be found here, and Mikronauts have done some research on adapters that work with a Banana Pi. I chose a TP-Link TL-WN723N. After plugging it in, lsmod showed that the 8188eu driver had been loaded for it: lsusb also showed it connected: Configuring the access point First, we want to give the wifi adapter a fixed IP address, so add the following to /etc/network/interfaces[1]: allow-hotplug wlan1 iface wlan1 inet static address 10.0.1.0 netmask 255.255.255.0 Next, we need to install hostapd, that will allow the bPi to function as an access point: sudo apt-get install hostapd-ap6210 Configure hostapd by editing /etc/hostapd/hostapd.conf and changing the following settings: interface = wlan1 ssid = ...YOUR SSID NAME... wpa_passphrase = ...PASSWORD... Now we can run hostapd: sudo hostapd -B /etc/hostapd/hostapd.conf If hostapd doesn't work If you get a "invalid/unknown driver 'nl80211'" error[2], nl80211 driver support is not available and we will have to compile hostapd from source. First, install the packages needed to compile: sudo apt-get install gcc git make sudo apt-get install libnl-3-dev libnl-genl-3-dev openssl libssl-dev pkg-config Then, get the source for hostapd: cd /tmp git clone git://w1.fi/srv/git/hostap.git Then, configure it: cd hostap/hostapd cp defconfig .config Edit .config and make sure that CONFIG_DRIVER_NL80211=y and CONFIG_LIBNL32=y are active i.e. not commented out. Then, compile and install it: make sudo cp hostapd /usr/sbin/ If hostapd still doesn't work 😐 In my case, it turns out I need to use a customized version of hostapd provided by RealTek :wall: Fortunately, Jens Segers has done some work to make this process easier. If you already installed the distro hostapd, remove it: sudo apt-get autoremove hostapd Install the packages needed to compile: sudo apt-get install gcc make sudo apt-get install openssl libssl-dev Get the source for the customized hostapd: cd /tmp wget https://github.com/jenssegers/RTL8188-hostapd/archive/v2.0.tar.gz tar -zxvf v2.0.tar.gz Compile hostapd: cd RTL8188-hostapd-2.0/hostapd make sudo make install Configure hostapd.conf as described above, then try to start it: sudo service hostapd start Configuring DHCP Hopefully, you should be able to connect to the access point, so we now need to update our DHCP server to assign IP addresses to any computers connecting via WiFi. Edit /etc/default/isc-dhcp-server and add the new interface to INTERFACES. Edit /etc/dhcp/dhcpd.conf and add another subnet entry e.g. subnet 10.0.1.0 netmask 255.255.255.0 { range 10.0.1.100 10.0.1.199 ; option domain-name-servers 10.0.0.1 ; option routers 10.0.0.1 ; } Then restart the DHCP service: sudo service isc-dhcp-server restart You should now be able to connect to the access point, be given an IP address, and get online. =============================== Setting up DNS-based ad-blocking ============== Ad-blocking is becoming more of a necessity these days, and while there are many browser plugins that will strip ads, they can be slow and memory-hungry. Blocking ads via DNS is an interesting alternative, that can work along-side browser-based solutions, and because it's done on the gateway, any computer that connects to the internet via the gateway will benefit from it. Normally, when a browser wants to load an ad from, say, annoyingads.com, it will do a DNS lookup on that domain name to get its IP address, and then send a request to that IP address to get an ad: However, since we are running our own DNS server, we can circumvent this process by returning something different for the IP address. If we set up a dummy web server and return the IP address of that[1], when the browser tries to load an ad, it will connect to that instead of the real server. If we configure the dummy web server to return blank images, then all we will see in the web page is empty space, rather than ads. Installing the web server Download the daemon version of pixelserv from here and save it somewhere e.g. /root/bin/pixelserv.pl. Make sure it's executable, then run it: sudo chmod 755 pixelserv.pl sudo ./pixelserv.pl Open a browser and go to http://10.0.0.1 - you should receive a 1x1 image. Setting up the DNS blacklist Save the script below somewhere (e.g. /root/bin/get-dns-blacklist.sh), which downloads a list of domains known to serve ads: curl "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=bindconfig&showintro=0&mimetype=plaintext" \ | sed -e "s/null.zone.file/\/etc\/bind\/db.pixelserv/" \ >/etc/bind/zones.blacklist service bind9 reload Make sure it's executable, then run it: sudo chmod 755 get-dns-blacklist.sh sudo ./get-dns-blacklist.sh Check that the zones blacklist file (/etc/bind/zones.blacklist) was created and populated. Create a zone file e.g. /etc/bind/db.pixelserv: $TTL 86400 ; one day @ IN SOA ads.example.com. hostmaster.example.com. ( 2001010100 ; serial number YYYYMMDDNN 28800 ; refresh 8 hours 7200 ; retry 2 hours 864000 ; expire 10 days 86400 ) ; min ttl 1 day NS my.dns.server.org A 10.0.0.1 @ IN A 10.0.0.1 * IN A 10.0.0.1 Then, add an entry to /etc/bind/named.conf.local: include "/etc/bind/zones.blacklist" ; Test the ad-blocker The DNS server should still be running with the old settings, so if we do a DNS lookup on a blacklisted domain, it should still resolve to the real IP address: Now, if we restart the DNS server: sudo service bind9 restart and run the same query again, we can see that the returned IP address is different, and the domain name is now pointing to us. This means that any attempt to connect to 101com.com will actually connect to our pixelserv web server, and any attempt to retrieve an ad will receive a 1x1 image instead. Configuring the ad-blocker to run at system startup We want pixelserv to run at startup, so we can add it to /etc/rc.local: # start pixelserv /root/bin/pixelserv.pl & Note the trailing ampersand, which tells the script to run in the background, so that the startup script doesn't block, waiting for it to finish. We also want to regularly download the latest blacklist, so we schedule a cron job to run the download script: sudo crontab -e In the screenshot, I've set the job to run at 3am every day, and to log the output, in case there are problems. =============================== Setting up OpenVPN ============================ A virtual private network gives you better security and privacy as you work online. An encrypted connection to a VPN server is created, and all your internet traffic is sent over that connection, where it is forwarded on to the real destination by the VPN server. Anyone snooping on your internet traffic will be able to see that you are using a VPN, but will not be able to decipher any of it, due to the encryption. Installing and configuring OpenVPN By far, the most popular open-source VPN software is OpenVPN, and to install it: sudo apt-get install openvpn Your VPN provider will supply you with configuration files (usually with a .ovpn extension) for connecting to their servers. Save these in /etc/openvpn/. You will also be given a username and password - put these in a password file (e.g. /etc/openvpn/auth) with the username on the first line, and password on the second line. We also need to change NAT so that internet requests are forwarded on to the VPN tunnel, instead of the normal network interface: sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE Now we can run OpenVPN[1]: sudo openvpn \ --cd /etc/openvpn/ \ --config XXX.ovpn \ --auth-user-pass /etc/openvpn/auth \ --auth-nocache \ -keepalive 10 60 You can check your external IP address like this: wget http://ipinfo.io/ip -qO - Or just fire up a browser and go to http://ipinfo.io. Configuring OpenVPN to run at startup To get OpenVPN to run at startup, you need to change[2] the iptables command to forward internet requests to the tun0 interface instead of wlan0 (as described above). Then, add the openvpn comand you used above, but with an extra --daemon parameter, so that it will run in the background. =============================== Setting up an email relay ===================== Email is messy. It's often useful to have programs send emails[1], so rather than forcing everyone to deal with the messiness themselves, it's often easier to set up an email relay. This is a program that runs on the gateway and accepts email from computers on the internal network, then forwards them on to the real recipients on the internet. Unfortunately, if we just send out the email ourself, there is virtually no chance of it reaching its destination, since most mail servers will not accept email from other servers unless they meet some stringent requirements[2]. So, the best way for our relay to forward emails is to forward them on again to another email server, one that is known to be acceptable to the internet at large, and have it send the email to the real recipient. Installing and configuring the mail server A popular mail server is exim4, and installing it is easy: sudo apt-get install exim4 Edit[3] /etc/exim4/update-exim4.conf.conf and set the following options: dc_eximconfig_configtype = 'satellite'[4] dc_other_hostnames = '' dc_local_interfaces = '10.0.0.1'[5] dc_readhost = 'gateway'[6] dc_smarthost = 'myserver.com'[7] dc_hide_mailname = 'true' dc_relay_nets = '10.0.0.0/24'[8] Edit /etc/mailname and put in the host name of the gateway machine. Your email server will almost certainly require authentication, so edit /etc/exim4/passwd.client and set the login details there e.g. myserver.com:USERNAME:PASSWORD Finally, edit /etc/email-addresses and set the email addresses you want to use when sending emails from each user account e.g. taka: taka@myserver.com root: root@myserver.com This means that if I send an email when logged on as taka, it will appear to have come from taka@myserver.com, or root@myserver.com if I am logged on as root. Now everything has been configured, we can install the new settings and restart the server: sudo update-exim4.conf sudo /etc/init.d/exim4 restart Testing the email relay Open a new console window and monitor the exim4 log file: sudo tail -f /var/log/exim4/mainlog Back in the original console, install the command-line email program and send a test email: sudo apt-get install mailutils echo body | mail -s "relay test" me@somewhere.com In the exim4 log, you should see it receive the email, forward it on, and a few seconds later, hopefully receive it at the final email address. A warning about relaying email We have configured our relay to not require any login, so we need to be very careful about restricting access to it - spammers just love it when they find an open email relay 🙁 Above, we configured dc_relay_nets so that we only relay emails from computers on our internal network, and you should also control access via the firewall, so the only danger is if one your computers in your internal network gets compromised, since it will be able to send out emails without restriction. Keep an eye on your logs! =============================== Setting up a firewall ========================= Of all the extra services we can have on our gateway, a firewall is the most useful and should be considered mandatory. In this section, we will block all incoming and outgoing traffic, and then selectively enable only the traffic we want to allow e.g. web browsing, email, etc. Before we start, it's important to understand the different types of messages that can be sent over a network: TCP messages These are sent between two computers who have set up a connection between themselves, and are usually request/response i.e. one computer sends the other one a message, which then sends back a reply. UDP messages These are "shouted out" on the network, to whoever might be listening[1]. In this case, there is no concept of request/response, it's just computers broadcasting messages to the network to whoever might be there. ICMP messages These are low-level messages that computers send to each other to pass information about the state of the network itself. We will use the iptables program to manage the firewall, which uses tables and chains. A chain is just a list of rules that are checked, in order, to see if a message should be allowed through, or blocked. There are several standard tables, but we will only be using the following: filter This table is used when checking whether to allow packets in or out, and has the following chains: INPUT: a list of rules that control what packets are allowed in OUTPUT: a list of rules that control what packets are allowed out FORWARD: a list of rules that control what packets can be forwarded on NAT This table is used to control NAT, and we will use only the following chain: POSTROUTING: allows packets to be modified after they have been routed So, for example, if a program running on a computer on the internal network wants to send out an email, it must go through the gateway[2], and iptables will go to the filter table and check all the rules in the OUTPUT chain, looking for one that specifies whether outgoing email is allowed or blocked. Basic configuration WARNING! It is very easy to lock yourself out of the computer if you make a mistake configuring the firewall. If you're using a keyboard and monitor that have been plugged in, it doesn't matter, but if you're connecting via SSH and accidentally block SSH traffic, you will no longer be able to communicate with the computer! This is especially bad if you've set the firewall rules to be applied when the system boots up, since even a reboot won't clear the problem - SSH will still be blocked and so the only solution will be to plug in a keyboard and monitor, or restore the SD card from a backup. For this reason, it's a good idea to disable firewall configuration in /etc/rc.local when you're working on it, until you're sure everything is OK. We will start[3] by configuring the firewall to block everything, and log anything that gets blocked: # clear out any existing configuration iptables --flush iptables --delete-chain # set the default policy to DROP iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -P FORWARD DROP # TODO: allow selected traffic through # create a custom chain that logs packets, then drops them iptables -N LOGDROP # nb: the first "limit-burst" packets will be logged, then only "limit" per minute iptables -A LOGDROP \ -m limit --limit-burst 10 --limit 10/m \ -j LOG --log-prefix "iptables: " iptables -A LOGDROP -j DROP # log and drop any remaining packets (nb: this must appear last) iptables -A INPUT -j LOGDROP iptables -A OUTPUT -j LOGDROP iptables -A FORWARD -j LOGDROP The first few lines reset everything, then set the default policy[4] to DROP. Near the end of the script, we create a custom chain called LOGDROP, and add a rule[5] to it to log the packet[6][7], and then another rule that drops the packet. At the very end of the script, we add a final rule to each of the filter chains that tell iptables to jump to the LOGDROP chain. In other words, for each packet, iptables will scan a chain looking for a rule that allows or rejects it (we will add these next), but if it doesn't find a match, the last rule tells it to jump to the LOGDROP chain, which will log the packet, and then drop it. Allowing TCP responses The first type of traffic we want to allow through are TCP responses. If a request has been issued by a computer on the internal network, we always want to allow its response to come back in: iptables -A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT So, we append a rule to the INPUT chain (-A INPUT) that says: for TCP traffic[8] (-p tcp), check the connection's state (-m state) and if it's either ESTABLISHED[9] or RELATED[10], then allow the packet through (-j ACCEPT). We also add a similar rule to the OUTPUT chain i.e. if we've already allowed a request to come in from outside, then allow the response to go out: iptables -A OUTPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT And also to the FORWARD chain: iptables -A FORWARD -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT Allowing loopback traffic Next, we allow all traffic on the loopback interface i.e. if a program on the computer is trying to communicate with another program on the same computer, always let that traffic through: iptables -A INPUT -i lo -j ACCEPT In other words, append a rule to the INPUT chain (-A INPUT) that says: traffic coming in on the loopback interface (-i lo) should be allowed (-j ACCEPT). Similarly, we add a rule to the OUTPUT chain that allows all traffic going out on the loopback interface: iptables -A OUTPUT -o lo -j ACCEPT Allowing ICMP traffic ICMP traffic is most commonly known as used by ping, but there's a whole lot more to it than that. In particular, DNS will get slow if you block it, so while there are certain types of attack that can be made using ICMP traffic, for a home gateway, you're probably better off just allowing everything: iptables -A INPUT -p icmp -j ACCEPT iptables -A OUTPUT -p icmp -j ACCEPT iptables -A FORWARD -p icmp -j ACCEPT Allowing DNS traffic DNS uses UDP, so to allow outgoing DNS traffic, we need to add a rule that allows UDP messages to go in and out on port 53 : iptables -A OUTPUT -p udp --dport 53 -j ACCEPT iptables -A INPUT -p udp --sport 53 -j ACCEPT However, certain types of DNS traffic uses TCP, so we add a rule that allows TCP traffic to go out on port 53, but only for new connections: iptables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT Note that there's no need to add a rule to allow the responses back in, since we added a generic rule earlier that allows all traffic for ESTABLISHED connections. We add similar rules to allow incoming DNS traffic: iptables -A INPUT -p udp --dport 53 -j ACCEPT iptables -A OUTPUT -p udp --sport 53 -j ACCEPT iptables -A INPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT Allowing DHCP traffic DHCP also runs over UDP (on ports 67 and 68), so while we could add rules similar to those we added above for DNS, we want to add an extra restriction: only allow this traffic for computers on the internal network. My computers connect to the gateway either via wired ethernet (on the eth0 interface) or via WiFi (on the wlan1 interface), so my rules look like this: iptables -I INPUT -i eth0 -p udp --dport 67:68 --sport 67:68 -j ACCEPT iptables -I OUTPUT -o eth0 -p udp --dport 67:68 --sport 67:68 -j ACCEPT iptables -I INPUT -i wlan1 -p udp --dport 67:68 --sport 67:68 -j ACCEPT iptables -I OUTPUT -o wlan1 -p udp --dport 67:68 --sport 67:68 -j ACCEPT My gateway computer connects to the internet via the wlan0 interface, but since the rules above are explicitly for the eth0 and wlan1 interfaces, any DHCP traffic on the wlan0 interface will be dropped. Allowing SSH traffic I only ever want to SSH in[11] to my gateway computer, from another computer on my internal network, so my rule for SSH traffic looks like this: iptables -A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT For safety, I explicitly allow incoming traffic for ESTABLISHED connections, and I also explicitly allow outgoing traffic: iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT These rules are important - if I make a mistake here, I will get locked out! :wall: Allow incoming HTTP traffic If you've set up the DNS-based ad-blocker, you will need to allow incoming requests to the pixel server: iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW -j ACCEPT Allow incoming email traffic If you've set up email relaying, you will need to allow incoming email: iptables -A INPUT -i eth0 -p tcp --dport 25 -m state --state NEW -j ACCEPT Note that it's critical to only allow this traffic from the local network, otherwise somebody from the outside could connect to your mail server and use it to send spam. Allowing other common traffic The following rules allow outgoing HTTP/HTTPS traffic[12]: PORTS=http,https iptables -A OUTPUT -p tcp -m multiport --dports $PORTS -m state --state NEW -j ACCEPT Note that we can use descriptive names for the ports[13] and again, we allow outgoing traffic for new connections only, responses are allowed by the generic "allow responses" rule defined earlier. We also want to allow NTP traffic[14], which runs over UDP: PORTS=ntp iptables -A OUTPUT -p udp -m multiport --dports $PORTS -j ACCEPT iptables -A INPUT -p udp -m multiport --sports $PORTS -j ACCEPT Note that these rules apply only to traffic that originates on the gateway computer; for traffic that originates on another computer on the internal network, we need to add rules to the NAT table, which we'll do next. Allowing common traffic over NAT As described in the section on setting up NAT, we need a rule to enable NAT: # clear out any existing configuration iptables -t nat --flush iptables -t nat --delete-chain # enable NAT iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE We can then allow outgoing traffic[15] for selected services: PORTS=http,https,pop3,pop3s,imap,imaps,smtp,smtps,587,ssh,ftp iptables -A FORWARD \ -i eth0 -o wlan0 \ -p tcp -m multiport --dports $PORTS \ -m state --state NEW \ -j ACCEPT Similarly, we allow UDP traffic for selected services: PORTS=ntp iptables -A FORWARD \ -i eth0 -o wlan0 \ -p udp -m multiport --dports $PORTS \ -j ACCEPT iptables -A FORWARD \ -i eth0 -o wlan0 \ -p udp -m multiport --sports $PORTS \ -j ACCEPT I also allow web traffic only from my WiFi-connected devices: PORTS=http,https iptables -A FORWARD \ -i wlan1 -o wlan0 \ -p tcp -m multiport --dports $PORTS \ -m state --state NEW \ -j ACCEPT Allowing VPN traffic If you are running OpenVPN, you will need the following rules to allow it to work: iptables -A OUTPUT -o wlan0 -p udp --dport 1194 -j ACCEPT iptables -A INPUT -i wlan0 -p udp --sport 1194 -j ACCEPT If you are running OpenVPN, any rules that specify the interface you use to connect to the internet (in my case, wlan0), need to be changed to refer to OpenVPN's tunnel interface instead i.e. tun0. The script supplied below takes care of this. Putting it all together There are a lot of rules described here, and the situation is complicated by OpenVPN, since the rules are different depending on whether or not you are using it, so I've put together a shell script[16] that takes care of everything, and can either: disable the firewall enables the firewall (with OpenVPN running) enables the firewall (with OpenVPN not running) You will obviously want to customize the rules for your own situation, but it's a good starting point, and once you've got it working the way you want, add it to /etc/rc.local so that your rules will be applied when the system boots up. Monitoring blocked packets At the very beginning of this section, we set things up so that any dropped packets get logged. By default, these appear in /var/log/messages, but since there will be a lot of these messages, it's far more convenient to collect them in a separate file. To do this, create the file /etc/rsyslog.d/iptables.conf that looks like this: :msg, contains, "iptables: " -/var/log/iptables & ~ This tells the logging daemon (rsyslogd) to look for messages that contain the string "iptables: " and send them to another file (/var/log/iptables). Since we've created a new log file, it's a good idea to set up log rotation for it. Create the /etc/logrotate.d/iptables file like this: /var/log/iptables { rotate 7 daily missingok notifempty delaycompress compress postrotate invoke-rc.d rsyslog rotate > /dev/null endscript } Finally, the log file contains a lot of information about each packet that we're usually not interested in, so next script will filter out the less-important stuff and provide an easier-to-read log. Script filter-iptables.py: #!/usr/bin/python # This script extracts key information from the iptables log file. # Full tutorial is here: http://awasu.com/weblog/bpi-gateway/firewall/ # # To process the entire log file: # sudo filter-iptables.py