[OpenBSD]

[Wstecz: Redundantny firewall z CARP i pfsync] [Spis treści]

PF: Przykład: Firewall dla sieci domowej lub małego biura


Spis treści


Wstęp

W tym FAQ zostanie omówiony przykład wykorzystania maszyny z OpenBSD i działającym PF do zbudowania firewalla i bramki NAT dla niewielkiej sieci w domu lub biurze. Głównym celem jest udostępnienie połączenia z Internetem komputerom w sieci wewnętrznej, a także umożliwienie ograniczonego dostępu z Internetu do maszyny spełniającej rolę ściany ogniowej, oraz udostępnienie wewnętrznego serwera www dla zewnętrznego internetu. Kompletny przykład będzie można znaleźć na końcu tego dokumentu.

Sieć

Topologia sieci wygląda następująco:
    
  [ KOMP1 ]    [ KOMP3 ]
      |            |                               
   ---+------+-----+------- xl0 [ OpenBSD ] fxp0 -------- ( Internet )
             |
         [ KOMP2 ]

Do sieci wewnętrznej przyłączonych jest kilka maszyn, co prawda na schemacie zaznaczone są trzy, ale w tym przypadku ich ilość nie ma żadnego znaczenia. Komputery te wykorzystywane są do codziennych zadań takich jak: przeglądanie stron www, wysyłanie poczty elektronicznej, rozmów, itd., za wyjątkiem KOMP3, który służy również jako niewielki serwer WWW. Przestrzeń adresowa sieci wewnętrznej zawiera się w bloku 192.168.0.0 / 255.255.255.0.

Router zbudowany na bazie OpenBSD to komputer z procesorem Celeron 300 i dwiema kartami sieciowymi: 3Com 3c509B (xl0) i Intel EtherExpress Pro/100 (fxp0). Połączony jest on z Internetem ethernetowym, a do udostępniania połączenia innym komputerom wykorzystywany jest NAT. Adres IP dla zewnętrznego interfejsu uzyskiwany jest dynamicznie od Dostawcy Usług Internetowych.

Założenia

Założenia, którymi należy kierować się przy budowie regułek filtrowania:

Wymagania

Podczas pisania tego FAQ przyjęto, że OpenBSD został poprawnie skonfigurowany do przyszłej pracy jako router, włączając w to właściwe przygotowanie sieci, połączenia z Internetem, oraz ustawienia zmiennych sysctl(3) net.inet.ip.forwarding i/lub net.inet6.ip6.forwarding na "1". Musisz mieć także uruchomionego PF-a przy pomocy pfctl(8) lub ustawioną właściwą zmienną w /etc/rc.conf.local.

Budowanie zestawu reguł

Wykonanie poleceń zawartych w następujących podrozdziałach zaowocuje otrzymaniem kompletnego zestawu reguł spełniającego wszystkie warunki podane powyżej.

Makra

Poniższe makra mają na celu ułatwienie zrozumienia oraz usprawnienie zarządzania zestawem reguł:
ext_if = "fxp0"
int_if = "xl0"

tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"

comp3 = "192.168.0.3"

Pierwsze dwie linie określają na jakich interfejsach będzie odbywać się filtrowanie. Dzięki zdefiniowaniu ich w tym miejscu, w sytuacji gdy będziemy chcieli przenieść nasz system na inną maszynę, z innym sprzętem, będziemy mogli zmienić tylko te dwie linie, a pozostała część zestawu reguł będzie wciąż użyteczna. Trzecia linia zawiera listę portów TCP (SSH i ident/auth), do których ruch z Internetu ma być przepuszczany. W czwartej linii określone są typy komunikatów ICMP, które będą akceptowane przez nasz "firewall". Ostatnia linia określa adres IP komputera KOMP3.

Uwaga: Jeśli połączenie internetowe odbywa się poprzez PPPoE, wtedy filtrowanie oraz translacja pakietów odbywać się będzie na interfejsie tun0 a nie na fxp0.

Opcje

Dwie poniższe opcje włączają domyślne odpowiedzi na zablokowane pakiety dla reguły block, a także zbieranie różnego rodzaju statystyk dla zewnętrznego interfejsu sieciowego.
set block-policy return
set loginterface $ext_if

Każdy system UNIX posiada interfejs pętli zwrotnej nazywany "loopback". Jest to wirtualny interfejs sieciowy używany przez procesy do komunikacji z innymi aplikacjami uruchomionymi w lokalnym systemie. Cały ruch na tym interfejsie powinien być przepuszczany bez żadnych ograniczeń. W OpenBSD interfejs "loopback" nazywa się: lo(4). Najlepszym pomysłem jest wyłączenie jakiegokolwiek filtrowania na tym interfejsie. W tym celu skorzystaj z opcji set skip.

set skip on lo
Zauważ, że wyłączyliśmy filtrowanie dla całej grupy interfejsów lo, w ten sposób w sytuacji gdy później dodamy interfejsy "loopback", nie będziemy musieli się martwić o dodawanie tej opcji do istniejącego zestawu reguł.

Normalizacja pakietów

Nie istnieje żaden ważny powód dla którego nadchodzące pakiety nie miały by zostać poddane normalizacji. Włączenie normalizowania pakietów odbywa się przez dodanie jednej, prostej linii:
scrub in

Translacja adresów

Włączenie translacji adresów (NAT) dla hostów w sieci wewnętrznej uzyskuje się przez dodanie regułki nat:
nat on $ext_if from !($ext_if) to any -> ($ext_if)

Wyrażenie "!($ext_if)", może być oczywiście łatwo zastąpione przez "$int_if", jednak jeżeli dodasz wiele wewnętrznych interfejsów, będziesz musiał dodać wiele reguł NAT, tymczasem w takim rozwiązaniu, NAT będzie obsługiwany na wszystkich zabezpieczonych interfejsach.

Jako że adres IP dla zewnętrznego interfejsu sieciowego jest uzyskiwany dynamicznie, nazwa interfejsu na którym odbywa się mapowanie adresów została wzięty w nawiasy, dzięki temu PF zostanie powiadomione o każdej zmianie adresu.

Ponieważ, chcemy mieć działające FTP-proxy, umieścimy w naszej konfiguracji również zakotwiczenie NAT:

nat-anchor "ftp-proxy/*"

Przekierowanie

Pierwsze przekierowania w tym zestawie reguł są dla ftp-proxy(8), aby klient FTP w sieci lokalnej mógł bez problemów połączyć się z serwerami FTP w Internecie.
rdr-anchor "ftp-proxy/*"
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021

Proszę zauważyć, że regułka ta obsługuje jedynie połączenia FTP na porcie 21. Jeśli zajdzie potrzeba umożliwienia korzystania z innych numerów portów, konieczne będzie podanie ich w postaci listy, na przykład: from any to any port { 21, 2121}

Ostatnia reguła rdr służy do przekierowania prób połączeń z portem 80 protokołu TCP firewalla. Poprawne połączenia z tym portem pochodzą od użytkowników chcących uzyskać dostęp do serwera WWW. Połączenia te powinny zostać przekierowane do komputera KOMP3:

rdr on $ext_if proto tcp from any to any port 80 -> $comp3

Regułki filtra pakietów

Po ustawieniu NAT i przekierowań można przystąpić do konfiguracji filtra pakietów. Filtr będzie pracował zgodnie z zasadą "domyślnego blokowania":
block in

W tym miejscu każdy ruch usiłujący wejść przez interfejs będzie blokowany, nawet ten pochodzący z sieci wewnętrznej. Kolejne regułki będą umożliwiały przejście datagramów zgodnie z wytycznymi podanymi wcześniej.

Pamiętaj, że pf może zablokować każdy ruch wchodzący lub wychodzący przez interfejs. Możesz sobie znacznie uprościć życie, jeżeli zdecydujesz się na filtrowanie ruchu w jednym kierunku, zamiast starać się bezpośrednio filtrować pewne rzeczy, przepuszczając inne. W naszym przypadku, zdecydowaliśmy się na filtrowanie przychodzącego ruchu, lecz gdy dany ruch zostanie raz przepuszczony przez interfejs, nie będziemy starali się go blokować. Zatem zrobimy coś takiego:

pass out keep state

Potrzebyjemy mieć zakotwiczenie dla ftp-proxy(8):

anchor "ftp-proxy/*"
Dobrze jest blokować sfałszowane adresy (ang. antispoof):
antispoof quick for { lo $int_if }

Następna regułka otwiera porty dla usług, które mają być udostępnione w Internecie. Na początek ruch który jest kierowany do samego firewall-a:

pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services flags S/SA keep state

Podanie portów w postaci makra $tcp_services sprawia, że łatwo dodać kolejne usługi, które mają zostać udostępnione. Wystarczy wyedytować makro i ponownie załadować zestaw reguł. Podobnie sprawa ma się z usługami bazującymi na protokole UDP, potrzeba tylko utworzyć makro $udp_services i dodać bardzo podobną regułkę, jak ta pokazana powyżej, z opcją proto udp.

Dodatkowo, obok reguły rdr, która przekierowuje ruch skierowany do serwera WWW do komputera KOMP3, konieczne jest przepuszczenie tego ruchu przez firewall:

pass in on $ext_if inet proto tcp from any to $comp3 port 80 \
    flags S/SA synproxy state

Aby odrobinę poprawić bezpieczeństwo zastosowano TCP SYN Proxy, który dodatkowo zabezpiecza serwer przed atakami z zewnątrz.

Przepuszczenie pakietów ICMP:

pass in inet proto icmp all icmp-type $icmp_types keep state

Podobnie jak makro $tcp_services, makro $icmp_types może być w łatwy sposób zmienione by umożliwić przepuszczanie innych typów pakietów ICMP przez firewall. Proszę zwrócić uwagę, że regułka ta odnosi się do wszystkich interfejsów sieciowych.

Kolejne regułki przepuszczają ruch z lub do sieci wewnętrznej. Przykład zakłada, że użytkownicy na wewnętrznym interfejsie dokładnie wiedzą co robią i nie będą powodować problemów. To niekoniecznie prawidłowe założenie, mniejsza swoboda może być bardziej odpowiednia w wielu przypadkach.

pass in quick on $int_if

Ruch TCP, UDP i ICMP jest przepuszczany do Internetu, ze względu na wcześniejszą regułę "pass out keep state". Informacja o stanie jest zachowywana, zatem pakiety które są odpowiedzią, będą przepuszczane przez firewall.

Kompletny zestaw reguł

# makra
ext_if = "xl0"
int_if = "fxp0"

tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"

comp3 = "192.168.0.3"

# opcje
set block-policy return
set loginterface $ext_if

set skip on lo0

# normalizacja datagramów 
scrub in

# nat/rdr
nat on $ext_if from !($ext_if) -> ($ext_if:0)
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"

rdr pass on $int_if proto tcp to port ftp -> 127.0.0.1 port 8021
rdr on $ext_if proto tcp from any to any port 80 -> $comp3

# regułki filtra pakietów
block in

pass out keep state

anchor "ftp-proxy/*"
antispoof quick for { lo $int_if }

pass in on $ext_if inet proto tcp from any to ($ext_if) \
    port $tcp_services flags S/SA keep state

pass in on $ext_if inet proto tcp from any to $comp3 port 80 \
    flags S/SA synproxy state

pass in inet proto icmp all icmp-type $icmp_types keep state

pass quick on $int_if

[Wstecz: Redundantny firewall z CARP i pfsync] [Spis treści]


[wstecz] www@openbsd.org
$OpenBSD$