6.5. Linux som firewall

I dette afsnit ser vi på Linux-kernens netfilter modul og hvad man kan gøre med det. Det er en forudsætning, at man kender til begreberne IP-adresse, netværksadresse, netmaske, routing og DNS. Hvis du ikke gør, så læs i det mindste indledningen til denne bog, eller se på http://www.netfilter.org/documentation/index.html#HOWTO efter Networking Concepts HOWTO.

De mere avancerede anvendelser af Network Address Translation, NAT, omtales sidst i denne del (Afsnit 6.5.4). Derefter omtales proxy opsætning med squid.

6.5.1. Iptables og netfilter i kerne 2.4 og 2.6

I Linux er pakkefiltrering i en avanceret version indbygget i kernen; kernedelen kaldes netfilter, og programmet iptables kommunikerer vores ønsker om hvad kernen skal foretage sig fra user-space til kerne-space.

For at kunne bruge kernens netfilter og iptables kommandoen, skal kernen være bygget med netfilter, og, hvis man planlægger at sikre en maskine, må det stærkt anbefales at man også inkluderer connection tracking. Det koster lidt belastning, men giver mange fordele. De fleste standard kerner fra distributioner med kerne 2.4.18 og frem har den slags. Det kan kontrolleres med ls -l /proc/net/ip_conntrack

Figur 6-2. Firestarter giver ikke ligefrem indtryk af at være en sikker firewall, tværtimod står den vildt udseende pingvin med en tændstik her. Men det *er* linux-humor og ikke en trussel!

Der mange gode front ends til iptables kommandoen. Hvis man er utryg ved anvendelse af kommandolinien, bør man først og fremmest under installationen læse vejledningen grundigt og indsætte et firewall filter af medium styrke allerede under installtionen. Desuden kan man begynde med en GUI som fx. RedHats system-konfigurations tool, setup eller /usr/sbin/lokkit . Disse nemme programmer er front-ends til den bagvedliggende mekanisme og fungerer bravt. De er til stede efter en normal installation. Firestarter kan man selv hente i forskellige grydeklare versioner, så den er bestemt også nem at komme igang med.

Hvis man vil noget særligt eller bare vil prøve kommandoerne direkte, så står der mere om det i de efterfølgende afsnit, som beskriver iptables anvendelse[1].

Firestarter er en generel front-end, som er meget nem at bruge, fordi den ligesom RedHats installations program har nogle meget fornuftige default værdier, hvis man bruger troldmand/hjælpe systemet til opsætning af sin første firewall.

Grafikken er rigtig pæn, og let at læse. I første vindue står en pingvin med en tændstik, og sådan noget kan godt gøre mig lidt urolog. Pingvinen ser dog ikke umiddelbart ud til at være i gang med ildspåsættelse!

I andet vindue skal man fortælle, hvilke netkort (d.v.s. interfaces) reglerne skal gælde for. De kan også gælde for modem opkobling med Point-to-Point Protocol (PPP), hvilket også er forklaret. Man lades ikke i stikken!

Det er meget fine forklaringer, også på det næste skærmbillede, hvor man rådes til i første omgang at lukke for alle "offentlige" services (disable public access to all services), så intet er tilgængeligt udefra. Så kan man åbne for dem senere, hvis man får brug for dem. Der burde stå, at man ikke bør åbne for telnet, men derimod kan klare de fleste opgaver med ssh.

Figur 6-3. Man kan åbne for de services, man har brug for

Der er et par skærmbilleder mere, som på en overskuelig måde tilbyder at justere på trafikken af forskellige typer. Denne form for justering vil blive meget mere almindelig i fremtiden, fordi mange typer service kræver en jævn datastrøm, men som udgangspunkt kan man blot acceptere default indstillingerne.

Ønsker man dansk tekst i sin GUI er guarddog (GPL) det klare valg. Gunner Poulsen har oversat til dansk, og man kan hente denne fra http://www.simonzone.com/software/guarddog/#download Guarddog kan skelne mellem lokalnet og demilitariseret zone, som er et område udenfor lokalnettet, hvor man har anbragt sine servere - tilbørligt sikrede, men der skal jo være en åben dør, for at folk kan komme ind og se på éns dejlige web-sider. Man kan selv definere flere zoner og zonetyper.

Læg mærke til, at guarddog styrer protokollerne pr. zone. Det vil sige, at man kan lukke for alt fra fx. externe numre og åbne for sine lokale 4 maskiner. Man kan have flere zoner, fx. kan en anden afdeling huset få adgang til noget specielt, som de har brug for.

Et andet fremragende GUI firewall-protection program er lokkit, som er bruges ved installation af RedHat og ved kørsel af setup programmet.

Her skal man blot angive fx. maximum sikkerhed og så åbne for den eller de services, som skal være tilgængelige udefra. (De skal jo så være sikret på anden måde, pas især på CGI scripting i Apache hvis den kører som root.)

Hvis du selv vil opdatere din kerne med source fra www.kernel.org så kommer nedenfor nogle screenshots som svarer til make xconfig . Her kan du se, hvor i menuerne du skal klikke; husk at læse help teksterne, det er gode forklaringer.

Figur 6-4. make xconfig, vælg network packet filtering

Figur 6-5. Længere nede vælges sub-menu for netfilter configuration

Figur 6-6. Den engelske hjælpetekst er meget fyldestgørende, se appendix Afsnit 6.8

iptables kommandoen skal bygges, så den passer til den kerne, man bruger, eller rettere, så den passer til den version af netfilter, som er i kernen. Også det er gjort i alle distributioner.

iptables indsætter som nævnt regler i kernens netfilter tabeller, hvilket betyder, at reglerne går tabt ved reboot. Du kan prøve at bruge kommandoerne iptables-save og iptables-restore.

Alternativt sætter man alle iptables kommandoerne ind i et start/stop script, som køres af rc kommandoen ved opstart. Man skal i så fald huske at få den til at foretage sig noget fornuftigt, hvis en af iptables kommandoerne fejler; normalt vil det være at starte /sbin/sulogin

6.5.1.1. Hvordan pakker rejser igennem filtrene

Navnet iptables hentyder til, at kernen har tre tabeller:

  • Filter tabellen, som bruges, hvis man udelukkende skal stoppe uvedkommende trafik.

  • NAT-tabellen, som bruges, hvis man skal foretage mapning / spejling af interne adresser, obligatorisk, hvis der er tale om private adresser som fx. 192.168.x.x.

  • Mangle-tabellen, som bruges, hvis man vil pille ved bits i pakkerne for at kunne klare vanskelige situationer.

Kernen begynder med at have 3 lister med regler i "filter" tabellen. Disse lister kaldes firewall kæder eller blot kæder, chains. De tre kæder kaldes INPUT, OUTPUT og FORWARD (pakker-ind, pakker-ud og pakker-til-videresendelse).

Her er en ASCII-kunstnerisk gengivelse af kædernes organisation (med tak til Rusty Russell's packet-filtering-HOWTO). Det er væsentligt forskelligt fra arrangementet i kerne 2.0 og 2.2.


                            _____
  Incoming                 /     \         Outgoing
         -->[Routing ]--->|FORWARD|------->
            [Decision]     \_____/        ^
                 |                        |
                 v                       ____
                ___                     /    \
               /   \                   |OUTPUT|
              |INPUT|                   \____/
               \___/                      ^
                 |                        |
                  ----> Local Process ----

Det ses, at en pakke kan komme fra to principielt forskellige kilder. Enten kommer pakkerne fra et netkort (rettere interface - men prøv at oversætte det til dansk) eller også kommer de fra et program, en lokal proces.

De tre "cirkler" repræsenterer de tre kæder nævnt ovenfor. Når en pakke ankommer til en cirkel i diagrammet, undersøges reglerne i denne kæde for at afgøre pakkens skæbne. Hvis kæden siger DROP pakken bliver den elimineret på stedet, men hvis kæden siger ACCEPT vil den fortsætte sin rejse gennem diagrammet.

En kæde er en tjekliste med regler. Hver regel siger "hvis pakke-headeren ser ud på denne-hersens-måde, så se her hvad der skal gøres med pakken". Hvis en regels pakke-beskrivelse passer på pakken, kalder man det et match. Det svarer selvfølgelig til en masse betingelser, som er opfyldt. Hvis pakken ikke matcher reglen fortsætter man til næste regel. Endelig når vi til et punkt, hvor der ikke er flere regler at undersøge. Nu ser kernen på kæde-policy for at afgøre, hvad der skal ske. I et sikkerheds-bevidst system siger denne policy som regel at kernen skal DROPpe pakken.

1. Når en pakke kommer ind, lad os sige fra ethernet-kortet ser kernen på pakkens destination: Dette kaldes routing (rutning eller bedre, ruting?)

2. Hvis den er til denne box bliver pakken sendt videre ned i diagrammet til INPUT kæden. Hvis den passerer denne, så vil alle processer, som venter på denne pakke, få den.

3. I modsat fald, hvis kernen ikke har videresendelse aktiveret, eller den ikke ved, hvordan pakken skal sendes videre, vil pakken blive droppet. Hvis videresendelse er aktiveret, og pakken er tiltænkt til et andet netværks-interface (hvis du har sådan et), så vil pakken gå fremad til FORWARD kæden. Hvis den accepteres her, bliver den sendt ud.

4. Sluttelig kan et program, som kører på boxen, sende netværkspakker. Disse passerer gennem OUTPUT kæden straks: Hvis den siger ACCEPT, så fortsætter pakken til hvad nu end det måtte være for et interface, som den er bestemt for.

6.5.2. Anvendelse af iptables kommandoen

iptables kommandoen har en ret detailleret manual side ( man iptables ) hvis du har brug for oplysninger om specielle ting.

Der er mange ting, man kan gøre med iptables kommandoen. Man begynder med at have de tre indbyggede kæder, INPUT, FORWARD og OUTPUT, som man ikke kan slette. Lad os først se på hvordan man administrerer hele kæder.

Brugerdefinerede kæder bruges til at strukturere filtreringen og demonstreres senere. Her er et simpelt eksempel på en kæde-kommando, som nulstiller tællerne i INPUT kæden. Prøv at liste før og efter med iptables -L INPUT -v :


[root@hven /]# iptables -Z INPUT

Der er fire kommandoer til at manipulere reglerne i en kæde:

En regel er en beskrivelse plus en handling.

Beskrivelsen er et match-udtryk og kan være sammensat af mange del-udtryk: Hvis pakken kommer fra adresse 44.55.66.77 og skal videre gennem interface eth1 ... Det ville man skrive sådan: --source 44.55.66.77 --out-interface eth1 .

En handling er et "jump", og det svarer til at tage en bestemmelse om, hvad der skal ske med pakken. Det, man hopper til, kaldes et mål eller target, og to af de indbyggede targes er de samme som de policy, vi tidligere har set, DROP, ACCEPT. At tage beslutning om at droppe en pakke skrives -j DROP

Man kan sætte flere match udtryk sammen. Nedenfor ses efter pakker, som kommer fra host 44.55.66.77 og som skal ud gennem interface eth1. Alle pakker, som har de to egenskaber, droppes:


[root@hven /]# iptables -A OUTPUT --source 44.55.66.77 --out-interface eth1 -j DROP 

Endvidere kan man hoppe til en anden, brugeroprettet kæde, eller man kan returnere fra en kæde (med -j RETURN ). Der er et REJECT target, som dog kræver at kernen er kompileret med support for det. Der er andre inbyggede targets, som kræver tilvalg i kernen: QUEUE beder kernen om at sende pakkerne til en pseudo-device, som et program i userspace kan lytte på, og så er der bl.a. også REDIRECT, SNAT, DNAT og LOG targets. (Lad være med at studere listen i detailler! Bladr frem.)

  1. ACCEPT

    Pakken sendes videre uden yderligere test og dermed uden yderligere tidsforbrug.

  2. DROP

    Pakken ignoreres ("smides væk").

  3. RETURN

    Der hoppes tilbage til den kæde, man kom fra eller for indbyggede kæder til default policy.

  4. REJECT

    Pakken droppes men der sendes en ICMP pakke til modtageren med besked.

  5. QUEUE

    Pakken lægges i kø til pseudodevice der tillader data at blive hentet til userspace.

  6. REDIRECT

    En -t nat funktion. Modtageradressen ændres, så pakken sendes til maskinen selv (lokalhost); for tcp/udp kan portnummer ændres. Bruges til proxy-funktionalitet.

  7. SNAT

    Kun for nat-tabellen, POSTROUTING kæden, specificerer at afsenderadresse skal ændres for denne og alle fremtidige pakker i denne forbindelse.

  8. DNAT

    Modtager adressen ændres for denne og følgende pakker i samme forbindelse.

  9. LOG

    Begynd kernel-logging for matchende pakker. Reglen behøver ikke at have noget target. Netfilter fortsætter med næste regel. Bruges til at analysere.

  10. MARK

    Bruges i mangle tabellen i forbindelse med iproute2.

  11. MASQUERADE

    Bruges til NAT-ing med dynamiske adresser.

  12. TCPMSS

    En speciel funktionalitet for fragmentering af ICMP pakker, som ens ISP ellers kasserer.

  13. TOS

    For mangle tabellen, ændring af Type Of Service (TOS) feltet i TCP headeren.

  14. ULOG

    Pakken multicastes til userspace for logging/analyse.

  15. DSCP

    Nyere version TOS mangling.

  16. ECN

    For løsning af problem med Explicit Congestion Notification.

  17. MIRROR

    Kun for forsøg, bytter om på afsender/modtager adresserne.

Listen er ordnet efter hvad jeg synes er vigtigst. Se manual page for nærmere detailler om targets. Lige nu er de vigtigste ACCEPT, DROP og SNAT, som kun kan bruges i nat-tabellens POSTROUTING chain.

Opsummerende kan vi sige, at en regel består af består af en eller flere kommandoparametre, som beskriver en egenskab ved en netværkspakke, samt (som regel) en besked om, hvad der skal ske med pakker, som beskrivelsen passer på. Hvis en beskrivelse passer, siger man at pakken matcher.

De vigtigste kommandoparametre til match er

Næsten alle options har en kort form, for eksempel -s i stedet for --source.

Adresser til --source og --destination kan specificeres på fire måder:

Man kan selektere alle pakker, som ikke kommer fra en adresse ved at negere adresse udtrykket, hertil bruges et udråbstegn, som skal have space før og efter: -s ! localhost vil matche alle pakker, som ikke kommer fra localhost.

6.5.2.1. Nogle praktiske eksempler

Nu til hands on! Vi antager, at vi har fem maskiner i huset og et en ADSL forbindelse på en af maskinerne. ADSL er på et separat netkort, som har betegnelsen eth1. De andre maskiner er forbundet via eth0 og vil gerne have lov at få del i ADSL forbindelsen.

Lad os lave en kæde af regler, som skal inspicere al trafik, der kommer ind på vores box, men kun, hvis det er fra ADSL interfacet, altså eth1.


[root@hven /]# iptables -N udefra 

Man kan liste den nye kæde sammen med de andre: iptables -L Kæden er ikke taget i brug, så der står "0 references". For at bruge den til noget må vi instruere kernen yderligere med en jump kommando. Vi laver en regel 1 for INPUT kæden.


[root@hven /]# iptables -A INPUT -i eth1 -j udefra 

                  __________
                _|  udefra  |--> regel 1 --> regel 2 ... 
               ^ |__________|                                    
              _|_____                                            
             /if eth1\                                           
            |  else   |                                          
             \_______/ _                                         
               ^        |   
   ______      |        v   
__|input |--> regel 1   regel 2 --> regel 3
  |______|
   ______
__|output|
  |______|
   _______
__|forward|
  |_______|

Det svarer til en if-sætning. Vi tester for om det var fra eth1 og hvis det er det, så fortsæt med regelkæden udefra.


   if (pakke_source == device_eth1) {
       tjek_reglerne_i_kaede_eth1();
   }
   else {
       fortsaet_med rule2();
   }

Lad os inspicere pakkerne udefra for, om de er til vores http server. Hvis de er det, så slip dem igennem, ellers skal de droppes.


[root@hven /]# iptables -A udefra -p tcp --dport 80 -j ACCEPT 

Når man specificerer -p tcp (eller --protocol tcp) så loader iptables et extension modul, og vi kan nu kigge ind i tcp-headeren, hvis vi vil - og det vil vi, vi undersøger, om pakkerne er bestemt for port 80, den velkendte port, som benyttes af http serveren. Alle pakker til serveren accepteres. Der er forskellige protocol extensions, som tillader avancerede ting: Læs manual-page hvis du vil vide mere.


[root@hven /]# iptables -A udefra -j DROP 

Derefter appender vi med -A endnu en regel, som siger, at alt andet skal droppes. Svarpakker til brugerne inde på lokalnettet vil imidlertid også blive stoppet af denne stop-regel, så nu vil vi benytte connection tracking og indsætte en regel, som siger, at alle pakker, som er beslægtede med en forbindelse, som allerede er oprettet, skal accepteres.


[root@hven /]# iptables -I udefra -m state --state ESTABLISHED,RELATED -j ACCEPT 

Denne regel bliver nu nummer 1, og de andre rykker ned som 2 og tre. Hvis vi hellere vil sætte denne regel ind som nummer 2, skal kommandoen bruge -I udefra 2 ; det er en meget bedre løsning, for connection tracking koster trods alt mere tid, så man bør acceptere så mange pakker som muligt med simple regler inden man bruger connection-regler.


[root@hven /]# iptables -I udefra 2 -m state --state ESTABLISHED,RELATED -j ACCEPT 

-m state fortæller kernen, at den skal benytte tilstandsmodulet, ip_conntrack. Derefter er det nødvendigt at bruge --state parameteren til at fortælle, hvilke tilstande, der skal accepteres. Ud over ESTABLISHED og RELATED er der bl.a. NEW og INVALID, som betyder at en pakke ikke tilhører nogen kendt forbindelse.

Læg mærke til, at der ikke er mellemrum efter kommaet mellem de to tilstande, det må der ikke være.


     +-----------------------------------------------------------
    _|  udefra  ---> udefra-regel1 --> udefra-regel2 ---->regel3
   ^ |  kæden        PORT 80?          RELATED?           DROP!
   | +------------   ACCEPT            ACCEPT
  _|_____               |                 |
 /if eth1\              |                 |
|  else   |             |                 |
 \_______/------------> +-----------------+----------> Sendes videre
   |     
   |        
INPUT-chain

Lidt forsimplet af pladshensyn, man skal spørge både på
ESTABLISHED og RELATED i regel 1 i "udefra"  regel kæden.

Lad os nu antage, at vi slet ikke kan lide telnet protokollen, heller ikke internt på det lille net, og derfor vil blokere for al telnet. Nu er telnet jo så en applikationsprotokol, så vi kan ikke bruge --protocol optionen, idet den kun kender protokollerne tcp, udp, icmp eller "all", eller også et nummer fra filen /etc/protocols . Med andre ord, telnet står ikke i /etc/protocols og derfor må vi "sigte efter telnet" på en anden måde, fx. ved at stoppe al trafik, som har destination port 23.


[root@hven /]# iptables -I INPUT -p tcp --dport 23 -j DROP 

Der benyttes -I, insert, fordi reglen skal komme før eth1-reglerne, hvis det skal nytte noget. Der står jo en accept inde i eth1-reglerne, som kunne forstyrre billedet (lidt). Nyere versioner af iptables vil kunne matche generelt på --ports 23, så det både er afsender/modtager pakker, som stoppes.

Eksemplet er ikke fuldkomment endnu, hvis maskinerne på lokalnettet har "private IP-adresser" - så næste opgave går ud på at opsætte NAT for lokalmaskiner.

6.5.3. Opsætning af NAT

NAT og Masquerading sker i nat-tabellens FORWARD kæde, når en datapakke skal til at forlade maskinen. Det kan kun ske her. Source adressen, som skal NATtes, er den interne eller private adresse, men man kan også angive netværket ved at skrive 0 for den sidste byte i en almindelig 192.168 - adresse og også angive netmaske, typisk 192.168.1.0/24, så vil alle de lokale adresser blive NAT-ede.

iptables har mange måder at angive adresser på, navne, numre, netværk, og for NAT også intervaller m.v., så hvis der opstår specielle behov, så kig lige en gang ekstra på manual page for iptables. Det er bedre at nøjes med én regel, som dækker flere adresser, end at have flere regler med hver deres adresse.


[root@hven /]# iptables -t nat -A POSTROUTING --src 192.168.1.0/24  -o eth1 -j SNAT --to x.y.w.z   

Hvis man får en dynamisk IP adresse fra sin internet leverandør, skal kommandoen se lidt anderledes ud, og så bruger man betegnelsen masquerading om metoden. Dynamiske adresser benyttes typisk med modemforbindelser, eller når man har en Point-to-Point Protocol (PPP) forbindelse til sin ISP. Man får en ny adresse hver gang. Linux kan tage denne adresse og bruge som den officielle adresse for NAT-ing af interne maskiner. Masquerading er oftest dynamisk NAT, med kun en ekstern adresse.

MASQUERADE target er kun muligt i nat tabellen, og kun i POSTROUTING kæden. Dette target bør kun benyttes med dynamiske IP-adresser.


# Eksempel på anvendelse af MASQUERADE target:

       # Masquerade out ppp0
       iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

       # Disallow NEW and INVALID incoming or forwarded packets from ppp0.
       iptables -A INPUT -i ppp0 -m state --state NEW,INVALID -j DROP
       iptables -A FORWARD -i ppp0 -m state --state NEW,INVALID -j DROP

       # Turn on IP forwarding
       echo 1 > /proc/sys/net/ipv4/ip_forward

Man kan godt bestemme, hvilken port-range, som må bruges til nat tabellen. Hvorfor skulle man gøre det? I nogle tilfælde laver man huller i firewallen for at sikre folk adgang til en bestemt protokol. Det er klart, at dette er en sikkerhedsfaktor, men hvis man skal have glæde af en server, så må der jo åbnes. Det kan evt. aftales med kendte brugere, at man kun holder et mindre port-interval åbent for bestemte protokoller.

DNS forespørgsler kan bruges som eksempel. Vi vil sætte en intern DNS server op, en hjælpeserver, som husker nyligt brugte adresser, så alle maskinerne på vores lille netværk ikke behøver at spørge igen og igen ud over det overbelastede ISP link. Alle på det interne net kan spørge denne maskine, men den skal være fuldstændig lukket udadtil, bortset fra, at den skal kunne spørge en remote DNS server. Det kaldes en DNS caching server. Til DNS benyttes User Datagram Protokol, UDP, som let kan udsættes for spoofing. Det ønsker vi at gøre alt for at forhindre. Det forbedrer selvfølgelig sikkerheden at køre en DNS caching server på en maskine for sig selv.

Når hjælpeserveren skal foretage en forespørgsel, bruger den som afsenderport et nummer som den får tildelt lidt tilfældigt, men det vil ligge i intervallet 1024 - 65535. Det kaldes de ikke-priviligerede porte. Netfilter skelner mellem 1-511, som er såkaldt privilegerede, velkendte portnumre, som kun kræver root privilegier, og som typisk bruges af specielle serverprogrammer som fx. httpd, 512-1023, som også er priviligerede, og så 1024 - 65535, der kan anvendes til alt. Netfilter mapper ikke portnumre fra en gruppe til en anden. (At mappe = at spejle eller sige a svarer til X, b svarer til Y, c svarer til Z og så fremdeles, en af de få ting, en computer er god til.) Man vil kunne begrænse DNS-klienten til at bruge ganske få portnumre for forespørgsler, og derved yderligere skærpe sikkerheden, men det er ikke netfilters område.

De eksterne DNS servere sender svar til det portnummer, som klienten brugte til at spørge.

Her kommer kommandoen, som tillader alle remote DNS servere at svare til vores maskines eksterne netkort på en ikke-priviligeret port:


[root@hven /]# iptables -A INPUT -p udp -s 0/0 --source-port 53 -d 66.14.136.144/32 --destination-port 1024:65535 

Det ville være væsentligt bedre, hvis vi kun brugte en enkelt server udenfor firewallen, men så begynder det at blive et stort setup. Med den foreslåede lokale caching server kan anvendelsen af udp på alle lokale maskiner begrænses til, at de kun må lave UDP til denne specifikke IP-adresse. Her kommer kommandoerne, som kan gøre det, idet vi antager, at caching serveren har lokalnummeret 192.168.1.2:


[root@hven /]# iptables -A INPUT -p udp -s 192.168.0.0/16 --destination-port 53 -d 192.168.136.144 -j ACCEPT
[root@hven /]# iptables -A INPUT -p udp -s 192.168.1.2/16 --source-port 53 -d 192.168.0.0/16 1024:65535 -j ACCEPT
[root@hven /]# iptables -A INPUT -p udp -j DROP

Som man kan se er det lidt mere besværligt at kontrollere UDP, fordi man ikke kan regne med connections - alle pakker er som en enkeltstående begivenhed. Det er en statusløs protokol. Rækkefølgen er kritisk. Det ville være en god ide at bruge -i for interface specifikation, så firewallen styrer på IP nummer og hardware.

Ligesom for tcp protokollen loades der et extension modul, når vi specificerer -p udp. De ekstra kriterier, som dette modul giver mulighed for, er dog kun portnumre for hhv. source og destination. Det ovenstående eksempel specificerer, at alle inputporte over 1023 må bruges. Det ville være meget bedre at sige til DNS-forwarder programmet at det kun må bruge fx. port 32109. Ved at bruge fast portnummer for hjælpeserverens udgående trafik kan antallet af åbne porte begrænses meget.


[root@hven /]# iptables -A INPUT -p tcp ! --syn --source-port 20 --destination-port 1024:65535 -j ACCEPT 

Her vises en måde at åbne for alle FTP-pakker udefra, som ikke forsøger at indlede en konversation. Optionen --syn betyder, at pakker, som ikkehar syn-flaget (synkroniserings-request) sat, skal have lov at passere. Det er en anden måde at specificere, at maskiner indenfor firewallen skal have lov til at gøre alt, men alligevel beskyttes de såkaldt priviligerede porte i intervallet 1 - 1024. En angriber kan godt sende en pakke, som ikke har syn flaget sat, men det er jo sværere at komme igennem til noget sårbart, når man nu ikke kan sende til portnumre under 1024.

En måske mere avanceret anvendelse af port-ranges er at åbne for et mindre område ved source NAT-ing; man reserverer et interval til et bestemt formål og kan på remote maskinen filtrere alle andre afsenderporte fra. Mange netværksprogrammer har en mulighed for at brugeren specificerer, hvilke porte, der må bruges.


[root@hven /]# iptables -t nat -A
POSTROUTING -j SNAT --to 129.142.141.140:47000-49000

Et eksempel på anvendelse af multiport extension, hvor der åbnes for (kendte) serverporte i et hug (mere effektivt, mindre load på firewall):


[root@hven /]# iptables -A INPUT -p tcp -m multiport --dport 21,25,80,110,143,443 -j ACCEPT 

I det efterfølgende eksempel bliver port specifikationer brugt til at omdirigere trafikken, en stærk feature, når man vil lave en HTML proxy.

6.5.4. Source/Destination NAT og omdirigering

I det følgende ses på henholdsvis source NAT og destination NAT. I source NAT er det afsenderens adresse+port, som oversættes til gateway-adresse + en anden port. I Destination NAT sendes pakker, som egentlig er til a.b.c.d i stedet til x.y.z.q, hvilket jo strengt taget blot er en omdirigering.

Destination NAT rummer imidlertid mange muligheder, og er nødvendigt, når fx. 1000 klienter i sekundet spørger på Google, der i snit måske er 1/100 sekund om at svare. Man kan hurtigt regne ud, at de har mange servere kørende!

6.5.4.1. Source NAT

Source NAT er det almindeligste, og er det, som vi hidtil har set på i forbindelse med i192.168-numre klienter bag en firewall. Man kan sige, at vi spejler, (mapper, afbilder) source adressen plus portnummer som en global (offentlig) IP adresse med et andet portnummer. Derved kan mange lokale maskiner deles om et enkelt IP nummer. Teoretisk set kan man løbe tør for portnumre på NAT maskinen, og det er der skam også taget højde for, idet maskinen simpelthen dropper alle pakker som ikke kan mappes til dens range af IP-numre+portnumre.

6.5.4.2. Destination NAT

Man kan også mappe (afbilde) destinationsadressen - Destination NAT - så folks forespørgsler f.eks. bliver omdirigeret hen til den lokale webserver eller til en server ud af en server pool.

For TCP og UDP kan man lave portmapping med iptables, hvor man skifter destinationsporten ud. F.eks. kan en klient oprette en forbindelse til en web-server på port 80, og NAT-serveren kan afbilde pakkerne til sin egen port 3128, hvor der kører en squid. Dette kaldes redirect, men er også en form for destination NAT. Resultatet er transparent proxying.

Lav destination NAT til ip 1.2.3.4, 1.2.3.5 eller 1.2.3.6


# iptables -t nat -A PREROUTING -i eth1 -j DNAT --to 1.2.3.4-1.2.3.6

Fordelingen til serverne nr. 4 - 6 sker efter tur. Det kaldes ofte round-robin princippet. Derved kan man få fordelt belastningen til flere servere. Det egner sig ikke til CGI eller .php løsninger, hvor man skal fastholde en klient, hertil kræves en router, som kan holde styr på connections og samtidig lave round robin.

Lav destinations NAT fra port 80 til den lokale port 3128, hvor squid kører


# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 \ 
-j REDIRECT --to-port 3128

Eksemplerne er taget mere eller mindre direkte fra Linux 2.4 NAT HOWTO, og er blot ment som illustration af, hvad man kan med iptables NAT.

For nærmere beskrivelse, se Linux 2.4 NAT HOWTO på http://www.netfilter.org/unreliable-guides/NAT-HOWTO/index.html Se desuden man-siden for iptables.

6.5.5. En komplet firewall

Selv om der allerede er givet eksempler på en firewall Afsnit 6.1.3.1 så vises her en lidt større konfiguration af en firewall. Eksemplet er valgt ud fra det kriterium, at det skal være en opsætning, som har fungeret og har vist sig at være stabil.

Setuppet er, at vi har en maskine, som har forbindelse til vores ISP med fast (eller næsten fast) adresse, 130.3.2.99. Den skal være gateway og firewall. Desuden står der et antal maskiner i vores lille computerworkshop, og de må gerne snakke med internettet gennem vores gateway/firewall, men da de ikke har "private adresser" må vi også sørge for, at firewallen laver NAT. Desuden vil vi gerne have, at firewallen er web-server. Dette er ikke realistisk for en virksomhed, som ønsker high-speed, ultimativ sikkerhed, her ville man sørge for at fordele belastningen på flere maskiner, men realistisk nok for at demonstrere mange pointer.

Firewall maskinen har 2 netkort, eth0 og eth1. På eth0 er den forbundet til en hub på det interne net, og på eth1 er der hul til ISP'ens gateway, der har nummer 130.3.2.1, en såkaldt klasse B adresse, som har netmaske 255.255.255.0 så den fungerer som en klasse A adresse, med max 255 maskiner i netværket.

Det interne net har adresser i området 192.168.67.0 - 255. Det er for at være lidt på tværs, at jeg altid anbefaler andet end 192.168.1.1-254 om ikke andet, så kan de værste root-kit til intrusion på lokalnet herved vanskeligere få adgang ved spoofing.

Vi starter med at konstatere, at man ikke kan lave en default policy som kun gælder for det ene netkort. Derfor adskilles trafikken, således at alt input fra eth1 ledes igennem en kæde, som kaldes door1.

Door1 skal ende med at droppe al trafik, som vi ikke ønsker ind i vores netværk. De ting, som vi gerne vil have med, skal accepteres med en kommando -j ACCEPT.

Det aller første, scriptet gør, er at sikre, at netfilter delen i kernen er i en kendt tilstand, d.v.s. vi flusher alle regler i alle kæder og sætter alle default policies. Hvis man prøver at optimere ved kun at foretage de nødvendige ting for ens opsætning efter et boot, så skal man lige sørge for at have en version liggende, som kan klare alle situationer.

Det næste, der sker, er at kæden door1 slettes. Det sker selvfølgelig for at sikre, at der ikke ligger rester af andre regler i door1.

Det kan gøres på mange mange andre måder, men denne her metode er valgt efter lidt eksperimenteren. Man får også nulstillet tællerne for door1, og fejlene er ikke nogen, som får systemet til at hænge, hvilket vistnok har kunnet forekomme med nogle af de iptables options, som giver fejl, hvis man kører dem selv om de ikke er nødvendige. Læseren kan eksperimentere med at flushe kæden door1 i stedet for (også hvis den ikke findes).

Næste skridt er så at oprette kæden door1. Nu er den tom - ingen regler, ingen forbindelse med andre kæder. Lister man med -L kommandoen, får man at vide "no references", svarende til død kode eller ubrugt variabel.

Nu installeres regel efter regel i firewallen. De vigtigste er stadig dem, som tillader brugere indefra at kommunikere frit, men man skal lige huske, at denne trafik altid starter med input fra eth0, som vi slet ikke ser i denne door1 kæde. Indtil videre er der fri passage indefra og ud. Det er først til sidst, at der etableres en regel som siger, at al indadgående trafik fra eth1 skal via door1. Det kunne lige så godt have været først, og under alle omstændigheder må man kun aktivere eth1, når alle reglerne i firewallen er opsat. Man kan godt opsætte regler for et interface, som er "down", ifconfig eth1 down .

Der åbnes for al trafik til ssh-porten, både den indefra-ud og udefra-ind. Ligeledes åbnes der for al trafik til http porten.

Næste regel åbner for indkommende trafik, der stammer fra port 53, nameservere.

Nu kommer en regel, som kun skal benyttes, hvis ISP benytter DHCP til kontrol af IP, nameservices og routing. Det er en god ting og forhindrer slet ikke, at man selv styrer konfigurationen.

Der åbnes også for ping. Det er ikke et krav for en firewall, men er ok at gøre på en maskine, der står udenfor en firewall men inden en gateway. I eksemplet her er gateway og firewall den samme, men det er ok at åbne for ping/ICMP, hvis man holder øje med trafikken.

Endelig kommer de spændende linier, hvor der åbnes for indgang for alt, hvad der er svar på forbindelser etableret indefra.

Dernæst er der kun opsætning af NAT-ing og aktivering af forwarding.


#/bin/ksh

iptables -t filter -F
iptables -t nat    -F
iptables -t mangle -F
iptables -X door1 2> /dev/null 1>&2
iptables -N door1

iptables -A door1 -m state --state INVALID -j DROP
# åbne for al ssh og http
iptables -A door1 -p tcp --sport ssh  -j ACCEPT
iptables -A door1 -p tcp --dport ssh  -j ACCEPT
iptables -A door1 -p tcp --sport http -j ACCEPT
iptables -A door1 -p tcp --dport http -j ACCEPT
# åbne for svar fra nameserere, DNS.
iptables -A door1 -p udp --sport 53   -j ACCEPT
# der åbnes for konversation med dhcp serveren på gatewayen.
iptables -A door1 -p udp --source 130.3.2.1 --dport bootps -j ACCEPT
# åbne for ping (mange vil foretrække at lukke i stedet!)
iptables -A door1 -p icmp             -j ACCEPT
# Alt, hvad der er etableret indefra, accepteres.
iptables -A door1 -m state --state ESTABLISHED,RELATED  -j ACCEPT
# alt andet smides væk.
iptables -A door1 -j DROP

# Hop til door1 hvis input er fra eth1
iptables -A INPUT -i eth1 -j door1

# NAT-ing sættes op, så alt, hvad der kommer fra lokalnettet,
# bliver videresendt som om det kommer fra firewallen.
iptables -t nat -A POSTROUTING --src 192.168.67.0/24 \
         -o eth1 -j SNAT --to 130.3.2.99

# for at det skal fungere, må vi aktivere forwarding:
echo 1 >> /proc/sys/net/ipv4/ip_forward

Der er mange andre ting, man kan foretage sig, for at maskinen bliver sikret: http://www.bastille-linux.org/. Det kaldes også "hardening", hærdning, af et system. For eksempel anbefales det på udsatte systemer at fjerne de tools, som en systemadministrator bruger til sletning, kopiering og omdøbning af filer, mount, diskformatering, oprettelse af filsystemer mv. Hvis en cracker opnår root-privilegier, vil aktionsmulighederne derved være begrænset. Men det vil for de fleste private medføre irritationsmomenter i det daglige arbejde. Man kunne selvfølgelig have en supplements-server stående, som man lige kunne hooke op når man havde brug for det ...

Sådan er der så mange ting, man kunne gøre. De fleste af disse tiltag beskrives i sidste afsnit

Kommentarer til ovenstående firewall er velkomne, særligt hvis der er konkrete ting, som er afprøvet, men også kommentarer, som bevæger sig i yderkanten af emnet.

6.5.6. Linux som proxy server

I det følgende beskrives den situation, at en virksomhed med 40 ihærdige brugere på en 2 Megabit forbindelse ønsker at forbedre browser-response, således, at når en person har hentet en web-side, så kan de andre hente den samme web-information lokalt fra en server med buffer, en såkaldt caching proxy.

6.5.6.1. Proxy med Squid

Squid er en god proxy server bl.a. til Linux, der kan findes på http://www.squid-cache.org/. Squid er en agent, der henter de hjemmesider, brugeren beder om, og videresender resultatet til brugeren. Samtidig kan Squid fungere som proxy-cache - den gemmer hjemmesiden i cache, og er der nu en anden bruger, der vil se den samme hjemmeside, hentes den direkte fra den lokale hukommelses- eller disk-cache på proxy-maskinen - det vil sige, uden at man skal via internettet. Squid tester, om en hjemmeside på nettet er nyere end den i cachen, og kun hvis cachen er forældet, vil en ny version blive hentet. Fordelen ved en proxy-cache er således, at man ofte kan spare måske 50% på båndbredden.

Det er naturligvis ikke alt, som kan gemmes i en cache, f.eks. skal cgi-kald netop ikke køre fra cache. Disse hindringer håndterer Squid dog transparent. Ud over hjemmesider (HTTP) er FTP, GOPHER, SSL og WAIS protokollen understøttet. Squid kan dog ikke klare POP-mail, NNTP (News grupper) og RealAudio.

6.5.6.2. Installation af Squid-serveren

Man bør ikke installere Squid, så den kører som root. Ofte vælger man at lade Squid køre som brugeren squid i sin egen gruppe squid, og kun med få rettigheder.

Vi har installeret squid-2.2.STABLE5-1.i386.rpm, som kan hentes fra http://www.squid-cache.org/. Squid startes op via /etc/rc.d/init.d/squid. Squids opsætningsfil hedder /etc/squid/squid.conf. Der er mange konfigurationsmuligheder. Basalt set skal man fjerne kommentartegnene fra nogle linjer i /etc/squid/squid.conf og udkommentere andre, og så starte Squid. Den originale /etc/squid/squid.conf er stor, og vi vil nu se nærmere på en simpel opsætning af squid.

6.5.6.2.1. Basal opsætning af squid.conf

Man kan i /usr/doc/squid-2.2.STABLE5/QUICKSTART finde en minimal beskrivelse af parametre for squid.conf. En meget bedre gennemgang fås ved at læse brugermanualen til Squid, som kan findes på http://www.squid-cache.org/Doc/Users-Guide/. En anden god start er også at læse (og gemme) den originale /etc/squid/squid.conf, som fulgte med RPM-pakken.

Vi skal nu vise en kort squid.conf, hvor vi lader squid køre som brugeren squid.


#squid.conf -  Basal opsætning

#Laveste niveau af logging
debug_options ALL,1

#Gruppe af IP numre, som kan tilgå Squid (Access Control List) 
#Vil man kun give access til netværket 192.168.0.0/255.255.255.0
#så brug følgende linje
acl all src 192.168.0.0/255.255.255.0

#Skal alle kunne bruge Squid så udkommenter følgende linje.
#acl all src 0.0.0.0/0.0.0.0

#Port, man anvender til konfiguration af Netscape klienter
http_port 3128

#Lad alle i ACL bruge Squid til HTTP
http_access allow  all

#test følgende sites for at tjeke, om maskinen er koblet til internettet
dns_testnames internic.net usc.edu cs.colorado.edu mit.edu yale.edu

#Kør som effektiv bruger squid og gruppe squid
cache_effective_user squid squid

# Squid vil oftest bruge to-tre gange denne RAM størrelse. Vil man max
# bruge 24 Mb RAM til Squid, så sæt cache_ram til 8 Mb. 
# Jo mere cache_mem desto hurtige er cachen (mindre diskaccess).
cache_mem  8 MB

#Maximal størrelse på object i cache
maximum_object_size 4096 KB

# Næste parameter-opsætning er disk cache struktur. Parametre er
#  Dirname - hvor på disken er disk cache, dvs. spool dir
#  Mbytes under spool dir - hvor mange Mb må gemmes i disk cache.
#  Level-1 dir antal - Antal underkataloger under Dirname
#  Level2 dir antal - Antal underkataloger for hver Level-1 kataloger
# Sæt ikke produktet mellem de to sidste vildt højt!
cache_dir /var/spool/squid 100 16 256

Lad os se nærmere på, hvad der installeres, og hvordan squid kører. Installer squid med


#rpm -ivh squid-2.2.STABLE5-1.i386.rpm

Ret /etc/squid/squid.conf til som vist ovenfor. Husk dog at gemme den originale /etc/squid/squid.conf før ovenstående eksempel anvendes.

  • /etc/squid/ indeholder konfigurationsfiler - specielt er /etc/squid/squid.conf vigtig.

  • /var/spool/squid indeholder den dynamiske database. (se parameteren cache_dir i squid.conf). Over 4000 filer laves med ovenstående opsætning.

  • /var/log/squid indeholder log-filer.

    • access.log - Hvad blev hentet fra nettet. Her kan systemadministratoren overvåge trafik.

    • cache.log - Opstartsmeddelelser.

    • store.log - Oversigt over, hvad der findes i proxy-cache nu.

Med installation af squid blev squid brugeren og tilsvarende gruppe oprettet. Kataloget /var/spool/squid er tomt men ejet af brugeren squid. Selve databasestrukturen skal man en gang for alle sætte op - hertil bruges parameteren cache_dir.


[root@sherwood root]# /usr/sbin/squid -z

Anvender man 16 og 256 som de sidste to parametre til cache_dir, skal man ikke blive bange, når man initialiserer databasen. Der køres hårdt på harddisken, og det tager måske flere minutter - databasen bliver stor!

6.5.6.2.2. Brugerens opsætning

For at man kan få squid til at virke sammen med lynx og wget, kan man sætte følgende environment variable (her hedder vores proxy-server "proxy.herne.dk")


% setenv http_proxy http://proxy.herne.dk:3128/
% setenv gopher_proxy http://proxy.herne.dk:3128/
% setenv ftp_proxy http://proxy.herne.dk:3128/ 

I Netscape skal brugerne under Edit->Preferences->Advanced->Proxies vælge Manual proxy configuration og tryk på View. Som det kan ses på det næste billede, skal man skive navnet på proxy maskinen (her anvender vi proxy.herne.dk), og port 3128 svarer til parameteren "http_port" i squid.conf.

Figur 6-7. Proxy opsætning i Netscape

Squid er i dagligdagen et meget driftsikkert program og kan anbefales. Vi skal dog lige huske at nævne, at hvis der ikke er blokeret for det via en firewall, så kan brugeren af Netscape faktisk godt køre forbi proxy cachen ved enten at udelade proxy-opsætningen eller at holde SHIFT nede, før der trykkes på et link. Derfor skal firewallopsætningen være lavet, så proxy-programmet godt kan hente data fra internettet, men at brugere ikke kan - hvis man virkelig ønsker, at folk skal bruge proxy-serveren.

6.5.6.3. Transparent proxy med squid

Man kan lave transparent proxy med squid sammen med iptables. Kernen skal være oversat med "Transparent proxying". Se Afsnit 6.5.4.2

Der findes også en mini-HOWTO på http://sunsite.dk/ldp/HOWTO/mini/TransparentProxy.html .

6.5.7. Masquerading med ipchains (kerne 2.2)

I Linux-kerne 2.2 hedder firewall kommandoen ipchains , og denne kommando bruges også til opsætning af masquerading.

Forwardkæden sættes op med en default target MASQ eller, hvis default politik (policy). Den kan stadig væk smide væk, men i ipchains hedder det DENY.

Den simple og hurtige måde at sætte IP masquerading op på er:


[root@myhost /root]# ipchains -A forward -i ppp0 -j MASQ
[root@myhost /root]# ipchains -A forward -s 0.0.0.0/0 -d 0.0.0.0/0 -l -j REJECT
[root@myhost /root]# echo 1 > /proc/sys/net/ipv4/ip_forward

hvor ppp0 er det interface, der peger ud imod verden, imod internettet, imod det net, man vil give sine maskiner adgang til via masquerading.

Det kan også give mening at sætte timeouts for masquerading forbindelserne:


[root@myhost /root]# ipchains -M -S 7200 10 160

Det første tal er timeout for en tcp forbindelse, det næste er hvor længe en tcp forbindelse skal kunne eksistere efter modtagelsen af en FIN pakke, og det sidste er timeout for UDP. Timeout tiderne er i sekunder. Default timeout er 15 minutter, og det kan være lidt kort for en tcp session.

Nu sættes de andre maskiner i lokalnetværket til at bruge myhost som default gateway, og voila! Man kan komme på internettet fra de andre maskiner.

6.5.7.1. Moduler til ipchains

Og dog. Http mm virker nu, men der er et par protokoller, der kræver særlige hensyn. Det er bla. ftp, realaudio, irc og forskellige spil.

For at kunne bruge ftp, real audio, irc, spille quake mm via masquerading, er vi nødt til gøre det lidt mere indviklet. Der findes moduler til ipchains , der kan håndtere en del forskellige applikationer: ip_masq_ftp, ip_masq_raudio, ip_masq_irc, ip_masq_quake etc. For at kunne bruge disse moduler, skal de være oversat med, da man lavede kernen. Det er inde under networking options, hvor man skal slå "IP masquerading special module support" og "ipportfw masq support" til. I kerne 2.2.12 er det nødvendigt at slå "prompt for development and/or incomplete code/drivers" til for at få lov til at vælge ipportfw.

Modulerne indlæses nu med:


[root@myhost /root]# /sbin/modprobe ip_masq_ftp
[root@myhost /root]# /sbin/modprobe ip_masq_raudio


Nu virker ftp og realaudio fra de andre maskiner. Gør det samme med de andre moduler, der skal bruges. Der findes også et værktøj, der hedder IPMASQADM, man kan bruge. Der findes en slags beskrivelse af emnet i IP-Masquerade-HOWTO'en på http://sunsite.dk/ldp/HOWTO/IP-Masquerade-HOWTO-6.html#ss6.8

6.5.7.2. Opsætning af de andre maskiner i nettet

Default gateway sættes med kommandoen route:


route add default gw myhost

Hvis det skal være permanent, er der lidt forskel på distributionerne. Nogle har et fint konfigurationsværktøj, det vil vi ikke komme ind på her. I SuSE er det en /etc/route.conf, man kan sætte det ind i. I debian er det direkte i /etc/init.d/ i et netværks startup script. I RedHat er det filen /etc/sysconfig/network, man sætter sin default gateway ind i.

For yderligere information om IP masquerading kan man læse IP-Masquerade-HOWTO'en http://sunsite.dk/ldp/HOWTO/IP-Masquerade-HOWTO . HOWTO'en indeholder også referencer til en række gode ressourcer.

Slutbemærkning:

[1]

Der kan være mange grunde til, at man selv vil skrive iptables kommandoerne. Ved afprøvningen af Firestarter konstatererede jeg, at den laver om på filer i /etc/ uden at aflevere en liste over hvilke filer, den har ændret. Firestarter kan ikke save sine resultat filer, firewall scriptet, uden at køre iptables kommandoen. Derfor kan man ikke "se den over skulderen" inden man vælger at acceptere den. Jeg kørte den i en 'chroot'ed partition og den stoppede min firewall uden at spørge.

For en begynder er det nok en fordel, at den opfører sig så håndfast uden at spørge.

Ældre versioner af Red Hats firewall-config bruger ipchains og forventer, at man har en modulariseret (distributions)kerne. Det gør ikke så meget, at den råber FEJL når man kører med optimeret non-modul kerne, hvis den i øvrigt bare fungerer. Den kan heller ikke vise, hvad den vil gøre uden at gøre det.

I de senere afsnit vises, hvordan man skriver et script med sine egne firewall regler, og hvis man har gjort det, så kan man jo tage en komplet kopi af /etc til fx /etc-bkup og på den måde sikre sine ændringer mod overskrivning.

RedHats setup er et xterm - menuprogram, og starter forskellige subprogrammer til opsætning og konfiguration. Bortset fra små problemer med samtidig konfiguration fra det ene/andet GUI er jeg glad for RedHat setup. Dens firewall configurator hedder /usr/sbin/lokkit og fungerer. Det er også den, som bruges under installation af RedHat, og den fås også som GUI version, /usr/sbin/redhat-config-network.