Форум: "Сети";
Текущий архив: 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.49 MB
Время: 0.007 c