Конференция "Сети" » WinSocket / Сокеты / RAW Socket - паралельное чтение [D5, D6, D7, WinXP]
 
  • bwwebm (19.04.10 14:04) [0]
    Возможно в 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);
    //замена SOCK_STREAM на SOCK_RAW - возмоно?
     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;

  • Сергей М. © (19.04.10 14:17) [1]
    Цель какая ?
    Ну получил ты, предположим, то что хотел.
    Что дальше с этим добром делать намерен ?
  • bwwebm (19.04.10 14:25) [2]
    Анализировать. Требуется собственный анализ данных, т.к. исходного кода приложения-клиента нет, а доп. аналитика требуется.
  • Сергей М. © (19.04.10 14:28) [3]

    > bwwebm   (19.04.10 14:25) [2]


    Для оффлайн-анализа вовсе не обязательно изобретать новый велосипед - вполне достаточно готовых программ-снифферов, протоколирующих сетевую активность приложений.
  • bwwebm (19.04.10 14:51) [4]
    Ознакомившись с информацией на 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, я не смог найти более менее вразумительного ответа.

    Возможно нужно еще немного уточнить мой вопрос: имеем соединение на локальной машине на свободном порту, необходимо запустить приложение, которое смогло бы данные на указанном порту получать параллельно.
  • bwwebm (19.04.10 15:00) [5]
    И я чуть ли не забыл главного, очень хочется разобраться в данном вопросе, а не использовать многофункциональное приложение как переходник, между получением данных и их обработкой, так и не разобравшись в работе сокетов.
  • NoRTeN (19.04.10 16:01) [6]
    Я решал эту проблему так:

    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;
    // Я рекомидую это запихивать в отдельный поток, чтобы главная форма не
    //зависала. При необходимости могу придоставить полный исходник
  • bwwebm (19.04.10 16:05) [7]

    > Я решал эту проблему так:
    ...


    Нет спасибо, этого примера достаточно, я пока поэкспериментирую, естественно вопросы задам.
  • bwwebm (19.04.10 17:00) [8]
    При вызове bind() ф-ия возвращает -1, а WSAGetLastError = WSAEACCES (10013).

    Я для теста запустил отдельно програмулину в которой на СокСервере и СокКлиенте реализовал постоянную отправку от сервера к клиенту данных.

    Соответственно в Delphi запускаю слушатель, но bind() не проходит, не на 127.0.0.1 не на адрес машины в сети.

    Сразу возник еще вопрос, в данном примере не указывается порт, я так понимаю что для уровня протокола IP порта еще не существует, будут ли сложности с реализацией фильтра для трафика на известном порту?
  • NoRTeN (19.04.10 17:52) [9]
    Порты существуют на более высоком уровне, например 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' это адрес той машины на которой запущен снифер.
    //Естественно в вашем случаи он будет другим
  • bwwebm (22.04.10 13:44) [10]
    Возникновение ошибки WSAEACCES было вызвано тем, что запуск был без прав Администратора.

    Кстати код очень помог, особенно понять что нужно для реализации, т.е. спасибо.

    Теперь есть еще одна проблема. Она в общем то выходит за рамки данного топика, но все равно: перехват пакетов работает замечательно, до определенного момента, при включении программы, пакеты которой необходимо перехватить, ее система защиты... в общем я предполагаю что она перехватывает recv() wsock32.dll и вставляет свой обработчик, который пропускает данные передаваемые на порты используемые программой.
    Кстати, у меня установлен KIS, и своим пакет-сканером он обнаруживает активность TCP трафика на порте используемом программой.
    Я делаю вывод, что проще реализовать дубликат данной ф-ии самостоятельно... но как это сделать пока не нашел.
 
Конференция "Сети" » WinSocket / Сокеты / RAW Socket - паралельное чтение [D5, D6, D7, WinXP]
Есть новые Нет новых   [134437   +29][b:0][p:0.002]