routing w linuksie

miałem ostatnio interesującą sytuację w firmie.

jeden z pracowników miał na swoim komputerze wersję demo nowego serwisu www. i trzeba było wystawić to dla klienta na zewnątrz.

teoretycznie trywiał – jak się okazało, nie do końca.

najpierw ogólnie.

sieć wygląda w uproszczeniu tak:

Diagram1.png

aplikacja była odpalona na komputerze “pracownik a".

na firewallu/routerze regułki były skomplikowane, ale dla uproszczenia przyjmijmy, że było tylko:

iptables -P INPUT DROP<br />
iptables -P FORWARD DROP<br />
iptables -F<br />
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT<br />
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT<br />
iptables -A INPUT -p icmp -j ACCEPT<br />
iptables -A FORWARD -p icmp -j ACCEPT<br />
iptables -A INPUT -i lo -j ACCEPT<br />
iptables -A FORWARD -i lo -j ACCEPT<br />
iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT # eth0 TO sieć lokalna, eth1 - internet<br />
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

jak widać nic skomplikowanego.

no więc pojawia się zadanie – klient ma mieć wystawiony serwis z “pracownik a" (port 80) na dowolnym porcie.

ok. robimy:

iptables -t nat -A PREROUTING -s 243.65.193.17 -p tcp --dport 82 -j DNAT --to-destination 172.30.0.2:80

i … działa. zero zdziwień. proste i miłe.

ale jak wyżej napisałem – trywiał, ale nie do końca. jaki więc haczyk?

no cóż. następnego dnia pojawił się drugi request:

tak jak klient wchodzi na http://192.0.2.94:82/ to pracownicy z sieci (np. pracownik b) też mają móc.

i tu zaczęły się schody.

pierwszy strzał:

iptables -t nat -A PREROUTING -s 172.30.0.0/24 -d 192.0.2.94 -p tcp --dport 82 -j DNAT --to-destination 172.30.0.2:80<br />
iptables -A FORWARD -i eth0 -o eth0 -j ACCEPT

i nie działa.

chwila zastanowienia – nic prostego się nie okazuje.

tak więc rozrysowaliśmy sobie sytuację:

  1. “pracownik b" wysyła pakiet do 192.0.2.94:82. adres źródłowy pakietu: 172.30.0.3:1031 (jakiś losowy, wysoki port)
  2. ponieważ pakiet jest do innej sieci niż 172.30.0.0/24, zostaje przekazany do routera
  3. router ma regułkę która pakiet dnatuje, więc dane pakietu zmieniają się na:
    źródło: 172.30.0.3:1031, cel: 172.30.0.2:80
  4. pakiet przechodzi przez firewalla zaakceptowany i wchodzi z powrotem do lanu.
  5. pakiet trafia do komputera “pracownik a". super! ale tu zaczynają się kłopoty.
  6. “pracownik a" odpowiada. zamienia miejscami nadawcę i odbiorcę pakietu, otrzymując:
    źródło: 172.30.0.2:80, cel: 172.30.0.3:1031
  7. ponieważ cel jest w sieci 172.30.0.0/24 – wysyła pakiet bezpośrednio do odbiorcy – z pominięciem routera.
  8. do komputera “pracownik b" trafia pakiet (ack/syn), na dobry port, ale od złego ip?! “pracownik b" chciał “rozmawiać" z 192.0.2.94:82, a tu dostaje pakiet od 172.30.0.2:80 – czyli jakaś pomyłka. pakiet zostaje olany.
  9. nie bangla.

po rozrysowaniu sprawa stała się jasna.

pozostaje naprawić. pojawił się pomysł by robić DNAT'a, na “pracownik a" (przekazując pakiet do routera), ale to było brzydkie.

co finalnie zrobiliśmy?

na routerze dodaliśmy jedną regułkę:

iptables -t nat -A POSTROUTING -s 172.30.0.0/24 -d 172.30.0.2 -p tcp --dport 80 -j SNAT --to-source 172.30.0.1

i działa!

pełny przesył wygląda teraz tak:

  1. “pracownik b" wysyła pakiet do 192.0.2.94:82. adres źródłowy pakietu: 172.30.0.3:1031 (jakiś losowy, wysoki port)
  2. ponieważ pakiet jest do innej sieci niż 172.30.0.0/24, zostaje przekazany do routera
  3. router ma regułkę która pakiet dnatuje, więc dane pakietu zmieniają się na:
    źródło: 172.30.0.3:1031, cel: 172.30.0.2:80
  4. pakiet przechodzi przez firewalla zaakceptowany
  5. przed wyjściem do lanu pakiej jest snatowany, więc dane pakietu zmieniają się na:
    źródło: 172.30.0.1:1031, cel: 172.30.0.2:80
  6. pakiet trafia do komputera “pracownik a".
  7. “pracownik a" odpowiada. zamienia miejscami nadawcę i odbiorcę pakietu, otrzymując:
    źródło: 172.30.0.2:80, cel: 172.30.0.1:1031
  8. ponieważ cel jest w sieci 172.30.0.0/24 – wysyła pakiet bezpośrednio do odbiorcy – ale w tym przypadku odbiorcą jest router
  9. mechanizm conntracka na routerze dokonuje odpowiednich (odwrotnych) translacji adresów, tak, że pakiet powrotny przyjmuje postać:
    źródło: 192.0.2.94:82, cel: 172.30.0.3:1031
  10. do komputera “pracownik b" trafia pakiet (ack/syn), na dobry port, i od słusznego ip.
  11. bangla.

po zapisaniu tego wszystkiego sprawa staje się jasna i oczywista. ale nie zmienia to faktu, że kilka razy słychać było – “nie da się".

powyższy pomysł/regułki dedykuję wszystkim zdającym test na pracownika do nas 🙂 tam jest mocno podobne pytanie 🙂

6 thoughts on “routing w linuksie”

  1. Ech depesz, depesz. Mieliśmy taką sytuację w CS jeszcze, za Twoich czasów o ile pamiętam. I tłumaczyłem wszystkim dlaczego to nie działało i co zrobiłem, żeby zaczęło. Trzeba było mnie słuchać… :->

    I zgadzam się, że to jest dobry test na zrozumienie działania IP. Spotkałem się z taką sytuacją już dobrych kilkanaście razy i co się przy tym nasłuchałem od “fachowców od sieci”, to moje. Może kiedyś wydam książkę z cytatami tych ekspertów. :->

  2. eh.
    tak tylko by sprosotować. ja o tym wiem. dlatego (m.in.) dałem pytanie o takie regułki do testu na administratora w firmie gdzie pracuję.
    okazało się jednak, że nie wszyscy wiedzą – i stąd ten wpis na blogu. może się komuś przyda.

  3. Proponowane przez Ciebie rozwiazanie ma wade. Otoz w logach serwera WWW nie bedzie informacji o adresie IP internauty. (nie testowalem, ale tak mi sie wydaje). Sugeruje inne rozwiazanie. Na publicznym dostepnym serwerze WWW (o ile taki serwer jest w Waszej sieci) ustawic regułki rewrite engine, np:
    RewriteRule ^/newstaf/(.*) http://192.168.0.111/~antek/newstaf/$1 [L,P]
    Dzięki temu serwer publiczny zaloguje adres IP internauty.

  4. no tak, ale wymaga to postawienia serwera www na routerze. a tego nie lubimy.
    sytuacja o której pisałem miała miejsce w sieci w biurze – serwery są zupełnie gdzie indziej.
    poza tym – identyczny mechanizm pojawia sie gdy np. chcesz zrobić transparent proxy w sieci, ale tak, że proxy jest na innej maszynie niż router i w dodatku jest (proxy) w normalnej sieci użytkowników.

  5. To, co lubimy i czego nie lubimy ma mniejsze znaczenie niz to, co jest bezpieczniejsz lub mniej bezpieczne. Z jednej strony jest Apache+mod_rewrite+mod_proxy, a z drugiej brak logowania IP w Apache (lub skomplikowane logi z routingu). Warto jednak pamietac, ze forwardujac caly port dajemy dostep do wszystkich aplikacji zainstalowanych na tym porcie na komputerze w naszej sieci ktory nalezy prawdopodobnie dewelopera . A to jest bardzo niebezpieczne.

  6. Sugerowane rozwiazanie:
    tunel i forwardowanie portow poprzez ssh do publicznego serwera www. na publicznym serwerze odpowiednie regolki dla mod_rewrite.

Comments are closed.