packet-analyzer

a network packet analyzer written in C


packet-analyzer / analyzer.c

analyzer.c (3.7K) raw | download
1#define _DEFAULT_SOURCE
2#define _POSIX_C_SOURCE 200809L
3#include <sys/socket.h>
4#include <netpacket/packet.h>
5#include <net/if.h>
6#include <linux/if_ether.h>
7#include <netinet/ip.h>
8#include <netinet/tcp.h>
9#include <netinet/udp.h>
10#include <netinet/ip_icmp.h>
11#include <arpa/inet.h>
12#include <unistd.h>
13#include <errno.h>
14#include <stdio.h>
15#include <string.h>
16
17static void
18analyze_packet(const unsigned char *packet, size_t size)
19{
20 struct ethhdr ethernet;
21 struct iphdr ip;
22 char source[INET_ADDRSTRLEN], destination[INET_ADDRSTRLEN];
23 const unsigned char *payload;
24 size_t header_len, total_len, payload_len;
25 unsigned int fragment;
26
27 if (size < sizeof(ethernet)) return;
28 memcpy(&ethernet, packet, sizeof(ethernet));
29 if (ntohs(ethernet.h_proto) != ETH_P_IP) return;
30 packet += sizeof(ethernet);
31 size -= sizeof(ethernet);
32 if (size < sizeof(ip)) return;
33 /* Ethernet headers can leave the IP header unaligned. */
34 memcpy(&ip, packet, sizeof(ip));
35 if (ip.version != 4 || ip.ihl < 5) return;
36 header_len = (size_t)ip.ihl * 4;
37 total_len = ntohs(ip.tot_len);
38 if (total_len < header_len || total_len > size) return;
39 fragment = ntohs(ip.frag_off);
40 if (fragment & IP_OFFMASK) return;
41 payload = packet + header_len;
42 payload_len = total_len - header_len;
43 if (inet_ntop(AF_INET, &ip.saddr, source, sizeof(source)) == NULL ||
44 inet_ntop(AF_INET, &ip.daddr, destination, sizeof(destination)) == NULL)
45 return;
46
47 switch (ip.protocol) {
48 case IPPROTO_TCP: {
49 struct tcphdr tcp;
50 size_t tcp_len;
51 if (payload_len < sizeof(tcp)) return;
52 memcpy(&tcp, payload, sizeof(tcp));
53 tcp_len = (size_t)tcp.doff * 4;
54 if (tcp_len < sizeof(tcp) || tcp_len > payload_len) return;
55 printf("TCP %s:%u -> %s:%u\n", source, (unsigned int)ntohs(tcp.source),
56 destination, (unsigned int)ntohs(tcp.dest));
57 break;
58 }
59 case IPPROTO_UDP: {
60 struct udphdr udp;
61 size_t udp_len;
62 if (payload_len < sizeof(udp)) return;
63 memcpy(&udp, payload, sizeof(udp));
64 udp_len = ntohs(udp.len);
65 if (udp_len < sizeof(udp) || (!(fragment & IP_MF) && udp_len > payload_len))
66 return;
67 printf("UDP %s:%u -> %s:%u\n", source, (unsigned int)ntohs(udp.source),
68 destination, (unsigned int)ntohs(udp.dest));
69 break;
70 }
71 case IPPROTO_ICMP: {
72 struct icmphdr icmp;
73 if (payload_len < sizeof(icmp)) return;
74 memcpy(&icmp, payload, sizeof(icmp));
75 printf("ICMP %s -> %s type %u code %u\n", source, destination,
76 (unsigned int)icmp.type, (unsigned int)icmp.code);
77 break;
78 }
79 }
80}
81
82int
83main(int argc, char **argv)
84{
85 unsigned char packet[65536 + ETH_HLEN];
86 struct sockaddr_ll address = {0};
87 unsigned int index;
88 int fd, status = 0;
89
90 if (argc != 2) {
91 fprintf(stderr, "usage: %s interface\n", argv[0]);
92 return 1;
93 }
94 index = if_nametoindex(argv[1]);
95 if (index == 0) { perror(argv[1]); return 1; }
96 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
97 if (fd < 0) { perror("socket"); return 1; }
98 address.sll_family = AF_PACKET;
99 address.sll_protocol = htons(ETH_P_ALL);
100 address.sll_ifindex = (int)index;
101 if (bind(fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
102 perror("bind");
103 close(fd);
104 return 1;
105 }
106 for (;;) {
107 ssize_t n = recvfrom(fd, packet, sizeof(packet), 0, NULL, NULL);
108 if (n < 0 && errno == EINTR) continue;
109 if (n < 0) { perror("recvfrom"); status = 1; break; }
110 analyze_packet(packet, (size_t)n);
111 if (fflush(stdout) == EOF) { perror("stdout"); status = 1; break; }
112 }
113 close(fd);
114 return status;
115}