[ Programowe tunelowanie połączeń TCP. ]



Podobne dokumenty
Kurs języka Python. Wątki

76.Struktura oprogramowania rozproszonego.

Komunikator internetowy w C#

Klient-Serwer Komunikacja przy pomocy gniazd

Platformy Programistyczne Zagadnienia sieciowe i wątki

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

Programowanie współbieżne i rozproszone

Zaawansowany kurs języka Python

Przykłady interfejsu TCP i UDP w Javie

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

Dokumentacja wstępna TIN. Rozproszone repozytorium oparte o WebDAV

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

W celu uruchomienia kontrolera należy w katalogu głównym kontrolera z wiersza poleceń wydać następujące polecenie: $ java -jar target/floodlight.

Aplikacja Sieciowa wątki po stronie klienta

Język JAVA podstawy. wykład 2, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Aplikacja Sieciowa. Najpierw tworzymy nowy projekt, tym razem pracować będziemy w konsoli, a zatem: File->New- >Project

SIP Studia Podyplomowe Ćwiczenie laboratoryjne Instrukcja

BAZY DANYCH. Obsługa bazy z poziomu języka PHP. opracowanie: Michał Lech

Wybrane działy Informatyki Stosowanej

Ćwiczenie 2. Obsługa gniazd w C#. Budowa aplikacji typu klient-serwer z wykorzystaniem UDP.

Wybrane działy Informatyki Stosowanej

Biuletyn techniczny. Konfiguracja połączenie z serwerem MSSQL 2000 CDN OPT!MA Copyright 2006 COMARCH SA

Architektury systemów rozproszonych LABORATORIUM. Ćwiczenie 1

Język C++ zajęcia nr 2

Aplikacja wielowątkowa prosty komunikator

Sieci komputerowe. Zajęcia 3 c.d. Warstwa transportu, protokoły UDP, ICMP

Zadanie1: Odszukaj w serwisie internetowym Wikipedii informacje na temat protokołu http.

Tworzenie aplikacji rozproszonej w Sun RPC

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Instalacja Czytnika Kart w systemie Windows 7, Windows XP, Windows Vista, Windows 2000.

Mechanizmy pracy równoległej. Jarosław Kuchta

Komunikatory typu TCP/IP lab2. Dr inż. Zofia Kruczkiewicz Programowanie aplikacji internetowych

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

Sieci komputerowe. Wykład 7: Transport: protokół TCP. Marcin Bieńkowski. Instytut Informatyki Uniwersytet Wrocławski

Sieci komputerowe. Wykład 5: Warstwa transportowa: TCP i UDP. Marcin Bieńkowski. Instytut Informatyki Uniwersytet Wrocławski

Modele danych walidacja widoki zorientowane na model

Dokumentacja techniczna

Wątki i komunikacja między nimi w języku Python

Program do obsługi ubezpieczeń minifort

Dokumentacja końcowa projektu z ZPR

Programowanie rozproszone w języku Java

Konfiguracja serwera OPC/DDE KEPSServerEX oraz środowiska Wonderware InTouch jako klienta DDE do wymiany danych

Część I Dostęp do danych oraz moŝliwości programowe (silnik bazy danych)

Wykład 5: Klasy cz. 3

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Polityka prywatności dla strony ELCEN Sp. z o.o. z siedzibą w Gdyni

Kurs rozszerzony języka Python

Instrukcja uŝytkownika narzędzia Skaner SMTP TP. Uruchamianie aplikacji

Wybrane działy Informatyki Stosowanej

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

1.1 Definicja procesu

EXSO-CORE - specyfikacja

Aplikacje RMI

Internetowy moduł prezentacji WIZYT KLIENTA PUP do wykorzystania np. na stronie WWW. Wstęp

Dzisiejszy wykład. Wzorce projektowe. Visitor Client-Server Factory Singleton

Zmienne i stałe w PHP

Podręcznik Integracji

Tomasz Greszata - Koszalin

Plan wykładu. Domain Name System. Hierarchiczna budowa nazw. Definicja DNS. Obszary i ich obsługa Zapytania Właściwości.

Sieciowa instalacja Sekafi 3 SQL

TEMAT : KLASY DZIEDZICZENIE

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Wykład 8: klasy cz. 4

SEGMENT TCP CZ. II. Suma kontrolna (ang. Checksum) liczona dla danych jak i nagłówka, weryfikowana po stronie odbiorczej

Programowanie Komponentowe WebAPI

Laboratorium 7 Blog: dodawanie i edycja wpisów

Teoretyczne wprowadzenie do programu pocztowego Microsoft Outlook 2007

JĘZYK PYTHON - NARZĘDZIE DLA KAŻDEGO NAUKOWCA. Marcin Lewandowski [ mlew@ippt.gov.pl ]

System operacyjny MACH

Transport. część 2: protokół TCP. Sieci komputerowe. Wykład 6. Marcin Bieńkowski

TCP - receive buffer (queue), send buffer (queue)

Iteracyjny serwer TCP i aplikacja UDP

ZESZYTY ETI ZESPOŁU SZKÓŁ W TARNOBRZEGU Nr 1 Seria: Teleinformatyka 2013

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

Forum Client - Spring in Swing

Konfigurowanie konta pocztowego w programie Netscape (wersja 7.2)

Złośliwe oprogramowanie Sandrorat (podszywające się pod oprogramowanie Kaspersky) na platformę Android WYNIKI ANALIZY

Informatyka I. Standard JDBC Programowanie aplikacji bazodanowych w języku Java

Zaawansowany kurs języka Python

Baza danych sql. 1. Wprowadzenie

Część XVII C++ Funkcje. Funkcja bezargumentowa Najprostszym przypadkiem funkcji jest jej wersja bezargumentowa. Spójrzmy na przykład.

Transport. część 2: protokół TCP. Sieci komputerowe. Wykład 6. Marcin Bieńkowski

Akademia Techniczno-Humanistyczna w Bielsku-Białej

Laboratorium nr 10. Temat: Funkcje cz.2.

Twisted. Silnik Twojego Internetu. Jan Urbański Ducksboard. PyWaw #25, Warszawa, 10 czerwca 2013

BSX PRINTER INSTRUKCJA UŻYTKOWNIKA. Autor: Karol Wierzchołowski 30 marca 2015

FUNKCJE WZORCOWE. Wykład 10. Programowanie Obiektowe (język C++) Funkcje wzorcowe wprowadzenie (2) Funkcje wzorcowe wprowadzenie (1)

JAVA I SIECI. MATERIAŁY:

Widoczność zmiennych Czy wartości każdej zmiennej można zmieniać w dowolnym miejscu kodu? Czy można zadeklarować dwie zmienne o takich samych nazwach?

SERWER AKTUALIZACJI UpServ

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Programowanie obiektowe

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL III TI 4 godziny tygodniowo (4x30 tygodni =120 godzin ),

Python wstęp. Michał Bereta

PORADNIKI. Atak SMB Man-In-The-Middle

SERWER AKTUALIZACJI UpServ

Instalacja i konfiguracja Symfonia.Common.Server oraz Symfonia.Common.Forte

Transkrypt:

[ Programowe tunelowanie połączeń TCP. ] Autor: Krystian Kloskowski (h07) <h07@interia.pl> -http://milw0rm.com/author/668 -http://www.h07.int.pl 0x00 [INTRO] Art ten jak zwykle kierowany jest do osób, które mają dość chałtury prezentowanej przez niektóre "hack" serwisy i chcą nauczyć się czegoś nowego, ciekawego, czegoś co poszerza horyzony i rozwija wyobraźnie. "Tunelowanie połączenia" jest procesem przesyłania danych między klientem a serwerem poprzez inny serwer lub grupę serwerów. Jedną z korzyści takiego połączenia jest zmiana adresu IP, dzięki czemu przykładowo moŝemy wejść na IRC pod "fałszywym" adresem IP. Inne korzyści, płynące z takiego rozwiązania przydają sie przede wszystkim audytorom oprogramowania ;) ale to juŝ inna bajka. Niniejszy artykuł opisuje, jak skonstruować serwer tunelujący połączenie TCP w języku Python. 0x01 [TEORIA] Obrazowo tunelowanie połączenia wygląda następująco: [klient](192.168.0.1) ----> [tunel](192.168.0.2) ----> [serwer](192.168.0.3) [klient](192.168.0.1) <---- [tunel](192.168.0.2) <---- [serwer](192.168.0.3) Z powyŝszego przykladu łatwo moŝna wywnioskować dwie zaleŝnosci. Z punktu widzenia klienta adres IP serwera docelowego jest adresem serwera tunelującego. Z punktu widzenia serwera docelowego adres IP klienta jest adresem serwera tunelującego. Reasumując "tunel" jest wirtualnym serwerem docelowym dla klienta oraz wirtualnym klientem dla serwera docelowego. MoŜna wyobrazić sobie, Ŝe serwer tunelujący składa się z dwóch "wtyczek". Jedna wtyczka zapewnia obsługe połączenia z klientem a druga z serwerem docelowym. Wtyczki te nawzajem przekazują sobie dane, co daje efekt "tunelu". 0x02 [ARCHITEKTURA] Projektowanie architektury jest najwaŝniejszą częścią całego etapu tworzenia serwera. To właśnie w tym momencie programista musi wyobrazić sobie w jaki sposób to wszystko ma działać i jak to "zlepić" w jedną, spójną, bezawaryjną całość. Czynność ta nazywana jest tworzeniem algorytmu elektronicznego. Na szczęscie Wy nie musicie się tym trudzić a jedynie zrozumieć moją myśl konstrukcyjną. Serwer przede wszystkim musi opierać się na architekturze wielowątkowej. Oznacza to, Ŝe kaŝde połącznie będzie obsługiwane przez osobny wątek co zapewni niezaleŝną obsługe kilku połączeń jednocześnie. Wtyczki o których wspomniałem w rzeczywistości będą reprezentowane przez obiekty opisane klasą. Ów obiekty będą automatycznie tworzone w momencie odebrania nowego połączenia przez serwer. Ponadto kaŝdy z tych obiektów będzie uruchamiany z poziomu nowego wątku co zapewni niezaleŝny przepływ danych między obiema wtyczkami. Jednak by przekazywanie danych było moŝliwe wtyczki uruchomione w osobnych wątkach muszą "wiedzieć" o swoim istnieniu.

Teoretycznie serwer mógłby posługiwać się globalną listą zawierającą wskaźniki obu wtyczek. W ten sposób wtyczki "widziałyby" się nawzajem pobierając dane z globalnej listy dostępnej dla wszystkich wątków. Jednak lista ta z natury byłaby jednowymiarowa co nie pozwoliłoby na obsługe kilku połączeń jednoczesnie. Zastosowanie listy wielowymiarowej znacznie skomplikowałoby działanie serwera, zatem całą konstrukcję oparłem o "wtyczki równoległe". Wszystko to brzmi dość niezrozumiale ale w rzeczywistośći jest banalnie proste w działaniu. Idea wtyczek równoległych polega na wyzwalaniu jednej wtyczki z drugiej. Dzięki takiemu mechanizmowi wtyczka wyzwalająca moze przekazać wtyczce wyzwalanej informacje o sobie w postaci listy. W ten sposób obie wtyczki pracują niezaleŝnie w osobnych wątkach ale "widzą" się wzajemie dzięki temu, Ŝe operują na identycznych listach wtyczek. Obrazowy przykład działania: [Nowy wątek] Wtyczka A A.lista[A, B] client ----> dane = sock.recv() lista[1].sock.send(dane) ----> server --->+ [Nowy wątek] Wtyczka B B.lista[A, B] dane = sock.recv() <----------------------+ +----<--- lista[0].sock.send(dane) Opis działania: 1) Klient wysyła zapytanie. 2) Wtyczka A odbiera dane od klienta za pomocą funkcji recv() po czym wywołuje funkcje send() wtyczki B przekazując odebrane dane jako argument. 3) Serwer otrzymuje dane i zwraca odpowiedź. 4). Wtyczka B odbiera dane od serwera i odsyła je do klienta wywołując funkcje send() wtyczki A. 5) Klient otrzymuje odpowiedź. Listy zawsze indeksowane są od zera. Jeśli lista zawiera wtyczki A i B to wtyczka A dostępna jest pod indekstem 0 a wtyczka B pod indeksem 1. 0x03 [PROGRAMOWANIE] Nadszedł czas przełoŝyć wyŝej obmyślony algorytm elektroniczny na kod w języku Python. Głównym elementem serwera będzie wyŝej juŝ opisana "wtyczka" i to właśnie nią zajmniemy się w pierwszej kolejności. Z punktu widzenia języka Python, wtyczka jest obiektem wskazującym na jakąś klase. Dla przypomnienia.. Klasa jest strukturą danych zawierającą zarówno zmienne jak i funkcje do których moŝna się odwołać za pośrednictwem operatora dostępu. Przykład: #!/usr/bin/python class new_kwadrat: def init (self): self.bok = 0 def Pole(self): self.bok * self.bok kwadrat = new_kwadrat() kwadrat.bok = 2 print kwadrat.pole() W definicjach klas uŝywa sie słowa kluczowego "self" oznaczającego, Ŝe

obiekt odwołuje się do samego siebie. Czas na wtyczkę.. Zmienne obiektu wtyczki: class new_plug_in: def init (self): self.sock = 0 self.send_to = 1 self.plugins = [] self.description = '' sock - gniazdo na którym wtyczka będzie operować. send_to - numer wtyczki równoległej w liscie plugins[]. plugins[] - lista zawierająca wskaźniki do wtyczek równoległych. description - opis. Funkcje obiektu wtyczki: def Run(self): if(len(self.plugins) == 0): self.plugins.append(self) s.connect((out_addr, out_port)) self.sock.close() tunnel_out = new_plug_in() tunnel_out.sock = s tunnel_out.send_to = 0 self.plugins.append(tunnel_out) self.description = '[CLIENT]' tunnel_out.description = '[SERVER]' tunnel_out.plugins = self.plugins tunnel_out.run() start_new_thread(self.recv, ()) Funkcja Run() jest najwaŝniejszą funkcją wtyczki. Pełni ona rolę inicjacji wtyczki wyzwalającej jak i wtyczki wyzwalanej. W pierwszej kolejności funkcja ustala, czy naleŝy do wtyczki wyzwalającej czy wyzwalanej przez sprawdzenie długości listy plugins[]. Jeśli długość tej listy równa jest zeru znaczy to, Ŝe lista wtyczek równoległych jest pusta i funkcja musi zainicjować wtyczkę równoległą. Funkcja dodaje wskaźnik "własnej" wtyczki do "własnej" listy plugins[] po czym próbuje nawiązac połączenie z serwerem docelowym. W przypadku niepowodzenia zamyka ona gniazda strumieniowe i kończy wątek. Jeśli połączenie zostało nawiązane, funkcja tworzy wtyczkę równoległą tunnel_out. Następnie wtyczka tunnel_out otrzymuje deskryptor gniazda strumieniowego (sock = s) oraz numer wtyczki równoległej w liscie plugins[] (send_to = 0). W dalszej kolejności następuje dodanie do "własnej" listy plugins[] wskaźnika do wtyczki równoległej tunnel_out. Wtyczka wyzwalająca dodaje "sobie" opis, Ŝe obsługuje stronę klienta a wtyczka wyzwalana strone serwera docelowego po czym następuje przekazanie listy plugins[] wtyczcie wyzwalanej przez wtyczke wyzwalającą. W ten sposób dwie wtyczki operują na tej samej liście plugins[]. Na koniec uruchamiania jest wtyczka wyzwalana tunnel_out funkcją Run(). Wtyczka wyzwolona posiada juŝ listę plugins[] zatem obie te wtyczki w tym samym czasie zaczną oczekiwać na dane startując z nowego wątku "własą" funkcje Recv(). Wiem, Ŝe moŝe wydawać się to niezrozumiałe ale kaŝdy, kto zna podstawy programowania w jakimś języku na pewno zrozumie w jaki sposób działa ten mechanizm ;) Dalej jest juŝ z górki.. def Recv(self): data = self.sock.recv(len_recv) if(len(data) == 0): print self.description

print HexDump(data) self.plugins[self.send_to].send(data) Funkcja Recv() jest odpowiedzialna za odbieranie danych i przekazywanie ich do wtyczki równoległej a właściwie za wywołanie funkcji Send() wtyczki równoległej przekazując jej dane jako argument. W przypadku wystąpienia błędu, wywoływana jest funkcja CloseTunnel(). def Send(self, data): self.sock.send(data) Funkcja Send() wysyła dane do hosta, z którym połączone jest gniazdo. W przypadku wystąpienia błędu, wywoływana jest funkcja CloseTunnel(). def CloseTunnel(self): self.plugins[self.send_to].sock.shutdown(1) self.plugins[self.send_to].sock.close() Funkcja CloseTunnel() zamyka gniazdo wtyczki równoległej. Funkcje serwerowe: def AcceptConnect(cl, addr): print "Connection accepted from: %s" % (addr[0]) tunnel_in = new_plug_in() tunnel_in.sock = cl tunnel_in.run() Funkcja AcceptConnect() przyjmuje nowe połączenie, tworząc nową wtyczkę wyzwalającą tunnel_in. def InitServer(bind_addr, bind_port): s.bind((bind_addr, bind_port)) print "Listening on %s:%d..." % (bind_addr, bind_port) s.listen(1) cl, addr = s.accept() start_new_thread(acceptconnect, (cl, addr,)) Funkcja InitServer() inicjuje nasłuchiwanie serwera na określonym porcie. Gdy połączenie zostanie odebranie, z poziomu nowego wątku uruchamiana jest funkcja AcceptConnect, której przekazywany jest deskryptor gniazda nowego połączenia oraz adres klienta. def HexDump(data): a = -1 out = '-' * 59 + '\n' out += '0x00000000: ' for i in range(0, len(data)): a += 1 if(a == 16): out += '\n0x%08x: ' % (i) a = 0 out += '%02x ' % (ord(data[i])) out += '\n' + ('-' * 59) out Funkcja HexDump() odpowiada za wyświetlanie danych przesyłanych przez wtyczki w systemie 16-stkowym. Zmienne globalne: LEN_RECV - określa w bajtach maksymalny rozmiar pojedynczego strumienia danych. in_addr - określa adres IP, na którym "tunel" będzie oczekiwał na połączenie. in_port - określa port TCP, na którym "tunel" będzie oczekiwał na połączenie. out_addr - określa adres IP serwera docelowego. out_port - określa port TCP serwera docelowego.

Kompletny kod źródłowy: #!/usr/bin/python # TCP tunnel 1.0 coded by h07 (C) 2007 ## from thread import start_new_thread from socket import * LEN_RECV = 262144 in_addr = '0.0.0.0' in_port = 80 out_addr = '64.233.183.147' out_port = 80 class new_plug_in: def init (self): self.sock = 0 self.send_to = 1 self.plugins = [] self.description = '' def CloseTunnel(self): self.plugins[self.send_to].sock.shutdown(1) self.plugins[self.send_to].sock.close() def Send(self, data): self.sock.send(data) def Recv(self): data = self.sock.recv(len_recv) if(len(data) == 0): print self.description print HexDump(data) self.plugins[self.send_to].send(data) def Run(self): if(len(self.plugins) == 0): self.plugins.append(self) s.connect((out_addr, out_port)) self.sock.close() tunnel_out = new_plug_in() tunnel_out.sock = s tunnel_out.send_to = 0 self.plugins.append(tunnel_out) self.description = '[CLIENT]' tunnel_out.description = '[SERVER]' tunnel_out.plugins = self.plugins tunnel_out.run() start_new_thread(self.recv, ()) def HexDump(data): a = -1 out = '-' * 59 + '\n' out += '0x00000000: ' for i in range(0, len(data)):

a += 1 if(a == 16): out += '\n0x%08x: ' % (i) a = 0 out += '%02x ' % (ord(data[i])) out += '\n' + ('-' * 59) out def AcceptConnect(cl, addr): print "Connection accepted from: %s" % (addr[0]) tunnel_in = new_plug_in() tunnel_in.sock = cl tunnel_in.run() def InitServer(bind_addr, bind_port): s.bind((bind_addr, bind_port)) print "Listening on %s:%d..." % (bind_addr, bind_port) s.listen(1) cl, addr = s.accept() start_new_thread(acceptconnect, (cl, addr,)) InitServer(in_addr, in_port) 0x04 [TEST] Nadszedł czas przetestować powyŝszy "twór", tunelując połączenie z lokalnej maszyny do serwera google.pl. W tym celu wprowadzamy adres serwera google (64.233.183.147) do zmiennej out_addr. Porty (in_port, out_port) ustawiamy na 80 (80/HTTP).. in_addr = '0.0.0.0' in_port = 80 out_addr = '64.233.183.147' out_port = 80 Uruchamiamy skrypt, w konsoli orzymujemy następujący komunikat.. Listening on 0.0.0.0:80... Teraz uruchamiamy przeglądarke internetową i w polu adres wpisujemy http://localhost/. W konsoli funkcja HexDump() wyświetla "płynące" dane a w przeglądarce pojawia się strona google.pl. Connection accepted from: 127.0.0.1 [CLIENT] ----------------------------------------------------------- 0x00000000: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 0x00000010: 48 6f 73 74 3a 20 6c 6f 63 61 6c 68 6f 73 74 0d 0x00000020: 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 4d 6f 7a 0x00000030: 69 6c 6c 61 2f 35 2e 30 20 28 57 69 6e 64 6f 77 0x00000040: 73 3b 20 55 3b 20 57 69 6e 64 6f 77 73 20 4e 54 0x00000050: 20 35 2e 31 3b 20 70 6c 3b 20 72 76 3a 31 2e 38 0x00000060: 2e 31 2e 33 29 20 47 65 63 6b 6f 2f 32 30 30 37 0x00000070: 30 33 30 39 20 46 69 72 65 66 6f 78 2f 32 2e 30 0x00000080: 2e 30 2e 33 0d 0a 41 63 63 65 70 74 3a 20 74 65 0x00000090: 78 74 2f 78 6d 6c 2c 61 70 70... [SERVER] ----------------------------------------------------------- 0x00000000: 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d 0x00000010: 0a 43 61 63 68 65 2d 43 6f 6e 74 72 6f 6c 3a 20 0x00000020: 70 72 69 76 61 74 65 0d 0a 43 6f 6e 74 65 6e 74 0x00000030: 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0x00000040: 3b 20 63 68 61 72 73 65 74 3d 55 54 46 2d 38 0d 0x00000050: 0a 53 65 74 2d 43 6f 6f 6b 69 65 3a 20 50 52 45 0x00000060: 46 3d 49 44 3d 33 63 63 31 64 31 32 33 62 34 32 0x00000070: 37 61 36 64 31 3a 54 4d 3d 31 31 37 38 39 37 37 0x00000080: 35 31 36 3a 4c 4d 3d 31 31 37 38 39 37 37 35 31 0x00000090: 36 3a 53 3d 6a 37 70 30 75 5f...

Dzięki opisom, którymi dysponują wtyczki widzimy, ktore dane pochodzą od klienta a które od serwera. Za pomocą programu Process Explorer moŝemy zaobserwować, jak "tunel" zarządza nowymi wątkami oraz połączeniami TCP. Mechanizm ten jest bardzo wydajny o czym świadczy niskie zuŝycie mocy obliczeniowej procesora oraz ilości pamięci. Tunel moŝemy bez problemu uruchomić równieŝ w systemach UNIX'owych bez potrzeby modyfikacji czegokolwiek w kodzie źródłowym. 0x05 [OUTRO] Art ten powstał od tak sobie, chciałem coś skrobnąć i skrobnąłem ;] Taka forma odpoczynku od audytu systemow operacyjnych i innego softu. CięŜka to robota i niewdzięczna więc trzema słowami kończe, "Być nie mieć". EoF;