На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
    > RAW sockets , как работать?
      Хочу научиться работать с RAW сокетами, а именно - хотелось бы написать сниффер пакетов (ну, для начала, хотя бы примитивный)...
      Так вот. Задача: я хочу получать на сокет ВСЕ IP пакеты. Как мне для этого создавать сокет? Как делать bind()?
      Получать UDP пакеты с порта 27015 я научился...

      ExpandedWrap disabled
        //create socket
        SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
        if(s==INVALID_SOCKET) return -1;
            
        //bind
        sockaddr_in local_addr;
        local_addr.sin_family = AF_INET;
        local_addr.sin_port = htons(27015);
        local_addr.sin_addr.S_un.S_addr = INADDR_ANY;
        if(bind(s, (const struct sockaddr *)&local_addr, sizeof(local_addr)) == SOCKET_ERROR) return -2;
         
        //recv
        sockaddr addr_from;
        int from_len = sizeof(addr_from);
        res = recvfrom(s, buf, buf_size-1, 0, &addr_from, &from_len); //buf - буфер, buf_size -  его длина
        if(res>0)
        {
            Log("NT: INFO: recvfrom() success");
            buf[res] = 0;
            Log(buf); // в общем - вывод на экран
        }
        else
        {
            //ошибка....
        }


      Я пробовал создавать сокет:
      ExpandedWrap disabled
        SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);

      Сокет создаётся. Без bind() recvfrom() вылетает с ошибкой WSAEINVAL, что говорит о том, что
      Цитата MSDN
      The socket has not been bound with bind...

      А к какому адресу биндиться-то RAW-сокету с IPPROTO_IP? Использовать ли sockaddr_in или просто sockaddr?..
      Код:
      ExpandedWrap disabled
        //bind
        sockaddr local_addr;
        local_addr.sa_family = AF_INET;
        memset(local_addr.sa_data, 0, 14);
      - после такого bind() завершается упешно, но recvfrom() зависает на очень длительное время, будто IP пакеты на комп вообще не приходят (а такое у меня невозможно ;) )...

      Как быть? как "схватить" все IP пакеты, которые машина получает?
        MinLexx
        Поиск по форуму дает это
          Цитата Oleg2004 @
          Поиск по форуму дает это

          Там всё на тему "как отправить", "как послать" итп... ПОиск я уже смотрел... не особо мне он помог....
          Мне бы как ПОЛУЧИТЬ пакет... причём не UDP, как в той ссылке, а любой IP-пакет....
            MinLexx
            SIO_RCVALL
            Cмотрите это
            и вот это
            Сообщение отредактировано: Oleg2004 -
              Посмотри это

              Цитата

              Ниже приведён полный код программы. Данный код не претендует на звание крутого снифера, однако при желании его можно доработать, чтобы можно было просматривать содержимое пакетов. Так же на его основе можно легко сделать простой анализатор трафика. А главное - не надо делать всяких драйверов; всё просто и понятно.

              Суть этого сниффера заключается в том, что используются соке

              Сокеты второй версии и созданный сокет переводится в режим promiscuous (прослушивания).


              ExpandedWrap disabled
                #include <conio.h>
                #include <stdio.h>
                #include <winsock2.h>
                 
                #define MAX_PACKET_SIZE    0x10000
                #define SIO_RCVALL         0x98000001
                // Буфер для приёма данных
                char Buffer[MAX_PACKET_SIZE]; // 64 Kb
                 
                //Структура заголовка IP-пакета
                 
                typedef struct IPHeader {
                  UCHAR   iph_verlen;   // версия и длина заголовка
                  UCHAR   iph_tos;      // тип сервиса
                  USHORT  iph_length;   // длина всего пакета
                  USHORT  iph_id;       // Идентификация
                  USHORT  iph_offset;   // флаги и смещения
                  UCHAR   iph_ttl;      // время жизни пакета
                  UCHAR   iph_protocol; // протокол
                  USHORT  iph_xsum;     // контрольная сумма
                  ULONG   iph_src;      // IP-адрес отправителя
                  ULONG   iph_dest;     // IP-адрес назначения
                } IPHeader;
                 
                char src[10];
                char dest[10];
                char ds[15];
                unsigned short lowbyte;
                unsigned short hibyte;
                 
                void main()
                {
                  WSADATA     wsadata;   // Инициализация WinSock.
                  SOCKET      s;         // Cлущающий сокет.
                  char        name[128]; // Имя хоста (компьютера).
                  HOSTENT*    phe;       // Информация о хосте.
                  SOCKADDR_IN sa;        // Адрес хоста
                  IN_ADDR sa1;        //
                  unsigned long        flag = 1;  // Флаг PROMISC Вкл/выкл.
                 
                  // инициализация
                  WSAStartup(MAKEWORD(2,2), &wsadata);
                  s = socket( AF_INET, SOCK_RAW, IPPROTO_IP );
                  gethostname(name, sizeof(name));
                  phe = gethostbyname( name );
                  ZeroMemory( &sa, sizeof(sa) );
                  sa.sin_family = AF_INET;
                  sa.sin_addr.s_addr = ((struct in_addr *)phe->h_addr_list[0])->s_addr;
                  bind(s, (SOCKADDR *)&sa, sizeof(SOCKADDR));
                  
                  // Включение promiscuous mode.
                  ioctlsocket(s, SIO_RCVALL, &flag);
                 
                  // Бесконечный цикл приёма IP-пакетов.
                  while( !_kbhit() )
                  {
                    int count;
                    count = recv( s, Buffer, sizeof(Buffer), 0 );
                    // обработка IP-пакета
                    if( count >= sizeof(IPHeader) )
                    {
                      IPHeader* hdr = (IPHeader *)Buffer;
                      //Начинаем разбор пакета...
                 
                strcpy(src,"Пакет: ");
                CharToOem(src,dest);
                printf(dest);
                // Преобразуем в понятный вид адрес отправителя.
                printf("From ");
                sa1.s_addr = hdr->iph_src;
                printf(inet_ntoa(sa1));
                 
                // Преобразуем в понятный вид адрес получателя.
                printf(" To ");
                sa1.s_addr = hdr->iph_dest;
                printf(inet_ntoa(sa1));
                 
                // Вычисляем протокол. Полный список этих констант
                // содержится в файле winsock2.h
                printf(" Prot: ");
                if(hdr->iph_protocol == IPPROTO_TCP) printf("TCP ");
                if(hdr->iph_protocol == IPPROTO_UDP) printf("UDP ");
                 
                // Вычисляем размер. Так как в сети принят прямой порядок
                // байтов, а не обратный, то прийдётся поменять байты местами.
                printf("Size: ");
                lowbyte = hdr->iph_length>>8;
                hibyte = hdr->iph_length<<8;
                hibyte = hibyte + lowbyte;
                printf("%s",itoa(hibyte,"",10));
                 
                // Вычисляем время жизни пакета.
                printf(" TTL:%s",itoa(hdr->iph_ttl,"",10));
                printf("\n");
                 
                    }
                  }
                 
                  closesocket( s );
                  WSACleanup();
                }
                MinLexx
                вот САМЫЙ простой пример сниффера на сокетах
                ExpandedWrap disabled
                  #include <iostream>
                  #include <winsock2.h>
                  #include <ws2tcpip.h>
                  #include <conio.h>
                  #define SIO_RCVALL 0x98000001
                  #pragma comment(lib,"ws2_32.lib")
                  void main(void){
                      WSADATA wsa;
                  WSAStartup(MAKEWORD(2,2),&wsa);
                  SOCKET s = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
                      sockaddr_in adr;
                      memset(&adr,0,sizeof(sockaddr_in));
                      adr.sin_addr.s_addr = INADDR_ANY;
                      adr.sin_family = AF_INET;
                      bind(s,(sockaddr*)&adr,sizeof(sockaddr_in));
                      DWORD d =1;
                      ioctlsocket(s,SIO_RCVALL,&d);
                      char buff[2000]={0};
                      while (recv(s,buff,2000,0)!=SOCKET_ERROR){
                          in_addr ip1 , ip2;
                          ip1.S_un.S_addr = *((int*)(buff+12));
                          ip2.S_un.S_addr = *((int*)(buff+16));
                          std::cout << "user " << inet_ntoa(ip1);
                          std::cout <<" shlot chtoto user-u " <<inet_ntoa(ip2) <<"\n";
                      }
                   
                      std::cout <<"Error N:" << WSAGetLastError();
                  _getch();
                  }


                Добавлено
                во , убрал еще 1 строчку)))
                ну что , кто короче?? :lol:
                Сообщение отредактировано: LuckLess -
                  Видимо быстрый у Вас инет) Шустро тыкаете по кнопочке "Поиск". :D
                  ФФсем спасип... буду копать.....
                    Цитата MinLexx @
                    Видимо быстрый у Вас инет) Шустро тыкаете по кнопочке "Поиск".

                    Э. Не нада. Я сам писал..

                    я уже спортом решил заняться.. в еще меньшее число строк это написал )))
                    ExpandedWrap disabled
                      #include <iostream>
                      #include <winsock2.h>
                      #include <ws2tcpip.h>
                      #define SIO_RCVALL 0x98000001
                      #pragma comment(lib,"ws2_32.lib")
                      void main(void){
                          WSADATA wsa;
                      WSAStartup(MAKEWORD(2,2),&wsa);
                      SOCKET s = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
                      sockaddr_in adr = {AF_INET , INADDR_ANY , 0 , 0};
                          bind(s,(sockaddr*)&adr,sizeof(sockaddr_in));
                          DWORD d =1;
                          ioctlsocket(s,SIO_RCVALL,&d);
                          char buff[2000]={0};
                          while (recv(s,buff,2000,0)!=SOCKET_ERROR){
                              in_addr ip1 , ip2;
                              ip1.S_un.S_addr = *((int*)(buff+12));
                              ip2.S_un.S_addr = *((int*)(buff+16));
                              std::cout << "user " << inet_ntoa(ip1);
                              std::cout <<" shlot chtoto user-u " <<inet_ntoa(ip2) <<"\n";
                          }
                          std::cout <<"Error N:" << WSAGetLastError();
                      }
                      Цитата MSDN
                      Return Values
                      Upon successful completion, the ioctlsocket returns zero. Otherwise, a value of SOCKET_ERROR is returned.

                      Так вот, вызов
                      ExpandedWrap disabled
                        //SIO_RCVALL
                        DWORD d = 1;
                        if(ioctlsocket(s, SIO_RCVALL, &d) == SOCKET_ERROR)
                        {
                            Log("NT: ERROR: ioctlsocket(... SIO_RCVALL ...) set failed.");
                        }

                      выводит на экран это сообщение. Хотя последующий вызов recvfrom() успешен...

                      Твой код, конечно, короткий, но он не проверяет ни одно возвращаемое значение...
                      Сообщение отредактировано: MinLexx -
                        MinLexx
                        Специфика SIO_RCVALL в том , что он срабатывает , но ioctlsocket возвращает ошибку.
                          Интересно где это про такие вот мелочи жизни литературу почитать можно? И почему константа SIO_RCVALL не определена стандартно? Почему в MSDN ничего нет толкового на эту тему? :wacko: :wall:
                            cozy
                            Цитата
                            Посмотри это

                            В данном коде содержится нехилая ошибка:
                            ExpandedWrap disabled
                              printf("%s",itoa(hibyte,"",10));
                                                      ^^ - как такое можно было написать ?
                              Извиняюсь, код не мой.
                              Copy'n'paste. :)

                              В принципе, код свою работу делает,
                              а исправить эту ошибку надеюсь труда не составит?
                                cozy
                                Цитата
                                Извиняюсь, код не мой.

                                Знаю.
                                Цитата
                                В принципе, код свою работу делает,

                                У меня TTL не печатал, так я эту ошибку и обнаружил :wall:
                                  Не хочу плодить темы.....
                                  Короче понял я, толковый сниффер на Винапи/Винсок не напишешь, тут нужен WinPcap.
                                  Ну, покопал я WinPcap, посмотрел примерчики - прикольно, этот WinPcap ловит пакеты на уровне Ethernet!!! :)
                                  Я даже смог разобрать заголовки Ethernet, IP, UDP, ... :)

                                  Короче, новая задача есть. В некоторой сети между сегментами не проходят UDP-пакеты (фильтруются на роутере). А надо сделать так, чтобы UDP-пакеты могли перемещаться от компа к компу за пределы сегментов. Однако, протокол TCP разрешён...

                                  Вариант решения таков: создать TCP туннель для связи нескольких компьютеров... На одном из компов запущен сервер, соединяющий клиентов. На компах, которые хотят связаться через UDP, запущены клиенты - клиенты соединяются с сервером по TCP. Клиент представляет из себя сниффер UDP-пакетов... Когда комп отправляет UDP пакет, клиент его прослушивает, записывает и запихивает в TCP-пакет, отсылает серверу. Далее, сервер, получая от клиента пакет, персылает его всем остальным клиентам. Клиенты, получившие такие пакеты, должны отправить их в свою подсеть.... Так, как будто они пришли из другой подсети (можно туннелировать ВЕСЬ IP-пакет, не проблема ;) ), не изменяя адреса отправителя/получателя, вообще не изменяя пакет...

                                  Внимание ВОПРОС

                                  Можно ли отправить пакет в сеть так, чтобы он вернулся из сети на свою же машину, будто посланный из сети?

                                  Допустим, комп из одной подсети шлёт UDP-пакет 10.70.24.60:6111 -> 255.255.255.255:6111
                                  Сниффер-клиент на нём запущенный, перехватывает этот пакет, шлёт по TCP серверу, сервер пересылает пакет компьютеру в другой сети, напиример, 10.70.18.4. Клиент на 2м компе, 10.70.18.4, Получает от сервера этот пакет в TCP-пакете. Далее, задача: послать этот UDP-пакет, взятый из TCP-пакета, самому себе, так, как будто он пришёл из сети извне. ТАКОЕ ВОЗМОЖНО????
                                  Т.е. в данном примере, комп 10.70.18.4 должен получить броадкаст-UDP пакет от 10.70.24.60:6111...

                                  :wall: :whistle:

                                  Как это сделать? :unsure:
                                  Сообщение отредактировано: MinLexx -
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,0485 ]   [ 16 queries used ]   [ Generated: 11.12.24, 12:58 GMT ]