source: mainline/uspace/app/pcapcat/eth_parser.c@ 46e2152

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

pcapcat: typos, small fixes, pcapctl: comments, docs

  • 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/** Offsets of interesting fields in packet. */
72
73#define ARP_SENDER_MAC 22
74#define ARP_SENDER_IP 28
75#define ARP_TARGET_MAC 32
76#define ARP_TARGET_IP 38
77
78#define TCP_SRC_PORT 34
79#define TCP_DST_PORT 36
80
81#define IP_HEADER_LEN 14
82#define IP_TOTAL_LEN 16
83#define IP_PROTOCOL 23
84#define IP_SRC_ADDR 26
85#define IP_DST_ADDR 30
86
87/** Read count bytes from char buffer.
88 * @param buffer of bytes to read from.
89 * @param start_idx index of the first byte to read.
90 * @param count number of byte to read.
91 * @param dst destination buffer.
92 */
93static void read_from_buffer(unsigned char *buffer, size_t start_idx, size_t count, uint8_t *dst)
94{
95 for (size_t i = start_idx; i < start_idx + count; ++i) {
96 dst[i - start_idx] = buffer[i];
97 }
98}
99
100/** Parse ARP packet and print out addresses.
101 * @param buffer ARP packet.
102 * @param size Size of the packet.
103 */
104static void parse_arp(unsigned char *buffer, size_t size)
105{
106 if (size < ARP_TARGET_IP + IPV4_ADDR_SIZE) {
107 printf("%s %s", ARP_TEXT, MALFORMED_PACKET);
108 return;
109 }
110
111 uint8_t sender_mac[ETH_ADDR_SIZE];
112 uint8_t sender_ip[IPV4_ADDR_SIZE];
113 uint8_t target_mac[ETH_ADDR_SIZE];
114 uint8_t target_ip[IPV4_ADDR_SIZE];
115
116 read_from_buffer(buffer, ARP_SENDER_MAC, ETH_ADDR_SIZE, sender_mac);
117 read_from_buffer(buffer, ARP_SENDER_IP, IPV4_ADDR_SIZE, sender_ip);
118 read_from_buffer(buffer, ARP_TARGET_MAC, ETH_ADDR_SIZE, target_mac);
119 read_from_buffer(buffer, ARP_TARGET_IP, IPV4_ADDR_SIZE, target_ip);
120
121 PRINT_MAC("Sender", sender_mac, ", ");
122 PRINT_IP("Sender", sender_ip, " ");
123 PRINT_MAC("Target", target_mac, ", ");
124 PRINT_IP("Target", target_ip, "\n");
125}
126
127/** Parce TCP and print ports.
128 * @param buffer TCP segment.
129 * @param size of the buffer.
130 */
131static void parse_tcp(unsigned char *buffer, size_t size)
132{
133 if (size < TCP_DST_PORT + TCP_PORT_SIZE) {
134 printf("%s %s\n", TCP_TEXT, MALFORMED_PACKET);
135 return;
136 }
137
138 uint16_t src_port = BIG_END_16(buffer, TCP_SRC_PORT);
139 uint16_t dst_port = BIG_END_16(buffer, TCP_DST_PORT);
140 printf(" [%s] source port: %d, destination port: %d\n", TCP_TEXT, src_port, dst_port);
141}
142
143/** Parse IP and print interesting parts.
144 * @param buffer IP packet.
145 * @param size size of the buffer.
146 * @param verbose verbosity flag.
147 */
148static void parse_ip(unsigned char *buffer, size_t size, bool verbose)
149{
150 uint16_t total_length;
151 uint8_t header_length;
152 uint16_t payload_length;
153 uint8_t ip_protocol;
154 uint8_t src_ip[IPV4_ADDR_SIZE];
155 uint8_t dst_ip[IPV4_ADDR_SIZE];
156
157 if (size < IP_DST_ADDR + IPV4_ADDR_SIZE) {
158 printf("%s %s", IP_TEXT, MALFORMED_PACKET);
159 return;
160 }
161
162 header_length = (buffer[IP_HEADER_LEN] & LOWER_4_BITS) * HDR_SIZE_COEF;
163 total_length = BIG_END_16(buffer, IP_TOTAL_LEN);
164 payload_length = total_length - header_length;
165 ip_protocol = buffer[IP_PROTOCOL];
166
167 read_from_buffer(buffer, IP_SRC_ADDR, IPV4_ADDR_SIZE, src_ip);
168 read_from_buffer(buffer, IP_DST_ADDR, IPV4_ADDR_SIZE, dst_ip);
169
170 printf("%s header: %dB, payload: %dB, protocol: 0x%x, ", IP_TEXT, header_length, payload_length, ip_protocol);
171 PRINT_IP("Source", src_ip, ", ");
172 PRINT_IP("Destination", dst_ip, "\n");
173
174 if (verbose && ip_protocol == IP_PROTOCOL_TCP) {
175 parse_tcp(buffer, size);
176 }
177}
178
179/** Parse ethernnet frame based on eth_type of the frame.
180 * @param data Ethernet frame.
181 * @param size Size of the frame.
182 * @param verbose_flag Verbosity flag.
183 */
184static void parse_eth_frame(void *data, size_t size, bool verbose_flag)
185{
186 unsigned char* buffer = (unsigned char*)data;
187
188 size_t eth_type_offset = 12;
189 uint16_t protocol = BIG_END_16(buffer, eth_type_offset);
190
191 switch (protocol){
192 case ETHER_TYPE_ARP:
193 printf("[%s] ", ARP_TEXT);
194 parse_arp(buffer, size);
195 break;
196 case ETHER_TYPE_IP4:
197 printf("[%s] ", IPV4_TEXT);
198 parse_ip(buffer, size, verbose_flag);
199 break;
200 case ETHER_TYPE_IP6:
201 printf("[%s]\n", IPV6_TEXT);
202 break;
203 default:
204 printf("[0x%x]\n", protocol);
205 break;
206 }
207}
208
209/** Parse file header of PCAP file.
210 * @param hdr PCAP header structure.
211 */
212void eth_parse_header(pcap_file_header_t *hdr)
213{
214 printf("LinkType: %d\n", hdr->additional);
215 printf("Magic number: 0x%x\n", hdr->magic_number);
216}
217
218/** Parse PCAP file.
219 * @param pcap_file file of PCAP format with dumped packets.
220 * @param count number of packets to be parsed and printed from file (if -1 all packets are printed).
221 * @param verbose_flag verbosity flag.
222 */
223void eth_parse_frames(FILE *pcap_file, int count, bool verbose_flag)
224{
225 pcap_packet_header_t hdr;
226
227 size_t read_bytes = fread(&hdr, 1, sizeof(pcap_packet_header_t), pcap_file);
228 int packet_index = 1;
229 while (read_bytes > 0)
230 {
231 if (read_bytes < sizeof(pcap_packet_header_t)) {
232 printf("Error: Could not read enough bytes (read %zu bytes)\n", read_bytes);
233 return;
234 }
235
236 printf("%04d) ", packet_index++);
237
238 void *data = malloc(hdr.captured_length);
239 read_bytes = fread(data, 1, (size_t)hdr.captured_length, pcap_file);
240 if (read_bytes < (size_t)hdr.captured_length) {
241 printf("Error: Could not read enough bytes (read %zu bytes)\n", read_bytes);
242 return;
243 }
244 parse_eth_frame(data, (size_t)hdr.captured_length, verbose_flag);
245 free(data);
246
247 //Read first count packets from file.
248 if (count != -1 && count == packet_index - 1) {
249 return;
250 }
251
252 memset(&hdr, 0, sizeof(pcap_packet_header_t));
253 read_bytes = fread(&hdr, 1, sizeof(pcap_packet_header_t), pcap_file);
254 }
255}
256
257/** @}
258 */
Note: See TracBrowser for help on using the repository browser.