从pcap打印出TCP标志信息

时间:2017-12-02 22:24:35

标签: c networking hex pcap

我正在编写一个程序,以便从pcap中的标题中获取某些信息。我不确定我是否做得对。它适用于我教授的所有测试,但是,我需要注意隐藏的测试。这是我不确定的TCP标志。它在索引47中工作,但不知道为什么,应该是46.(以太网报头(14)+ IPv4报头(20)+ TCP报头(13)-1中的第13个字节(考虑从0开始的数组)= 46)。这是一个侥幸,它在现场47工作?

这是我的代码:

#include <pcap/pcap.h>
#include <stdlib.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
/*
 * Most of this file is the background functionality to open a capture file or to
 * open an inteface for a live capture. You can ignore all this unless you are
 * interested in an example of how pcap works.
 *
 * To use the file, simply insert your code in the "Put your code here" section and
 * create a Makefile for compilation.
 */

/* Maximum time that the OS will buffer packets before giving them to your program. */
#define MAX_BUFFER_TIME_MS (300)

/* Maximum time the program will wait for a packet during live capture.
 * Measured in MAX_BUFFER_TIME_MS units. Program closes when it expires. */
#define MAX_IDLE_TIME 100 /* 100*MAX_BUFFER_TIME_MS idle time at most */

/* Function that creates the structures necessary to perform a packet capture and
 * determines capture source depending on arguments. Function will terminate the
 * program on error, so return value always valid. */
pcap_t* setup_capture(int argc, char *argv[], char *use_file);

/* Cleanup the state of the capture. */
void cleanup_capture(pcap_t *handle);

/* Check for abnormal conditions during capture.
 * 1 returned if a packet is ready, 0 if a packet is not available.
 * Terminates program if an unrecoverable error occurs. */
char valid_capture(int return_value, pcap_t *pcap_handle, char use_file);

int main(int argc, char *argv[]) {

  pcap_t *pcap_handle = NULL;             /* Handle for PCAP library */
  struct pcap_pkthdr *packet_hdr = NULL;  /* Packet header from PCAP */
  const u_char *packet_data = NULL;       /* Packet data from PCAP */
  int ret = 0;                            /* Return value from library calls */
  char use_file = 0;                      /* Flag to use file or live capture */

  /* Setup the capture and get the valid handle. */
  pcap_handle = setup_capture(argc, argv, &use_file);

  /* Loop through all the packets in the trace file.
   * ret will equal -2 when the trace file ends.
   * ret will never equal -2 for a live capture. */
  ret = pcap_next_ex(pcap_handle, &packet_hdr, &packet_data);

  struct ether_header
  {
    u_int8_t  ether_dhost[6];   /* destination eth addr */
    u_int8_t  ether_shost[6];   /* source ether addr    */
    u_int16_t ether_type;               /* packet type ID field */
  };
  struct ether_header *eptr;
  char src[INET_ADDRSTRLEN];
  char dst[INET_ADDRSTRLEN];
  char src6[INET6_ADDRSTRLEN];
  char dst6[INET6_ADDRSTRLEN];

  while( ret != -2 ) {
    if( valid_capture(ret, pcap_handle, use_file) ){
      eptr = (struct ether_header *) packet_data;
      fprintf(stdout,"%s -> ",ether_ntoa((const struct ether_addr *)&eptr->ether_shost));
      fprintf(stdout,"%s \n",ether_ntoa((const struct ether_addr *)&eptr->ether_dhost));
      if(packet_data[12] == 0x08 && packet_data[13] == 0x00)
      {
        printf("    [IPv4] ");
        fprintf(stdout,"%s -> ", inet_ntop(AF_INET,(const void *)packet_data+26,src,INET_ADDRSTRLEN));
        fprintf(stdout,"%s\n", inet_ntop(AF_INET,(const void *)packet_data+30,dst,INET_ADDRSTRLEN));
        if(packet_data[23] == 0x06)
        {
          printf("    [TCP] %d -> ",packet_data[34]*256+packet_data[35]);
          printf("%d ",packet_data[36]*256+packet_data[37]);
        //  printf("%02X ",packet_data[47]); //print out value of flag;
           if(packet_data[47] & (1!=0))
             printf("FIN \n");
             else if((packet_data[47] == 0x02 || packet_data[47] == 0x12) & (2!=0))
             printf("SYN \n");

             else{
             printf("\n");
             }

        }
        else if(packet_data[23] == 0x11)
        {
          printf("    [UDP] %d -> ",packet_data[34]*256+packet_data[35]);
          printf("%d \n",packet_data[36]*256+packet_data[37]);
        }
        else{
          printf("    [%d] \n",packet_data[23]);
        }
      }
      else if(packet_data[12] == 0x86 && packet_data[13] == 0xdd)
      {

        printf("    [IPv6] ");
        printf("%s -> ", inet_ntop(AF_INET6, (const void *)packet_data+22, src6, INET6_ADDRSTRLEN));
        printf("%s \n", inet_ntop(AF_INET6, (const void *)packet_data+38, dst6, INET6_ADDRSTRLEN));

        if(packet_data[20] == 0x06)
        {
          printf("    [TCP] %d -> ",packet_data[54]*256+packet_data[55]);
          printf("%d ",packet_data[56]*256+packet_data[57]);
         // printf("%02X ",packet_data[67]); //print out value of flag

             if(packet_data[67] & (1!=0))
             printf("FIN \n");
             else if((packet_data[67] == 0x02 || packet_data[67] == 0x12) & (2!=0))
             printf("SYN \n");
             else{

          printf("\n");
          }



        }
        else if(packet_data[20] == 0x11)
        {

          printf("    [UDP] %d -> ",packet_data[54]*256+packet_data[55]);
          printf("%d \n",packet_data[56]*256+packet_data[57]);
        }
        else{
          printf("    [%d] \n",packet_data[20]);
        }
      } else {
        fprintf(stdout,"    [%d] \n",ntohs(eptr->ether_type));
      }
    }
    /* Get the next packet */
    ret = pcap_next_ex(pcap_handle, &packet_hdr, &packet_data);
  }

  cleanup_capture(pcap_handle);
  return 0;
}

pcap_t* setup_capture(int argc, char *argv[], char *use_file) {
  char *trace_file = NULL;                /* Trace file to process */
  pcap_t *pcap_handle = NULL;             /* Handle for PCAP library to return */
  char pcap_buff[PCAP_ERRBUF_SIZE];       /* Error buffer used by pcap functions */
  char *dev_name = NULL;                  /* Device name for live capture */

  /* Check command line arguments */
  if( argc > 2 ) {
    fprintf(stderr, "Usage: %s [trace_file]\n", argv[0]);
    exit(-1);
  }
  else if( argc > 1 ){
    *use_file = 1;
    trace_file = argv[1];
  }
  else {
    *use_file = 0;
  }

  /* Open the trace file, if appropriate */
  if( *use_file ){
    pcap_handle = pcap_open_offline(trace_file, pcap_buff);
    if( pcap_handle == NULL ){
      fprintf(stderr, "Error opening trace file \"%s\": %s\n", trace_file, pcap_buff);
      exit(-1);
    }
  }
  /* Lookup and open the default device if trace file not used */
  else{
    dev_name = pcap_lookupdev(pcap_buff);
    if( dev_name == NULL ){
      fprintf(stderr, "Error finding default capture device: %s\n", pcap_buff);
      exit(-1);
    }

    /* Use buffer length as indication of warning, per pcap_open_live(3). */
    pcap_buff[0] = 0;

    pcap_handle = pcap_open_live(dev_name, BUFSIZ, 1, MAX_BUFFER_TIME_MS, pcap_buff);
    if( pcap_handle == NULL ){
      fprintf(stderr, "Error opening capture device %s: %s\n", dev_name, pcap_buff);
      exit(-1);
    }
    if( pcap_buff[0] != 0 ) {
      printf("Warning: %s\n", pcap_buff);
    }

    printf("Capturing on interface '%s'\n", dev_name);
  }

  return pcap_handle;

}

void cleanup_capture(pcap_t *handle) {
  /* Close the trace file or device */
  pcap_close(handle);
}

char valid_capture(int return_value, pcap_t *pcap_handle, char use_file) {
  static int idle_count = 0;  /* Count of idle periods with no packets */
  char ret = 0;               /* Return value, invalid by default */

  /* A general error occurred */
  if( return_value == -1 ) {
    pcap_perror(pcap_handle, "Error processing packet:");
    cleanup_capture(pcap_handle);
    exit(-1);
  }

  /* Timeout occured for a live packet capture */
  else if( (return_value == 0) && (use_file == 0) ){
    if( ++idle_count >= MAX_IDLE_TIME ){
      printf("Timeout waiting for additional packets on interface\n");
      cleanup_capture(pcap_handle);
      exit(0);
    }
  }

  /* Unexpected/unknown return value */
  else if( return_value != 1 ) {
    fprintf(stderr, "Unexpected return value (%i) from pcap_next_ex()\n", return_value);
    cleanup_capture(pcap_handle);
    exit(-1);
  }
  /* Normal operation, packet arrived */
  else{
    idle_count = 0;
    ret = 1;
  }

  return ret;
}

这里有几个样本打印输出:(左边是教授的结果,右边是我的,我有额外的打印输出来查看阵列中那个位置的内容)。感谢

0:0:86:5:80:da -> 0:60:97:7:69:ea                           0:0:86:5:80:da -> 0:60:97:7:69:ea 
    [IPv6] 3ffe:507:0:1:200:86ff:fe05:80da -> 3ffe:501:410:0:2c0:dfff:fe47:33e          [IPv6] 3ffe:507:0:1:200:86ff:fe05:80da -> 3ffe:501:410:0:2c0:dfff:fe47:33e 
    [TCP] 1022 -> 22 SYN                                |       [TCP] 1022 -> 22 02 SYN 
0:60:97:7:69:ea -> 0:0:86:5:80:da                           0:60:97:7:69:ea -> 0:0:86:5:80:da 
    [IPv6] 3ffe:501:410:0:2c0:dfff:fe47:33e -> 3ffe:507:0:1:200:86ff:fe05:80da          [IPv6] 3ffe:501:410:0:2c0:dfff:fe47:33e -> 3ffe:507:0:1:200:86ff:fe05:80da 
    [TCP] 22 -> 1022 SYN                                |       [TCP] 22 -> 1022 12 SYN 

1 个答案:

答案 0 :(得分:1)

以下是如何找到TCP标志:

如果我们假设我们正在讨论以太网,那么以太网帧头将是14个字节:一个6字节的目标,后跟一个6字节的源,然后是一个2字节的以太网类型(对于802.3 / SNAP / Ethernet II,这是最有可能的)

如果从帧开头偏移12/13处的Ethertype包含0x0800,则表示您正在查看TCP / IP。

 if(frame[12]==0x08 && frame[13]==0x00) { /* IP packet inside */ }

假设你有一个IP Ethertype,下一个字节将包含两个半字节大小的字段:IP版本号(可能是你的0x40),然后是IP头长度(可能是0x05)。把那些小吃放在一起,你就会有0x45坐在那个领域。检查该字段是非常重要的。你可以像这样掩盖上半字节:

  ihl = frame[14]&0x0f;

获取IP头长度字段。此号码将告诉您在哪里可以找到下一个协议层的标头。通常你会有一个5(20字节标题),但如果有IP选项,这个数字会更大。让我们从这里得到这个数字并计算:

  embedded_protocol_header = frame[ihl * 4];

接下来,您应该验证您确实拥有TCP数据包。这可以通过检查IP头中的字节偏移9来验证:

  ip_header_start = frame[14];
  embedded_protocol = ip_header_start[9];
  if(embedded_protocol == 6) { tcp_header = embedded_protocol_header; }

现在我们知道它是TCP,我们可以获取TCP标志。这些将在TCP标题中的偏移量为13:

  tcp_flags = tcp_header[13];

要检查SYN / ACK位,您可以屏蔽其他所有内容:

  synack = tcp_flags & 0x3f;

您现在可以检查它是否是SYN ACK:

  if(synack == 0x12) { /* SYN and ACK were set */

您可能想知道上面的0x3f掩码。原因是如果系统支持ECN,则TCP标志中的两个高位用于ECN。如果支持,则在这些位中的3次握手期间以及IP报头的TOS字节中的两个低位比特(差分服务字节)中发生ECN协商。而不是处理所有可能的情况,最简单的方法是完全关闭这些位并检查您是否仍然有SYN和ACK。