【问题标题】:How to read the UDP data payload coming from a port using C program如何使用 C 程序读取来自端口的 UDP 数据负载
【发布时间】:2015-07-28 20:39:50
【问题描述】:

我正在尝试从端口 6343 捕获 UDP 数据包。在捕获它的同时,我还必须捕获有效负载。我正在获取 ASCII 格式的有效负载。我必须阅读有效载荷的内容。以下是我的代码:

#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>
#define PORT 6343


void print_udp_packet(unsigned char*, int);
void ProcessPacket(unsigned char*, int);
void PrintData (unsigned char* , int);

int sockt;
int i,j;

struct sockaddr_in source,dest; 

int main()
{
    int saddr_size,data_size;
    struct sockaddr_in saddr;
    struct sockaddr_in daddr;

    //struct in_addr in;
    unsigned char *buffer = (unsigned char *)malloc(65536); // Its Big ! Malloc allocates a block of size bytes of memory,returning a pointer to the begining of the block

    struct udphdr *udph = (struct udphdr*)(buffer + sizeof(struct iphdr));
    struct iphdr *iph = (struct iphdr *)buffer;
    memset(&source,0,sizeof(source));
    source.sin_addr.s_addr = iph ->saddr;
    memset(&dest,0,sizeof(dest));
    dest.sin_addr.s_addr = iph->daddr;
    unsigned short iphdrlen = iph->ihl*4;


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

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

    //Bind
    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...");

    //Receive a packet
    data_size = recvfrom(sockt , buffer ,65536 , 0 , (struct sockaddr*) &saddr , (socklen_t*)&saddr_size);
    if(data_size <0)
    {
      printf("Packets not recieved \n");
      return 1;
    }

    printf("Packets arrived from %d \n",ntohs(daddr.sin_port));
    printf("\t Source Port : %d , Destination Port : %d, UDP Length : %d,Protocol : %d, total length : %d \n", ntohs(udph->source), ntohs(udph->dest), ntohs(data_size), (unsigned int)iph->protocol, ntohs(iph->tot_len)); 
    printf("Source IP        : %s\n",inet_ntoa(saddr.sin_addr));
    printf("Destination IP   : %s\n",inet_ntoa(daddr.sin_addr));
    ProcessPacket(buffer,data_size);
    }
    close(sockt);
    printf("Finished");
    return 0;
}

void ProcessPacket(unsigned char* buffer, int size)
{

    print_udp_packet(buffer ,size);

}

void print_udp_packet(unsigned char *buffer , int size)
{

    unsigned short iphdrlen;

    struct iphdr *iph = (struct iphdr *)buffer;
    iphdrlen = iph->ihl*4;

    struct udphdr *udph = (struct udphdr*)(buffer + iphdrlen);

    printf("Data Payload\n");  
    PrintData(buffer + iphdrlen + sizeof udph ,( size - sizeof udph - iph->ihl * 4 ));

    printf("\n###########################################################");
}

void PrintData (unsigned char* data , int size)
{

    for(i=0 ; i < size ; i++)
    {
        if( i!=0 && i%16==0)   //if one line of hex printing is complete...
        {
            printf("         ");
            for(j=i-16 ; j<i ; j++)
            {
                if(data[j]>=32 && data[j]<=128)
                    printf("%c",(unsigned char)data[j]); //if its a number or alphabet

                else printf("."); //otherwise print a dot
            }
            printf("\n");
        } 

        if(i%16==0) printf("   ");
            printf(" %02X",(unsigned int)data[i]);

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

            printf("   ");

            for(j=i-i%16 ; j<=i ; j++)
            {
                if(data[j]>=32 && data[j]<=128) printf("%c",(unsigned char)data[j]);
                else printf(".");
            }
            printf("\n");
        }
    }
}

我收到的输出如下:

Source Port : 55784 , Destination Port : 59568, UDP Length : 5122,Protocol : 188, total length : 5122 
Source IP        : 147.188.195.6
Destination IP   : 0.0.0.0
Data Payload
    93 BC C0 06 00 00 00 00 00 1F 39 D4 D9 E8 E8 B0         ..........9.....
    00 00 00 03 00 00 00 01 00 00 00 9C 00 B1 C9 4E         ...............N
    00 00 00 1D 00 00 01 00 78 F9 F5 6B 00 10 67 8F         ........x..k..g.
    00 00 00 1D 00 00 00 28 00 00 00 02 00 00 00 01         .......(........
    00 00 00 5C 00 00 00 01 00 00 00 4E 00 00 00 04         ...\.......N....
    00 00 00 4C F0 92 1C 48 C2 00 00 0E 0C 30 C7 C7         ...L...H.....0..
    08 00 45 00 00 3C 28 4D 40 00 25 06 1C 7E 4C 5C         ..E..<(M@.%..~L\
    70 AE 93 BC C0 2A B4 FE 00 50 59 41 29 30 00 00         p....*...PYA)0..
    00 00 A0 02 FF FF FD BF 00 00 02 04 05 B4 04 02         ................
    08 0A 00 13 01 7D 00 00 00 00 01 03 03 06 00 00         .....}..........
    00 00 03 E9 00 00 00 10 00 00 00 03 00 00 00 02         ................
    00 00 00 02 FF FF FF FF 00 00 00 01 00 00 00 A8         ................
    00 B1 C9 4F 00 00 00 1D 00 00 01 00 78 F9 F6 82         ...O........x...
    00 10 67 8F 00 00 00 1D 00 00 00 00 00 00 00 02         ..g.............
    00 00 00 01 00 00 00 68 00 00 00 01 00 00 00 59         .......h.......Y
    00 00 00 04 00 00 00 58 F0 92 1C 48 C2 00 00 0E         .......X...H....
    0C 30 C7 C7 08 00 45 00 00 47 D8 94 00 00 2F 11         .0....E..G..../.
    2F 0A 46 27 EA 1F 93 BC C0 04 17 72 00 35 00 33         /.F'.......r.5.3
    BF 19 43 B9 00 10 00 01 00 00 00 00 00 01 03 6E         ..C............n
    73 32 04 73 75 73 78 02 61 63 02 75 6B 00 00 01         s2.susx.ac.uk...
    00 01 00 00 29 10 00 00 00 80 00 00 00 00 00 00         ....)....�......
    00 00 03 E9 00 00 00 10 00 00 00 03 00 00 00 02         ................
    00 00 00 02 FF FF FF FF 00 00 00 01 00 00 00 9C         ................
    00 B1 C9 50 00 00 00 1D 00 00 01 00 78 F9 F6 F0         ...P........x...
    00 10 67 8F 00 00 00 00 00 00 00 1D 00 00 00 02         ..g.............
    00 00 00 01 00 00 00 5C 00 00 00 01 00 00 00 50         .......\.......P
    00 00 00 04 00 00 00 4C 00 0E 0C 30 C7 C7 F0 92         .......L...0....
    1C 48 C2 00 08 00 45 00 00 3E BC F6 00 00 3F 11         .H....E..>....?.
    38 9F 93 BC C0 04 C2 53 70 05 00 35 BE FE 00 2A         8......Sp..5...*
    28 53 82 D8 81 05 00 01 00 00 00 00 00 00 03 77         (S.............w
    77 77 06 67 6F 6F 67 6C 65 02 63 6F 02 75 6B 00         ww.google.co.uk.
    00 01 00 01 00 00 03 E9 00 00 00 10 FF FF FF FF         ................
    00 00 00 00 00 00 00 03 FF FF FF FF               ............

我很困惑如何把这些数据变成可读的形式来知道payload的内容?

【问题讨论】:

  • 你需要知道应用协议的结构。
  • 有什么理由不使用tcpdumpWireshark?他们有所有常见协议的解码器。
  • 这看起来可能是 DNS 协议。因此阅读 DNS RFC 以查看 DNS 有效负载的布局,然后编写一个解码器。或者从tcpdump获取代码。
  • 我被要求通过 C 编程解码有效载荷。

标签: c udp


【解决方案1】:

首先,您打印的端口号、协议和数据长度不正确。正如我在my answer to your previous question 中提到的,IP 和UDP 标头不包含在recvfrom 填充的缓冲区中。源端口和目的端口分别在saddr.sin_portdaddr.sin_port(打印前一定要在那些字段上调用ntohs),UDP有效载荷长度是recvfrom的返回值,即data_size

至于数据负载的格式,你需要确切地知道你收到的数据是什么格式的。基于此,您可以提取相关字段并以可读格式打印它们。对于初学者,您可以从main 调用PrintData 而不是ProcessPacket,因为您无需担心IP 和UDP 标头。

【讨论】:

  • 感谢您的 cmets。我使用了上述建议,输出如下:源端口:61842,目标端口:6343,UDP 长度:61444。这是正确的吗?这里出现的一个疑问是目标端口是 6343(我试图捕获数据的端口)应该是源端口,因为那是我收集数据的端口?不知道我的理解是否正确?
  • 源端口和目的端口正确。您的套接字绑定到端口 6343,因此在该套接字上接收到的所有数据包都应将 6343 作为目标端口。
  • 感谢您的 cmets。协议怎么样?我在打印前调用 iph->protocol。这是正确的做法吗?
  • IP 标头不包含在您的数据缓冲区中,因此您不应该尝试读取它。因为您接收的套接字类型为 AF_INET / SOCK_DGRAM,所以 IP 标头中的协议将始终为 17 (UDP)。
  • 好的..现在对我来说很有意义。但是我出于好奇而问这个问题有没有可能通过更改套接字类型来显示协议字段??
猜你喜欢
  • 2018-12-18
  • 1970-01-01
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-14
  • 1970-01-01
相关资源
最近更新 更多