[Rozw.] icmp echo reply problem

Problemy dotyczące programowania.

Moderatorzy: Moderatorzy, Administratorzy

urfel
Użytkownik
Posty: 5
Rejestracja: 2007-07-28, 21:01

[Rozw.] icmp echo reply problem

Post autor: urfel »

Napisałem programik który na surowym gnieździe przechwytuje pakiet ICMP przerabia go odpowiednio i odsyła, ale niestety host pingujący nie widzi odpowiedzi. Schemat działania wygląda mniej więcej tak:
1) Przechwycenie pakietu, sprawdzenie czy jest to echo request.
2) Zamiana miejscami adresów docelowych i źródłowych.
3) Skopiowanie id i seq.
4) Obliczenie sum kontrolnych dla IP i ICMP.
4) Skopiowanie danych po nagłówku ICMP.
5) Złożenie w całość i odesłanie.

Tworzenie nagłówka ICMP:

Kod: Zaznacz cały

struct icmphdr *CreateIcmpHeader(struct icmphdr *icmphdr_input, int data)
{
	struct icmphdr *icmp_header;
	
	/* Parsowanie otrzymanego pakietu ICMP. Najpierw rozbieram stary
	pakiet i wyluskuje z niego numer id oraz numer sekwencyjny a 
	pozniej laduje te wartosci do wysylanego pakietu ICMP Echo Reply*/
	
	icmp_header = (struct icmphdr *)malloc(sizeof(struct icmphdr));

	icmp_header->type = 0;
	icmp_header->code = 0;
	icmp_header->un.echo.id = icmphdr_input->un.echo.id;
	icmp_header->un.echo.sequence = icmphdr_input->un.echo.sequence;
	memset(icmp_header+4, 0, 4);
	icmp_header->checksum = ComputeChecksum((unsigned char *)icmp_header, sizeof(struct icmphdr));
	

	return (icmp_header);
}
Widzę np. w iptraf, że wyszedł ode mnie pakiet echo reply do hosta pingującego, ale na tym hoście już nie widać odpowiedzi. Natomias widać ją jeśli nie dołączę do pakietu danych, aczkolwiek wtedy mam mismatch czyli niedopasowanie odpowiedzi:

Kod: Zaznacz cały

Reply from 192.168.0.xx: bytes=32 - MISCOMPARE at offset 0 - time<1ms TTL=84
Próbowałem liczyć sumę kontrolną z danymi bez danych, ustawiać sztucznie pola danych i nic jak narazie nie skutkuje. Proszę o pomoc, może ktoś ma jakiś pomysł.

[ Komentarz dodany przez: Zielony: 2007-09-16, 18:52 ]
Tag o rozwiązanym problemie wygląda tak: "[Rozw.]"!
Ostatnio zmieniony 2007-09-16, 17:51 przez urfel, łącznie zmieniany 2 razy.

acek
Użytkownik
Posty: 47
Rejestracja: 2006-09-26, 21:27
Kontakt:

Re: icmp echo reply problem

Post autor: acek »

urfel pisze:

Kod: Zaznacz cały

icmp_header = (struct icmphdr *)malloc(sizeof(struct icmphdr));
memset(icmp_header+4, 0, 4);
To nie wygląda dobrze. Czy nie chciałeś napisać

Kod: Zaznacz cały

icmp_header = (struct icmphdr *)malloc(sizeof(struct icmphdr));
memset((char *)icmp_header+4, 0, 4);
?
Ostatnio zmieniony 2007-09-04, 14:22 przez acek, łącznie zmieniany 1 raz.

darkstar2111
Użytkownik
Posty: 51
Rejestracja: 2007-09-02, 11:22

Re: [Rozw.] icmp echo reply problem

Post autor: darkstar2111 »

Tak jak napisał przedmówca, adres dla memset jest zły. Kłania się arytmetyka wskaźników, przesuwasz nie o 4 bajty, tylko o 4 długości tej struktury.

urfel
Użytkownik
Posty: 5
Rejestracja: 2007-07-28, 21:01

Re: [Rozw.] icmp echo reply problem

Post autor: urfel »

Idąc za waszą radą rzutowałem na (char *), ale wtedy zerował mi już nie tylko dane ale także identyfikator i numer sekwencyjny. Bez rzutowania zachowuje mi oba pola i zeruje dane. Też mi się wydawało że powinienem rzutować, ale w praktyce wygląda to inaczej.

Wracając do problemu, zauważyłem że po dołączeniu danych źle liczy mi sumę kontrolną nagłówka ICMP.

Funkcja licząca sumę:

Kod: Zaznacz cały

unsigned short ComputeChecksum(unsigned char *data, int len)
{
	long sum = 0;  /* assume 32 bit long, 16 bit short */
	unsigned short *temp = (unsigned short *)data;

	while(len > 1){
		sum += *temp++;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		len -= 2;
	}

	if(len)       /* take care of left over byte */
		sum += (unsigned short) *((unsigned char *)temp);
          
	while(sum>>16)
		sum = (sum & 0xFFFF) + (sum >> 16);

	return ~sum;
}
I tworzenie nagłówka ICMP:

Kod: Zaznacz cały

struct icmphdr *CreateIcmpHeader(struct icmphdr *icmphdr_input, int data)
{
	struct icmphdr *icmp_header;
	
	icmp_header = (struct icmphdr *)malloc(sizeof(struct icmphdr));

	icmp_header->type = 0;
	icmp_header->code = 0;
	icmp_header->un.echo.id = icmphdr_input->un.echo.id;
	icmp_header->un.echo.sequence = icmphdr_input->un.echo.sequence;
	memset(icmp_header+4, 0, 4);
	icmp_header->checksum = ComputeChecksum((unsigned char *)icmp_header, sizeof(struct icmphdr) + data);
	

	return (icmp_header);
}
Jako data przekazuję długość pola danych. Jak nie dołączę danych do pakietu to dobrze liczy sumę kontrolną... WTF?

acek
Użytkownik
Posty: 47
Rejestracja: 2006-09-26, 21:27
Kontakt:

Re: [Rozw.] icmp echo reply problem

Post autor: acek »

urfel pisze:

Kod: Zaznacz cały

[...]
icmp_header = (struct icmphdr *)malloc(sizeof(struct icmphdr));
[...]
memset(icmp_header+4, 0, 4);
[...]
ComputeChecksum((unsigned char *)icmp_header, sizeof(struct icmphdr) + data);
[...]
Teraz wiem, dlaczego w BASICu nie ma wskaźników. ;)

darkstar2111
Użytkownik
Posty: 51
Rejestracja: 2007-09-02, 11:22

Re: [Rozw.] icmp echo reply problem

Post autor: darkstar2111 »

Rozumiem, że rzutujesz tylko w memset ? Jeżeli nie, to tak właśnie zrób, bo to rzutowanie służy tylko i wyłącznie ustawieniu prawidłowego offsetu. Nie znam się na pakietach icmp, sprawdź czy masz wszędzie dobrą kolejność bajtów itp.

urfel
Użytkownik
Posty: 5
Rejestracja: 2007-07-28, 21:01

Re: [Rozw.] icmp echo reply problem

Post autor: urfel »

Znalazłem rozwiązanie problemu, jak zwykle proste a jak długo mi to zajęło :].
4) Obliczenie sum kontrolnych dla IP i ICMP.
5) Skopiowanie danych po nagłówku ICMP.
Dobrze liczyłem sumę kontrolną nagłówka ICMP

Kod: Zaznacz cały

ComputeChecksum((unsigned char *)icmp_header, sizeof(struct icmphdr) + data); 
Tylko że w miejscu w którym liczyłem jeszcze nie było żadnych danych...
Teraz tworzę pomocniczy pseudonagłówek + dane i z niego liczę sumę kontrolną:

Kod: Zaznacz cały

struct icmphdr *CreateIcmpHeader(struct icmphdr *icmphdr_input, int data, unsigned char * dane)
{
	struct icmphdr *icmp_header;
	unsigned char * icmp_temporary;
	
	icmp_header = (struct icmphdr *)malloc(sizeof(struct icmphdr));
	icmp_temporary = (unsigned char *)malloc(sizeof(struct icmphdr) + data);
	
	icmp_header->type = 0;
	icmp_header->code = 0;
	icmp_header->un.echo.id = icmphdr_input->un.echo.id;
	icmp_header->un.echo.sequence = icmphdr_input->un.echo.sequence;
		
	memset((unsigned char *)icmp_header+2, 0, 2);
	
	memcpy(icmp_temporary, icmp_header, sizeof(struct icmphdr));
	memcpy(icmp_temporary + sizeof(struct icmphdr), dane, data);
	icmp_header->checksum = ComputeChecksum(icmp_temporary, sizeof(struct icmphdr)+data);
	
	return (icmp_header);
}
Dziękuję serdecznie za wszystkie rady :).
Ostatnio zmieniony 2007-09-11, 21:15 przez urfel, łącznie zmieniany 1 raz.

ODPOWIEDZ