Med egen server på samme lokale nettverk som klientene får man en utfordring når man prøver å nå de interne ressursene, da særlig websider. For å komme rundt dette har man forskjellige muligheter; den enkleste er å legge inn informasjon om IP-adresser og dns-navn i hosts-filen på klienten som skal nå den angitte ressursen. For en enkelt klient er dette en akseptabel løsning, men idet man får flere klienter blir det fort et prosjekt å holde alt oppdatert og synkronisert. Man kan også sette opp en såkalt DMZ for serveren og på den måten fjerne den fra klientnettverket, men dette medfører routing og ekstra oppsett på brannmuren, og i mange tilfeller går ikke trafikken via brannmuren i det hele tatt siden alle enheter på nettverket bruker lokale adresser. Man trenger derfor en DNS-server.
Etter mye googling om emnet kom jeg over Dnsmasq. Dette er en lettvekts DNS-server laget spesielt for slike scenarier som dette, der man har klienter og servere på samme nettverk.
En server ble spunnet opp, Dnsmasq installert og så satt opp etter den offisielle manualen og den offisielle eksempelconfigen, serveren ble satt som eneste DNS-server for både brannmur og i DHCP-serveren, og vips, så fungerte ting nesten som det skulle. Av en eller annen grunn ble domenenavnet jeg bruker i DHCP automatisk og uregelmessig lagt til enkelte oppslag, så blant annet autodiscovery for Outlook sluttet plutselig å virke sånn uten forvarsel. Videre fikk jeg en haug sertifikatfeil der sertifikatet for et av mine egne domener ble presentert som sertifikatet for nettstedet jeg forsøkte besøke, og det er jo ikke helt heldig.
Jeg fant lite i loggene eller på nettet som pekte meg i retning av en løsning, så til slutt fant jeg ut at jeg bare dropper Dnsmasq fullstendig og setter opp en full, split-horizon validerende og rekurserende DNS-server. Jeg har erfaring med BIND og PowerDNS fra tidligere, men BIND har de siste årene blitt en svær, bloated klump av usikker kode, og PowerDNS ble et for stort prosjekt, så jeg gikk for Unbound i stedet. Er den bra nok som default i FreeBSD og OpenBSD, er den bra nok for meg.
# portsnap fetch update # cd /usr/ports/dns/unbound # make config install clean
Unbound kommer preinstallert i FreeBSD, men da kun som en lokal recursing server, så jeg måtte installere den komplette Unbound-pakken fra ports. Jeg måtte installere fra ports siden jeg trengte støtte for Python og klientsubnett. Her er alternativene jeg valgte:
+----------------------------- unbound-1.6.7_1 --------------------------------+ | +--------------------------------------------------------------------------+ | | | [ ] DNSCRYPT Enable dnscrypt support | | | | [ ] DNSTAP Enable dnstap logging support | | | | [x] DOCS Build and/or install documentation | | | | [x] ECDSA Enable ECDSA (elliptic curve) support (OpenSSL >= 1.0) | | | | [ ] EVAPI (Experimental) pluggable event based libunbound API sup | | | | [ ] FILTER_AAAA Build with AAAA filter functionality (contrib) | | | | [x] GOST Enable GOST support (requires OpenSSL >= 1.0) | | | | [x] LIBEVENT Build against libevent | | | | [ ] MUNIN_PLUGIN Install Munin plugin | | | | [x] PYTHON Python bindings or support | | | | [x] SUBNET Enable client subnet support | | | | [ ] TFOCL Enable TCP Fast Open for client mode | | | | [ ] TFOSE Enable TCP Fast Open for server mode | | | | [x] THREADS Threading support | | | +--------------------------------------------------------------------------+ | +------------------------------------------------------------------------------+ | < OK > <Cancel> | +------------------------------------------------------------------------------+
Med det i boks og Unbound installert, var det på tide å legge inn støtte for split horizon.
For å få dette til, må man installere ub-split-map. Det ub-split-map gjør, er å mappe en ekstern (internet-synlig) adresse til en lokal (intranet-synlig).
Installasjonen er egentlig veldig enkel; last ned eller klone kildekoden fra github, kjør standard Python installasjonsrutine:
cd ub-split-map-x.x.x sudo python setup.py install
I mitt tilfelle var ikke Python installert som python, men python2.7 (FreeBSD). Man kan da enten lage en symlink eller bare spesifisere python2.7 som kommando; Jeg gjorde det siste da denne serveren ikke skal brukes interaktivt.
Oppsett av ub-split-map er relativt enkelt – alt man trenger å vite er hvor ub-split-map.ini blir installert. Jeg tror det var noe magi involvert, for filen havnet i /usr/local/etc/unbound med en gang, dog med .sample-extension. Filen ble renamet til ub-split-map.ini og åpnet i vim (siden Emacs og nano er for pyser). Et stykke nede i filen finner man en [maps]-seksjon. Her skal man legge til IP-adressene man skal mappe fra og til. Har man for eksempel en statisk internet-synlig IP-adresse 55.56.57.58 og en intern webserver med IP-adresse 192.168.1.1, legger man inn følgende under [maps]:
55.56.57.58 = 192.168.1.1
Det er alt, lagre filen og avslutt vim (ESC :wq).
Oppsett av Unbound er litt mer omfattende, så det tok noe tid å finne ut av (siden jeg igjen aldri hadde vært borti Unbound tidligere). Mye googling og bruk av unbound.conf-eksempelfilen hjalp.
VIKTIG: Mange installasjoner av Unbound setter opp et chroot-miljø som standard. Dette er på ingen måte noen dum idé (og er faktisk anbefalt i de fleste tilfeller), men i dette oppsettet slås chroot av siden det finnes en hel del store utfordringer som oppstår av å kjøre i chroot. Å løse disse er langt utenfor hva vi holder på med her, og uansett 1) skal serveren ikke brukes interaktivt; 2) den skal ikke være tilgjengelig fra internet, 3) den skal ikke brukes av andre enn meg, 4) den skal kun kjøre lokal DNS for noen domener jeg hoster for meg selv, så om den går ned slutter hele internettet å virke for hele lokalnettet, og da får jeg beskjed om det.
Det første vi gjør er å koble inn ub-split-map. For å få ub-split-map aktivert trenger man bare etpar linjer i unbound.conf:
server: module-config: "validator python iterator" python: python-script: "/usr/local/lib/python2.7/site-packages/ubsplitmap.py"
Det er alt. I server-delen forteller vi Unbound at vi på module-config-linjen skal ha inn python. Deretter, i python-delen, forteller vi python-modulen hvilket script den skal bruke. Ganske enkelt, igrunn.
Dette avsnittet er valgfritt. Hvis du ikke har noe på det interne nettverket ditt du ønsker å kunne nå via navn, kan du hoppe over hele avsnittet.
Siden jeg har en hel del ting som skal kunne nås via navn, setter vi opp en “sonefil” for den interne sonen.
La oss si du vil kalle den interne sonen “example.com“. Dette er det du trenger i unbound.conf:
server: local-zone: "example.com" typetransparent include: /usr/local/etc/unbound/internal/*.zone
La oss sette opp en “sonefil”.
Den årvåkne leser vil ha lagt merke til at vi har en “include:“-linje som ser etter hva som helst som slutter på .zone i /usr/local/etc/unbound/internal-mappen. Vi oppretter mappen:
mkdir /usr/local/etc/unbound/internal
Åpne så /usr/local/etc/unbound/internal/example.com.zone i en teksteditor. I denne filen legger du til local-data:-direktiver for alle maskiner/dingser på nettverket som skal ha et domenenavn kun for ditt interne nettverk. La oss si du har en printer du ønsker å kunne nå på printer.example.com med IP-adresse 192.168.1.10 og en filserver på files.example.com med IP-adresse 192.168.1.20, så legger du til følgende i example.com.zone-filen:
local-data: "printer.example.com. IN A 192.168.1.10" local-data: "files.example.com. IN A 192.168.1.20"
VIKTIG: Legg merke til punktumet etter domenenavnet!
Du kan legge til så mange local-data:-linjer du ønsker og trenger for sonen din.
Hvis du har flere domener du ønsker å gjøre dette for, for eksempel hvis man har en webserver bak en reverseproxy (helt tilfeldig eksempel), kan man gjøre som følger:
server: local-zone: "webhosting" typetransparent include: /usr/local/etc/unbound/internal/*.zone
/usr/local/etc/unbound/internal/webhosting.zone kan da inneholde:
local-data: "example.com. IN A 192.168.1.1" local-data: "www.example.com. IN A 192.168.1.1" local-data: "example.org. IN A 192.168.1.1" local-data: "www.example.org. IN A 192.168.1.1" local-data: "labs.example.org. IN A 192.168.1.1" local-data: "foo.com. IN A 192.168.1.1" local-data: "test.bar.org. IN A 192.168.1.1"
Og så videre….
Man kan ha så mange sonefiler man ønsker, eller bare én. Poenget er at alle domenene man hoster websider for peker til reverseproxyen, ikke til webserveren, siden vi driver og herjer med SSL/TLS inni alt dette i tillegg. For at SSL skal fungere skikkelig, må alle forespørsler gå via reverseproxyen for å hente SSL-sertifikatet. For ukrypterte sider (HTTP) kan man enten gå via reverseproxyen eller direkte til webserveren; det vil ikke ha noen betydning uansett. Siden målet mitt er å ha HTTPS for alle websider på alle domener peker jeg rubbel og bit til reverseproxyen sånn at jeg slipper å gjøre noe mer i etterkant enn å opprette virtualhosts og hente sertifikater for dem på reverseproxyen.
Som nevnt tidligere, pass på at den følgende linjen er med i server:-delen av konfigurasjonen:
chroot: ""
Det slår av chroot-miljøet for unbound.
Du vil sannsynligvis trenge å gjøre flere endringer til unbound.conf for å få alt til å virke som forventet, som å sette access-control-alternativer og sikkert en hel del annet, avhengig av hvordan systemet du kjører har satt opp standardinnstillingene.
Det skal være alt som trengs, og du skal nå kunne starte Unbound og teste om de eksterne-til-interne IP-mappingene fungerer som forventet, samt at du fremdeles kan nå tjenester på nettet.
Problem:
c:\> nslookup google.com DNS request timed out. timeout was 2 seconds. Server: UnKnown Address: 192.168.1.10 DNS request timed out. timeout was 2 seconds. DNS request timed out. timeout was 2 seconds. DNS request timed out. timeout was 2 seconds. DNS request timed out. timeout was 2 seconds. *** Request to UnKnown timed-out C:\>
Løsning:
Unbound er ikke satt opp med en av de følgende config-linjene:
interface: 0.0.0.0 # lytter på alle ipadresser i systemet (standard er kun localhost) access-control: 127.0.0.0/8 allow # tillat localhost å spørre serveren access-control: 192.168.1.0/24 allow # tillat subnet 192.168.1.0/24 å spørre serveren
Problem:
Oppslag av lokale hostnavn fungerer, men ikke for eksterne.
Løsning:
Legg til følgende i /etc/resolv.conf på Unbound-serveren:
nameserver 80.80.80.80 nameserver 80.80.81.81
(eller 8.8.8.8 og 8.8.4.4 eller ISP’en din sine – poenget er at de må være offentlige internettadresser og tilgjengelige på nettet)
Her er unbound.conf for mitt oppsett, dvs det som avviker fra defaults:
server: interface: 0.0.0.0 prefer-ip6: no do-ip4: yes # Enable IPv4, "yes" or "no". do-ip6: no # Enable IPv6, "yes" or "no". do-udp: yes # Enable UDP, "yes" or "no". do-tcp: yes # Enable TCP, "yes" or "no". access-control: 127.0.0.0/8 allow access-control: 192.168.1.0/24 allow chroot: "" # If you give "" no chroot is performed. The path must not end in a /. logfile: "/var/log/unbound.log" use-syslog: no # log-queries: no # changed to yes for debugging then back to no and commented out root-hints: "/usr/local/etc/unbound/named.cache" hide-identity: yes # enable to not answer id.server and hostname.bind queries. hide-version: yes # enable to not answer version.server and version.bind queries. module-config: "validator python iterator" local-zone: "168.192.in-addr.arpa." nodefault local-zone: "localnet" typetransparent include: /usr/local/etc/unbound/localnet/*.zone python: python-script: "/usr/local/lib/python2.7/site-packages/ubsplitmap.py"
Dette er kun det jeg endret/la til for å få oppsettet her til å fungere. For fullt oppsett av en “skikkelig” DNS-server vil jeg anbefale å lese gjennom den offisielle dokumentasjonen samt se på forskjellige konfigurasjonseksempler på nettet.