Rzutowanie w C i operacje na bitach - program sieciowy

0

Witam
Analizuję program sieciowy wysyłający pakiety ICMP. Mam jednak problem ze zrozumieniem kilki fragmentów kodu:
Deklarujemy strukturę icmphdr:

struct icmphdr
{
    u_int8_t type;      /* message type */
    u_int8_t code;      /* type sub-code */
    u_int16_t checksum;
    union
    {
        struct
        {
            u_int16_t   id;
            u_int16_t   sequence;
        } echo;         /* echo datagram */
        u_int32_t   gateway;    /* gateway address */
        struct
        {
            u_int16_t   __unused;
            u_int16_t   mtu;
        } frag;         /* path mtu discovery */
    } un;
};

następnie definiujemy funkcję sprawdzającą sumę kontrolną nagłówka ICMP:

unsigned short in_cksum(unsigned short *ptr, int nbytes)
{
    register long sum;
    u_short oddbyte;
    register u_short answer;
 
    sum = 0;
    while (nbytes > 1) {
        sum += *ptr++;
        nbytes -= 2;
    }
 
    if (nbytes == 1) {
        oddbyte = 0;
        *((u_char *) & oddbyte) = *(u_char *) ptr;
        sum += oddbyte;
    }
 
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
 
    return (answer);
}

W treści funkcji main spotkałem instrukcję:

icmph->checksum = in_cksum((unsigned short *)icmph, packet_size);

Mam pytanie odnośnie rzutowania struktury icmph do typu (unsigned short *). Jak to rzutowanie się odbywa i co się tutaj tak naprawdę dzieje. Struktura icmph tak naprawdę składa się z kilku pól o rozmiarze 8 bitów, 16 bitów a nawet 32 bitów. Które pola tej struktury są wypełniane przez to rzutowanie. I drugie pytanie odnośnie tego fragmentu z funkcji in_cksum:

sum = 0;
    while (nbytes > 1) {
        sum += *ptr++;
        nbytes -= 2;

załóżmy, że packet size ma 512 bitów. W jaki sposób w tej pętli będzie odczytywana wartość ptr, które przecież zawiera liczbę typu unsigned short 16 bitów?

0

Dajesz informację kompilatorowi, że wiesz co robisz, przekazując inny wskaźnik niż masz w deklaracji...Dodatkowo - masz niepopakowane struktury, więc mogą byc problemy....

1

Po pierwsze zapewne struktura icmphdr zapewne jest otoczona jakimiś makrami zmieniającymi ustawienia kompilatora, żeby nie nastąpiło wyrównywanie pół do słowa albo dwusłowa (standardowe optymalizacje kodu, które w tym wypadku wykrzywiają dane do wysyłania).

Po drugie in_cksum to funkcja obliczająca sumę kontrolną jakiegoś dowolnego fragmentu pamięci. Autor zdecydował się na wskaźnik do short co według mnie jest dziwne, bo większość kompilatorów sizeof(short) == 2 a tymczasem drugim argumentem jest coś o nazwie nbytes.
Z tego co widzę takie jest też założenie w kodzie.
Moim zdaniem lepiej było użyć void* i cast do short* zrobić wewnątrz funkcji, wtedy nie trzeba robić cast jak się funkcji używa.

Tymczasem jak się tej funkcji używa to cast jest konieczny, bo kompilator widzi problem przy cast wskaźnika na strukturę do short *. Mówisz po prostu kompilatorowi: wiem co robię to to na pewno jest bezpieczne, oblicz mi sumę kontrolną.

Radziłby poczytać RFC 792 oraz RFC 1071, będzie łatwiej zrozumieć co ten kod ma robić.

1 użytkowników online, w tym zalogowanych: 0, gości: 1