Protokół komunikacyjny (Python)

https://chacker.pl/

Do implementacji protokołu użyjemy Construct,6 modułu Pythona do pisania parserów binarnych. Zamiast używać serii wywołań pack/unpack, Construct umożliwia nam pisanie kodu w stylu deklaratywnym, co generalnie prowadzi do bardziej zwięzłej implementacji. Inne moduły, które zaimportujemy, to fixedint,7, aby zastąpić typ całkowity „bignum” Pythona, oraz crc32c,8, aby użyć tej samej implementacji CRC32-C, co jądro.

WSKAZÓWKA : Zanim przejdziesz dalej, zaleca się zapoznanie się z dokumentacją Construct, aby się z nią zapoznać.

Zacznijmy od zdefiniowania nagłówka wiadomości:

Ten kod wygląda podobnie do swojego odpowiednika w C, ale w tym przypadku oddzieliliśmy pole hdr_csum od reszty nagłówka, który jest zawinięty w RawCopy (1), aby uzyskać do niego dostęp jako do binarnego blobu za pomocą c.this.hdr.data. W ten sposób możemy obliczyć jego CRC32-C(2). Innym ważnym rozróżnieniem jest wprowadzenie syntetycznego pola o nazwie _csum_offset (3), które służy do przechowywania bieżącej pozycji strumienia. Później użyjemy tego pola, aby uzyskać dostęp do pola sumy kontrolnej (4) podczas obliczania CRC32-C treści wiadomości. Postępując zgodnie z tą samą kolejnością, co implementacja w C, zdefiniujemy wartości TP i prymitywy (liczby całkowite):

IntPrefixes (1) to grupa wartości TP odpowiadająca typom prymitywnym, a IntConstructs (2) to powiązana z nią grupa konstrukcji. Zamiast używać dużych liczb całkowitych Pythona, chcemy pracować z wartościami o stałym rozmiarze. W tym celu utworzyliśmy listę adapterów zwanych IntAdapters (3). Na koniec mapujemy wartości TP na ich odpowiednie adaptery w IntAlist (4). Typy złożone wymagają więcej pracy, głównie ze względu na implementację adapterów w celu ich konwersji na standardowe kolekcje:

Zaczynamy od CompAlist (1), listy asocjacyjnej wartości TP reprezentujących typy złożone i ich odpowiednie konstrukcje. Pierwszym elementem tej listy jest typ tablicy (2), w którym definiujemy konstrukcję dla nagłówka Array_t, po którym następuje pole „v” do przechowywania elementów tablicy. Konstrukcja jest opakowana przez ArrayAdapter (3), który konwertuje wynikowy obiekt na krotkę Pythona. Następnym elementem jest typ ciągu (4), który jest bezpośrednio powiązany z konstrukcją CString. Na koniec mamy typ listy (5). W tym przypadku wiążemy konstrukcję z symbolem List (6), abyśmy mogli odwoływać się do niego rekurencyjnie. Możemy zobaczyć, że konstrukcja odwołuje się również do symbolu o nazwie Body (7), którego jeszcze nie zdefiniowaliśmy. Aby umożliwić pracę z deklaracjami forward, używamy LazyBound. Konstrukcja jest opakowana przez ListAdapter (8), aby przekonwertować wynikowy obiekt na listę Pythona. Body analizuje prefiks TP i szuka powiązanej z nim konstrukcji zarówno w IntAlist, jak i CompAlist. Ta konstrukcja może analizować (lub budować) dowolną wartość TP, więc odwołujemy się do niej podczas analizowania elementów listy, ale także podczas analizowania treści wiadomości. Owijamy ją za pomocą BodyAdapter (9), aby usunąć teraz zbędny prefiks TP podczas konwersji obiektu na kolekcję Pythona. Aby ukończyć implementację, potrzebujemy konstrukcji dla całych wiadomości:

Message (1) łączy konstrukcje MsgHdr i Body, i oblicza CRC32-C tej ostatniej, która jest stosowana do pola sumy kontrolnej w nagłówku. Osiąga się to poprzez przekazanie wartości z _csum_offset do Pointer. (2) Ostateczny interfejs jest udostępniany przez funkcje recv (3) i send (4). Biorąc pod uwagę obiekt czytelnika, recv deserializuje wiadomość, zwracając krotkę z typem wiadomości i jej treścią. W przypadku send przyjmuje obiekt pisarza i treść żądania (jako standardową kolekcję Pythona), serializuje wiadomość i zapisuje ją do obiektu.

Gość (1) to menedżer kontekstu, w którym zarządzanym przez nas zasobem jest instancja maszyny wirtualnej. Obecnie używamy QEMU/KVM, ale moglibyśmy utworzyć podklasę, aby współpracować z innymi celami. Generator wiadomości (2) odbiera i analizuje przychodzące wiadomości wysyłane przez jądro. Napiszmy prosty skrypt testowy, aby uruchomić maszynę wirtualną i wydrukować otrzymane wiadomości:

Skrypt generuje następujące dane wyjściowe:

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *