source: mainline/uspace/app/pcapcat/eth_parser.c@ caac052

Last change on this file since caac052 was caac052, checked in by Nataliia Korop <n.corop08@…>, 10 months ago

pcapcat: docs, no literals, time fix in pcap lib

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2024 Nataliia Korop
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup pcapcat
30 * @{
31 */
32/** @file Implementation of functions for parsing PCAP file of LinkType 1 (LINKTYPE_ETHERNET).
33 */
34
35#include <stdint.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <stdbool.h>
39#include <str.h>
40#include <pcap.h>
41#include "eth_parser.h"
42
43#define ETH_ADDR_SIZE 6
44#define IPV4_ADDR_SIZE 4
45#define TCP_PORT_SIZE 2
46
47#define ETHER_TYPE_ARP 0x0806
48#define ETHER_TYPE_IP4 0x0800
49#define ETHER_TYPE_IP6 0x86DD
50
51#define BYTE_SIZE 8
52#define HDR_SIZE_COEF 4
53#define LOWER_4_BITS 0xf
54
55#define IP_PROTOCOL_TCP 0x06
56#define IP_PROTOCOL_UDP 0x11
57#define IP_PROTOCOL_ICMP 0x01
58
59#define TCP_TEXT "TCP"
60#define IP_TEXT "IP"
61#define MAC_TEXT "MAC"
62#define ARP_TEXT "ARP"
63#define IPV4_TEXT "IPv4"
64#define IPV6_TEXT "IPv6"
65#define MALFORMED_PACKET "packet is malformed.\n"
66
67#define PRINT_IP(msg, ip_addr, spaces) printf("%s %s: %d.%d.%d.%d%s", msg, IP_TEXT, ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3], spaces)
68#define PRINT_MAC(msg, mac, spaces) printf("%s %s: %02x:%02x:%02x:%02x:%02x:%02x%s", msg, MAC_TEXT, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], spaces)
69#define BIG_END_16(buffer, idx) buffer[idx] << BYTE_SIZE | buffer[idx + 1]
70
71/** Read count bytes from char buffer.
72 * @param buffer of bytes to read from.
73 * @param start_idx index of the first byte to read.
74 * @param count number of byte to read.
75 * @param dst destination buffer.
76 */
77static void read_from_buffer(unsigned char *buffer, size_t start_idx, size_t count, uint8_t *dst)
78{
79 for (size_t i = start_idx; i < start_idx + count; ++i) {
80 dst[i - start_idx] = buffer[i];
81 }
82}
83
84/** Parse ARP packet and print out addresses.
85 * @param buffer ARP packet.
86 * @param size Size of the packet.
87 */
88static void parse_arp(unsigned char *buffer, size_t size)
89{
90 size_t sender_mac_offset = 22;
91 size_t sender_ip_offset = 28;
92 size_t target_mac_offset = 32;
93 size_t target_ip_offset = 38;
94 if (size < target_ip_offset + IPV4_ADDR_SIZE) {
95 printf("%s %s", ARP_TEXT, MALFORMED_PACKET);
96 return;
97 }
98
99 uint8_t sender_mac[ETH_ADDR_SIZE];
100 uint8_t sender_ip[IPV4_ADDR_SIZE];
101 uint8_t target_mac[ETH_ADDR_SIZE];
102 uint8_t target_ip[IPV4_ADDR_SIZE];
103
104 read_from_buffer(buffer, sender_mac_offset, ETH_ADDR_SIZE, sender_mac);
105 read_from_buffer(buffer, sender_ip_offset, IPV4_ADDR_SIZE, sender_ip);
106 read_from_buffer(buffer, target_mac_offset, ETH_ADDR_SIZE, target_mac);
107 read_from_buffer(buffer, target_ip_offset, IPV4_ADDR_SIZE, target_ip);
108
109 PRINT_MAC("Sender", sender_mac, ", ");
110 PRINT_IP("Sender", sender_ip, " ");
111 PRINT_MAC("Target", target_mac, ", ");
112 PRINT_IP("Target", target_ip, "\n");
113}
114
115/** Parce TCP and print ports.
116 * @param buffer TCP segment.
117 * @param size of the buffer.
118 */
119static void parse_tcp(unsigned char *buffer, size_t size)
120{
121 size_t src_port_offset = 34;
122 size_t dst_port_offset = 36;
123
124 if (size < dst_port_offset + TCP_PORT_SIZE) {
125 printf("%s %s\n", TCP_TEXT, MALFORMED_PACKET);
126 return;
127 }
128
129 uint16_t src_port = BIG_END_16(buffer, src_port_offset);
130 uint16_t dst_port = BIG_END_16(buffer, dst_port_offset);
131 printf(" [%s] source port: %d, destination port: %d\n", TCP_TEXT, src_port, dst_port);
132}
133
134/** Parse IP and print interesting parts.
135 * @param buffer IP packet.
136 * @param size size of the buffer.
137 * @param verbose verbosity flag.
138 */
139static void parse_ip(unsigned char *buffer, size_t size, bool verbose)
140{
141 uint16_t total_length;
142 uint8_t header_length;
143 uint16_t payload_length;
144 uint8_t ip_protocol;
145 uint8_t src_ip[IPV4_ADDR_SIZE];
146 uint8_t dst_ip[IPV4_ADDR_SIZE];
147
148 size_t hdr_length_offset = 14;
149 size_t total_len_offset = 16;
150 size_t protocol_offset = 23;
151 size_t src_ip_offset = 26;
152 size_t dst_ip_offset = 30;
153
154 if (size < dst_ip_offset + IPV4_ADDR_SIZE) {
155 printf("%s %s", IP_TEXT, MALFORMED_PACKET);
156 return;
157 }
158
159 header_length = (buffer[hdr_length_offset] & LOWER_4_BITS) * HDR_SIZE_COEF;
160 total_length = BIG_END_16(buffer, total_len_offset);
161 payload_length = total_length - header_length;
162 ip_protocol = buffer[protocol_offset];
163
164 read_from_buffer(buffer, src_ip_offset, IPV4_ADDR_SIZE, src_ip);
165 read_from_buffer(buffer, dst_ip_offset, IPV4_ADDR_SIZE, dst_ip);
166
167 printf("%s header: %dB, payload: %dB, protocol: 0x%x, ", IP_TEXT, header_length, payload_length, ip_protocol);
168 PRINT_IP("Source", src_ip, ", ");
169 PRINT_IP("Destination", dst_ip, "\n");
170
171 if (verbose && ip_protocol == IP_PROTOCOL_TCP) {
172 parse_tcp(buffer, size);
173 }
174}
175
176/** Parse ethernnet frame based on eth_type of the frame.
177 * @param data Ethernet frame.
178 * @param size Size of the frame.
179 * @param verbose_flag Verbosity flag.
180 */
181static void parse_eth_frame(void *data, size_t size, bool verbose_flag)
182{
183 unsigned char* buffer = (unsigned char*)data;
184
185 size_t eth_type_offset = 12;
186 uint16_t protocol = BIG_END_16(buffer, eth_type_offset);
187
188 switch (protocol){
189 case ETHER_TYPE_ARP:
190 printf("[%s] ", ARP_TEXT);
191 parse_arp(buffer, size);
192 break;
193 case ETHER_TYPE_IP4:
194 printf("[%s] ", IPV4_TEXT);
195 parse_ip(buffer, size, verbose_flag);
196 break;
197 case ETHER_TYPE_IP6:
198 printf("[%s]\n", IPV6_TEXT);
199 break;
200 default:
201 printf("[0x%x]\n", protocol);
202 break;
203 }
204}
205
206/** Parse file header of PCAP file.
207 * @param hdr PCAP header structure.
208 */
209void eth_parse_header(pcap_file_header_t *hdr)
210{
211 printf("LinkType: %d\n", hdr->additional);
212 printf("Magic number: 0x%x\n", hdr->magic_number);
213}
214
215/** Parse PCAP file.
216 * @param pcap_file file of PCAP format with dumped packets.
217 * @param count number of packets to be parsed and printed from file (if -1 all packets are printed).
218 * @param verbose_flag verbosity flag.
219 */
220void eth_parse_frames(FILE *pcap_file, int count, bool verbose_flag)
221{
222 pcap_packet_header_t hdr;
223
224 size_t read_bytes = fread(&hdr, 1, sizeof(pcap_packet_header_t), pcap_file);
225 int packet_index = 1;
226 while (read_bytes > 0)
227 {
228 if (read_bytes < sizeof(pcap_packet_header_t)) {
229 printf("Error: Could not read enough bytes (read %zu bytes)\n", read_bytes);
230 return;
231 }
232
233 printf("%04d) ", packet_index++);
234
235 void *data = malloc(hdr.captured_length);
236 read_bytes = fread(data, 1, (size_t)hdr.captured_length, pcap_file);
237 if (read_bytes < (size_t)hdr.captured_length) {
238 printf("Error: Could not read enough bytes (read %zu bytes)\n", read_bytes);
239 return;
240 }
241 parse_eth_frame(data, (size_t)hdr.captured_length, verbose_flag);
242 free(data);
243
244 //Read first count packets from file.
245 if (count != -1 && count == packet_index - 1) {
246 return;
247 }
248
249 memset(&hdr, 0, sizeof(pcap_packet_header_t));
250 read_bytes = fread(&hdr, 1, sizeof(pcap_packet_header_t), pcap_file);
251 }
252
253 fclose(pcap_file);
254}
255
256/** @}
257 */
Note: See TracBrowser for help on using the repository browser.