Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Сырые сокеты в WinXP  (Прочитано 16717 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Avatar
Гость
« : 29-12-2003 12:23 » new

Добрый день, господа.
Необходимо из под WinXP программно формировать, отправлять и получать tcp-пакеты. Пробовал сделать по примеру как это делается в *nix - системах, но, понятно, ничего не вышло. Очень буду признателен, если кто-нибудь подкинет статейку или какой-нибудь сорец..... Очень нужно разобраться....
И ещё один вопросик: при попытке установить опции на сырой сокет с параметром IP_HDRINCL, борланд си 6-ой сказал, что он вообще не знает, что это такое, хотя в MSDN этот макрос описывается.... В хиадерах включена winsock2.h.... В чём может быть дело?
Записан
ysv_
Помогающий

ua
Offline Offline

« Ответ #1 : 29-12-2003 12:47 » 

А IP_HDRINCL нету в winsock2.h. Он лежит в Ws2tcpip.h.
Записан
ixania
Гость
« Ответ #2 : 30-12-2003 00:16 » 

Для этого тебе нужны  RAW сокеты, например для IP протокола тебе нужно открыть следующий сокет:

SOCKET sfd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);

Вот и структура IP заголовка:

/* The IP header */
typedef struct iphdr {
unsigned int h_len:4;          // length of the header
unsigned int version:4;        // Version of IP
unsigned char tos;             // Type of service
unsigned short total_len;      // total length of the packet
unsigned short ident;          // unique identifier
unsigned short frag_and_flags; // flags
unsigned char  ttl;  
unsigned char proto;           // protocol (TCP, UDP etc)
unsigned short checksum;       // IP checksum  
unsigned int sourceIP;
unsigned int destIP;  
}IpHeader;
Записан
ixania
Гость
« Ответ #3 : 30-12-2003 00:19 » 

#define IP_HDRINCL      2 /* header is included with data */
Записан
Avatar
Гость
« Ответ #4 : 31-12-2003 11:14 » 

Спасибо за помощь. Получился следующий код:

#include <vcl.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>


#pragma hdrstop
#pragma pack(1)

#define WIN32_LEAN_AND_MEAN

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
#define MAX_MESSAGE        4068
#define MAX_PACKET         4096

#define DEFAULT_MESSAGE    "This is a test"

struct tcpheader
{
 unsigned short int th_sport;
 unsigned short int th_dport;
 unsigned int th_seq;
 unsigned int th_ack;
 unsigned char th_x2:4, th_off:4;
 unsigned char th_flags;
 unsigned short int th_win;
 unsigned short int th_sum;
 unsigned short int th_urp;

 unsigned  char identity [4];
 unsigned  char data [200];
} ; /* total tcp header length: 20 bytes (=160 bits) */

struct ipheader {
 unsigned char ip_hl:4, ip_v:4; /* this means that each member is 4 bits */
 unsigned char ip_tos;
 unsigned short int ip_len;
 unsigned short int ip_id;
 unsigned short int ip_off;
 unsigned char ip_ttl;
 unsigned char ip_p;
 unsigned short int ip_sum;
 unsigned int ip_src;
 unsigned int ip_dst;
}; /* total ip header length: 20 bytes (=160 bits) */


typedef struct ps_hdr
{
    unsigned int   source_address;   // Source Address       =>     4 Bytes
    unsigned int   dest_address;     // Destination Address    =>     4 Bytes
    unsigned char  placeholder;        // Place Holder       =>     1 Bytes
    unsigned char  protocol;        // Protocol       =>     1 Bytes
    unsigned short tcp_length;        // TCP Length       =>    +  2 Bytes
                 //                   = 12 Bytes
    struct tcpheader tcp;

}PS_HDR;


char           strMessage[MAX_MESSAGE]; // Message to send
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

USHORT checksum(USHORT *buffer, int size)
{
    unsigned long cksum=0;

    while (size > 1)
    {
        cksum += *buffer++;
        size  -= sizeof(USHORT);    
    }
    if (size)
    {
        cksum += *(UCHAR*)buffer;    
    }
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);

    return (USHORT)(~cksum);
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    WSADATA            wsd;
    SOCKET             s;
    DWORD              i;
    char               *datagram="", ident[] = "ScMX";
    hostent            *h = NULL;
    int                bOpt = 1, y, len;
    char               RecvBuf[200];

    struct ipheader *iph = (struct ipheader *) malloc(sizeof(struct ipheader));
    struct tcpheader *tcph = (struct tcpheader *) malloc( sizeof (struct tcpheader));
    struct ps_hdr *ps = (struct ps_hdr *) malloc( sizeof (struct ps_hdr));
    datagram = (char *) malloc(sizeof(struct ipheader) + sizeof(struct tcpheader));
    struct sockaddr_in sin, dest;


    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
    {
        ShowMessage("WSAStartup() failed: " + IntToStr(GetLastError()));
        return;
    }

    s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_RAW, NULL, 0,0);
    if (s == INVALID_SOCKET)
    {
        ShowMessage("WSASocket failed: " + IntToStr(GetLastError()));
        return;
    }


    iph= (struct ipheader *) datagram;
    tcph=(struct tcpheader *) (datagram+ sizeof(struct ipheader));

    sin.sin_family = AF_INET;
    sin.sin_port = htons (110);
    h = gethostbyname("localhost");
    if(h == NULL)
     ShowMessage("╬°шсър gethostbyname");

    sin.sin_addr.s_addr = inet_addr (inet_ntoa(*((struct in_addr *)h->h_addr)));

    iph->ip_hl = 5;
    iph->ip_v = 4;
    iph->ip_tos = 0;
    iph->ip_len = sizeof (struct ipheader) + sizeof (struct tcpheader);

    iph->ip_id = 1;
    iph->ip_off = 0;
    iph->ip_ttl = 255;
    iph->ip_p = IPPROTO_TCP;
    iph->ip_sum = 0;
    iph->ip_src = inet_addr ("127.0.0.1");
    iph->ip_dst = sin.sin_addr.s_addr;

    tcph->th_sport = htons (1999);
    tcph->th_dport = htons (135);
    tcph->th_seq = 666;
    tcph->th_ack = htons (6234);
    tcph->th_x2 = 0;
    tcph->th_off = 5;
    tcph->th_flags = 16; // SYN
    tcph->th_win = htons(65535);
    tcph->th_sum = 0;
    tcph->th_urp = 0;

    strncpy((char *)tcph->identity,ident,4);

    for(i = 0; i < strlen(strMessage); i++)
     tcph->data=strMessage;

    ps->source_address   = inet_addr ("127.0.0.1");
    ps->dest_address  = sin.sin_addr.s_addr;
    ps->placeholder  = 0;
    ps->protocol  = IPPROTO_TCP;
    ps->tcp_length  = htons(sizeof(struct tcpheader));

    ps->tcp = *tcph;

    tcph->th_sum = checksum((unsigned short *)ps, sizeof(struct ps_hdr));
    iph->ip_sum  = checksum((unsigned short *)iph, sizeof(struct ipheader));

    setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&bOpt, sizeof(bOpt));

    if (sendto(s, datagram, iph->ip_len, 0, (SOCKADDR *)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
     ShowMessage("sendto() failed: " + IntToStr(WSAGetLastError()));
     return;
    }
   
    memset(datagram,0,strlen(datagram));

    i = 0;
    len = sizeof(sin);

    i = recvfrom(s, RecvBuf, 200, 0,(sockaddr*)&sin, &len);
    if(i > 0)
     RichEdit1->Lines->Add("╧юыєўхэ яръхЄ.");
    /*while(i < 1)
    {
     memset(RecvBuf, 0, sizeof(RecvBuf));
     i = recv(s, RecvBuf, 200, 0);
    }
    RichEdit1->Lines->Add("╧юыєўхэ яръхЄ.");  */

    closesocket(s) ;
    WSACleanup() ;
}
//---------------------------------------------------------------------------

Никак не могу понять почему в ответ не приходит вообще никакого пакета (recivefrom), когда, по идее, должен прийти пакет с флагом ask.
Очень буду признателе за помощь.
Цель: получить tcp - пакет от удалённой машины, дабы в дальнейшем из tcp-заголовка достать размер окна....
Записан
ixania
Гость
« Ответ #5 : 31-12-2003 13:36 » 

Попробуй послать на сокет открытый тобой, чтоб увидеть если ваще пакет приходит. И почему тебе просто не вызвать getsockopt с опцией

SO_MAX_MSG_SIZE
Maximum size of a message for message-oriented socket types (for example, SOCK_DGRAM). Has no meaning for stream oriented sockets.
Записан
Avatar
Гость
« Ответ #6 : 02-01-2004 10:52 » 

Попробую послать что либо на этот сокет. Пробовал повесить сервер на сыром сокете на 1999 порту, но он ничего не получает. Если не сложно поясните смысл использовать в данном случае getsockopt.
Может есть ещё какой-то варионт осуществить данную цель?
Записан
ixania
Гость
« Ответ #7 : 02-01-2004 14:45 » 

Вешай сервак на нормальном сокете, а от на стороне клиента играйся с сырыми, иначе самому над будет отсылать АЦК. Не понял что ты именно хош узнаить про
getsockopt.

Во нашел пример и выкладываю насколько понял он рабочий:

--------head.h-----------------------------------------------
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdio.h>


unsigned short checksum(unsigned short *addr, int len);
struct tcpheader {
unsigned short int th_sport;
unsigned short int th_dport;
unsigned int th_seq;
unsigned int th_ack;
unsigned char th_x2:4, th_off:4;
unsigned char th_flags;
unsigned short int th_win;
unsigned short int th_sum;
unsigned short int th_urp;
}; /* total tcp header length: 20 bytes (=160 bits) */

struct ipheader {
unsigned char ip_hl:4, ip_v:4; /* this means that each member is 4
bits */
unsigned char ip_tos;
unsigned short int ip_len;
unsigned short int ip_id;
unsigned short int ip_off;
unsigned char ip_ttl;
unsigned char ip_p;
unsigned short int ip_sum;
unsigned int ip_src;
unsigned int ip_dst;
}; /* total ip header length: 20 bytes (=160 bits) */

// Psuedo Header


struct body
{

unsigned char data [40];


};


struct ps_hdr
{
unsigned int source_address; // Source Address => 4 Bytes
unsigned int dest_address; // Destination Address => 4
Bytes
unsigned char placeholder; // Place Holder => 1 Bytes
unsigned char protocol; // Protocol => 1 Bytes
unsigned short tcp_length; // TCP Length => + 2 Bytes

struct tcpheader tcp;
struct body data;

};
-------------------EOF-----------------------------------------


---------------main.cpp-----------------------------------
#include "head.h"

#define PORT 25

int main (void)
{

WSADATA wsd;
char *datagram="";
int bOpt = 1;
char info[30] ="das ist ein test";

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("WSAStartup() failed: %d\n", GetLastError());
return -1;
}

// Create a raw socket

SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (s == INVALID_SOCKET)
{
printf("WSASocket() failed: %d\n", WSAGetLastError());
return -1;
}



struct ipheader *iph = (struct ipheader *) malloc(sizeof(struct
ipheader));
struct tcpheader *tcph = (struct tcpheader *) malloc( sizeof
(struct tcpheader));
struct body *bo = (struct body *) malloc( sizeof (struct body));
struct ps_hdr *ps = (struct ps_hdr *) malloc( sizeof (struct
ps_hdr));

datagram = (char *) malloc(sizeof(struct ipheader) + sizeof(struct
tcpheader)+sizeof (struct body));



struct sockaddr_in sin;



iph= (struct ipheader *) datagram;
tcph=(struct tcpheader *) (datagram+ sizeof(struct ipheader));
bo= (struct body *) (datagram+sizeof(struct ipheader)+ sizeof(struct
tcpheader));
memset(bo->data,'\0',strlen((char *)bo->data));


sin.sin_family = AF_INET;
sin.sin_port = htons (PORT);
sin.sin_addr.s_addr = inet_addr ("193.99.144.71");


printf("%i\n",sizeof(datagram));
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof (struct ipheader) + sizeof (struct
tcpheader)+sizeof(struct body);

iph->ip_id = 1;
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = 6;
iph->ip_sum = 0;
iph->ip_src = inet_addr ("192.168.0.113");
iph->ip_dst = sin.sin_addr.s_addr;

tcph->th_sport = htons (1234);
tcph->th_dport = htons (PORT);
tcph->th_seq = rand();
tcph->th_ack = htons (6234);
tcph->th_x2 = 0;
tcph->th_off = 5;
tcph->th_flags = 16; // SYN
tcph->th_win = htons(65535);
tcph->th_sum = 0;
tcph->th_urp = 0;





// Build the Psuedo Header

ps->source_address = inet_addr ("192.168.0.113");
ps->dest_address = sin.sin_addr.s_addr;
ps->placeholder = 0;
ps->protocol = IPPROTO_TCP;
ps->tcp_length = htons(sizeof(struct tcpheader)+sizeof(struct
body));

ps->tcp = *tcph;
ps->data=*bo;

strcpy((char *)bo->data,info);
// Calculate Checksum


tcph->th_sum = checksum((unsigned short *)ps, sizeof(struct
ps_hdr));
iph->ip_sum = checksum((unsigned short *)iph, sizeof(struct
ipheader));




// ENABLE IPHDRINCL

if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&bOpt,
sizeof(bOpt)) == SOCKET_ERROR)
{
printf("setsockopt(IP_HDRINCL) failed: %d\n", WSAGetLastError());
return -1;
}



// Send The Packet

if (sendto(s, datagram, iph->ip_len, 0, (SOCKADDR *)&sin,
sizeof(sin)) == SOCKET_ERROR)
{
printf("sendto() failed: %d\n", WSAGetLastError());
return -1;
}


return 0;
}
-------------------EOF--------------------------------




----------------------check.cpp----------------------------
#include "head.h"

unsigned short checksum(unsigned short *addr, int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;

/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we
add
* sequential 16 bit words to it, and at the end, fold back all
the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}

/* mop up an odd byte, if necessary */
if (nleft == 1)
{
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff);/* add hi 16 to low 16 */
sum += (sum >> 16);/* add carry */
answer = ~sum;/* truncate to 16 bits */
return (answer);
}
------------------------------EOF-------------------------------------
Записан
Avatar
Гость
« Ответ #8 : 05-01-2004 14:05 » 

Спасибо за помощь - кажется почти разобрался и уже почти работает Улыбаюсь, за малым исключением того, что вместо пакетов с конкретного ip я получаю все пакеты (приходиться фильтровать в программе). Сделал прослушку сокета при помощи WSAIoctl. При помощи каких параметров WSAIoctl можно заставить сокет принимать пакеты только с нужного ip?
Записан
ixania
Гость
« Ответ #9 : 05-01-2004 14:27 » 

Ты хочеш сказать что шлёшь на оперделенный IP а получаешь от нескольких, чтото не вяжется, покажи сырец, по идее если шлешь на определенный IP и определенный сокет, то должен отозватся только адрессуемый, или я чтото недопонимаю?
Записан
Avatar
Гость
« Ответ #10 : 05-01-2004 14:54 » 

Точно - ты что-то не допонимаешь Улыбаюсь). Я один сокет повесил на интерфейс, т.е. он работает как снифер (ловит все пакеты вообще независимо от того отправляю я что-то или нет). Если я отправляю пакет с син флагом, то среди всей кучи принятых пакетов (сетевая активность всегда хоть какая-то есть в сети) есть пакет с аск флагом от той машины, которой был послан с син флагом. Вопрос в том, как сделать так, чтобы сокет работал не просто в режиме снифера, а принимал только те пакеты, которые нужны без дополнительных алгоритмов фильтрации...
Записан
ixania
Гость
« Ответ #11 : 05-01-2004 15:27 » 

Дума придется всетаки написать фильтр   Вот такой я вот, либо открой другой нормальный сокет, вот тебе и фильтр.
Записан
Avatar
Гость
« Ответ #12 : 10-01-2004 08:51 » 

Печально, но видимо прийдётся делать фильтр: не хотел чтобы при большой сетевой активности программа сильно грузила ось....
Спасибо за помощь.
Записан
Chkalov
Гость
« Ответ #13 : 26-01-2004 09:50 » 

А как ты сокет повесил на интерфейс???
раскажи пожалуйста поподробней
Записан
Avatar
Гость
« Ответ #14 : 26-01-2004 10:29 » 

Сырой сокет и повесил (сервером).
Записан
Chkalov
Гость
« Ответ #15 : 27-01-2004 08:06 » 

Так ты  создал  сырой сокет повесил его сервером и он стал ловить все пакеты приходящие на машину?? или как?
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines