Kategória: OpenWrt

Zmenené: 7. august 2013

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.

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:

Pridanie nového „rozhrania”

Pridanie nového rozhrania

Nastavenie mena a rozhrania

Nastavenie mena a rozhrania

Nastavenie masky a IP

Nastavenie masky a IP

Výsledok

Výsledok

Celý postup je v pár krokoch:

  1. v LuCI vyberte v menu Network
  2. v časti Network vyberte Interfaces
  3. kliknite na Add new interface
  4. nastavte meno rozhrania (tu LAN2)
  5. priraďte mu „fyzické” rozhranie (tu br-lan)
  6. uložte zmeny klknutím na Submit
  7. nastavte adresu IP (192.168.0.253)
  8. 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:

  1. zakomentovať nepoužívanú službu [chili]
  2. 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…