Blokovanie reklamy II
Pred časom som popísal postup nastavenia centrálneho blokovania reklamných serverov v článku Blokovanie reklamy. Pretože som menil smerovač, prestal mi pixelserv fungovať, musel som to urobiť inak, a to pomocou webového servera nginx.
Obsah článku
Upozornenie
Vrámci mojich pokusov som si skompiloval pixelserv pre novú architektúru, ale zistil som, že napriek tvrdeniam autora, neodpovedá na požiadavky JavaScript prázdnym súborom…
Rada
V celom dokumente budem používať adresu IP 192.168.0.254 ako vnútornú adresu smerovača, teda vnútorná sieť je 192.168.0.0/24.
Príprava
Pred samotným nastavením blokovania som musel vykonať niekoľko prípravných krokov:
- nastavenie aliasu IP
- nastavenie webového rozhrania na konkrétnu IP
- nainštalovanie nginx a stunnel
Nastavenie aliasu IP
V podstate tento krok nie je potrebný, ale pretože som chcel ponechať webové
rozhranie (LuCI) na
štandardnom porte (80), rozhodol som sa vytvoriť na smerovači dodatočnú
lokálnu (LAN) adresu IP. Trošku problém nastal, keď som zistil, že predtým
používaná konfigurácia na nastavenie aliasu (config alias
) je označená
za zastaranú a naozaj nefunguje.
Chvíľu som sa pokúšal vytvoriť nové rozhranie pomocou webového rozhrania, a hoci sa mi to podarilo, nebol som s výsledkom spokojný, pretože nástroj ipconfig mi nedokázal zobraziť ďalšiu IP, čo by síce problém nebol, ale som na to jednoducho naučený…
Pomocou ifconfig
Nakoniec som to vyriešil prosto – pridal som do súboru /etcúrc.local
riadok (pred riadok exit 0
):
ifconfig br-lan:1 192.168.0.253 netmask 255.255.255.0 up
Teraz môžete smerovač reštartovať, aby ste si overili, že sa po reštarte nové virtuálne rozhranie (alias) nastaví, alebo môžete tento príkaz priamo spustiť.
Spôsobom podľa OpenWrt
Do súboru /etc/config/network
pridajte na koniec súboru riadky:
config interface 'LAN2'
ption proto 'static'
option ifname 'br-lan'
option ipaddr '192.168.0.253'
option netmask '255.255.255.0'
Pomocou LuCI
A pre tých, ktorí obľubujú klikacie rozhranie, tu je súbor obrázkov, ktoré ukazujú postup pridania vo webovom rozhraní LuCI:
Celý postup je v pár krokoch:
- v LuCI vyberte v menu
- v časti vyberte
- kliknite na Add new interface
- nastavte meno rozhrania (tu LAN2)
- priraďte mu „fyzické” rozhranie (tu br-lan)
- uložte zmeny klknutím na Submit
- nastavte adresu IP (192.168.0.253)
- zadajte masku siete (255.255.255.0)
Ako sami môžete vidieť, je to trošku mätúce, pretože teraz máte dve rozhrania (LAN a LAN2), pričom obe majú zobrazené rovnaké adresy IP…
Upozornenie
Nastavenie druhej IP je púotrebné urobiť spôsobom, ktorý si budete pamätať (nájdete ho) aj po niekoľkých rokoch, pretože to nei je Windows a za normálnych okolností už do smerovača veľmi zasahovať netreba, iba ak budete chcieť zase niečo pridať…
Zviazanie LuCI s IP
Keď už mám dve IP adresy lokálneho rozhrania, postupujem k previazaniu webového
rozhrania s konkrétnou adresou IP, pretože predvolene sa viaže na všetky adresy
IP (0.0.0.0). Postup je jednoduchý, stačí si otvoriť súbor /etc/config/uhttpd
a zmeniť riadok:
list listen_http 0.0.0.0:80
na:
list listen_http 192.168.0.254:80
Ostáva už len reštartovať uhttpd:
/etc/init./uhttpd restart
Rada
V prípade, že používate pre LuCI aj HTTPS, zmeňte podobne riadok s portom 443.
Varovanie
Týmto nastavením je zároveň zablokovaný prístup k webovému rozhraniu z vonkajšej siete. Ak potrebujete prístup aj z vonkajšej adresy pridajte ďalší riadok list listen_http s vonkajšou adresou IP!
Inštalácia nginx a stunnel
V predchádzajúcom návode som popisoval inštaláciu pixelserv, čo bol veľmi jednoduchý webový server, ktorý na každý požiadavok odpovedal prázdnym obrázkom GIF s veľkosťou 1×1 pixel. Tentokrát som sa rozhodol implementovať túto funkciu pomocou webového servera nginx.
Upozornenie
Možno si poviete, že použitie nginx na tento účel je príliš silná káva – a budete mať pravdu, ale plánujem jeho využitie aj na ďalšie účely (napr. pre LuCI), tak prečo by neposlúžil aj ako blokovací server?
Inštalácia nginx je prostá, stačí aktualizovať zoznam balíkov (ak ešte nemáte) a spustiť inštaláciu:
opkg update
opkg install nginx
Verzia nginx, ktorá je súčasťou OpenWrt 12.09, je zostavená bez podpory SSL. Mohol by som si síce podporu SSL skompilovať, ale rozhodol som sa použiť nástroj stunnel, ktorý dokáže vytvoriť tunel SSL pre služby, ktoré SSL neposkytujú. Takže nainštalujem aj stunnel:
opkg install stunnel
Rada
Našiel som aj balík matrixtunnel, ktorý sa pýši tým, že je to odľahčená verzia stunnel, ale nenašiel som k nemu skoro žiadnu dokumentáciu, tak som nemal odvahu ho skúšať. Možno neskôr…
Nastavenie webového servera
Po pripravení potrebných častí prichádza prvá časť – nastavenie webového servera tak, aby na každý požiadavok odpovedal prázdnym GIFom, ale pre istotu ešte urobím, aby na požiadavok súboru JavaScript odpovedal prázdnym súborom skriptu.
Tip
Možno by bolo do budúcnosti lepšie zmeniť túto schému, presnejšie otočiť ju – aby na každú požiadavku odpovedal prázdnym súborom a len na obrázky odpovedal GIFom, ale o tom inokedy…
Nastavenie nginx
Nginx je potrebné po nainštalovaní nastaviť. nerobil som si s nastavením veľkú
hlavu a využil som prostý konfiguračný súbor, ktorý je súčasťou inštalácie,
/etc/nginx/nginx.conf
:
user nobody nogroup;
worker_processes 1;
error_log /dev/null crit;
pid /var/log/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
access_log off;
log_not_found off;
sendfile on;
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 15;
send_timeout 10;
gzip off;
server {
listen 192.168.0.253:80 default_server;
server_name _ localhost adblock.skk;
root /etc/nginx/empty;
location / {
empty_gif;
location ~ \.js$ {
return 200 empty.js;
}
}
}
}
Čo je v tomto nastavení iné? najprv som trochu prispôsobil nastavenia časových limitov (voľby *_timeout), na nižšie ako predvolené hodnoty - server funguje len pre lokálnu sieť, nepotrebuje tu veľké hodnoty. Ďalej som vypol komprimáciu (gzip off) i chybový záznam (error_log /dev/null …).
Samotné nastavenie servera je tiež prosté – zviazal som ho s adresou 192.168.0.253
a nastavil som tento server ako predvolený (default_server), teda aby odpovedal
nielen na domény, ktoré sú vymenované vo voľbe server_name. No a potom už len
nasleduje nastavenie, aby odpovedal na všetko prázdnym GIFom (empty_gif), o
čo sa postará zabudovaný modul nginx. Pre istotu som pridal odlišné spracovanie
požiadaviek, ktoré končia na .js
, kedy vraia prázdny súbor empty.js
.
Aby to celé fungovalo je potrebné pripraviť adresár s prázdnym súborom:
mkdir /etc/nginc/empty
touch /etc/nginc/empty/empty.js
/etc/init.d/nginx restart
Po reštarte možno otestovať funkčnosť z iného počítača, ja som použil nástroj Perl, s názvom HEAD:
HEAD http://192.168.0.253/daco.js
200 OK
Connection: close
Date: Wed, 07 Aug 2013 16:45:21 GMT
Server: nginx/1.2.2
Content-Length: 8
Content-Type: application/x-javascript
Client-Date: Wed, 07 Aug 2013 16:45:21 GMT
Client-Peer: 192.168.0.253:80
Client-Response-Num: 1
Super, funguje. Ak skúsite čokoľvek, čo nekončí na js, dostanete prázdny GIF 1×1 pixel.
Nastavenie stunnel
Ako som už spomenul, stunel poskytne SSL tunel k môjmu 1pixelovému nginxu, ktorý nemá podporu SSL priamo zakompilovanú. Ak sa pýtate, že načo je to dobré, tak som si všimol, že kopa reklamných serverov používa HTTPS, teda šifrovanú verziu HTML. Nepýtajte sa ma, že prečo, jednoducho to tak je a takéto servery by potom namiesto prázdneho miesta zobrazovali nepekné chybové hlásenie.
Celé nastavenie je súbore /etc/stunnel/stunnel.conf
, kde som potreboval
urobiť len niekoľko zmien:
- zakomentovať nepoužívanú službu [chili]
- nastaviť adresy IP služby [https]
[https]
accept = 192.168.0.253:443
connect = 192.168.0.253:80
TIMEOUTclose = 0
;[chilli]
;accept = 3443
;connect = 3442
;TIMEOUTclose = 0
Ak však teraz nedočkavo reštartujete stunnel, nedočkáte sa žiadaného výsledku, pretože zatiaľ chýba certifikát. Podrobnostiam generovania certifikátu sa tu venovať nebudem (už dlhšie mám v pláne napísať samostatný návod), tak len krátky (mierne upravený) postup z dokumentácie:
openssl req -new -x509 -days 3650 -nodes -out stunnel.pem -keyout stunnel.pem
openssl gendh 2048 >> stunnel.pem
Po spustení prvého príkazu budete vyzvaný na niekoľko údajov, tak ich vyplňte
podľa vlastnej úvahy. Vykonanie druhého zase môže trvať dlhšiu dobu. Výsledkom
bude súbor stunnel.pem
v aktuálnom adresári, ktorý preneste do adresára
/etc/stunnel
smerovača a potom môžete stunnel spustiť:
/etc/init.d/stunnel restart
Po reštarte možno spojenie vyskúšať, ale príkazu je potrebné pridať nastavenie, ktoré má za cieľ vypnúť striktnú kontrolu certifikátu:
PERL_LWP_SSL_VERIFY_HOSTNAME=0 HEAD https://192.168.0.253/daco.js
200 OK
Connection: close
Date: Wed, 07 Aug 2013 17:11:30 GMT
Server: nginx/1.2.2
Content-Length: 8
Content-Type: application/x-javascript
Client-Date: Wed, 07 Aug 2013 17:11:31 GMT
Client-Peer: 192.168.0.253:443
Client-Response-Num: 1
Nastavenie presmerovania
Celé doterajšie snaženie je závislé na jednej veci, a tou je presmerovanie požiadaviek zo známych reklamných serverov na môj server, ktorý som nastavil pred chvíľou. Túto úlohu splní server DNS, ktorým je v prípade OpenWrt odľahčený dnsmasq.
Tento server DNS (a DHCP a TFTP) poskytuje pomerne jednoduchý spôsob ako nastaviť konkrétnym doménovým menám konkrétnu adresu IP, ostáva len získať zoznam tých „správnych” domén…
Získavanie zoznamu domén
Tip
Tu nebudem vymýšľať nič nové a použijem postup zo starého článku, ktorý som však medzitým trochu vylepšil.
Do súboru /usr/sbin/get_adblock.sh
pridám tento obsah:
#!/bin/sh
CFG_DIR="/etc/dnsmasq.d/"
CFG_FILE="dnsmasq_adblock.conf"
IP_ADDR="192.168.0.253"
# prepare config dir
[ -d $CFG_DIR ] || mkdir -p $CFG_DIR
# prepare tmp file
TMP_FILE=$(mktemp /tmp/adblock.XXXXXX) || { echo "Failed to create temp file"; exit 1; }
# Down the DNSmasq formatted ad block list
wget -q "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=dnsmasq&showintro=0&mimetype=plaintext" -O $TMP_FILE
# Replace all occurrences of 127.0.0.1 with the IP address our ad block server is listening on.
sed -i "s/127.0.0.1/$IP_ADDR/g" $TMP_FILE
mv $TMP_FILE $CFG_DIR$CFG_FILE
# Restart DNSmasq
/etc/init.d/dnsmasq restart
# for safety
rm -f $TMP_FILE
exit 0
Nezabudnite nastaviť skriptu práva na spustenie:
chmod +x /usr/sbin/get_adblock.sh
Aby som nemusel aktualizovať zoznam ručne (ale môžete) ostáva pridať úlohu
do cron, presnejšie do súboru /etc/crontab/root
pridajte:
#min hour day month dayofweek command
# update adblock domain list
30 19 * * 5 /usr/sbin/get_adblock.sh
Po zmene som (pre istotu) reštartoval a povolil cron:
/etc/init.d/cron restart
/etc/init.d/cron enable
Nastavenie dnsmasq
Posledná vec, ktorá ostala nevyriešená, je pridanie súboru so zoznamom domén
do nastavenia dnsmasq. Veci sa od minula zlepšili, pretože celá veda
je v pridaní jednej konfiguračnej voľby na koniec súboru
/etc/dnsmasq.conf
:
# include custom config files
conf-dir=/etc/dnsmasq.d
Pridávanie vlastných domén
Ak ste sa pozastavili, prečo nastavujem dnsmasq tak, aby načítaval
dodatočné nastavenia z adresára, tak dôvod je prostý – akýkoľvek iný konfiguračný
súbor (samozrejme so syntakticky správny), ktorý umiestnite do adresára
/etc/dnsmasq.d/
bude pri reštarte dnsmasq načítaný. Dôsledkom
predošlej vety je, že stačí vytvoriť ďalší súbor, povedzme
/etc/dnsmasq.d/local.conf
a do neho pridať, napríklad:
address=/reklama.sk/192.168.0.253
No a budete mať blokovanú aj doménu reklama.sk, vrátane všetkých jej subdomén! Ak si nebudete pamätať správny zápis, stačí sa pozrieť do toho automaticky sťahovaného…