Невозможно распечатать ответ TCP с использованием Raw Sockets

0

Я использую сырые сокеты для отправки дейтаграмм, как указано в этом уроке (раздел III). Однако я не могу правильно отладить ответ (показывая символы нежелательной почты). Не уверен, что не так с программой. Кто-нибудь, способный идентифицировать ошибку?

#define P 80        /* TCP port 80 - HTTP */

unsigned short /* this function generates header checksums */
csum(unsigned short *buf, int nwords)
{
    //checksum code here, omitting for stackoverflow question
}

int main()
{
    int s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); /* open raw socket */
    char datagram[4096]; /* this buffer will contain ip header, tcp header,
     and payload. we'll point an ip header structure
     at its beginning, and a tcp header structure after
     that to write the header values into it */
    struct ip *iph = (struct ip *) datagram;
    struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof(struct ip);
    struct sockaddr_in sin;
    /* the sockaddr_in containing the dest. address is used
     in sendto() to determine the datagrams path */

    sin.sin_family = AF_INET;
    sin.sin_port = htons(P);/* you byte-order >1byte header values to network
     byte order (not needed on big endian machines) */
    sin.sin_addr.s_addr = inet_addr("74.125.224.72"); //google ip address

    memset(datagram, 0, 4096); /* zero out the buffer */

    /* we'll now fill in the ip/tcp header values, see above for explanations */
    iph->ip_hl = 5;
    iph->ip_v = 4;
    iph->ip_tos = 0;
    iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr); /* no payload */
    iph->ip_id = htonl(54321); /* the value doesn't matter here */
    iph->ip_off = 0;
    iph->ip_ttl = 255;
    iph->ip_p = 6;
    iph->ip_sum = 0; /* set it to 0 before computing the actual checksum later */
    iph->ip_src.s_addr = inet_addr("1.2.3.4");/* SYN can be blindly spoofed */
    iph->ip_dst.s_addr = sin.sin_addr.s_addr;
    tcph->th_sport = htons(1234); /* arbitrary port */
    tcph->th_dport = htons(P);
    tcph->th_seq = random();/* in a SYN packet, the sequence is a random */
    tcph->th_ack = 0;/* number, and the ack sequence is 0 in the 1st packet */
    tcph->th_x2 = 0;
    tcph->th_off = 0; /* first and only tcp segment */
    tcph->th_flags = TH_SYN; /* initial connection request */
    tcph->th_win = htonl(65535); /* maximum allowed window size */
    tcph->th_sum = 0;/* if you set a checksum to zero, your kernel IP stack
     should fill in the correct checksum during transmission */
    tcph->th_urp = 0;

    iph->ip_sum = csum((unsigned short *) datagram, iph->ip_len >> 1);

    /* finally, it is very advisable to do a IP_HDRINCL call, to make sure
     that the kernel knows the header is included in the data, and doesn't
     insert its own header into the packet before our data */
    int one = 1;
    const int *val = &one;
    if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
        printf("Warning: Cannot set HDRINCL!\n");

    if (sendto(s,datagram,iph->ip_len,0,(struct sockaddr *) &sin, sizeof(sin)) < 0) 
        printf("error\n");
    else
        printf(".\n\n");

    sleep(2); // giving enough time to receive response

    char buffer[8192]; /* single packets are usually not bigger than 8192 bytes */
    memset(buffer, 0, 8192); /* zero out the buffer */
    while (recv(s, buffer, 8192, 0) > 0)
        printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));

    close(s);
    return 0;
}

Результат, который я получаю, показан на этом изображении: http://imgur.com/jjjhp39

  • 1
    Прежде всего, используйте такие инструменты, как Wireshark, чтобы увидеть, что происходит в сети. Во-вторых, похоже, что вы пытаетесь установить соединение, и в этом случае вы не получите ответ с какими-либо данными. И вы даже не проверяете, получили ли вы ответ с данными, вы просто печатаете «данные» в любом случае.
  • 0
    Я думаю, что программа будет печатать только тогда, когда некоторые данные получены с функцией recv() . Так как это пакет SYN, я думаю, что сервер должен отправить ACK.
Показать ещё 3 комментария
Теги:
sockets
network-programming
raw-sockets

3 ответа

0

Вам нужно использовать библиотеку libpcap для извлечения пакета из уровня ссылки.

0

Попробуйте изменить:

printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));

чтобы:

printf("Caught tcp packet: %s\n", buffer);
  • 0
    Спасибо Davinder, но полученный ответ даст четкий вывод только после ipheader и tcpheader.
  • 0
    Правильно. Я понял после публикации ответа.
0
while (recv(s, buffer, 8192, 0) > 0)
    printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));

Не всегда правильно хранить результат recv() в переменной. Вам нужно проверить его на ноль и -1, и в противном случае использовать его как длину полученных данных. Попробуй это:

int count;
while ((count = recv(s, buffer, sizeof buffer, 0)) > 0)
    printf("Caught tcp packet: %.*s\n", count - sizeof(struct iphdr) - sizeof(struct tcphdr, buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));
if (count < 0)
    perror("recv");

EDIT Кажется, вы пытаетесь распечатать содержимое пакета SYN-ACK. Их нет.

  • 0
    Спасибо, EJP, но я все еще получаю похожие "ненужные символы" с вашим кодом.
  • 2
    Это потому, что count - это количество полученных байтов, а не количество печатаемых символов. Вы никогда не писали никакого кода, чтобы разумно получать данные и организовывать их печать. Вы ожидаете, что это сработает по волшебству.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню