Hate ads on your smart phone? Pi-hole it permanently!

Sorry about spammy headline ;).

Below I will describe how I got rid of ads on my android phone without rooting it.
It is very easy to get rid of ads on an android smart phone if you have root access. Unfortunately pesky manufacturers insist on declining warranty if the phone is rooted.
I will probably one day test this is in small claims court for a cheaper phone. I digress…

The requirements:

  • Some linux box/container/VM. In this post I used Ubuntu 16.04 LTS
  • Public IP on the box from above
  • Some linux/cli/unix experience

How does it work?

  1. Smart phone connects to the Linux box via OpenVPN
  2. Linux box is running Pi-hole which acts as a selective DNS server
  3. ???
  4. Proft!

Build.

OpenVPN:

1) Install OpenVPN and easy-rsa:
apt-get install openvpn easy-rsa

2) Setup easy-rsa depository:
make-cadir ~/ca
cd ~/ca

3) Configure easy-rsa:
emacs vars

Modify the following to match your set up:
export KEY_COUNTRY="NZ"
export KEY_PROVINCE="North Island"
export KEY_CITY="Auckland"
export KEY_ORG="pihole.example.com"
export KEY_EMAIL="pihole@example.com"
export KEY_OU="pihole.example.com"
export KEY_NAME="pihole"

4) Set up the environment:
source vars
./clean-all

5) Build CA, the server key and DH:
./build-ca
./build-key-server server
./build-dh

6)Copy the certs and keys to the OpenVPN directory:
cd keys
cp ca.crt server.crt server.key dh2048.pem /etc/openvpn

7) Create OpenVPN config:
echo "port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
server 10.12.34.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"
keepalive 10 120
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
status openvpn-status.log
verb 3
mute 20
cipher AES-128-CBC" > /etc/openvpn/server.conf

8) Start the OpenVPN server:
systemctl start openvpn@server.service

Note: Steps 1) through 8) needs to be done only once.

9) Build client key and cert:
./build-key client0

10) Because android OpenVPN client is very limited from configuration point of view and can only import pkcs12 keys (and does not “understand” inline certs), one needs to “pack” the CA cert, client cert and key into pkcs12 file:
openssl pkcs12 -export -in client0.crt -inkey client0.key -certfile ca.crt -name client0 -out client0.p12

11) Create client config (replace server after “remote” to your server domain name or IP):
echo "client
dev tun
remote pihole.example.com
resolv-retry infinite
nobind
persist-key
persist-tun
verb 1
keepalive 10 120
port 1194
proto udp
comp-lzo
cipher AES-128-CBC" > client0.ovpn

12) Securely copy the two files (client0.ovpn and client0.p12) to the android phone in question.

13) Install and configure the OpenVPN client on android. The config is imported by selecting “OVPN Profile” and using the import to import OVPN file and PKCS#12 certificate. The UI might differ, generally the import function can be accessed from “hamburger” menu.
Note: When importing the PKCS#12 certificate you will have to set pin/pattern (I don’t think there is work around for that).

14) On first connection the OpenVPN app will prompt which certificate to use with connection, make sure select the one that was imported in step 13).

Note: Steps 9) through 14) have to be repeated for each client; make sure to change the file name (client0 in this example) to something else for next client.

At this stage the OpenVPN tunnel in itself is functional but will not pass traffic through (see IPTABLES section).

Pi-Hole:

To install Pi-Hole one simply runs this:
curl -sSL https://install.pi-hole.net | bash
and follows on screen prompts.

IPTABLES:

To pass the traffic through the following rules needs to be set up:

  • MASQUERADE (aka as NAT): iptables -t nat -A POSTROUTING -s 10.12.34.0/24 -o eth0 -j MASQUERADE
  • Enable forwarding: echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf; sysctl -p

The above is basic minimum needed for tunnel to pass the traffic.

The evil thing that android does is completely ignores DNS servers given by DHCP, thus we will need to intercept that at the firewall level:
iptables -t nat -A PREROUTING -i tun0 -p udp -m udp --dport 53 -j DNAT --to-destination 10.12.34.1:53
Without the above pi-hole will not have any effect!

I would recommend having some other firewall rules to actually secure the linux box, being lazy I use post-up /usr/local/bin/firewall.sh in the interfaces file to set up the firewall where the /usr/local/bin/firewall.sh (don't forget to chmod +x /usr/local/bin/firewall.sh) looks something like this:
#!/bin/bash
IPTABLES=/sbin/iptables

$IPTABLES -P INPUT ACCEPT
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
$IPTABLES -F
$IPTABLES -X
$IPTABLES -t nat -F
$IPTABLES -t nat -X
$IPTABLES -t mangle -F
$IPTABLES -t mangle -X
$IPTABLES -t raw -F
$IPTABLES -t raw -X

$IPTABLES -t nat -A PREROUTING -i tun0 -p udp -m udp --dport 53 -j DNAT --to-destination 10.12.34.1:53
$IPTABLES -t nat -A POSTROUTING -s 10.12.34.0/24 -o ens160 -j MASQUERADE

$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A INPUT -m state --state INVALID -j DROP
$IPTABLES -A INPUT -i tun0 -j ACCEPT
$IPTABLES -A INPUT -p icmp -j ACCEPT
$IPTABLES -A INPUT -p udp -m udp --dport 1194 -j ACCEPT
$IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

$IPTABLES -P INPUT DROP
Warning: The above does not deal with ssh and will promptly lock you out 😉 (unless you have existing session running to fix the screw-up).

Conclusion:

This set up has other advantages beyond the ad blocking:

  • IP blocking (via iptables or ipsets) on top of DNS blocking
  • Ensures security when captive portals and other insecure networks are used
  • Prevents overzealous employers from snooping DNS

Although this set up comes with some disadvantages:

  • Might not work well under bad networking conditions
  • Requires a machine on the internet that runs 24/7 (cloud/electricity costs)
  • Minor annoyance of having OpenVPN running all the time on the phone

On top of regular ad blocking this set up allowed me to block the whole facebook, which is a huge win.

Leave a Reply

Your email address will not be published. Required fields are marked *