Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2002.08.12;
Скачать: [xml.tar.bz2];

Вниз

ICMP Ping   Найти похожие ветки 

 
Donal_Graeme   (2002-05-28 13:43) [0]

написал тут пинг на основе Raw Socket и ICMP протокола. и получил интересный результат.
я пингую сам себя (127.0.0.1) много раз подряд, при этом часть запросов попадает куда надо, т.е. на меня же, и пинг получается 0, как и должно быть, но часть запросов уходит неизвестно куда (в локальную сеть), и возвращается оттуда спустя некоторое время (секунды 2-3) с совершенно другим ICMP заголовком. Скомпилил сишный проект (с которого писал дельфовый), у них всё нормально работает.
Кто-нибудь знает, в чём может быть проблема?


 
Wonder   (2002-05-28 14:09) [1]

Если пакеты уходят в сеть, значит IP-адрес получателя не локальный.
Какое ICMP-сообщение приходит в ответ? Или хотя бы тип сообщения (тот, который ICMPHeader->type) какой?


 
Donal_Graeme   (2002-05-28 14:56) [2]

в том то и дело, что ставлю 127.0.0.1 :-)
а тип ответа оказался 3.


 
Wonder   (2002-05-28 15:13) [3]

Ну ясное дело :)
ICMP_DEST_UNREACH 3

А ты вообще уверен, что пакет уходит в сеть? Может ошибка в другом?

Смотри поле code в пришедшем ICMP-сообщении
Code:
0 = net unreachable;
1 = host unreachable;
2 = protocol unreachable;
3 = port unreachable;
4 = fragmentation needed and DF set;
5 = source route failed.

Выводи перед посылкой пакета фактический адрес из структуры sockaddr_in ( inet_ntoa(dest.sin_addr) ) и смотри куда на самом деле шлется.



 
Donal_Graeme   (2002-05-28 15:19) [4]

спасибо, попробую


 
Donal_Graeme   (2002-05-28 15:24) [5]

вау... говорит, порт недостижим.


 
Wonder   (2002-05-28 15:40) [6]

Вот это вот вообще нонсенс. По логике, в ответ на echo не может приходить port unreachable. Порты используются в TCP, а тут используется только IP...


 
Donal_Graeme   (2002-05-28 16:36) [7]

вот и мне так казалось.
пакеты идут на 127.0.0.1, по-крайней мере dest.sin_addr именно так и говорит, а вот те пакеты, которые уходят в локалку, обычно возвращаются с компа, отведённого под SQL-сервер.


 
Wonder   (2002-05-28 17:04) [8]

Тогда код давай. Можешь на мыло.


 
Donal_Graeme   (2002-05-29 09:48) [9]

да никакого секрета нет :-)


unit scsocket;

interface

uses Windows, Classes, WinSock2, SCNet;

const

ICMP_ECHOREPLY = 0;
ICMP_ECHO = 8;

MAX_PACKET = 1024;

// коды ошибок для Ping

SCPE_STARTUP = $FFFFFFFF;
SCPE_INVHOST = $FFFFFFFE;
SCPE_SETTIMEOUT = $FFFFFFFD;
SCPE_SENDTO = $FFFFFFFC;
SCPE_RECVTO = $FFFFFFFB;
SCPE_RECVPARAMS = $FFFFFFFA;
SCPE_INVPACKET = $FFFFFFF9;
SCPE_INVSOCKET = $FFFFFFF8;

type
TSCIPHeader = packed record
h_len: Byte;
version: Byte;
tos: Byte;
total_len: Word;
ident: Word;
frag_and_flags: Word;
ttl: Byte;
proto: Byte;
checksum: Word;
sourceIP: DWord;
destIP: DWord;
end;

TSCICMPHeader = packed record
i_type: Byte;
i_code: Byte;
i_cksum: Word;
i_id: Word;
i_seq: Word;
timestamp: DWord;
end;

function SCICMPPing (var Host: AnsiString; SeqNo, DataSize, TimeOut: Word): DWord;

implementation

function SCICMPPing (var Host: AnsiString; SeqNo, DataSize, TimeOut: Word): DWord;
var
S: THandle; // сокет
WSD: TWSAData;
IH, IHR: TSCICMPHeader;
IPR: TSCIPHeader;
Dest, From: TSockAddrIn;
SendBuf, RecvBuf: Array [0..MAX_PACKET -1] of Byte;
CI: TSC_CompInfo; //это мой тип, там айпишники хоста записываются
TS, TR: Int64;
CS, I: Word;
FL, TOut, Sent, Recvd : LongInt;
begin
Result := SCPE_STARTUP;
S := INVALID_SOCKET;
FillMemory (@RecvBuf[0], MAX_PACKET, 0);
FillMemory (@SendBuf[0], MAX_PACKET, 0);

If Failed (WSAStartUp (MakeWord (2, 2), WSD)) then Exit;

try
S := WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, nil, 0, WSA_FLAG_OVERLAPPED);
If S = INVALID_SOCKET then
begin
Result := SCPE_INVSOCKET;
Exit;
end;
//--- настраиваем таймаут отправки и приёма
Result := SCPE_SETTIMEOUT;
TOut := TimeOut;
If Failed (SetSockOpt (S, SOL_SOCKET, SO_RCVTIMEO, @TOut,
SizeOf (TOut))) then Exit;
TOut := TimeOut;
If Failed (SetSockOpt (S, SOL_SOCKET, SO_SNDTIMEO, @TOut,
SizeOf (TOut))) then Exit;
//--- заполняем адрес проверяемого хоста
If inet_addr (PChar (Host)) = INADDR_NONE then
begin
//--- получаем адрес по имени хоста
CI := SC_GetCompInfo (Host); //моя функция, возвращает айпи хоста по его имени, вызывается, только если хост - доменное имя
Host := CI.IPs[0].IPStr; //в этой переменной содержится адрес в dotted-notation
If inet_addr (PChar (Host)) = INADDR_NONE then
begin
Result := SCPE_INVHOST;
Exit;
end;
end;
FillMemory (@Dest, SizeOf (Dest), 0);
Dest.sin_family := AF_INET;
Dest.sin_addr.S_addr := inet_addr (PChar (Host));
//--- заполняем заголовок ICMP
IH.i_type := ICMP_ECHO;
IH.i_code := 0;
IH.i_id := GetCurrentProcessId;
IH.i_cksum := 0;
IH.i_seq := SeqNo;
IH.timestamp := GetTickCount;
//--- заполняем буфер отправки
CopyMemory (@SendBuf[0], @IH, SizeOf (IH));
FillMemory (@SendBuf[SizeOf (IH)], DataSize, Ord ("S"));
//--- считаем контрольную сумму
CS := 0;
For I := 0 to Length (SendBuf) div 2 -1 do
CS := CS +SendBuf[I *2] +256*SendBuf[I *2 +1];
If Length (SendBuf) mod 2 = 1 then CS := CS +SendBuf [Length (SendBuf) -1];
CS := (CS SHR 16) +(CS and $FFFF);
CS := not (CS + (CS SHR 16));
SendBuf [2] := Lo (CS);
SendBuf [3] := Hi (CS);
//--- отправляем пакет
Sent := SendTo (S, SendBuf[0], SizeOf (IH) +DataSize, 0, Dest, SizeOf (Dest));
If Failed (Sent) then
begin
Result := SCPE_SENDTO;
Exit;
end;
TS := GetTickCount;
//--- принимаем ответ
FL := SizeOf (From);
Recvd := RecvFrom (S, RecvBuf[0], MAX_PACKET, 0, From, FL);
TR := GetTickCount;
If Failed (Recvd) then
begin
If WSAGetLastError = WSAETIMEDOUT then Result := SCPE_RECVTO
else Result := SCPE_RECVPARAMS;
Exit;
end;
//--- читаем IP-заголовок
IPR.h_len := 4*(RecvBuf[0] and 15);
IPR.version := RecvBuf[0] shr 4;
CopyMemory (@IPR.tos, @RecvBuf[1], SizeOf (IPR) -1);
CopyMemory (@IHR, @RecvBuf[IPR.h_len], SizeOf (IHR));
Result := SCPE_INVPACKET;
//--- проверяем, наш ли это пакет
//If IPR.sourceIP <> Dest.sin_addr.S_addr then Exit;
//If IHR.i_id <> IH.i_id then Exit;
//If IHR.i_seq <> IH.i_seq then Exit;
//If IHR.timestamp <> IH.timestamp then Exit;
Result := DWord (TR) -DWord (TS);
finally
If S <> INVALID_SOCKET then CloseSocket (S);
WSACleanUp;
end;
end;

end.



 
Wonder   (2002-05-29 11:30) [10]

Вроде бы как и должно быть :)
Проверь, а точнее посмотри и сравни id посылаемого и принятого ICMP-сообщения.
Скорее всего пришедшее сообщение не ответ на посланное тобой.


 
Donal_Graeme   (2002-05-29 11:51) [11]

в принципе, так и есть, ни одно из полей ICMP заголовка принятого пакета не совпадает с отправленным :-) но тогда возникает другой вопрос, куда девался мой пакет? :-)


 
Wonder   (2002-05-29 12:31) [12]

А кто сказал, что пакет куда-то делся?
Последовательно меняй sequence number перед посылкой очередного сообщения (допустим прибавляй каждый раз единицу) и смотри этот же номер в ответе. Узнаешь, теряются ли сообщения или нет. И читай все, что приходит, в цикле до ошибки или до успешного чтения, а не одной строчкой. Т.е. если пришел пакет c другим sequence number или другим id - просто игнорируй или выдавай предупреждение и читай дальше.


 
Donal_Graeme   (2002-05-29 14:07) [13]

ждал полчаса... мой пакет не пришёл... а, кстати, не может быть такого, что запрос идёт нормально, а ответ отправляется не на 127.0.0.1, а мой адрес в локальной сети? при этом проходит через наши сервера в локалке?


 
Wonder   (2002-05-29 14:26) [14]

Ответ отправляется на адрес твоего сетевого интерфейса.
Блуждать по сети он не может.

Примерно должно быть так:


//Посылаем echo
while (true) {
//Читаем ответ - RecvFrom
if (ошибка чтения) {
if (отправленный_seq_no <> полученный_seq_no) {
//Ругаемся
continue;
}
else {
//Останавливаемся - ошибка чтения
break;
}
}
if (отправленный_id = полученный_id) {
//Это наше. Останавливаемся
break;
}
}
//Разбираем полученное и смотрим все поля.
//Размер возвращенных данных, seq_no, и т.п.
//Ежели чего не так - выводим сообщения о несоответствии.



 
Donal_Graeme   (2002-05-29 15:19) [15]

моего пакета не приходит. и вообще интересно, приходят пакеты с двух компов, при этом id и seqno у них всегда нулевые, а в ICMP-заголовке код об ошибке port unreachable.
и вот ещё что интересно, ведь сишный код работает отлично.


 
Donal_Graeme   (2002-05-30 09:25) [16]

спасибо за помощь, буду считать, что дело в неправильном переводе Winsock2 для Дельфей... хотя не знаю даже, что там можно не так перевести.



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2002.08.12;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.61 MB
Время: 0.037 c
1-35357
prorok2
2002-07-30 14:24
2002.08.12
Кодировка в Database Desktop


14-35431
Baz
2002-07-15 13:59
2002.08.12
Вопрос врачам или спортсменам


1-35300
VictorT
2002-07-29 15:25
2002.08.12
test


6-35401
ZED
2002-05-30 00:33
2002.08.12
TWebBrowser - как узнать содержимое формы


3-35136
Piton X
2002-07-19 16:45
2002.08.12
При подключении к базе Interbase 6 выскакивает окно подключения к





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский