-
Возможно в API сокетов "параллельное чтение сокета" - называется по другому, если что поправьте. Никак не могу разобраться, в том числе и понять что именно нужно применять. Для начала постановка задачи: есть сервер и приложение, сервер удаленный, а приложение находится на локальной машине. Исходников нет, но известно что приложение и клиент обмениваются пакетами. Необходимо параллельно получать в свою программу то, что шлет сервер - клиенту в чистом виде. Известно что сервер устанавливает с клиентом соединение типа STREAM и шлет непрерывно пакеты фиксированного размера? или почти непрерывно. Вот, в общем то полноценный кусок кода, которым я пытаюсь запараллелить соединение:
...
uses ScktComp, winsock;
type RRecvData = record
Socket: TSocket;
buf: array [0..254] of Char;
buf_size: Integer;
recv_len: Integer;
th_id: Cardinal;
th_handle: Integer;
th_stop: Boolean;
hook: Boolean;
end;
PRecvData = ^RRecvData;
var
hParalell: TSocket;
paralell_recv: RRecvData;
WSA: WSAData;
procedure recv_data(wParam: Pointer);
var
Addr_in: sockaddr_in;
Addr_size: Integer;
begin
if wParam = nil then
EndThread(0);
FillChar(Addr_in,SizeOf(sockaddr_in),0);
Addr_in.sin_family:= AF_INET;
Addr_in.sin_addr.s_addr := inet_addr(PChar('0.0.0.0'));
Addr_in.sin_port := HToNS(0);
Addr_size:=SizeOf(Addr_in);
repeat
PRecvData(wParam)^.recv_len:=recvfrom(PRecvData(wParam)^.Socket, PRecvData(wParam)^.buf, PRecvData(wParam)^.buf_size, 0, Addr_in, Addr_size)
until (PRecvData(wParam)^.th_stop) OR (PRecvData(wParam)^.recv_len <> SizeOf(PRecvData(wParam)^.buf));
EndThread(1);
end;
procedure make_paralell;
var
Addr_in: sockaddr_in;
Addr_size: Integer;
bOptAddr: Bool;
begin
WSAStartup($202, WSA);
hParalell:=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if hParalell= SOCKET_ERROR then begin
Exit;
end;
bOptAddr:=True;
if setsockopt(hParalell, SOL_SOCKET, SO_REUSEADDR, @bOptAddr, SizeOf(Bool)) <> 0 then begin
Exit;
end;
FillChar(Addr_in,SizeOf(sockaddr_in),0);
Addr_in.sin_family:= AF_INET;
Addr_in.sin_addr.s_addr := inet_addr(PChar('127.0.0.1'));
Addr_in.sin_port := HToNS(25471);
Addr_size:=SizeOf(Addr_in);
if bind(hParalell, Addr_in, Addr_size) = SOCKET_ERROR then begin
closesocket(hSocket);
Exit;
end;
paralell_recv.Socket:=hParalell;
paralell_recv.buf_size:=SizeOf(paralell_recv.buf);
paralell_recv.th_stop:=False;
paralell_recv.hook:=True;
sock_recv.th_handle:=BeginThread(nil, 0, @recv_data, PRecvData(@paralell_recv), 0, paralell_recv.th_id);
end;
-
Цель какая ? Ну получил ты, предположим, то что хотел. Что дальше с этим добром делать намерен ?
-
Анализировать. Требуется собственный анализ данных, т.к. исходного кода приложения-клиента нет, а доп. аналитика требуется.
-
> bwwebm (19.04.10 14:25) [2]
Для оффлайн-анализа вовсе не обязательно изобретать новый велосипед - вполне достаточно готовых программ-снифферов, протоколирующих сетевую активность приложений.
-
Ознакомившись с информацией на MSDN: - msdn.microsoft.com/en-us/library/ms738545(v=VS.85).aspx и еще - msdn.microsoft.com/en-us/library/ms740548%28VS.85%29.aspx
почитав electro-2006.narod.ru/text/stati/snifer.html и попробовав, разве что я не устанавливал WinPCap, а данный пример без него не работоспособен.
проглядев форумы, примеры порт - сканеров, клиент серверных многопоточных приложений, которые по сути уже реализованы в ClientSocket и ServerSocket компонентах Delphi, я не смог найти более менее вразумительного ответа.
Возможно нужно еще немного уточнить мой вопрос: имеем соединение на локальной машине на свободном порту, необходимо запустить приложение, которое смогло бы данные на указанном порту получать параллельно.
-
И я чуть ли не забыл главного, очень хочется разобраться в данном вопросе, а не использовать многофункциональное приложение как переходник, между получением данных и их обработкой, так и не разобравшись в работе сокетов.
-
Я решал эту проблему так:
var Data:TWSAData; Sock:TSocket; Adrr:TSockAddr; ret:integer; arg:u_long; RB:integer; buf: array [0..64000] of Byte; I: Integer; str,strIP:string; AdrIP:AnsiString; flag:Boolean; begin WSAStartup($0202,Data); //Инициализ. библиатеку 2.2 Sock:=socket(AF_INET, SOCK_RAW, IPPROTO_IP);//Самый низкий уровень IP AdrIP:=AnsiString('IP адресс какой будим читать'); FillChar(Adrr, sizeof(Adrr), 0); Adrr.sin_family:=AF_INET; Adrr.sin_addr.S_addr:=inet_addr(PAnsiChar(AdrIP)); ret:=Bind(Sock,Adrr,sizeof(Adrr)); arg:=1; IOCTLsocket(Sock,SIO_RECVALL, arg); //переводим сокет в режим чтения // обсалютно всей информации поступающий на сетивую карту //Надо создать константу тсандартной ее нет //const //SIO_RECVALL=$98000001; // Теперь в бесконечном цикли читаем то-что приходит на наш адресс while True do begin //проверяем есть ли что-нибудь в буфере IOCTLSocket(Sock,FIONREAD,arg); if arg>0 then begin //Читаем пришеждший пакет ReedByte:=Recv(Sock,buf,sizeof(buf),0); IPT:=@buf;
// Synchronize(Form1.GetPacket); тут можно вставить обработчик пакета sleep(10) ; end; if CmdF=1 then begin CmdF:=0; exit; end; end; end; // Я рекомидую это запихивать в отдельный поток, чтобы главная форма не //зависала. При необходимости могу придоставить полный исходник
-
> Я решал эту проблему так: ...
Нет спасибо, этого примера достаточно, я пока поэкспериментирую, естественно вопросы задам.
-
При вызове bind() ф-ия возвращает -1, а WSAGetLastError = WSAEACCES (10013).
Я для теста запустил отдельно програмулину в которой на СокСервере и СокКлиенте реализовал постоянную отправку от сервера к клиенту данных.
Соответственно в Delphi запускаю слушатель, но bind() не проходит, не на 127.0.0.1 не на адрес машины в сети.
Сразу возник еще вопрос, в данном примере не указывается порт, я так понимаю что для уровня протокола IP порта еще не существует, будут ли сложности с реализацией фильтра для трафика на известном порту?
-
Порты существуют на более высоком уровне, например TCP UDP. На уровне IP мы получаем IP пакет в который входит заголовок IP и поле данных IP. В поле данных IP пакета размещается заголовок внутреннего протокола, например TCP или UDP, а также его поле данных. И только уже в поле данных этого пакета возможно находяться интересующие данные. А вполне возможно там находиться еще один протокол. Контролировать пакет с заданным портом просто. В заголовке IP пакета присутсвует поля отвечающие за тип внутреннего протокола. Для TCP это 6 для UDP это 17 и для ICMP это 1. Далее после анализа нажного протокола залезаем во внутреней протокл и смотрим его заголовок. В заголовках TCP и UDP присутсвует такое поле как порт, его и контралируем, тока нужно помнить что порт там находиться в защифрованном виде. Прежде чем заниматьсярасшифровкой я рекоминдую ознакомиться с протоколом IP, TCP и UDP самые основные протоколы. Там особо слоджных моментов на это дело уйдет не много времяни. Теперь что касается Bind. Тут несколько варинтов 1 Может быть например у вас Windows 7 2 Ошибка в создании сокета или заполнения структуры TSockAdr На всякий случай можно заменить строчку с указанием адреса на такую //Adrr.sin_addr.S_addr:=inet_addr('192.168.0.3'); //'192.168.0.3' это адрес той машины на которой запущен снифер. //Естественно в вашем случаи он будет другим
-
Возникновение ошибки WSAEACCES было вызвано тем, что запуск был без прав Администратора.
Кстати код очень помог, особенно понять что нужно для реализации, т.е. спасибо.
Теперь есть еще одна проблема. Она в общем то выходит за рамки данного топика, но все равно: перехват пакетов работает замечательно, до определенного момента, при включении программы, пакеты которой необходимо перехватить, ее система защиты... в общем я предполагаю что она перехватывает recv() wsock32.dll и вставляет свой обработчик, который пропускает данные передаваемые на порты используемые программой. Кстати, у меня установлен KIS, и своим пакет-сканером он обнаруживает активность TCP трафика на порте используемом программой. Я делаю вывод, что проще реализовать дубликат данной ф-ии самостоятельно... но как это сделать пока не нашел.
|