Raspberry PI as antispam wireless accesspoint

Goal, Project Description

I need a Wireless accesspoint with an integrated Adblocker for my mobile devices at home. The hardware should be based upon the new Raspberry PI model B+.

  • Using dhcp on the ethernet port it connects to your network
  • The Wireless accesspoint is based on a USB-dongle from Edimax which has a “Realtek 8188 CUS” chip in it.
  • Clients connecting to the accesspoint are given an IP-addresses via DHCP.
  • Web-traffic, coming from the wireless interface with target-ports 80, 8080, 8008 is redirected via iptables to the squid-proxy process which filters out advertising by blocking the tcp-connection.
  • Squid acts as proxy and has 2 blacklists defined. The first one is automatically updated every night and contains a regex’d list of domains. The second list can be maintained manually and includes regexes for domains and url’s. Feel free to enhance that list.
  • All related configuration can be performed by writing files on the FAT32-based /config partition on the SD-card.

Download Raspbian Linux and put onto SD-Card

Retrieve Raspbian from http://www.raspberrypi.org/downloads/ as ISO image. Next Copy that image-file onto SD-Card using dd. Below is a example:

sudo dd bs=4M if=2014-06-20-wheezy-raspbian.img of=/dev/mmcblk0

/dev/mmcblk0 may change and depends on your hardware. I was using a class 4, 4GB micro-SD card.

Configure/Setup

Login to Raspberry via SSH

ssh -l pi raspberry <IP-OF-RASPBERRY-PI>

Cleanup stuff. We have a Server and don’t need that Desktop stuff. So let’s remove that. This will free a lot disk (SD-card) space.

sudo apt-get remove --purge \
    xorg* lightdm* libgtk* libwebkitgtk* samba* \
    weston* wolfram-engine alsa* cifs-utils cups* desktop-base

sudo apt-get remove --purge \
    gksu desktop-file-utils esound-common galculator \
    gnome* libqt4* libvorbis* libx11* lxappearance lxde*

sudo apt-get remove --purge \
    openbox oracle-java* poppler*

Now install needed software/packages and cleanup some leftovers:

sudo apt-get install vim resolvconf dnsmasq dnsutils dosfstools
sudo apt-get autoremove
sudo apt-get autoclean

cd ~
rm -rf python_games Desktop

Configure RPI

sudo raspi-config
  • 4 Internationalization Options -> I2 Change Timezone
  • 8 Advanced Options -> A3 memory split -> 8 MB for Graphics

Create /config partition for configfiles exposed to the end-user

fdisk the SD-card and create a new partition:

sudo cfdisk /dev/mmcblk0
  • choose the free space
  • choose NEW from menu
  • create PRIMARY partition
  • set size to 16 (MB)
  • choose from the beginning
  • choose TYPE from the menu
  • choose 0B (W95 Fat32)
  • choose WRITE in the menu

check the resulting partition table:

sudo fdisk -l /dev/mmcblk0

That partition must be mounted automatically on system boot by editing fstab

sudo vim /etc/fstab

And add the following line:

/dev/mmcblk0p3  /config         vfat    defaults          0       2

Now create the directory which will be used as mount-target

sudo mkdir /config

Reboot now.

Create the filesystem on that newly created config-partition

sudo mkfs.vfat /dev/mmcblk0p3

Mount that filesystem to test things and put the initial configfiles for hostapd and the squid-blacklist on it.

sudo mount /dev/mmcblk0p3 /config

From now on, some selected configfiles will be put on /config. That folder is then accessible on the SD-card when putting into your PC.

Configure networking and web-traffic routing

First, enable IPv4 forwarding. By modifying sysctl.conf we enable it from the next boot on and its permanently:

sudo vim /etc/sysctl.conf

Make the contents look like:

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

To make it work immediately without a reboot, enter (otherwise reboot):

sudo sysctl -w net.ipv4.ip_forward=1

Check it and retrieve the current setting

sudo sysctl net.ipv4.ip_forward

Next we set the wireless interface (wlan0) IP-Addresses and some traffic routing. The Raspberry’s wired ethernet port is set to retrieve it’s IP-Address via DHCP, the wireless interface will be set to a static Address from a different IP-Address-space.

After setting up the wireless interface we will utilize iptables to redirect non-ssl-http-traffic to squid-proxy running on port 3128 which will handle the traffic.

Edit the network-configuration:

sudo vim /etc/network/interfaces

and make it look like this:

# loopback adapter
auto lo
iface lo inet loopback

# wired adapter
iface eth0 inet dhcp

# wireless adapter
iface wlan0 inet static
address 10.0.0.1
network 10.0.0.0
netmask 255.255.255.0
broadcast 10.0.0.255

# force-up the wlan0 interface
up ifup wlan0

# insert iptables-rules for redirecting http-traffic to squid-proxy
post-up iptables -t nat -A PREROUTING -i wlan0 -p tcp -m tcp --dport 80   -j REDIRECT --to-port 3128
post-up iptables -t nat -A PREROUTING -i wlan0 -p tcp -m tcp --dport 8080 -j REDIRECT --to-port 3128
post-up iptables -t nat -A PREROUTING -i wlan0 -p tcp -m tcp --dport 8008 -j REDIRECT --to-port 3128
# also redirect ssl traffic. requires man-in-the-middle ssl attacks/logic
#post-up iptables -t nat -A PREROUTING -i wlan0 -p tcp -m tcp --dport 443  -j REDIRECT --to-port 3128
#post-up iptables -t nat -A PREROUTING -i wlan0 -p tcp -m tcp --dport 8443 -j REDIRECT --to-port 3128
post-up iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Some debugging tips as this step is THE KEY feature. You may or may not use it. See all iptables-entries:

sudo iptables --list
sudo iptables --list-rules
sudo iptables --list --table nat

Flush/Remove all iptables entries

sudo iptables --flush
sudo iptables -t nat --flush
sudo iptables -t mangle --flush
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

Installing DHCP Server and configure “DNS”

We will use dnsmasq for DHCP+DNS deployment. After installation the daemon started automatically. Stop it, secure the original configuration and make our changes:

sudo service dnsmasq stop
sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.original

sudo vim /etc/dnsmasq.conf

Make the dnsmasq configfle look like:

interface=wlan0
expand-hosts
domain=local
dhcp-range=10.0.0.10,10.0.0.50,24h
dhcp-option=3,10.0.0.1

Now start dnsmasq service:

sudo /etc/init.d/dnsmasq start

From now on, clients connecting to wlan0-interface get assigned an IP-address from 10.0.0.10 to 10.0.0.50, the leasetime is 24 hours.

Choose and install the correct hostapd for your wireless device

If you happen to have a Wireless USB Device with a chip named “Realtek RTL8188CUS” you might NOT want to use the stock hostapd from the official repositories but want to compile your own one as the stock one does not have proper drivers for the realtek chip.

Check whether we got such a chip:

# lsusb | grep "802.11"
Bus 001 Device 005: ID 7392:7811 Edimax Technology Co., Ltd EW-7811Un 802.11n Wireless Adapter [Realtek RTL8188CUS]

Yep, at least I’m doomed. If you do NOT have this realtek-chip, issue the following command and install hostapd from the official repositories:

sudo apt-get install hostapd

and you’re done with this step. Please continue with the next point of this how-to. Else, retrieve a proper hostapd that works with this chip, extract, compile, install…

For more information see here for help: http://forums.adafruit.com/viewtopic.php?f=19&t=47716&start=15

http://www.realtek.com/downloads

Communications Network ICS ->
Wireless Lan ICs ->
WLAN NIC ->
Software ->
Check RTL8192C

Pick Linux Kernel 2.6.18~3.9 Download from one of the locations. The site is heavily JavaScript utilized…

I got a file RTL8188C_8192C_USB_linux_v4.0.2_9000.20130911.zip which I transferred to the raspberry and then just followed the instructions:

unzip RTL8188C_8192C_USB_linux_v4.0.2_9000.20130911.zip
cd RTL8188C_8192C_USB_linux_v4.0.2_9000.20130911/wpa_supplicant_hostapd/
tar xzf wpa_supplicant_hostapd-0.8_rtw_r7475.20130812.tar.gz
cd wpa_supplicant_hostapd-0.8_rtw_r7475.20130812/hostapd
make
sudo make install

Register hostapd as startup service to make it start upon system boot

cd /etc/init.d
sudo update-rc.d hostapd defaults

You may also retrieve the final hostapd-tarball-source-file from my site here: wpa_supplicant_hostapd-0.8_rtw_r7475.20130812.tar.gz

Configure hostapd

Edit/create the hostapd configuration file on the /config partition

sudo vim /config/hostapd.conf

And change to match the following content:

# Basic configuration
interface=wlan0
ssid=WITHOUT-ADS
channel=1

# WPA and WPA2 configuration
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=3
wpa_passphrase=WITHOUT-ADS-SECRET
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

# Hardware configuration
driver=rtl871xdrv
ieee80211n=1
hw_mode=g
device_name=RTL8192CU
manufacturer=Realtek

# Logging
# comment out when everything works... !!!
#
# Logging Channel (-1 = all)
# Logging Levels (minimum value for logged events):
#  0 = verbose debugging
#  1 = debugging
#  2 = informational messages
#  3 = notification
#  4 = warning
#
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2

You should change the following values to match your wireless accesspoint configuration:

  • ssid
  • channel
  • wpa_passphrase

Make sure the hostapd startup-script knows from that configfile and uses it:

sudo vim /etc/init.d/hostapd

Modify the path to the configfile:

DAEMON_CONF=/config/hostapd.conf

And (re)start the hostapd service:

$ sudo service hostapd restart
[ ok ] Stopping advanced IEEE 802.11 management: hostapd.
[ ok ] Starting advanced IEEE 802.11 management: hostapd.

Peek into syslog to make sure everything is ok:

tail /var/log/syslog

Install and configure squid proxy acting as adblocker

Install squid3 proxy

sudo apt-get install squid3 

Secure the original and modify the squid configfile:

sudo mv /etc/squid3/squid.conf /etc/squid3/squid.conf.original
sudo vim /etc/squid3/squid.conf

The squid configfile should be like the following:

# acl lists
acl manager proto cache_object
acl localhost src 127.0.0.1/32 ::1
acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1
acl localnet src 10.0.0.0/8 ::1

# port connections
acl SSL_ports port 443
acl SSL method CONNECT
acl Safe_ports port 80 8080 8008 # http
acl Safe_ports port 443 8443     # https
acl CONNECT method CONNECT

# allow/deny
http_access allow manager localhost
http_access deny manager

# Deny requests to certain unsafe ports
http_access deny !Safe_ports

# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports

# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on "localhost" is a local user
http_access deny to_localhost

# disable access advertising http DOMAINS ( http://pgl.yoyo.org/adservers/ )
acl ads_domains dstdom_regex -i "/etc/squid3/adservers.blacklist.txt"
http_access deny ads_domains
deny_info TCP_RESET ads_domains

# disable custom http URL
acl custom_urls url_regex -i "/config/custom-urls.blacklist.txt"
http_access deny custom_urls
deny_info TCP_RESET custom_urls

# Example rule allowing access from your local networks.
http_access allow localnet
http_access allow localhost

## And finally deny all other access to this proxy
http_access deny all

# bind address default port is 3128
#http_port 3128
http_port 3128 transparent

# caching
cache_mem 128 MB

# logging
access_log none
#access_log /var/log/squid3/access.log squid
logfile_rotate 9

As we have deny_info set, we create a file to sent a customized error-message to the clients browser:

sudo vim /usr/share/squid3/errors/en/TCP_RESET

"BLOCKED BY YOUR ADBLOCK-PROXY"

Next we configure the daily refreshed adserver-domain-blacklist. We fetch it once manually, it will be automated later on. Create the shellscript which will fetch the configfile:

sudo vim /etc/cron.daily/getadblock.sh

The script below is from http://wiki.linuxmce.org/index.php/Squid_as_ad_blocker and tweaked a little bit:

#!/bin/sh

### short script that downloads a list of ad servers for use with squid to block ads.
###
### details on configuring squid itself can be found here:
###
###    http://pgl.yoyo.org/adservers/#withsquid
###
### - originally by Stephen Patterson <steve@lexx.uklinux.net>
### - butchered by Peter Lowe <pgl@yoyo.org>
### - LMCE 10.04 adjustments by Joakim Lindbom

## set things

# URL of the ad server list to download
listurl='http://pgl.yoyo.org/adservers/serverlist.php?hostformat=squid-dstdom-regex;showintro=0&mimetype=plaintext' 

# location of the list of ad servers used by Squid
targetfile='/etc/squid3/adservers.blacklist.txt'

# command to reload squid - change according to your system
reloadcmd='/etc/init.d/squid3 reload' 

# temp file to use
tmpfile="/tmp/.adlist.$$"

# command to fetch the list (alternatives commented out)
fetchcmd="wget -q $listurl -O $tmpfile"

# get a fresh list of ad server addresses for squid to refuse
$fetchcmd

# check the temp file exists OK before overwriting the existing list
if [ ! -s $tmpfile ]
then
    echo "$(date -R) temp file '$tmpfile' either doesn't exist or is empty; quitting"
    exit
fi

cp  $tmpfile $targetfile

# clean up
rm $tmpfile 

# reload Squid
$reloadcmd

Make that shellscript executable:

sudo chmod +x /etc/cron.daily/getadblock.sh

and run it once to see if it works and fetch the initial blacklist…

sudo /etc/cron.daily/getadblock.sh

Also maintain another blacklist file that holds complete URLs instead of domains. That file is located on the /custom partition and thus can be modified by the end-user easily.

Create that blacklist:

sudo vim /config/custom-urls.blacklist.txt

I was able to maintain some domains and URLs for my sites i visit most:

#
# this a handcrafted blacklist for http (non ssl) URLs as regex
#

#
# google services / urls
#
^http://.*\.googleadservices\.com/
^http://www\.googletagservices\.com/
^http://apis\.google\.com/js/plusone\.js
^http://apis\.google\.com/js/platform\.js
^http://apis\.google\.com/.*/fastbutton\?.*
^http://.*google-analytics\.com/
^http://plusone\.google\.com/.*/fastbutton\?.*


#
# facebook crap goes here
#
^http://connect\.facebook\.net/
^http://graph\.facebook\.com/
^http://www\.facebook\.com/connect/ping
^http://www\.facebook\.com/.*plugins/comments\.php
^http://www\.facebook\.com/.*plugins/share_button\.php
^http://www\.facebook\.com/.*plugins/like\.php


#
# twitter
#
^http://platform\.twitter\.com/
^http://twitter\.com/i/jot

#
# generic stuff
#
^http://ads\..*\.(de|com|net|org|info|biz|it|pl|uk|jp|tw|us|fr|ch|dk|se|pl)/
^http://.*\.nuggad\.net/
^http://.*\.meetrics\.net/
^http://.*\.t4ft\.de/
^http://.*\.yieldlab\.net/
^http://.*\.ioam\.de/
^http://.*\.ivwbox\.de/
^http://.*\.krxd\.net/
^http://.*\.quality-channel\.de/
^http://.*\.adition\.com/
^http://.*\.mkt922\.com/
^http://.*\.doubleclick\.net/
^http://.*\.bonniercorp\.com/
^http://.*\.skimresources\.net/
^http://.*\.scorecardresearch\.com/
^http://.*\.mxcdn\.net/
^http://.*\.vgwort\.de/
^http://.*\.taboolasyndication\.com/
^http://.*\.econda-monitor\.de/
^http://.*/nm_trck\.gif\?.*
^http://.*/nm_empty\.gif\?.*
###^http://.*\.veeseo\.com/widgets/.*
^http://.*\.plista\.com/

At this point we’re done configuring stuff. Reboot for the last time. We should have a wireless accesspoint available that we can connect to. Non-SSL http traffic is redirected to squid which filters out domains and URLs. SSL-Encrypted traffic is not proxied through squid. One needs to perform a man-in-the-middle-attack on the SSL traffic - I won’t do that here. Search for “mitmproxy” to gain further information.

A WPA-2 AES-CCMP hostapd configfile

Here is a working hostapd.conf file for WPA-2 encryption with AES-CCMP, as seen on http://www.pi-point.co.uk/documentation/

interface=wlan0
# activate some syslogging
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
dump_file=/tmp/hostapd.dump
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
# WLAN Name (SSID), county setting and WLAN mode and channel
ssid=Raspberry
country_code=UK
hw_mode=g
channel=2
# Timing Parameter
beacon_int=100
dtim_period=2
max_num_sta=32
rts_threshold=2347
fragm_threshold=2346
macaddr_acl=0
auth_algs=3
ignore_broadcast_ssid=0
wmm_enabled=0
ap_max_inactivity=300
# WPA key settings
wpa=2
wpa_passphrase=raspberry
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
rsn_pairwise=CCMP
wpa_group_rekey=600