Поиск октета в полезной нагрузке данных UDP в программе C

Я пытаюсь собрать информацию о полезной нагрузке данных UDP, используя программу C, перехватив пакет из порта 6343. Код, который я использую, выглядит следующим образом:

#include<stdio.h>             //For standard things
#include<stdlib.h>            //malloc
#include<string.h>            //memset
#include<netinet/ip_icmp.h>   //Provides declarations for icmp header
#include<netinet/udp.h>       //Provides declarations for udp header
#include<netinet/tcp.h>       //Provides declarations for tcp header
#include<netinet/ip.h>        //Provides declarations for ip header
#include<sys/socket.h>
#include<arpa/inet.h>
#include<net/ethernet.h>
#include<netinet/if_ether.h>
#define PORT 6343             // define the port to connect
#define ETH_P_IP 0x0800

void ProcessPacket(unsigned char*, int);
void print_ethernet_header(unsigned char*, int);
void print_ip_header(unsigned char* , int);
void print_udp_packet(unsigned char*, int);
void Dataint (unsigned char* , int);
void print(const int *, const int);
int sockt;
int i,j;
struct sockaddr_in source,dest; 

const MAX_HEADER_SIZE = 256;   /* The maximum sampled header size. */

struct sampled_header {
header_protocol protocol;       /* Format of sampled header */
unsigned int frame_length;      /* Original length of packet before
                                  sampling */
opaque header{MAX_HEADER_SIZE}; /* Header bytes */
}

/* Packet IP version 4 data */

struct sampled_ipv4 {
unsigned int length;     /* The length of the IP packet excluding
                           lower layer encapsulations */
unsigned int protocol;   /* IP Protocol type
                           (for example, TCP = 6, UDP = 17) */
ip_v4 src_ip;            /* Source IP Address */
ip_v4 dst_ip;            /* Destination IP Address */
unsigned int src_port;   /* TCP/UDP source port number or
                           equivalent */
unsigned int dst_port;   /* TCP/UDP destination port number or
                           equivalent */
unsigned int tcp_flags;  /* TCP flags */
unsigned int tos;        /* IP type of service */
}
/* Packet IP version 6 data */

struct sampled_ipv6 {
unsigned int length;     /* The length of the IP packet excluding
                           lower layer encapsulations */
unsigned int protocol;   /* IP next header
                           (for example, TCP = 6, UDP = 17) */
ip_v6 src_ip;            /* Source IP Address */
ip_v6 dst_ip;            /* Destination IP Address */
unsigned int src_port;   /* TCP/UDP source port number or
                           equivalent */
unsigned int dst_port;   /* TCP/UDP destination port number or
                           equivalent */
unsigned int tcp_flags;  /* TCP flags */
unsigned int priority;   /* IP priority */
}

struct extended_switch {
unsigned int src_vlan;     /* The 802.1Q VLAN id of incoming frame */
unsigned int src_priority; /* The 802.1p priority of incoming
                             frame */
unsigned int dst_vlan;     /* The 802.1Q VLAN id of outgoing frame */
unsigned int dst_priority; /* The 802.1p priority of outgoing
                             frame */
}

 int main()
 {

int saddr_size,data_size, datasize; 
struct sockaddr_in saddr;
struct sockaddr_in daddr;
struct in_addr addr;
int protocol=17;
unsigned char* buffer = (unsigned char *)malloc(65535); // Its Big ! Malloc allocates a block of size bytes of memory,returning a pointer to the begining of the block

//Create a socket

sockt = socket(AF_INET ,SOCK_DGRAM ,IPPROTO_UDP);
if(sockt < 0)
{
    printf("Socket Error\n");
    return 1;
}
memset((char *)&daddr,0,sizeof(daddr));

//prepare the sockaddr_in structure
saddr.sin_family = AF_INET;
daddr.sin_family = AF_INET;
daddr.sin_addr.s_addr = htonl(INADDR_ANY);
daddr.sin_port = htons(PORT);
saddr.sin_port = htons(PORT);
//Bind the socket

if(bind(sockt,(struct sockaddr *)&daddr, sizeof(daddr))<0)
{
  printf("bind failed");
  return 1;
}
printf("bind done");

while(1)
{
saddr_size = sizeof saddr;
printf(" waiting for data...\n");

//Receive a packet

datasize = recvfrom(sockt , buffer ,65535 , 0 , (struct sockaddr*) &saddr , (socklen_t*)&saddr_size);
data_size = recvfrom(sockt , buffer ,65535 , 0 , NULL , NULL);
if(data_size <0)
{
  printf("Packets not recieved \n");
  return 1;
}
printf("Packets arrived from %d \n",ntohs(daddr.sin_port));
printf("packet recieved : %lu bytes\n", datasize);

ProcessPacket(buffer , data_size);

}
close(sockt);
printf("Finished");
return 0;
}


void ProcessPacket(unsigned char* buffer, int len)
{
  print_udp_packet(buffer , len);

}

void print_ethernet_header(unsigned char* buffer, int len)
{
  struct ethhdr *eth = (struct ethhdr *)buffer;
  printf("Ethernet Header\n");
  printf("---------------------------------------\n");
  printf("Ethernet Header Length   : %u bytes \n",sizeof(eth));
  printf("Destination MAC : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_dest[0] , eth->h_dest[1] , eth->h_dest[2] , eth->h_dest[3] , eth->h_dest[4] , eth->h_dest[5] );
  printf("Source MAC      : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_source[0] , eth->h_source[1] , eth->h_source[2] , eth->h_source[3] , eth->h_source[4] , eth->h_source[5] );
  printf("Ethernet Type   : %u \n",eth->h_proto);
  printf("---------------------------------------\n");
  }

  void print_ip_header(unsigned char* buffer, int len)
  {
  //print_ethernet_header(buffer , len);

  struct iphdr *iph = (struct iphdr *)(buffer + sizeof(struct ethhdr));
  unsigned short iphdrlen = iph->ihl*4;

  memset(&source,0,sizeof(source));
  source.sin_addr.s_addr = iph ->saddr;
  memset(&dest,0,sizeof(dest));
  dest.sin_addr.s_addr = iph->daddr;

  printf("IP Header\n");
  printf("---------------------------------------\n");
  printf("IP Length        : %d\n", ntohs(iph->tot_len));
  printf("Source IP        : %s\n",inet_ntoa(source.sin_addr));
  printf("Destination IP   : %s\n",inet_ntoa(dest.sin_addr));
  printf("Protocol         : %d\n", iph->protocol);
  printf("Type Of Service  : %d\n",htons(iph->tos));
  printf("---------------------------------------\n");
  }


  void print_udp_packet(unsigned char* buffer , int len)
  {
  struct sockaddr_in saddr;
  struct sockaddr_in daddr;
  unsigned short iphdrlen;
  unsigned char* payload = (unsigned char *)malloc(1024);
  struct iphdr *iph = (struct iphdr *)(buffer+ sizeof(struct ethhdr));
  iphdrlen = iph->ihl*4;

   struct udphdr *udph = (struct udphdr*)(buffer + sizeof(struct iphdr)+sizeof(struct ethhdr));

   int header_size =  sizeof(struct ethhdr) + iphdrlen + sizeof udph;

   print_ip_header(buffer,len);

   printf("UDP Header\n");
   printf("---------------------------------------\n");
   printf("UDP Length       : %d\n", ntohs(udph->len));
   //printf("UDP Length       : %d\n", ntohs(sizeof (struct udphdr))); 
   printf("Source Port      : %d\n ",ntohs(udph->source));
   printf("Destination Port : %d\n ",ntohs(udph->dest));
   printf("Source Port      : %d\n ",ntohs(saddr.sin_port));
   printf("Destination Port : %d\n ",ntohs(daddr.sin_port)); 
   printf("---------------------------------------\n");

   printf("Data Payload\n");  
   //PrintData(buffer + header_size , len - header_size);
   Dataint(buffer ,len);
   printf("--------------------------------------------\n"); 


   }

  void Dataint (unsigned char* buffer , int len)
  {

  int i,j;
  i=0;
  for(i=0 ; i <= len ; i++)
  {
    if( i!=0 && i%16==0)   // prints every hex line with a space
    {
        printf("  ");
    } 

     // prints entire data in integer
      if(i%16==0) 
        printf("   ");                           // prints the first element of hex line                      
        printf(" %d",(unsigned int)buffer[i]);  

    //print the last spaces         
    if( i==len-1)  
    {
        for(j=0;j<16-i%16;j++) 
        printf("   ");

    }
   }
  } 

У меня полезная нагрузка преобразована в целочисленную форму, как показано ниже:

0 0 0 5 0 0 0 1 147 188 192 6 0 0 0 0      0 50 170 143 37 107 3 154 0 0 0 6 0 0 0 1      0 0 0 208 1 30 136 36 0 0 0 29 0 0 1 0      236 205 212 188 0 22 44 215 0 0 0 29 0 0 0 40      0 0 0 2 0 0 0 1 0 0 0 144 0 0 0 1      0 0 5 238 0 0 0 4 0 0 0 128 240 146 28 72      194 0 0 14 12 48 199 199 8 0 69 0 5 220 65 28      64 0 47 6 24 125 193 104 215 69 147 188 192 24 0 80      142 152 237 55 211 205 114 104 162 142 128 16 0 54 188 178      0 0 1 1 8 10 139 71 198 30 37 2 188 177 205 144      135 164 154 194 155 33 30 238 48 113 112 179 62 180 223 221      169 24 234 48 163 41 188 139 148 98 130 255 16 229 123 58      202 165 56 101 14 217 132 108 10 156 47 29 77 156 220 141      202 248 196 75 240 252 232 27 19 140 52 187 0 0 3 233      0 0 0 16 0 0 0 3 0 0 0 2 0 0 0 2      255 255 255 255 0 0 0 1 0 0 0 208 1 30 136 37      0 0 0 29 0 0 1 0 236 205 214 47 0 22 44 215      0 0 0 29 0 0 0 40 0 0 0 2 0 0 0 1      0 0 0 144 0 0 0 1 0 0 5 238 0 0 0 4      0 0 0 128 240 146 28 72 194 0 0 14 12 48 199 199      8 0 69 0 5 220 65 243 64 0 47 6 23 166 193 104      215 69 147 188 192 24 0 80 142 152 237 60 147 229 114 104      162 142 128 16 0 54 13 151 0 0 1 1 8 10 139 71      198 66 37 2 188 213 16 243 209 241 120 208 124 252 85 108      101 62 10 255 21 98 62 58 136 127 106 62 238 76 85 231      227 224 70 62 31 217 151 211 47 106 246 111 160 87 164 114      43 83 45 230 197 131 18 49 110 159 251 162 207 148 178 31      212 40 81 190 0 0 3 233 0 0 0 16 0 0 0 3      0 0 0 2 0 0 0 2 255 255 255 255 0 0 0 1      0 0 0 148 1 30 136 38 0 0 0 29 0 0 1 0      236 205 214 158 0 22 44 215 0 0 0 0 0 0 0 29      0 0 0 2 0 0 0 1 0 0 0 84 0 0 0 1      0 0 0 70 0 0 0 4 0 0 0 68 0 14 12 48      199 199 240 146 28 72 194 0 8 0 69 0 0 52 28 175      64 0 63 6 50 146 147 188 192 24 193 104 215 69 142 152      0 80 114 104 162 142 237 62 109 231 128 16 36 63 51 129      0 0 1 1 8 10 37 2 188 231 139 71 198 66 0 0      0 0 3 233 0 0 0 16 255 255 255 255 0 0 0 0      0 0 0 3 255 255 255 255 0 0 0 1 0 0 0 208      1 30 136 39 0 0 0 29 0 0 1 0 236 205 215 173      0 22 44 215 0 0 0 29 0 0 0 40 0 0 0 2      0 0 0 1 0 0 0 144 0 0 0 1 0 0 5 238      0 0 0 4 0 0 0 128 240 146 28 72 194 0 0 14      12 48 199 199 8 0 69 0 5 220 67 10 64 0 47 6      22 143 193 104 215 69 147 188 192 24 0 80 142 152 237 66      188 223 114 104 162 142 128 16 0 54 185 33 0 0 1 1      8 10 139 71 198 102 37 2 188 248 226 4 177 86 140 52      15 181 49 144 230 162 19 81 72 179 190 46 196 123 24 85      38 153 175 213 96 59 3 73 194 138 211 35 187 143 148 46      200 190 255 249 6 223 220 57 180 2 123 223 184 204 149 28      127 218 240 134 94 247 236 103 0 0 3 233 0 0 0 16      0 0 0 3 0 0 0 2 0 0 0 2 255 255 255 255      0 0 0 1 0 0 0 208 1 30 136 40 0 0 0 29      0 0 1 0 236 205 216 48 0 22 44 215 0 0 0 29      0 0 0 40 0 0 0 2 0 0 0 1 0 0 0 144      0 0 0 1 0 0 5 238 0 0 0 4 0 0 0 128      240 146 28 72 194 0 0 14 12 48 199 199 8 0 69 0      5 220 67 144 64 0 47 6 22 9 193 104 215 69 147 188      192 24 0 80 142 152 237 69 173 223 114 104 162 142 128 16      0 54 47 172 0 0 1 1 8 10 139 71 198 102 37 2      188 249 253 49 241 16 12 100 96 130 25 195 170 251 218 202      149 6 45 216 81 206 145 254 7 147 240 20 103 185 112 138      115 50 158 226 156 204 78 113 98 240 114 65 240 51 253 252      102 174 242 80 12 50 241 179 148 204 90 200 196 66 118 137      0 0 3 233 0 0 0 16 0 0 0 3 0 0 0 2      0 0 0 2 255 255 255 255 0 0 0 1 0 0 0 148      1 30 136 41 0 0 0 29 0 0 1 0 236 205 217 14      0 22 44 215 0 0 0 29 0 0 0 25 0 0 0 2      0 0 0 1 0 0 0 84 0 0 0 1 0 0 0 70      0 0 0 4 0 0 0 68 240 146 28 72 194 0 0 14      12 48 199 199 8 0 69 0 0 52 174 239 0 0 48 6      219 72 216 58 210 78 147 188 194 70 1 187 179 154 222 83      63 174 28 240 175 235 128 16 5 91 120 31 0 0 1 1      8 10 94 165 224 71 49 84 232 65 0 0 0 0 3 233      0 0 0 16 0 0 0 3 0 0 0 2 0 0 0 14      255 255 255 255 

Это данные потока, собранные с основного коммутатора. Поэтому мне нужно найти Ethernet, IPv4, IPv6, расширенные данные коммутатора из этой полезной нагрузки и распечатать их. Перед этим мне нужно найти позицию октета каждого из них в полезной нагрузке. Можете ли вы посоветовать мне, как мне найти позицию октета каждого из них?

Ошибки при использовании структур в приведенном выше коде:

     udps.c:25: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘ip_v4’
udps.c:26: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘ip_v6’
udps.c:33: error: two or more data types in declaration specifiers
udps.c:33: error: expected ‘)’ before ‘type’
udps.c:45: error: expected specifier-qualifier-list before ‘header_protocol’
udps.c:58: error: expected specifier-qualifier-list before ‘ip_v4’
udps.c:69: error: two or more data types in declaration specifiers
udps.c:74: error: expected specifier-qualifier-list before ‘ip_v6’
udps.c:87: error: two or more data types in declaration specifiers
udps.c:93: error: two or more data types in declaration specifiers
udps.c:93: error: two or more data types in declaration specifiers
udps.c:93: error: expected ‘)’ before ‘type’
udps.c:115: error: two or more data types in declaration specifiers
udps.c: In function ‘main’:
udps.c:131: error: incompatible types when returning type ‘int’ but ‘struct extended_switch’ was expected
udps.c:147: error: incompatible types when returning type ‘int’ but ‘struct extended_switch’ was expected
udps.c:163: error: incompatible types when returning type ‘int’ but ‘struct extended_switch’ was expected
udps.c:173: error: incompatible types when returning type ‘int’ but ‘struct extended_switch’ was expected

person user known    schedule 12.08.2015    source источник
comment
так же, как обычно. Определите структуру для заголовка ipv4, заголовка ipv6, заголовка udp. теперь используйте эти структуры для анализа ваших данных и получения нужной информации... в какой момент вы боретесь?   -  person Joshua K    schedule 12.08.2015
comment
анализатор пакетов в C посмотрите, как он использует структуру и указатель   -  person axellink    schedule 12.08.2015
comment
Поскольку это данные Sflow, мне нужно получить конкретную информацию. в документации по sflow, на которую я ссылался, URL такой: sflow.org/sflow_version_5.txt. Он определяет структуру для каждого из них, о котором я упоминал в своем вопросе. Я думал, что могу определить эти структуры в своем коде и использовать memcpy для извлечения информации из буфера. Но чтобы указать их расположение, мне нужно найти для них значение октета. это то место, где я смущен.   -  person user known    schedule 12.08.2015
comment
Как именно вы захватили этот пакет? В частности, можете ли вы показать код, который вы использовали для открытия сокета и чтения данных?   -  person dbush    schedule 12.08.2015
comment
@dbush Я прикрепил свой код к вопросу.   -  person user known    schedule 12.08.2015


Ответы (1)


При использовании создания сокета типа AF_INET/SOCK_DGRAM операционная система обрабатывает заголовки Ethernet, IP и UDP и удаляет их, прежде чем передать их вам. В буфере вы видите то, что следует сразу за заголовком UDP.

Пятый параметр recvfrom дает вам исходный IP-адрес и исходный порт входящего пакета. Если вы хотите увидеть больше, чем просто это, вам нужно использовать библиотеку захвата пакетов, такую ​​​​как libpcap.

Редактировать:

Кажется, что этот пакет данных содержит IP-адреса как часть данных sflow. Вы пытались проанализировать его, как если бы это был необработанный кадр Ethernet. Вместо этого вам нужно взглянуть на определение дейтаграммы sflow и использовать его, чтобы выяснить, как устроен пакет, и соответствующим образом проанализировать его. Вам не нужно использовать memcpy для этого, просто используйте указатели на соответствующие структуры, чтобы указать на нужное место в буфере. Это та же базовая техника, которую вы использовали раньше, только с другим набором структур.

Редактировать 2:

Похоже, мы далеки от того, как выглядят данные. Я взял байты из пакета, указанного выше, прочитал их в буфер и отправил в UDP-пакете. Я запустил Wireshark, который выдал нам следующее:

Захват Wireshark

Итак, пакет содержит:

  • Версия sflow, 32-разрядная (5)
  • 32-битное целое число (значение = 1)
  • a struct sample_datagram_v5
  • количество выборок (32-битное целое, значение = 6)
  • шесть образцов

Первый образец содержит:

  • Тип образца как data_format (в данном случае образец потока)
  • a struct flow_sample
  • количество выборок потока (32-битное целое, значение = 2)

Первый поток в первом примере:

  • Тип потока как data_format (в данном случае необработанный образец пакета, так что...)
  • длина данных потока (32-битное целое число, значение = 144)
  • a struct sampled_header
  • 4 байта, которые пропускаются в соответствии со значением sampled_header.stripped
  • Ethernet-заголовок
  • Заголовок IP (полезная нагрузка = TCP)
  • Заголовок TCP (порт = 80)
  • байт данных (62)

Второй поток в первом примере:

  • Тип потока как data_format (в данном случае расширенные данные переключения)
  • длина данных потока (32-битное целое число, значение = 16)
  • a struct extended_switch

Затем еще пять проб. В этом случае все образцы содержат необработанный заголовок пакета и расширенные данные коммутатора.

Таким образом, это должно дать вам лучшее представление о том, что вам нужно делать. Поскольку каждый пакет данных будет другим, вам нужно будет определить, сколько у вас есть образцов. Затем для каждого образца вам нужно будет определить тип и на его основе выяснить, как анализировать отдельные потоки.

Если вам нужно больше примеров, я настоятельно рекомендую использовать Wireshark для захвата этих пакетов sflow, чтобы вы могли точно увидеть, что в них находится, чтобы проверить, работает ли ваш парсер для всех ожидаемых входных данных.

Связанный вопрос для справки: использование memcpy для хранения данные из буфера в структуру

person dbush    schedule 12.08.2015
comment
Мой руководитель сказал мне не использовать библиотеку захвата пакетов, такую ​​как libpcap. Также пакет, который я получаю, является пакетом UDP. В этом случае SOCK_DGRAM является правильным типом носка, не так ли ?? есть ли другой способ упомянуть тип носка? - person user known; 12.08.2015
comment
Как вы сказали, если заголовки Ethernet, IP и UDP удалены и в буфере хранятся только полезные данные, то не будет ли буфер содержать какую-либо информацию об IP-адресе, порте и т. д., которые видны в заголовках? - person user known; 12.08.2015
comment
@userknown Да, SOCK_DGRAM — правильный тип сокета. Поскольку вы не можете использовать библиотеку захвата пакетов, буфер, который вы возвращаете из recvfrom, содержит только данные sflow и ничего из заголовков верхнего уровня. Все, что вы получаете от этого, это информация о сокете, возвращаемая в пятом параметре для recvfrom. - person dbush; 12.08.2015
comment
Полезная нагрузка, о которой я упоминал выше, содержит IP-адреса и другую информацию. Как я могу распечатать их из упомянутой выше полезной нагрузки. Является ли использование memcpy мудрой идеей? - person user known; 12.08.2015
comment
@userknown Смотрите мое редактирование. Дайте мне знать, если у вас есть еще вопросы. - person dbush; 13.08.2015
comment
Я пытаюсь использовать структуры, соответствующие параметрам, которые мне нужно выбрать из полезной нагрузки, но они показывают много ошибок. - person user known; 13.08.2015
comment
udps.c:131: ошибка: несовместимые типы при возврате типа «int», но ожидалась «struct extended_switch» udps.c:147: ошибка: несовместимые типы при возврате типа «int», но ожидалась «struct extended_switch» udps.c: 163: ошибка: несовместимые типы при возврате типа «int», но ожидалась «struct extended_switch» udps.c:173: ошибка: несовместимые типы при возврате типа «int», но ожидалась «struct extended_switch» - person user known; 13.08.2015
comment
udps.c:45: ошибка: ожидаемый список спецификаторов перед 'header_protocol' udps.c:58: ошибка: ожидаемый список спецификаторов перед 'ip_v4' udps.c:69: ошибка: два или более типов данных в спецификаторы объявления udps.c:74: ошибка: ожидаемый список спецификаторов-квалификаторов перед 'ip_v6' udps.c:87: ошибка: два или более типов данных в спецификаторах объявлений udps.c:93: ошибка: два или более типов данных в спецификаторы объявления udps.c:93: ошибка: два или более типов данных в спецификаторах объявлений udps.c:93: ошибка: ожидается «)» перед «типом» udps.c:115: ошибка: два или более типов данных в спецификаторах объявлений - person user known; 13.08.2015
comment
Перечисленные вами ошибки не появляются при компиляции вашего кода. Пожалуйста, обновите свой вопрос, указав код, который вы на самом деле пытаетесь использовать, а также ошибки, которые вы получаете при его создании. - person dbush; 13.08.2015
comment
Я обновил код структурами, которые я использую, а также вставил свой журнал ошибок в вопрос. - person user known; 13.08.2015