使用H.248 SCTP有效负载创建pcap数据包

时间:2017-05-01 21:13:45

标签: c libpcap

我正在尝试使用pcap C库创建一个包含BER格式的H.248消息的数据包,以便使用wireshark应用程序对其进行解码。我写的代码和它的工作原理如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <pcap.h>
#include <pcap/vlan.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/if_ether.h>


#ifdef LINUX
#include <netinet/ether.h>
#endif

#define LINE_LEN 16

// chunk identifier 
#define SH_DATA 0
#define SH_INIT 1
#define SH_INIT_ACK 2
#define SH_SACK 3
#define SH_HEARTBEAT 4
#define SH_HEARTBEAT_ACK 5
#define SH_ABORT 6
#define SH_SHUTDOWN_ACK 8
#define SH_COOKIE_ECHO 10
#define SH_COOKIE_ACK 11
#define SH_ECNE 12
#define SH_CWR 13
#define SH_SHUTDOWN_COMPLETE 14

//payload protocol identifier for SCTP
#define RESERVED 0 //[RFC4960]  
#define IUA      1 //[RFC4233]  
#define M2UA     2 //[RFC3331]  
#define M3UA     3 //[RFC4666]  
#define SUA      4 //[RFC3868]  
#define M2PA     5 //[RFC4165]  
#define V5UA     6 //[RFC3807]  
#define H248     7 
#define BICC     8  
#define TALI     9 //[RFC3094]  
#define DUA     10 //[RFC4129]  
#define ASAP    11 //[RFC5352]  
#define ENRP    12 //[RFC5353]  
#define H323    13  
#define QIPC    14 //Q.2150.3       
#define SIMCO   15  
#define DDPSEGC 16   
#define DDPSSC  17      
#define S1AP    18 
#define RUA     19 
#define HNBAP   20 
#define FORCESHP 21     
#define FORCESMP 22 
#define FORCESLP 23 
#define SBCAP    24    
#define NBAP     25 
#define UNASSIGNED 26       
#define X2AP    27

u_char payload[] = {0x30, 0x82, 0x01, 0x60, 0xa1, 0x82, 0x01, 0x5c, 0x80, 0x01, 0x02,0xa1, 0x04, 0x84, 0x02, 0x24, 0x1a, 0xa2, 0x82, 0x01, 0x4f, 0xa1, 0x82, 0x01, 0x4b, 0xa0, 0x82, 0x01, 0x47, 0x80, 0x04, 0x2f, 0x00, 0x00, 0xaa, 0xa1, 0x82, 0x01, 0x3d, 0x30, 0x82, 0x01, 0x39,0x80, 0x04, 0x10, 0x00, 0x00, 0x0f, 0xa3, 0x82, 0x01, 0x2f, 0x30, 0x82, 0x01, 0x2b, 0xa0, 0x82, 0x01, 0x27, 0xa6, 0x82, 0x01, 0x23, 0xa0, 0x0a, 0x30, 0x08, 0xa0, 0x00, 0x81, 0x04, 0x28, 0x40, 0x00, 0x07, 0xa1, 0x82, 0x01, 0x13, 0x80, 0x01, 0x2f, 0xa1, 0x82, 0x01, 0x0c, 0x30, 0x2f, 0x80, 0x04, 0x00, 0x21, 0x00, 0x01, 0x81, 0x02, 0x00, 0xff, 0xa2, 0x0d, 0x30, 0x0b, 0x80, 0x02, 0x00, 0x01, 0xa1, 0x05, 0x04, 0x03, 0x0a, 0x01, 0x01, 0xa3, 0x14, 0x80, 0x08, 0x02, 0x00, 0x00, 0x07, 0x00, 0x06, 0x00, 0x05, 0x81, 0x08, 0x01, 0x08, 0x03, 0x01, 0x01, 0x02, 0x03, 0x04, 0x30, 0x81,
0xa7, 0x80, 0x04, 0x00, 0x22, 0x00, 0x01, 0xa2, 0x81, 0x9e, 0x30, 0x81, 0x9b, 0x80, 0x02, 0x00, 0x01, 0xa1, 0x81, 0x94, 0x04, 0x81, 0x91, 0x04, 0x81, 0x8e, 0x20, 0x20, 0x76, 0x3d, 0x30, 0x0d, 0x0a, 0x6f, 0x3d, 0x2d, 0x20, 0x30, 0x20, 0x30, 0x20, 0x49, 0x4e, 0x20, 0x49, 0x50, 0x34, 0x20, 0x31, 0x30, 0x2e, 0x33, 0x2e, 0x31, 0x2e, 0x34, 0x0d, 0x0a, 0x73, 0x3d, 0x2d, 0x0d, 0x0a, 0x63, 0x3d, 0x49, 0x4e, 0x20, 0x49, 0x50, 0x34, 0x20, 0x31, 0x30, 0x2e, 0x33, 0x2e, 0x31, 0x2e, 0x34, 0x0d, 0x0a, 0x74, 0x3d, 0x30, 0x20, 0x30, 0x0d, 0x0a, 0x61, 0x3d, 0x69, 0x70, 0x62, 0x63, 0x70, 0x3a, 0x31, 0x20, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x0d, 0x0a, 0x6d, 0x3d, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x31, 0x38, 0x39, 0x34, 0x38, 0x20, 0x52, 0x54, 0x50, 0x2f, 0x41, 0x56, 0x50, 0x20, 0x39, 0x36, 0x0d, 0x0a, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x39, 0x36, 0x20, 0x56, 0x4e, 0x44, 0x2e, 0x33, 0x47, 0x50, 0x50, 0x2e, 0x49, 0x55, 0x46, 0x50, 0x2f, 0x31, 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x30, 0x2f, 0x80, 0x04, 0x00, 0x21, 0x00, 0x02, 0x81, 0x02, 0x00, 0xff, 0xa2, 0x0d, 0x30, 0x0b, 0x80, 0x02, 0x00, 0x01, 0xa1, 0x05, 0x04, 0x03, 0x0a, 0x01, 0x01, 0xa3, 0x14, 0x80, 0x08, 0x02, 0x00, 0x00, 0x07, 0x00, 0x06, 0x00, 0x05, 0x81,
0x08, 0x01, 0x08, 0x03, 0x01, 0x01, 0x02, 0x03, 0x04};

int SCTP_payload = sizeof payload / sizeof(u_char);

struct chunk
{
  u_char        identifier; // type
  u_char        flags;
  u_short           length;
  unsigned int          seq_num;
  u_short               stream_id;
  u_short               stream_seq_num;
  unsigned int      payload_id;
};


struct sctphdr
{
  /*
    The data types/sizes we need to use are: unsigned char - 1 byte (8 bits),
    unsigned short int - 2 bytes (16 bits) and unsigned int - 4 bytes (32 bits)
  */
  u_short           sport;
  u_short           dport;
  unsigned int      veriftag;
  unsigned int      sctp_sum;
  // chunk follows
  struct chunk          chnk;
};


struct ethernet {
  u_char        mac1[6];
  u_char        mac2[6];
  u_short       protocol;
};


struct packet{

//struct ethernet ether;

struct iphdr iph;

struct sctphdr sctph;

u_char payload_data[396];

};



int main()
{
  pcap_t *fd;

  char errbuf[PCAP_ERRBUF_SIZE];

  struct pcap_pkthdr *header;
  const u_char *pkt_data;
  u_int i=1;

  pcap_t *pd;
  pcap_dumper_t *pdumper;

  pd = pcap_open_dead(DLT_RAW, 65535);
  pdumper = pcap_dump_open(pd, "test3.pcap");


  //lets move on to SCTP header

  struct packet mypacket;


  #if __BYTE_ORDER == __LITTLE_ENDIAN
  mypacket.sctph.sport = htons(2945);
  mypacket.sctph.dport = htons(2945);
  #endif
  mypacket.sctph.veriftag = 0;
  mypacket.sctph.sctp_sum = 0;

  mypacket.sctph.chnk.identifier =  SH_DATA;
  mypacket.sctph.chnk.flags      =  0x03;

  #if __BYTE_ORDER == __LITTLE_ENDIAN
  mypacket.sctph.chnk.length = htons(sizeof(struct chunk)+SCTP_payload);


  mypacket.sctph.chnk.seq_num    =  htonl(206);
  mypacket.sctph.chnk.stream_id  =  htons(0x0001);
  mypacket.sctph.chnk.stream_seq_num = htons(205);
  mypacket.sctph.chnk.payload_id     = htonl(H248);
  #endif


  printf("SCTP_payload:%d\n",SCTP_payload);  


  struct pcap_pkthdr packet_header;
  struct timeval ts;

  packet_header.ts = ts;
  packet_header.caplen = sizeof(struct packet) + SCTP_payload;
  packet_header.len =  sizeof(struct packet) + SCTP_payload;


  #if __BYTE_ORDER  == __LITTLE_ENDIAN
  //write data for IP protocol header

  char dst_addr[]={"10.87.25.136"};
  char src_addr[]={"10.92.152.7"};

  mypacket.iph.saddr = inet_addr(src_addr);
  mypacket.iph.daddr = inet_addr(dst_addr);

  mypacket.iph.version = 4;
  mypacket.iph.ihl = 5; //20 bytes
  mypacket.iph.tos = 0; //type of service
  #endif

  #if __BYTE_ORDER  == __LITTLE_ENDIAN

  mypacket.iph.tot_len = htons(sizeof(struct iphdr)+sizeof(struct sctphdr)+SCTP_payload);



  printf("iph.tot_len:%d\n",sizeof(struct iphdr));



  mypacket.iph.id = htons(0x9152); //identification
  mypacket.iph.frag_off = 0; //fragment offset
  mypacket.iph.ttl=255;
  mypacket.iph.protocol = 132; //SCTP
  mypacket.iph.check = htons(0x6069);
  #endif



  memcpy(mypacket.payload_data,&payload[0],SCTP_payload*sizeof(u_char));

  pcap_dump((u_char*)pdumper, &packet_header, (const u_char*)&mypacket);


  pcap_close(pd);
  pcap_dump_close(pdumper);


}

运行此代码后,生成可以使用wireshark应用程序打开的test3.pcap文件。请查看下图:

test3.pcap opened with wireshark

我现在要做的是通过使用 u_char * payload_data 来为有效负载数据 u_char payload_data [396]; 创建一个更动态的应用程序。

为了执行此操作,我已经用 u_char * payload_data 替换了 u_char payload_data [396]; ,并在main()函数中使用了以下代码行: / p>

mypacket.payload_data = (u_char *)malloc(SCTP_payload*sizeof(u_char));
memcpy(mypacket.payload_data,&payload[0],SCTP_payload*sizeof(u_char));

不幸的是,当我运行修改的C程序时,无法识别数据包的SCTP有效负载(H.248消息),因为在SCTP有效载荷协议标识符(00 00 00 07)之后插入了一些垃圾数据。请查看下图:

test3.pcap with dynamic solution opened with wireshark

我在这里做错了什么?

提前谢谢!

1 个答案:

答案 0 :(得分:0)

pcap_dump() - 函数需要整个第三个参数(在您的情况下为mypacket)中指定的数据。在您第一次尝试时,就是这种情况,因为数据直接存储在结构struct packet

struct packet {
    struct iphdr iph;
    struct sctphdr sctph;
    u_char payload_data[396];
};

然后你把它改成了:

struct packet {
    struct iphdr iph;
    struct sctphdr sctph;
    u_char *payload_data;
};

现在,不是数据本身存储在结构中,而是存储数据的指针存储位置pcap_dump对数据的语义一无所知,因此它当然不能取消引用该指针并使用存储在那里的数据,但它只是存储内存位置。

一种可能的解决方案是按如下方式定义结构:

struct packet {
    struct iphdr iph;
    struct sctphdr sctph;
    u_char payload_data[1];
};

然后为整个结构分配内存,如:

struct packet *p = malloc(sizeof(struct packet)+payloadlen);

这样,您可以使有效负载长度动态,但数据仍然是整体的,因此适用于pcap_dump()