Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > извлечь data из ethernet пакета (TCP)


Автор: lazycat2012 2.9.2012, 17:47
Помогите разобрать на составляющие Ethernet пакет.

принимаю так: 
Код


    struct buffer {
    __u8  head_eth [14];
    __u8  head_ip [20];
    __u8  body [1484];
} buff_p;

raw_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
rec = recvfrom(raw_socket, (char *)buff, ETH_FRAME_LEN, 0, NULL, NULL);

        memcpy((void *)&buff_p, buff, ETH_FRAME_LEN);
        
        write(foutput2, buff_p.body, (rec-38)); 


получаю TCP пакет выделенный из Ethernet пакета (я надеюсь).

Но мне нучно выделить данные из  TCP, a там заголовок может быть разного размера, как быть? 

подскажите как эти пакеты разбирают (чистый Си - под линукс)

Автор: leniviy 2.9.2012, 19:04
переделай структуру:
Код

#include <sys/types.h>
struct buffer {
    u_int8_t  head_eth [14];
    u_int8_t  frame_data [1504];
} buff_p;

 

указатель на данные:
Код

#include <netinet/ip.h>

#define GET_DATA(p_iphdr) ( (u_int8_t*)(p_iphdr) + ((p_iphdr)->ihl*4) )

  struct iphdr* p_iphdr = (struct iphdr*)&buff_p.frame_data;
  // p_iphdr->ihl = 5;
  u_int8_t*pdata = GET_DATA(p_iphdr);
  printf("%u\n", pdata - (u_int8_t*)&buff_p.frame_data);

Автор: leniviy 2.9.2012, 19:49
переделал

Автор: lazycat2012 3.9.2012, 17:02
Использовал структуры заголовков IP и TCP, получилось так:

Код

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>


int main(void)
{
    extern int errno;
    int            foutput; // дескриптор файла дампа
    int            rec; // получено из сокета
    int            size_data; // объем полезных данных
    struct iphdr ip; // IP заголовок
    struct tcphdr tcp; // TCP заголовок
    int    raw_socket; // дескриптор сокета
    
    __u8 buff[ETH_FRAME_LEN]; // буфер ETH пакета
    __u8  buff_tcp[1460]; // буфер данных

    foutput = open("dump-rtmp", O_WRONLY | O_TRUNC | O_CREAT  , 0644);
    if (foutput < 0)
    {
        fprintf(stderr, "Cannot open file 'dump-rtmp' -%s\n", strerror(errno));
        exit(1);
    }

    if ((raw_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) <0)
    {
        fprintf(stderr,"Cannot open socket\n");
        exit(1);
    }

    for (;;)
    {
        rec = recvfrom(raw_socket, (char *)buff, ETH_FRAME_LEN, 0, NULL, NULL);
        
        if (rec < 0 || rec > ETH_FRAME_LEN)
        {
            fprintf(stderr,"recvfrom - error\n");
            return -1;
        }

        memcpy((void *)&ip, buff + ETH_HLEN, sizeof(struct iphdr));

        if ((ip.version) == 4)
        {
            memcpy((void *)&tcp, buff + ETH_HLEN + ip.ihl * 4, sizeof(struct tcphdr));

            if ((ip.protocol == IPPROTO_TCP) & (ntohs(tcp.dest) == 1935))
            {
                size_data = (rec-tcp.doff*4-ip.ihl*4-ETH_HLEN);
                memcpy((void *)&buff_tcp, (buff + ETH_HLEN + ip.ihl*4 + tcp.doff*4), size_data);

                if (size_data > 0)
                {
                    printf("TCP пакет - %u\n", size_data);
                    write(foutput, buff_tcp, size_data);
                }
            }
        }
    }
    exit(0);
}


работает, пишет что нужно.

Автор: leniviy 3.9.2012, 18:05
по мне так, первые 2 memcpy - это лишнее, так как длина полей
ip.version,ip.protocol,ip.ihl,tcp.dest

не превышает 16 бит, то unaligned access не случится.
айпишники длиной 32+ бита действительно надо копировать с помощью memcpy, но здесь они не проверяются.

Оптимальнее всего в recvfrom() передавать указатель на буфер+ (offsetof(чего-нибудь)), чтобы начало ip пакета делилось на 4.


Код

size_data = (rec-tcp.doff*4-ip.ihl*4-ETH_HLEN);

Это работает? Если я правильно прочитал википедию, tcp.doff и ip.ihl - оба указывают на начало полезных данных, а длина пакета в другом поле

Автор: lazycat2012 3.9.2012, 18:21
Цитата

Это работает? 

да работает 
size_data = (rec-tcp.doff*4-ip.ihl*4-ETH_HLEN)
tcp.doff*4   заголовок tcp
ip.ihl*4        заголовок ip
ETH_HLEN  заголовок ETH

в итоге размер "чистых данных"

Цитата

по мне так, первые 2 memcpy - это лишнее, так как длина полей


Иначе я не смогу получить параметры ip.version,  ip.protocol, tcp.dest, tcp.doff, ip.ihl,  а их надо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)