sobota, 10 marca 2012

Ultra przeźroczyste domowe proxy

W ostatnich latach serwer proxy w firmie stał się już prawie standardem. Nawet jeżeli nie ma parcia na różnego rodzaju odciążanie łącza czy serwerów, to czasami jest parcie na blokowanie czy kontrolowanie stron odwiedzanych przez pracowników.

Jeżeli się głębiej nad tym zastanowić to z tych samych powodów możemy chcieć postawić proxy w naszej domowej sieci. Będziemy kontrolować na jakie strony wchodzą nasze pociechy (czasem blokować) oraz odciążymy łącze. Ostatnio korzystanie z internetu opiera się głównie o serwisy w stylu youtube, demotywatory itp które potrafią wysycić praktycznie każde łącze i są generalnie uciążliwe przy współużytkowaniu na słabym łączu domowym :)



To czym nasz domowy serwer proxy będzie się wyróżniał spośród typowych instalacji firmowych to długie czasy niedostępności. Można raczej być pewnym, że nadgorliwa mama wyłączy "niepotrzebnie" działający komputer. Równie ciężko będzie wytłumaczyć pewne fakty 2 letniemu dziecku ;]

Z tego powodu musimy wziąć pod uwagę auto-konfiguracje i auto-wykrywanie proxy w sieci. Zakładam, że dostęp do internetu jest oferowany z jakiegoś mini routerka, obok którego stawiamy nasz serwerek - nie koniecznie jako urządzenie pełniące role firewalla. Auto konfiguracja opiera się zwykle o plik wpad.dat który wystarczy udostępnić poprzez serwer www. Treść takiego pliku to prosty skrypt w javascript, np taki:

function FindProxyForURL(url, host) {
return "PROXY wpad:8080; DIRECT";
}

Funkcja zwraca adres i port naszego serwera proxy. W przypadku gdy nie będzie go w sieci przeglądarka odwoła się do strony bezpośrednio - DIRECT. Możemy teraz wskazać taki plik jako skrypt auto-konfiguracji proxy w ustawieniach przeglądarki.

Problem jest jednak taki, że gdy nasz serwer proxy będzie niedostępny, może to wygenerować pewne opóźnienia przy wczytywaniu stron. Lepszym pomysłem jest więc zwykle kliknięcie "Automatycznie wykrywaj ustawienia serwerów proxy". Teraz pytanie, jak ta auto-konfiguracja następuje? Opcji jest kilka, ale standardowo przeglądarka stara się rozwiązać nazwe wpad w lokalnej domenie jako adres serwera www który udostępnia plik wpad.dat. Taki alias należy zdefiniować na lokalnym serwerze dns w naszej lokalne strefie, poniżej fragment z konfiguracji strefy DNS w bind:

$TTL 86400
$ORIGIN local.

@ IN SOA zlomex.local. adrb.wp.pl. (

2012030401 ; // serial
1200 ; // refresh
1200 ; // retry
2419200 ; // expire
86400 ; // time-to-live
)

@ IN NS zlomex
@ IN A 10.2.1.3
zlomex IN A 10.2.1.3
mx IN MX 5 zlomex
wpad IN CNAME zlomex

Jest tutaj jedno ale... stacje z systemem Windows używają w tym celu serwerów WINS i protokołu NetBIOS. Musimy zatem doinstalować pakiet samba i skonfigurować w nim dwie opcje tj:

wins support = yes
dns proxy = yes

Teraz samba będzie pełnić role serwera WINS i przekazywać zapytania do DNS. Konfiguracje możemy przetestować wykonując polecenie nmblookup, np:

nmblookup -U zlomex.local -R "wpad"

Sambe możemy równierz wykorzytać jako lokalne miejsce do współdzielenia plików w domowej sieci ;] Na naszym ruterku definiujemy odpowiednio adres serwera WINS w DHCP. W rzeczywistości, serwer WINS jest nam bardzo na rękę. Gdybyśmy używali tylko serwera DNS do autokonfiguracji proxy, to w przypadku jego niedostępności tracimy około jednej sekundy przy każdym zapytaniu o nazwę - po tym czasie Windows odpyta secondary dns. Sekunda niby nie dużo, ale przeciętna strona ma mnóstwo linków i powiązań które często wskazują na inne serwery www itp.

Pozostała na koniec konfiguracja serwera proxy. Tą role z powodzeniem będzie pełnić squid. Wystarczy standardowa konfiguracja bez żadnych udziwnień z jednym wyjątkiem... youtube. Serwis youtube korzysta z dosyć zaawansowanego systemu reverse proxy, który skutkuje tym, że filmiki nie mają stałego adresu url. By squid sobie z tym poradził musimy zdefiniować sposób w jaki będzie normalizował adresy url:

acl store_rewrite_list urlpath_regex \/(get_video\?|videodownload\?|videoplayback.*id)

storeurl_access allow store_rewrite_list
storeurl_access deny all
storeurl_rewrite_program /etc/squid/zlomex-storeurl.py
storeurl_rewrite_children 1
storeurl_rewrite_concurrency 10

#youtube's videos
refresh_pattern (get_video\?|videoplayback\?|videodownload\?) 5259487 100% 5259487 ignore-no-cache override-expire ignore-reload ignore-private negative-ttl=0
refresh_pattern -i \.flv$ 10080 90% 999999 ignore-no-cache override-expire ignore-private

Jak widać za to przepisywanie adresów url odpowiedzialny jest skrypt pythona zlomex-storeurl.py. Skorzystałem tutaj z bardzo dobrego wpisu na blogu, odrobinę tylko przerabiając i dostosowując go do swoich potrzeb:

#!/usr/bin/env python
# vim:et:ts=4:sw=4:

import re
import sys
import urlparse

youtube_math = [
re.compile(r"^http:\/\/(.*?)\/videoplayback\?.*$"),
]

def parse_params(url):
"Convert a URL's set of GET parameters into a dictionary"
params = {}
for param in urlparse.urlsplit(url)[3].split("&"):
if "=" in param:
n, p = param.split("=", 1)
params[n] = p
return params

while True:
line = sys.stdin.readline()
if line == "":
break
try:
channel, url, other = line.split(" ", 2)
matched = False

for re in youtube_math:
if re.match(url):
params = parse_params(url)

if "itag" in params and not "range" in params:
print channel, "http://video-srv.youtube.com.SQUIDINTERNAL/videoplayback?id=%s&itag=%s" % (params["id"], params["itag"])
matched = True
break

if not matched:
print channel, url

except Exception:
# For Debugging only. In production we want this to never die.
#raise
print line

sys.stdout.flush()

Niestety musimy odczekać jeszcze jakiś czas zanim squid zcachuje sporą część ruchu z youtuba, i dopiero wtedy cieszyć się z odetkanego łącza :)