OpenWRT Adblock with Pixelserv

By | January 21, 2014

adblock

There’re many ways of doing this. The scenario and configuration is flexible enough, depending on what you want to achieve.

The easy way

Others have recently developed packages for this same functionality, and done it better than anything I could do. Use the packages instead of this script:

Description

In its basic usage, this script will modify the router such that blocked addresses are null routed and unreachable. Since the address blocklist is full of advertising, malware, and tracking servers, this setup is generally a good thing. In addition, the router will update the blocklist weekly. However, the blocking is leaky, so do not expect everything to be blocked.

Setup

The script must be copied to an OpenWRT router (gargoyle firmware works fine, too).

For example, if the router is located at 192.168.1.1:

# scp adblock.sh [email protected]:/etc/adblock.sh

Make the script executable:

# chmod +x /etc/adblock.sh

Basic usage

If you are running the script for the first time:

# sh /etc/adblock.sh -f

There should be status updates in the output, but there should be no errors. If these commands complete without errors, the adblocking is active. You can test it by looking up, say, google analytics.

Whitelists and blacklists

The script supports defining whitelisted urls. That is, urls that will be filtered out of the downloaded blocklists. To whitelist urls, place them (one per line) in /etc/white.list.

Similarly, the script supports defining blacklisted urls – urls that will be added to the downloaded blocklists. To blacklist urls, place them (one per line) in /etc/black.list.

NOTE: The whitelist support is pretty stupid, so don’t expect smart filtering (e.g., domain extrapolation). I’ve found it tedious, but worthwhile, to find the offending url in /etc/block.hosts and copy it to /etc/white.list.

Advanced usage

Toggle on and off

To toggle the blocking on and off, run the script with the -t switch:

# sh /etc/adblock.sh -t

Note: This does not delete the blocklist, whitelist, or blacklist.

Manually update blocklist

To manually update the blocklist, run the script without switches:

# sh /etc/adblock.sh

Full reinstall

To reinstall the current implementation:

# sh /etc/adblock.sh -r

Configuration

The config section of the script has some variables that alter the behaviour of the script.

For example, if you change:

ONLY_WIRELESS="N"

to

ONLY_WIRELESS="Y"

Then only the wireless interface of the router will filter the blocklist.

To change the configuration of an already active installation, I would toggle the adblocking off first, change the script, then toggle it back on. That is,

# sh /etc/adblock.sh -t # turn off
...modify variables...
# sh /etc/adblock.sh -t # turn on

However, if you change certain variables, you must re-update the blocklist because the redirection values will have changed. Other variables require a full restart because they must install or verify dependencies.

Configurable variables:

  • ONLY_WIRELESS (Y/N): Only filter on wireless interface
  • EXEMPT# (Y/N): Exempt ip range from filtering (between START_ RANGE and END_RANGE)
  • IPV6*: (Y/N): Add IPv6 support
  • SSL# (Y/N): Install wget with ssl support (only needed for ssl websites)
  • TRANS#: (Y/N): Modify router web server to server transparent pixel responses for blocked websites
  • ENDPOINT_IP4/IP6*: Define the IP to return for blocked hostnames (IPv4 and IPv6)
  • CRON: The cron line to put in the crontab

*: Requires blocklist update.

: Requires full reinstall

view raw

README.md

hosted with ❤ by GitHub


#!/bin/sh
#Put in /etc/adblock.sh
#Block ads, malware, etc.
#### CONFIG SECTION ####
# Only block wireless ads? Y/N
ONLY_WIRELESS="N"
# IPv6 support? Y/N
IPV6="N"
# Need SSL websites?
SSL="N"
# Try to transparently serve pixel response?
# If enabled, understand the consequences and mechanics of this setup
TRANS="N"
# Exempt an ip range
EXEMPT="N"
START_RANGE="192.168.1.0"
END_RANGE="192.168.1.255"
# Redirect endpoint
ENDPOINT_IP4="0.0.0.0"
ENDPOINT_IP6="::"
#Change the cron command to what is comfortable, or leave as is
CRON="0 4 * * 0,3 sh /etc/adblock.sh"
#### END CONFIG ####
#### FUNCTIONS ####
cleanup()
{
#Delete files used to build list to free up the limited space
echo 'Cleaning up…'
rm -f /tmp/block.build.list
rm -f /tmp/block.build.before
}
install_dependencies()
{
#Need iptables-mod-nat-extra installed
if opkg list-installed | grep -q iptables-mod-nat-extra
then
echo 'iptables-mod-nat-extra is installed!'
else
echo 'Updating package list…'
opkg update > /dev/null
echo 'Installing iptables-mod-nat-extra…'
opkg install iptables-mod-nat-extra > /dev/null
fi
#Need iptable-mod-iprange for exemption
if [ "$EXEMPT" = "Y" ]
then
if opkg list-installed | grep -q iptables-mod-iprange
then
echo 'iptables-mod-iprange installed'
else
echo 'Updating package list…'
opkg update > /dev/null
echo 'Installing iptables-mod-iprange…'
opkg install iptables-mod-iprange > /dev/null
fi
fi
#Need wget for https websites
if [ "$SSL" = "Y" ]
then
if opkg list-installed wget | grep -q wget
then
if wget –version | grep -q +ssl
then
echo 'wget (with ssl) found'
else
# wget without ssl, need to reinstall full wget
opkg update > /dev/null
opkg install wget –force-reinstall > /dev/null
fi
else
echo 'Updating package list…'
opkg update > /dev/null
echo 'Installing wget (with ssl)…'
opkg install wget > /dev/null
fi
fi
}
add_config()
{
if [ "$ONLY_WIRELESS" = "Y" ]
then
echo 'Wireless only blocking!'
if [ "$EXEMPT" = "Y" ]
then
echo 'Exempting some ips…'
FW1="iptables -t nat -I PREROUTING -m iprange ! –src-range $START_RANGE-$END_RANGE -i wlan+ -p tcp –dport 53 -j REDIRECT –to-ports 53"
FW2="iptables -t nat -I PREROUTING -m iprange ! –src-range $START_RANGE-$END_RANGE -i wlan+ -p udp –dport 53 -j REDIRECT –to-ports 53"
else
FW1="iptables -t nat -I PREROUTING -i wlan+ -p tcp –dport 53 -j REDIRECT –to-ports 53"
FW2="iptables -t nat -I PREROUTING -i wlan+ -p udp –dport 53 -j REDIRECT –to-ports 53"
fi
else
if [ "$EXEMPT" = "Y" ]
then
echo "Exempting some ips…"
FW1="iptables -t nat -I PREROUTING -m iprange ! –src-range $START_RANGE-$END_RANGE -p tcp –dport 53 -j REDIRECT –to-ports 53"
FW2="iptables -t nat -I PREROUTING -m iprange ! –src-range $START_RANGE-$END_RANGE -p udp –dport 53 -j REDIRECT –to-ports 53"
else
FW1="iptables -t nat -I PREROUTING -p tcp –dport 53 -j REDIRECT –to-ports 53"
FW2="iptables -t nat -I PREROUTING -p udp –dport 53 -j REDIRECT –to-ports 53"
fi
fi
echo 'Updating config…'
#Update DHCP config
uci add_list dhcp.@dnsmasq[0].addnhosts=/etc/block.hosts > /dev/null 2>&1 && uci commit
#Add to crontab
echo "$CRON" >> /etc/crontabs/root
#Update dnsmasq config for Tor
TOR=`uci get tor.global.enabled 2> /dev/null`
if [ "$TOR" == "1" ]
then
TORPORT=`uci get tor.client.dns_port`
TORIP="127.0.0.1:$TORPORT"
uci set dhcp.@dnsmasq[0].noresolv='1' > /dev/null &2>1 && uci commit
uci add_list dhcp.@dnsmasq[0].server="$TORIP" > /dev/null &2>1 && uci commit
fi
# Add firewall rules
echo "$FW1" >> /etc/firewall.user
echo "$FW2" >> /etc/firewall.user
# Provide hint if localservice is 1
LS=`uci get dhcp.@dnsmasq[0].localservice 2> /dev/null`
if [ "$LS" == "1" ]
then
echo "HINT: localservice is set to 1"
echo " Adblocking (and router DNS) over a VPN may not work"
echo " To allow VPN router DNS, manually set localservice to 0"
fi
# Determining uhttpd/httpd_gargoyle for transparent pixel support
if [ "$TRANS" = "Y" ]
then
if [ ! -e "/www/1.gif" ]
then
/usr/bin/wget -O /www/1.gif http://upload.wikimedia.org/wikipedia/commons/c/ce/Transparent.gif > /dev/null
fi
if [ -s "/usr/sbin/uhttpd" ]
then
#The default is none, so I don't want to check for it, so just write it
echo "uhttpd found…"
echo "updating server error page to return transparent pixel…"
uci set uhttpd.main.error_page="/1.gif" && uci commit
elif [ -s "/usr/sbin/httpd_gargoyle" ]
then
# Write without testing
echo "httpd_gargoyle found…"
echo "updating server error page to return transparent pixel…"
uci set httpd_gargoyle.server.page_not_found_file="1.gif" && uci commit
else
echo "Cannot find supported web server…"
fi
fi
}
update_blocklist()
{
#Delete the old block.hosts to make room for the updates
rm -f /etc/block.hosts
# Correct endpoint for transparent pixel response
if [ "$TRANS" = "Y" ] && [ -e "/www/1.gif" ] && ([ -s "/usr/sbin/uhttpd" ] || [ -s "/usr/sbin/httpd_gargoyle" ])
then
ENDPOINT_IP4=$(uci get network.lan.ipaddr)
if [ "$IPV6" = "Y" ]
then
ENDPOINT_IP6=$(uci get network.lan6.ipaddr)
fi
fi
echo 'Downloading hosts lists…'
#Download and process the files needed to make the lists (enable/add more, if you want)
wget -qO- http://www.mvps.org/winhelp2002/hosts.txt| awk -v r="$ENDPOINT_IP4" '{sub(/^0.0.0.0/, r)} $0 ~ "^"r' > /tmp/block.build.list
wget -qO- "http://adaway.org/hosts.txt"|awk -v r="$ENDPOINT_IP4" '{sub(/^127.0.0.1/, r)} $0 ~ "^"r' >> /tmp/block.build.list
#wget -qO- http://www.malwaredomainlist.com/hostslist/hosts.txt|awk -v r="$ENDPOINT_IP4" '{sub(/^127.0.0.1/, r)} $0 ~ "^"r' >> /tmp/block.build.list
#wget -qO- "http://hosts-file.net/.\ad_servers.txt"|awk -v r="$ENDPOINT_IP4" '{sub(/^127.0.0.1/, r)} $0 ~ "^"r' >> /tmp/block.build.list
#Add black list, if non-empty
if [ -s "/etc/black.list" ]
then
echo 'Adding blacklist…'
awk -v r="$ENDPOINT_IP4" '/^[^#]/ { print r,$1 }' /etc/black.list >> /tmp/block.build.list
fi
echo 'Sorting lists…'
#Sort the download/black lists
awk '{sub(/\r$/,"");print $1,$2}' /tmp/block.build.list|sort -u > /tmp/block.build.before
#Filter (if applicable)
if [ -s "/etc/white.list" ]
then
#Filter the blacklist, supressing whitelist matches
# This is relatively slow =-(
echo 'Filtering white list…'
egrep -v "^[[:space:]]*$" /etc/white.list | awk '/^[^#]/ {sub(/\r$/,"");print $1}' | grep -vf – /tmp/block.build.before > /etc/block.hosts
else
cat /tmp/block.build.before > /etc/block.hosts
fi
if [ "$IPV6" = "Y" ]
then
safe_pattern=$(printf '%s\n' "$ENDPOINT_IP4" | sed 's/[[\.*^$(){}?+|/]/\\&/g')
safe_addition=$(printf '%s\n' "$ENDPOINT_IP6" | sed 's/[\&/]/\\&/g')
echo 'Adding ipv6 support…'
sed -i -re "s/^(${safe_pattern}) (.*)$/\1 \2\n${safe_addition} \2/g" /etc/block.hosts
fi
}
restart_firewall()
{
echo 'Restarting firewall…'
if [ -s "/usr/lib/gargoyle/restart_firewall.sh" ]
then
/usr/lib/gargoyle/restart_firewall.sh > /dev/null 2>&1
else
/etc/init.d/firewall restart > /dev/null 2>&1
fi
}
restart_dnsmasq()
{
if [ "$1" -eq "0" ]
then
echo 'Re-reading blocklist'
killall -HUP dnsmasq
else
echo 'Restarting dnsmasq…'
/etc/init.d/dnsmasq restart
fi
}
restart_http()
{
if [ -s "/usr/sbin/uhttpd" ]
then
echo 'Restarting uhttpd…'
/etc/init.d/uhttpd restart
elif [ -s "/usr/sbin/httpd_gargoyle" ]
then
echo 'Restarting httpd_gargoyle…'
/etc/init.d/httpd_gargoyle restart
fi
}
restart_cron()
{
echo 'Restarting cron…'
/etc/init.d/cron restart > /dev/null 2>&1
}
remove_config()
{
echo 'Reverting config…'
# Remove addnhosts
uci del_list dhcp.@dnsmasq[0].addnhosts=/etc/block.hosts > /dev/null 2>&1 && uci commit
# Remove cron entry
sed -i '/adblock/d' /etc/crontabs/root
# Remove firewall rules
sed -i '/–to-ports 53/d' /etc/firewall.user
# Remove Tor workarounds
uci del_list dhcp.@dnsmasq[0].server > /dev/null 2>&1 && uci commit
uci set dhcp.@dnsmasq[0].noresolv='0' > /dev/null 2>&1 && uci commit
# Remove proxying
uci delete uhttpd.main.error_page > /dev/null 2>&1 && uci commit
uci set httpd_gargoyle.server.page_not_found_file="login.sh" > /dev/null 2>&1 && uci commit
}
toggle()
{
# Check for cron as test for on/off
if grep -q "adblock" /etc/crontabs/root
then
# Turn off
echo 'Turning off!'
remove_config
else
# Turn on
echo 'Turning on!'
add_config
fi
# Restart services
restart_firewall
restart_dnsmasq 1
restart_http
restart_cron
}
#### END FUNCTIONS ####
### Options parsing ####
case "$1" in
# Toggle on/off
"-t")
toggle
;;
#First time run
"-f")
install_dependencies
add_config
update_blocklist
restart_firewall
restart_dnsmasq 1
restart_http
restart_cron
cleanup
;;
#Reinstall
"-r")
remove_config
install_dependencies
add_config
update_blocklist
restart_firewall
restart_dnsmasq 1
restart_http
restart_cron
cleanup
;;
#Default updates blocklist only
*)
update_blocklist
restart_dnsmasq 0
cleanup
;;
esac
#### END OPTIONS ####
exit 0

view raw

adblock.sh

hosted with ❤ by GitHub


#/etc/black.list
#add some server that the list doesn't block
example1.block.com

view raw

black.list

hosted with ❤ by GitHub


#/etc/sysupgrade.conf
#This file is a list of files that should be preserved through upgrades
#OPTIONAL!!!!!
/etc/passwd
/etc/shadow
/etc/adblock.sh #ADD THIS LINE
/etc/white.list #AND THIS ONE
/etc/block.hosts #AND THIS ONE
/etc/black.list #AND THIS ONE

view raw

sysupgrade.conf

hosted with ❤ by GitHub


#/etc/white.list
#Add whitelisted addresses, when appropriate, etc.
a248.e.akamai.net

view raw

white.list

hosted with ❤ by GitHub

My review: Provide the simplest method, poisoned DNS record will be redirected to 127.0.0.1. Longer page load due to no content served in 127.0.0.1 (wait until connection timeout). However this script let you manually control on white list and black list domain.


#!/bin/sh /etc/rc.common
# Copy this skript to /etc/init.d/adblock and enable:
# chmod +x /etc/init.d/adblock
# /etc/init.d/adblock enable
START=90
ADS='http://pgl.yoyo.org/as/serverlist.php?hostformat=dnsmasq&showintro=0&mimetype=plaintext'
WWW2="/tmp/www2"
GIF1="1.gif"
DM_CONF=/var/etc/dnsmasq.conf
DM_BAD=/var/etc/dnsmasq.bad
ssd=start-stop-daemon
UPID1=/var/run/uhttpd_main.pid
UPID2=/var/run/uhttpd_www2.pid
UH=/usr/sbin/uhttpd
start() {
mkdir -p $WWW2
echo -ne 'GIF89a1010\x8000\xff\xff\xff000!\xf9\x0400000,000010100\x02\x02D10;' | tr 01 '\000\001' > $WWW2/$GIF1
# Choose an unused IP
ip=$(uci get network.lan.ipaddr)
ip2=10.3.5.3
case $ip in 10.3.*) ip2=10.4.6.4 ;; esac
ifconfig br-lan:1 inet $ip2 netmask 255.255.255.255
# Restart uhttpd to listen only LAN
if [ -f "$UPID1" ]; then
uargs="$(cat /proc/$(cat $UPID1)/cmdline | tr '\000' ' ' | cut -d ' ' -f 2- )"
if echo "$uargs" | grep -q '0.0.0.0'; then
uargs=$(echo $uargs | sed -e "s/0\.0\.0\.0/$ip/")
$ssd -Kqs HUP -p $UPID1
sleep 1
$ssd -Sqbmp $UPID1 -x $UH — $uargs
fi
fi
# Start another uhttpd
$ssd -Sqbmp $UPID2 -x $UH — -f -h $WWW2 -E /$GIF1 -I $GIF1 -p $ip2:80
# Add rules to dnsmasq
wget -qO $DM_BAD "$ADS" && sed -i -e "s/127\.0\.0\.1/$ip2/" $DM_BAD
if [ -f $DM_CONF -a -f $DM_BAD ] && ! grep -q $DM_BAD $DM_CONF; then
$ssd -Kqn dnsmasq
sleep 1
echo "conf-file=$DM_BAD" >> $DM_CONF
$ssd -Sqx dnsmasq — -C $DM_CONF
fi
}
stop() {
$ssd -Kqs HUP -p $UPID2
}

view raw

adblock

hosted with ❤ by GitHub

My review: The script will attempt to create another interface alias and run pixelserv (simple webserver serving 1×1 pixel transparent gif) on that interface. However, you’ll not be able to manually control on white/black list as previous script.

My method

Again, this might not be the best way, but it served my requirements. I’ll be using the same script except that i tweaked it to suit my environment.

Step 1: Create interface alias
I need my pixelserv to run in different ip address (let say my LAN ip is 192.168.1.1/24 i want pixelserv to run on 192.168.88.1/24) so that my uhttpd can listen on 192.168.1.1:80 for LuCI. Add below interface to /etc/config/network

#nano /etc/config/network
config interface 'lan2'
	option ifname 	'eth0'
	option proto	'static'
	option ipaddr 	'192.168.88.1'
	option netmask	'255.255.255.0'

Restart network interfaces
#/etc/init.d/network restart

Verify new interface alias created

root@OpenWrt:~# ifconfig
br-lan    Link encap:Ethernet  HWaddr 08:00:27:9A:88:DD
          inet addr:192.168.1.1  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:629 errors:0 dropped:0 overruns:0 frame:0
          TX packets:661 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:73752 (72.0 KiB)  TX bytes:393608 (384.3 KiB)

eth0      Link encap:Ethernet  HWaddr 08:00:27:9A:88:DD
          inet addr:192.168.88.1  Bcast:192.168.88.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:633 errors:0 dropped:0 overruns:0 frame:0
          TX packets:769 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:82836 (80.8 KiB)  TX bytes:528224 (515.8 KiB)

eth1      Link encap:Ethernet  HWaddr 08:00:27:9C:1E:FF
          inet addr:10.0.3.15  Bcast:10.0.3.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:157 errors:0 dropped:0 overruns:0 frame:0
          TX packets:138 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:15482 (15.1 KiB)  TX bytes:13962 (13.6 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:16 errors:0 dropped:0 overruns:0 frame:0
          TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1648 (1.6 KiB)  TX bytes:1648 (1.6 KiB)

root@OpenWrt:~# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         10.0.3.2        0.0.0.0         UG    0      0        0 eth1
10.0.3.0        *               255.255.255.0   U     0      0        0 eth1
192.168.1.0     *               255.255.255.0   U     0      0        0 br-lan
192.168.88.0    *               255.255.255.0   U     0      0        0 eth0

Step 2: Pixelserv setup
We already have a web server installed on the router (serving LuCI), we just need to configure a new uHTTPd server instance.

mkdir /www_pixelserv
wget -O /www_pixelserv/blank.gif http://probablyprogramming.com/wp-content/uploads/2009/03/tinytrans.gif

Edit /etc/config/uhttpd

config uhttpd 'main'
list listen_http '0.0.0.0192.168.1.1:80'
list listen_https '0.0.0.0:443'
option home '/www'

config uhttpd 'pixelserv'
list listen_http '192.168.88.1:80'
option home '/www_pixelserv'
option error_page '/blank.gif'

Restart uhttpd

/etc/init.d/uhttpd restart

Step 3: Adblock for dnsmasq
Follow installation instruction at https://gist.github.com/teffalump/7227752
For adblock.sh, add following lines to 127.0.0.1 with 192.168.88.1

....
#Download and process the files needed to make the lists (add more, if you want)
wget -qO- "http://adaway.org/hosts.txt"|grep "^127.0.0.1" >> /tmp/block.build.list

#Replace 127.0.0.1 with 192.168.88.1
sed -i 's/127.0.0.1/192.168.88.1/g' /tmp/block.build.list
#Add black list, if non-empty
[ -s "/etc/black.list" ] && sed -e 's/^/192.168.88.1\t/g' /etc/black.list >> /tmp/block.build.list
...

Update:

Above mentioned method (creating interface alias) is valid for interface that do not have vlan tagging. For my case, eth0 is tagged with vlan500 and vlan600 (eth0.500 and eth0.600) and I cannot find any documentation for creating alias for tagged interfaces. As workaround, I’ve changed the pixelserv uhttpd to listen to 192.168.1.1:80, while for router web ui (LuCI) listened to port 443.

This is my modified adblock.sh

!/bin/sh   
#Put in /etc/adblock.sh

#Script to grab and sort a list of adservers and malware

#Delete the old block.hosts to make room for the updates
rm -f /etc/block.hosts

#Download and process the files needed to make the lists (add more, if you want)
wget -qO- http://www.mvps.org/winhelp2002/hosts.txt| sed 's/0.0.0.0/127.0.0.1/g' |grep "^127.0.0.1" > /tmp/block.build.list
wget -qO- http://www.malwaredomainlist.com/hostslist/hosts.txt|grep "^127.0.0.1" >> /tmp/block.build.list
wget -qO- "http://hosts-file.net/.\ad_servers.txt"|grep "^127.0.0.1" >> /tmp/block.build.list
wget -qO- "http://adaway.org/hosts.txt"|grep "^127.0.0.1" >> /tmp/block.build.list

#Replace 127.0.0.1 with 192.168.88.1
sed -i 's/127.0.0.1/192.168.88.1/g' /tmp/block.build.list
#Add black list, if non-empty
[ -s "/etc/black.list" ] && sed -e 's/^/192.168.1.1\t/g' /etc/black.list >> /tmp/block.build.list

#Sort the download/black lists
sed -e 's/\r//g' -e 's/^192.168.88.1[ ]\+/192.168.88.1\t/g' /tmp/block.build.list|sort|uniq > /tmp/block.build.before

if [ -s "/etc/white.list" ]
then
    #Filter the blacklist, supressing whitelist matches
    sed -e 's/\r//g' /etc/white.list > /tmp/white.list
    grep -vf /tmp/white.list /tmp/block.build.before > /etc/block.hosts
    rm -f /tmp/white.list
else
    cat /tmp/block.build.before > /etc/block.hosts
fi

#Delete files used to build list to free up the limited space
rm -f /tmp/block.build.before

References:
http://jazz.tvtom.pl/adblock-w-openwrt-gargoyle/

Others have recently developed packages for this same functionality, and done it better than anything I could do. Use the packages instead of this script:

Description

In its basic usage, this script will modify the router such that blocked addresses are null routed and unreachable. Since the address blocklist is full of advertising, malware, and tracking servers, this setup is generally a good thing. In addition, the router will update the blocklist weekly. However, the blocking is leaky, so do not expect everything to be blocked.

Setup

The script must be copied to an OpenWRT router (gargoyle firmware works fine, too).

For example, if the router is located at 192.168.1.1:

# scp adblock.sh [email protected]:/etc/adblock.sh

Make the script executable:

# chmod +x /etc/adblock.sh

Basic usage

If you are running the script for the first time:

# sh /etc/adblock.sh -f

There should be status updates in the output, but there should be no errors. If these commands complete without errors, the adblocking is active. You can test it by looking up, say, google analytics.

Whitelists and blacklists

The script supports defining whitelisted urls. That is, urls that will be filtered out of the downloaded blocklists. To whitelist urls, place them (one per line) in /etc/white.list.

Similarly, the script supports defining blacklisted urls – urls that will be added to the downloaded blocklists. To blacklist urls, place them (one per line) in /etc/black.list.

NOTE: The whitelist support is pretty stupid, so don’t expect smart filtering (e.g., domain extrapolation). I’ve found it tedious, but worthwhile, to find the offending url in /etc/block.hosts and copy it to /etc/white.list.

Advanced usage

Toggle on and off

To toggle the blocking on and off, run the script with the -t switch:

# sh /etc/adblock.sh -t

Note: This does not delete the blocklist, whitelist, or blacklist.

Manually update blocklist

To manually update the blocklist, run the script without switches:

# sh /etc/adblock.sh

Full reinstall

To reinstall the current implementation:

# sh /etc/adblock.sh -r

Configuration

The config section of the script has some variables that alter the behaviour of the script.

For example, if you change:

ONLY_WIRELESS="N"

to

ONLY_WIRELESS="Y"

Then only the wireless interface of the router will filter the blocklist.

To change the configuration of an already active installation, I would toggle the adblocking off first, change the script, then toggle it back on. That is,

# sh /etc/adblock.sh -t # turn off
...modify variables...
# sh /etc/adblock.sh -t # turn on

However, if you change certain variables, you must re-update the blocklist because the redirection values will have changed. Other variables require a full restart because they must install or verify dependencies.

Configurable variables:

  • ONLY_WIRELESS (Y/N): Only filter on wireless interface
  • EXEMPT# (Y/N): Exempt ip range from filtering (between START_ RANGE and END_RANGE)
  • IPV6*: (Y/N): Add IPv6 support
  • SSL# (Y/N): Install wget with ssl support (only needed for ssl websites)
  • TRANS#: (Y/N): Modify router web server to server transparent pixel responses for blocked websites
  • ENDPOINT_IP4/IP6*: Define the IP to return for blocked hostnames (IPv4 and IPv6)
  • CRON: The cron line to put in the crontab

*: Requires blocklist update.

: Requires full reinstall

view raw

README.md

hosted with ❤ by GitHub


#!/bin/sh
#Put in /etc/adblock.sh
#Block ads, malware, etc.
#### CONFIG SECTION ####
# Only block wireless ads? Y/N
ONLY_WIRELESS="N"
# IPv6 support? Y/N
IPV6="N"
# Need SSL websites?
SSL="N"
# Try to transparently serve pixel response?
# If enabled, understand the consequences and mechanics of this setup
TRANS="N"
# Exempt an ip range
EXEMPT="N"
START_RANGE="192.168.1.0"
END_RANGE="192.168.1.255"
# Redirect endpoint
ENDPOINT_IP4="0.0.0.0"
ENDPOINT_IP6="::"
#Change the cron command to what is comfortable, or leave as is
CRON="0 4 * * 0,3 sh /etc/adblock.sh"
#### END CONFIG ####
#### FUNCTIONS ####
cleanup()
{
#Delete files used to build list to free up the limited space
echo 'Cleaning up…'
rm -f /tmp/block.build.list
rm -f /tmp/block.build.before
}
install_dependencies()
{
#Need iptables-mod-nat-extra installed
if opkg list-installed | grep -q iptables-mod-nat-extra
then
echo 'iptables-mod-nat-extra is installed!'
else
echo 'Updating package list…'
opkg update > /dev/null
echo 'Installing iptables-mod-nat-extra…'
opkg install iptables-mod-nat-extra > /dev/null
fi
#Need iptable-mod-iprange for exemption
if [ "$EXEMPT" = "Y" ]
then
if opkg list-installed | grep -q iptables-mod-iprange
then
echo 'iptables-mod-iprange installed'
else
echo 'Updating package list…'
opkg update > /dev/null
echo 'Installing iptables-mod-iprange…'
opkg install iptables-mod-iprange > /dev/null
fi
fi
#Need wget for https websites
if [ "$SSL" = "Y" ]
then
if opkg list-installed wget | grep -q wget
then
if wget –version | grep -q +ssl
then
echo 'wget (with ssl) found'
else
# wget without ssl, need to reinstall full wget
opkg update > /dev/null
opkg install wget –force-reinstall > /dev/null
fi
else
echo 'Updating package list…'
opkg update > /dev/null
echo 'Installing wget (with ssl)…'
opkg install wget > /dev/null
fi
fi
}
add_config()
{
if [ "$ONLY_WIRELESS" = "Y" ]
then
echo 'Wireless only blocking!'
if [ "$EXEMPT" = "Y" ]
then
echo 'Exempting some ips…'
FW1="iptables -t nat -I PREROUTING -m iprange ! –src-range $START_RANGE-$END_RANGE -i wlan+ -p tcp –dport 53 -j REDIRECT –to-ports 53"
FW2="iptables -t nat -I PREROUTING -m iprange ! –src-range $START_RANGE-$END_RANGE -i wlan+ -p udp –dport 53 -j REDIRECT –to-ports 53"
else
FW1="iptables -t nat -I PREROUTING -i wlan+ -p tcp –dport 53 -j REDIRECT –to-ports 53"
FW2="iptables -t nat -I PREROUTING -i wlan+ -p udp –dport 53 -j REDIRECT –to-ports 53"
fi
else
if [ "$EXEMPT" = "Y" ]
then
echo "Exempting some ips…"
FW1="iptables -t nat -I PREROUTING -m iprange ! –src-range $START_RANGE-$END_RANGE -p tcp –dport 53 -j REDIRECT –to-ports 53"
FW2="iptables -t nat -I PREROUTING -m iprange ! –src-range $START_RANGE-$END_RANGE -p udp –dport 53 -j REDIRECT –to-ports 53"
else
FW1="iptables -t nat -I PREROUTING -p tcp –dport 53 -j REDIRECT –to-ports 53"
FW2="iptables -t nat -I PREROUTING -p udp –dport 53 -j REDIRECT –to-ports 53"
fi
fi
echo 'Updating config…'
#Update DHCP config
uci add_list dhcp.@dnsmasq[0].addnhosts=/etc/block.hosts > /dev/null 2>&1 && uci commit
#Add to crontab
echo "$CRON" >> /etc/crontabs/root
#Update dnsmasq config for Tor
TOR=`uci get tor.global.enabled 2> /dev/null`
if [ "$TOR" == "1" ]
then
TORPORT=`uci get tor.client.dns_port`
TORIP="127.0.0.1:$TORPORT"
uci set dhcp.@dnsmasq[0].noresolv='1' > /dev/null &2>1 && uci commit
uci add_list dhcp.@dnsmasq[0].server="$TORIP" > /dev/null &2>1 && uci commit
fi
# Add firewall rules
echo "$FW1" >> /etc/firewall.user
echo "$FW2" >> /etc/firewall.user
# Provide hint if localservice is 1
LS=`uci get dhcp.@dnsmasq[0].localservice 2> /dev/null`
if [ "$LS" == "1" ]
then
echo "HINT: localservice is set to 1"
echo " Adblocking (and router DNS) over a VPN may not work"
echo " To allow VPN router DNS, manually set localservice to 0"
fi
# Determining uhttpd/httpd_gargoyle for transparent pixel support
if [ "$TRANS" = "Y" ]
then
if [ ! -e "/www/1.gif" ]
then
/usr/bin/wget -O /www/1.gif http://upload.wikimedia.org/wikipedia/commons/c/ce/Transparent.gif > /dev/null
fi
if [ -s "/usr/sbin/uhttpd" ]
then
#The default is none, so I don't want to check for it, so just write it
echo "uhttpd found…"
echo "updating server error page to return transparent pixel…"
uci set uhttpd.main.error_page="/1.gif" && uci commit
elif [ -s "/usr/sbin/httpd_gargoyle" ]
then
# Write without testing
echo "httpd_gargoyle found…"
echo "updating server error page to return transparent pixel…"
uci set httpd_gargoyle.server.page_not_found_file="1.gif" && uci commit
else
echo "Cannot find supported web server…"
fi
fi
}
update_blocklist()
{
#Delete the old block.hosts to make room for the updates
rm -f /etc/block.hosts
# Correct endpoint for transparent pixel response
if [ "$TRANS" = "Y" ] && [ -e "/www/1.gif" ] && ([ -s "/usr/sbin/uhttpd" ] || [ -s "/usr/sbin/httpd_gargoyle" ])
then
ENDPOINT_IP4=$(uci get network.lan.ipaddr)
if [ "$IPV6" = "Y" ]
then
ENDPOINT_IP6=$(uci get network.lan6.ipaddr)
fi
fi
echo 'Downloading hosts lists…'
#Download and process the files needed to make the lists (enable/add more, if you want)
wget -qO- http://www.mvps.org/winhelp2002/hosts.txt| awk -v r="$ENDPOINT_IP4" '{sub(/^0.0.0.0/, r)} $0 ~ "^"r' > /tmp/block.build.list
wget -qO- "http://adaway.org/hosts.txt"|awk -v r="$ENDPOINT_IP4" '{sub(/^127.0.0.1/, r)} $0 ~ "^"r' >> /tmp/block.build.list
#wget -qO- http://www.malwaredomainlist.com/hostslist/hosts.txt|awk -v r="$ENDPOINT_IP4" '{sub(/^127.0.0.1/, r)} $0 ~ "^"r' >> /tmp/block.build.list
#wget -qO- "http://hosts-file.net/.\ad_servers.txt"|awk -v r="$ENDPOINT_IP4" '{sub(/^127.0.0.1/, r)} $0 ~ "^"r' >> /tmp/block.build.list
#Add black list, if non-empty
if [ -s "/etc/black.list" ]
then
echo 'Adding blacklist…'
awk -v r="$ENDPOINT_IP4" '/^[^#]/ { print r,$1 }' /etc/black.list >> /tmp/block.build.list
fi
echo 'Sorting lists…'
#Sort the download/black lists
awk '{sub(/\r$/,"");print $1,$2}' /tmp/block.build.list|sort -u > /tmp/block.build.before
#Filter (if applicable)
if [ -s "/etc/white.list" ]
then
#Filter the blacklist, supressing whitelist matches
# This is relatively slow =-(
echo 'Filtering white list…'
egrep -v "^[[:space:]]*$" /etc/white.list | awk '/^[^#]/ {sub(/\r$/,"");print $1}' | grep -vf – /tmp/block.build.before > /etc/block.hosts
else
cat /tmp/block.build.before > /etc/block.hosts
fi
if [ "$IPV6" = "Y" ]
then
safe_pattern=$(printf '%s\n' "$ENDPOINT_IP4" | sed 's/[[\.*^$(){}?+|/]/\\&/g')
safe_addition=$(printf '%s\n' "$ENDPOINT_IP6" | sed 's/[\&/]/\\&/g')
echo 'Adding ipv6 support…'
sed -i -re "s/^(${safe_pattern}) (.*)$/\1 \2\n${safe_addition} \2/g" /etc/block.hosts
fi
}
restart_firewall()
{
echo 'Restarting firewall…'
if [ -s "/usr/lib/gargoyle/restart_firewall.sh" ]
then
/usr/lib/gargoyle/restart_firewall.sh > /dev/null 2>&1
else
/etc/init.d/firewall restart > /dev/null 2>&1
fi
}
restart_dnsmasq()
{
if [ "$1" -eq "0" ]
then
echo 'Re-reading blocklist'
killall -HUP dnsmasq
else
echo 'Restarting dnsmasq…'
/etc/init.d/dnsmasq restart
fi
}
restart_http()
{
if [ -s "/usr/sbin/uhttpd" ]
then
echo 'Restarting uhttpd…'
/etc/init.d/uhttpd restart
elif [ -s "/usr/sbin/httpd_gargoyle" ]
then
echo 'Restarting httpd_gargoyle…'
/etc/init.d/httpd_gargoyle restart
fi
}
restart_cron()
{
echo 'Restarting cron…'
/etc/init.d/cron restart > /dev/null 2>&1
}
remove_config()
{
echo 'Reverting config…'
# Remove addnhosts
uci del_list dhcp.@dnsmasq[0].addnhosts=/etc/block.hosts > /dev/null 2>&1 && uci commit
# Remove cron entry
sed -i '/adblock/d' /etc/crontabs/root
# Remove firewall rules
sed -i '/–to-ports 53/d' /etc/firewall.user
# Remove Tor workarounds
uci del_list dhcp.@dnsmasq[0].server > /dev/null 2>&1 && uci commit
uci set dhcp.@dnsmasq[0].noresolv='0' > /dev/null 2>&1 && uci commit
# Remove proxying
uci delete uhttpd.main.error_page > /dev/null 2>&1 && uci commit
uci set httpd_gargoyle.server.page_not_found_file="login.sh" > /dev/null 2>&1 && uci commit
}
toggle()
{
# Check for cron as test for on/off
if grep -q "adblock" /etc/crontabs/root
then
# Turn off
echo 'Turning off!'
remove_config
else
# Turn on
echo 'Turning on!'
add_config
fi
# Restart services
restart_firewall
restart_dnsmasq 1
restart_http
restart_cron
}
#### END FUNCTIONS ####
### Options parsing ####
case "$1" in
# Toggle on/off
"-t")
toggle
;;
#First time run
"-f")
install_dependencies
add_config
update_blocklist
restart_firewall
restart_dnsmasq 1
restart_http
restart_cron
cleanup
;;
#Reinstall
"-r")
remove_config
install_dependencies
add_config
update_blocklist
restart_firewall
restart_dnsmasq 1
restart_http
restart_cron
cleanup
;;
#Default updates blocklist only
*)
update_blocklist
restart_dnsmasq 0
cleanup
;;
esac
#### END OPTIONS ####
exit 0

view raw

adblock.sh

hosted with ❤ by GitHub


#/etc/black.list
#add some server that the list doesn't block
example1.block.com

view raw

black.list

hosted with ❤ by GitHub


#/etc/sysupgrade.conf
#This file is a list of files that should be preserved through upgrades
#OPTIONAL!!!!!
/etc/passwd
/etc/shadow
/etc/adblock.sh #ADD THIS LINE
/etc/white.list #AND THIS ONE
/etc/block.hosts #AND THIS ONE
/etc/black.list #AND THIS ONE

view raw

sysupgrade.conf

hosted with ❤ by GitHub


#/etc/white.list
#Add whitelisted addresses, when appropriate, etc.
a248.e.akamai.net

view raw

white.list

hosted with ❤ by GitHub


#!/bin/sh /etc/rc.common
# Copy this skript to /etc/init.d/adblock and enable:
# chmod +x /etc/init.d/adblock
# /etc/init.d/adblock enable
START=90
ADS='http://pgl.yoyo.org/as/serverlist.php?hostformat=dnsmasq&showintro=0&mimetype=plaintext'
WWW2="/tmp/www2"
GIF1="1.gif"
DM_CONF=/var/etc/dnsmasq.conf
DM_BAD=/var/etc/dnsmasq.bad
ssd=start-stop-daemon
UPID1=/var/run/uhttpd_main.pid
UPID2=/var/run/uhttpd_www2.pid
UH=/usr/sbin/uhttpd
start() {
mkdir -p $WWW2
echo -ne 'GIF89a1010\x8000\xff\xff\xff000!\xf9\x0400000,000010100\x02\x02D10;' | tr 01 '\000\001' > $WWW2/$GIF1
# Choose an unused IP
ip=$(uci get network.lan.ipaddr)
ip2=10.3.5.3
case $ip in 10.3.*) ip2=10.4.6.4 ;; esac
ifconfig br-lan:1 inet $ip2 netmask 255.255.255.255
# Restart uhttpd to listen only LAN
if [ -f "$UPID1" ]; then
uargs="$(cat /proc/$(cat $UPID1)/cmdline | tr '\000' ' ' | cut -d ' ' -f 2- )"
if echo "$uargs" | grep -q '0.0.0.0'; then
uargs=$(echo $uargs | sed -e "s/0\.0\.0\.0/$ip/")
$ssd -Kqs HUP -p $UPID1
sleep 1
$ssd -Sqbmp $UPID1 -x $UH — $uargs
fi
fi
# Start another uhttpd
$ssd -Sqbmp $UPID2 -x $UH — -f -h $WWW2 -E /$GIF1 -I $GIF1 -p $ip2:80
# Add rules to dnsmasq
wget -qO $DM_BAD "$ADS" && sed -i -e "s/127\.0\.0\.1/$ip2/" $DM_BAD
if [ -f $DM_CONF -a -f $DM_BAD ] && ! grep -q $DM_BAD $DM_CONF; then
$ssd -Kqn dnsmasq
sleep 1
echo "conf-file=$DM_BAD" >> $DM_CONF
$ssd -Sqx dnsmasq — -C $DM_CONF
fi
}
stop() {
$ssd -Kqs HUP -p $UPID2
}

view raw

adblock

hosted with ❤ by GitHub

The Best Ad Blocking Method


https://forum.openwrt.org/viewtopic.php?id=35023&p=2

 

Loading

Incoming search terms:

  • openwrt adblock
  • 192 168 88 1
  • luci-app-vnstat
  • adblock openwrt
  • 192 168 88