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…
- 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?
- Smart phone connects to the Linux box via OpenVPN
- Linux box is running Pi-hole which acts as a selective DNS server
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:
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="email@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 firstname.lastname@example.org
Note: Steps 1) through 8) needs to be done only once.
9) Build client key and cert:
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).
To install Pi-Hole one simply runs this:
curl -sSL https://install.pi-hole.net | bash
and follows on screen prompts.
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).
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.