pcap.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include "esp_log.h"
  10. #include "esp_check.h"
  11. #include "pcap.h"
  12. static const char *TAG = "pcap";
  13. #define PCAP_MAGIC_BIG_ENDIAN 0xA1B2C3D4 /*!< Big-Endian */
  14. #define PCAP_MAGIC_LITTLE_ENDIAN 0xD4C3B2A1 /*!< Little-Endian */
  15. typedef struct pcap_file_t pcap_file_t;
  16. /**
  17. * @brief Pcap File Header
  18. *
  19. */
  20. typedef struct {
  21. uint32_t magic; /*!< Magic Number */
  22. uint16_t major; /*!< Major Version */
  23. uint16_t minor; /*!< Minor Version */
  24. uint32_t zone; /*!< Time Zone Offset */
  25. uint32_t sigfigs; /*!< Timestamp Accuracy */
  26. uint32_t snaplen; /*!< Max Length to Capture */
  27. uint32_t link_type; /*!< Link Layer Type */
  28. } pcap_file_header_t;
  29. /**
  30. * @brief Pcap Packet Header
  31. *
  32. */
  33. typedef struct {
  34. uint32_t seconds; /*!< Number of seconds since January 1st, 1970, 00:00:00 GMT */
  35. uint32_t microseconds; /*!< Number of microseconds when the packet was captured (offset from seconds) */
  36. uint32_t capture_length; /*!< Number of bytes of captured data, no longer than packet_length */
  37. uint32_t packet_length; /*!< Actual length of current packet */
  38. } pcap_packet_header_t;
  39. /**
  40. * @brief Pcap Runtime Handle
  41. *
  42. */
  43. struct pcap_file_t {
  44. FILE *file; /*!< File handle */
  45. pcap_link_type_t link_type; /*!< Pcap Link Type */
  46. unsigned int major_version; /*!< Pcap version: major */
  47. unsigned int minor_version; /*!< Pcap version: minor */
  48. unsigned int time_zone; /*!< Pcap timezone code */
  49. uint32_t endian_magic; /*!< Magic value related to endian format */
  50. };
  51. esp_err_t pcap_new_session(const pcap_config_t *config, pcap_file_handle_t *ret_pcap)
  52. {
  53. esp_err_t ret = ESP_OK;
  54. pcap_file_t *pcap = NULL;
  55. ESP_GOTO_ON_FALSE(config && ret_pcap, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
  56. ESP_GOTO_ON_FALSE(config->fp, ESP_ERR_INVALID_ARG, err, TAG, "pcap file handle can't be NULL");
  57. pcap = calloc(1, sizeof(pcap_file_t));
  58. ESP_GOTO_ON_FALSE(pcap, ESP_ERR_NO_MEM, err, TAG, "no mem for pcap file object");
  59. pcap->file = config->fp;
  60. pcap->major_version = config->major_version;
  61. pcap->minor_version = config->minor_version;
  62. pcap->endian_magic = config->flags.little_endian ? PCAP_MAGIC_LITTLE_ENDIAN : PCAP_MAGIC_BIG_ENDIAN;
  63. pcap->time_zone = config->time_zone;
  64. *ret_pcap = pcap;
  65. return ret;
  66. err:
  67. if (pcap) {
  68. free(pcap);
  69. }
  70. return ret;
  71. }
  72. esp_err_t pcap_del_session(pcap_file_handle_t pcap)
  73. {
  74. ESP_RETURN_ON_FALSE(pcap, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  75. if (pcap->file) {
  76. fclose(pcap->file);
  77. pcap->file = NULL;
  78. }
  79. free(pcap);
  80. return ESP_OK;
  81. }
  82. esp_err_t pcap_write_header(pcap_file_handle_t pcap, pcap_link_type_t link_type)
  83. {
  84. ESP_RETURN_ON_FALSE(pcap, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  85. /* Write Pcap File header */
  86. pcap_file_header_t header = {
  87. .magic = pcap->endian_magic,
  88. .major = pcap->major_version,
  89. .minor = pcap->minor_version,
  90. .zone = pcap->time_zone,
  91. .sigfigs = 0,
  92. .snaplen = 0x40000,
  93. .link_type = link_type,
  94. };
  95. size_t real_write = fwrite(&header, sizeof(header), 1, pcap->file);
  96. ESP_RETURN_ON_FALSE(real_write == 1, ESP_FAIL, TAG, "write pcap file header failed");
  97. /* Save the link type to pcap file object */
  98. pcap->link_type = link_type;
  99. /* Flush content in the buffer into device */
  100. fflush(pcap->file);
  101. return ESP_OK;
  102. }
  103. esp_err_t pcap_capture_packet(pcap_file_handle_t pcap, void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds)
  104. {
  105. ESP_RETURN_ON_FALSE(pcap && payload, ESP_ERR_INVALID_ARG, TAG, "invalid argumnet");
  106. size_t real_write = 0;
  107. pcap_packet_header_t header = {
  108. .seconds = seconds,
  109. .microseconds = microseconds,
  110. .capture_length = length,
  111. .packet_length = length
  112. };
  113. real_write = fwrite(&header, sizeof(header), 1, pcap->file);
  114. ESP_RETURN_ON_FALSE(real_write == 1, ESP_FAIL, TAG, "write packet header failed");
  115. real_write = fwrite(payload, sizeof(uint8_t), length, pcap->file);
  116. ESP_RETURN_ON_FALSE(real_write == length, ESP_FAIL, TAG, "write packet payload failed");
  117. /* Flush content in the buffer into device */
  118. fflush(pcap->file);
  119. return ESP_OK;
  120. }
  121. esp_err_t pcap_print_summary(pcap_file_handle_t pcap, FILE *print_file)
  122. {
  123. esp_err_t ret = ESP_OK;
  124. long size = 0;
  125. char *packet_payload = NULL;
  126. ESP_RETURN_ON_FALSE(pcap && print_file, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  127. // get file size
  128. fseek(pcap->file, 0L, SEEK_END);
  129. size = ftell(pcap->file);
  130. fseek(pcap->file, 0L, SEEK_SET);
  131. // file empty is allowed, so return ESP_OK
  132. ESP_RETURN_ON_FALSE(size, ESP_OK, TAG, "pcap file is empty");
  133. // packet index (by bytes)
  134. uint32_t index = 0;
  135. pcap_file_header_t file_header;
  136. size_t real_read = fread(&file_header, sizeof(pcap_file_header_t), 1, pcap->file);
  137. ESP_RETURN_ON_FALSE(real_read == 1, ESP_FAIL, TAG, "read pcap file header failed");
  138. index += sizeof(pcap_file_header_t);
  139. //print pcap header information
  140. fprintf(print_file, "------------------------------------------------------------------------\n");
  141. fprintf(print_file, "Pcap packet Head:\n");
  142. fprintf(print_file, "------------------------------------------------------------------------\n");
  143. fprintf(print_file, "Magic Number: %x\n", file_header.magic);
  144. fprintf(print_file, "Major Version: %d\n", file_header.major);
  145. fprintf(print_file, "Minor Version: %d\n", file_header.minor);
  146. fprintf(print_file, "SnapLen: %d\n", file_header.snaplen);
  147. fprintf(print_file, "LinkType: %d\n", file_header.link_type);
  148. fprintf(print_file, "------------------------------------------------------------------------\n");
  149. uint32_t packet_num = 0;
  150. pcap_packet_header_t packet_header;
  151. while (index < size) {
  152. real_read = fread(&packet_header, sizeof(pcap_packet_header_t), 1, pcap->file);
  153. ESP_GOTO_ON_FALSE(real_read == 1, ESP_FAIL, err, TAG, "read pcap packet header failed");
  154. // print packet header information
  155. fprintf(print_file, "Packet %d:\n", packet_num);
  156. fprintf(print_file, "Timestamp (Seconds): %d\n", packet_header.seconds);
  157. fprintf(print_file, "Timestamp (Microseconds): %d\n", packet_header.microseconds);
  158. fprintf(print_file, "Capture Length: %d\n", packet_header.capture_length);
  159. fprintf(print_file, "Packet Length: %d\n", packet_header.packet_length);
  160. size_t payload_length = packet_header.capture_length;
  161. packet_payload = malloc(payload_length);
  162. ESP_GOTO_ON_FALSE(packet_payload, ESP_ERR_NO_MEM, err, TAG, "no mem to save packet payload");
  163. real_read = fread(packet_payload, payload_length, 1, pcap->file);
  164. ESP_GOTO_ON_FALSE(real_read == 1, ESP_FAIL, err, TAG, "read payload error");
  165. // print packet information
  166. // currently only print info for 802.11
  167. if (file_header.link_type == PCAP_LINK_TYPE_802_11) {
  168. fprintf(print_file, "Packet Type: %2x\n", (packet_payload[0] >> 4) & 0x03);
  169. fprintf(print_file, "Packet Subtype: %2x\n", packet_payload[0] & 0x0F);
  170. fprintf(print_file, "Destination: ");
  171. for (int j = 0; j < 5; j++) {
  172. fprintf(print_file, "%2x ", packet_payload[4 + j]);
  173. }
  174. fprintf(print_file, "%2x\n", packet_payload[9]);
  175. fprintf(print_file, "Source: ");
  176. for (int j = 0; j < 5; j++) {
  177. fprintf(print_file, "%2x ", packet_payload[10 + j]);
  178. }
  179. fprintf(print_file, "%2x\n", packet_payload[15]);
  180. fprintf(print_file, "------------------------------------------------------------------------\n");
  181. } else if (file_header.link_type == PCAP_LINK_TYPE_ETHERNET){
  182. fprintf(print_file, "Destination: ");
  183. for (int j = 0; j < 5; j++) {
  184. fprintf(print_file, "%2x ", packet_payload[j]);
  185. }
  186. fprintf(print_file, "%2x\n", packet_payload[5]);
  187. fprintf(print_file, "Source: ");
  188. for (int j = 0; j < 5; j++) {
  189. fprintf(print_file, "%2x ", packet_payload[6 + j]);
  190. }
  191. fprintf(print_file, "%2x\n", packet_payload[11]);
  192. fprintf(print_file, "Type: 0x%x\n", packet_payload[13] | (packet_payload[12] << 8));
  193. fprintf(print_file, "------------------------------------------------------------------------\n");
  194. }
  195. else {
  196. fprintf(print_file, "Unknown link type:%d\n", file_header.link_type);
  197. fprintf(print_file, "------------------------------------------------------------------------\n");
  198. }
  199. free(packet_payload);
  200. packet_payload = NULL;
  201. index += packet_header.capture_length + sizeof(pcap_packet_header_t);
  202. packet_num ++;
  203. }
  204. fprintf(print_file, "Pcap packet Number: %d\n", packet_num);
  205. fprintf(print_file, "------------------------------------------------------------------------\n");
  206. return ret;
  207. err:
  208. if (packet_payload) {
  209. free(packet_payload);
  210. }
  211. return ret;
  212. }