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:
-
Gargoyle package by @lantis1008
-
OpenWRT package by @dibdot
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.
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
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.
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.
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.
To manually update the blocklist, run the script without switches:
# sh /etc/adblock.sh
To reinstall the current implementation:
# sh /etc/adblock.sh -r
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/etc/black.list | |
#add some server that the list doesn't block | |
example1.block.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/etc/white.list | |
#Add whitelisted addresses, when appropriate, etc. | |
a248.e.akamai.net |
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 | |
} |
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:
-
Gargoyle package by @lantis1008
-
OpenWRT package by @dibdot
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.
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
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.
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.
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.
To manually update the blocklist, run the script without switches:
# sh /etc/adblock.sh
To reinstall the current implementation:
# sh /etc/adblock.sh -r
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/etc/black.list | |
#add some server that the list doesn't block | |
example1.block.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/etc/white.list | |
#Add whitelisted addresses, when appropriate, etc. | |
a248.e.akamai.net |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 | |
} |
https://forum.openwrt.org/viewtopic.php?id=35023&p=2
Incoming search terms:
- openwrt adblock
- 192 168 88 1
- luci-app-vnstat
- adblock openwrt
- 192 168 88