c - 从 pcap 打印出 TCP 标志信息

标签 c networking hex pcap

我正在编写一个程序来从 pcap 中的 header 中获取某些信息。我不确定我这样做是否正确。它适用于我教授的所有测试,但是,我需要注意一些隐藏的测试。这是我不确定的 TCP 标志。它在索引 47 中工作,但不知道为什么,应该是 46。(以太网 header (14)+ IPv4 header (20)+ TCP header 中的第 13 个字节(13)-1(考虑从 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 

最佳答案

以下是定位 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 以太网类型,下一个字节将包含两个半字节大小的字段:IP 版本号(对您来说可能是 0x40),然后是 IP header 长度(可能是 0x05)。将这些半字节放在一起,您将在该字段中找到 0x45。检查该字段非常重要。你可以像这样屏蔽掉上面的半字节:

  ihl = frame[14]&0x0f;

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

  embedded_protocol_header = frame[ihl * 4];

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

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

现在我们知道它是 TCP,我们可以获取 TCP 标志。这些将位于 TCP header 中的偏移量 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。如果支持,则 ECN 协商会在这些位和 IP header 的 TOS 字节(差分服务字节)中的两个低位中的 3 次握手中发生。最简单的方法不是处理所有可能的情况,而是完全关闭这些位并检查您是否还有 SYN 和 ACK。

关于c - 从 pcap 打印出 TCP 标志信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47613244/

相关文章:

c# - 计算热图颜色

c - 抑制函数中未使用参数的警告

c++ - 是否有任何 C 或 C++ 标准识别内存映射文件的存在?

c# - Directory.Exist - 查明是否超时或目录不存在

networking - 使用 PowerShell 从远程计算机发出请求

http - 为什么 SNDBUF 太低会破坏 HTTP?

javascript - 为什么 || JavaScript 中的 (or) 和 && (and) 运算符的行为与 C 中的不同(返回非 bool 值)?

指针到函数指针之间的转换错误

java - 如何将 RGB 编码和解码为十六进制

css - 具有十六进制值的多个背景的着色图像