Neale Pickett
·
2020-09-21
pcat.c
1/*
2 * pcat.c -- pcap to text
3 *
4 * Reads pcap on stdin, dumps text representation to stdout.
5 * This discards or ignores some parts of packets. If fidelity is a concern,
6 * deal directly with the original pcap.
7 *
8 * Output lines are of the form:
9 *
10 * PROTO SRC DST OPTS PAYLOAD
11 *
12
13 */
14
15#include <stdio.h>
16#include <stdint.h>
17#include "pcap.h"
18#include "stream.h"
19
20#define IPPROTO_TCP 6
21#define IPPROTO_UDP 17
22#define IPPROTO_ICMP 1
23
24#define TH_FIN 0x01
25#define TH_SYN 0x02
26#define TH_RST 0x04
27#define TH_PSH 0x08
28#define TH_ACK 0x10
29#define TH_URG 0x20
30
31void
32ip4_addr(char *addr_s, uint32_t addr)
33{
34 snprintf(addr_s, 16, "%u.%u.%u.%u", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr >> 0) & 0xff);
35}
36
37void
38print_nybble(uint8_t nybble)
39{
40 if (nybble < 10) {
41 putchar(nybble + '0');
42 } else {
43 putchar(nybble - 10 + 'a');
44 }
45}
46
47/* About 3x faster than printf("%02x", octet); */
48void
49printx(uint8_t octet)
50{
51 print_nybble(octet >> 4);
52 print_nybble(octet & 0xf);
53}
54
55void
56print_payload(struct stream *s)
57{
58 while (s->len) {
59 printx(read_uint8(s));
60 }
61}
62
63void
64process_tcp(struct stream *s, char *saddr_s, char *daddr_s)
65{
66 uint16_t sport = read_uint16(s);
67 uint16_t dport = read_uint16(s);
68 uint32_t seq = read_uint32(s);
69 uint32_t ack = read_uint32(s);
70 uint8_t off = read_uint8(s);
71 uint8_t hlen = (off >> 4) * 4;
72 uint8_t flags = read_uint8(s);
73 uint16_t window = read_uint16(s);
74 uint16_t chksum = read_uint16(s);
75 uint16_t urgent = read_uint16(s);
76
77 if (hlen < 20) {
78 printf("!");
79 }
80
81 printf("TCP\t%s,%u\t%s,%u\t%u,%u,%d\t", saddr_s, sport, daddr_s, dport, seq, ack, flags);
82}
83
84void
85process_udp(struct stream *s, char *saddr_s, char *daddr_s)
86{
87 uint16_t sport = read_uint16(s);
88 uint16_t dport = read_uint16(s);
89 uint16_t len = read_uint16(s);
90 uint16_t chksum = read_uint16(s);
91
92 printf("UDP\t%s,%u\t%s,%u\t0\t", saddr_s, sport, daddr_s, dport);
93}
94
95void
96process_icmp(struct stream *s, char *saddr_s, char *daddr_s)
97{
98 uint8_t type = read_uint8(s);
99 uint8_t code = read_uint8(s);
100 uint16_t checksum = read_uint16(s);
101
102 printf("ICMP\t%s\t%s\t%d,%d\t", saddr_s, daddr_s, type, code);
103}
104
105void
106process_ip4(struct stream *s)
107{
108 uint8_t vhl = read_uint8(s);
109 uint8_t ihl = (vhl & 0x0f) * 4;
110 uint8_t tos = read_uint8(s);
111 uint16_t length = read_uint16(s);
112 uint16_t id = read_uint16(s);
113 uint16_t off = read_uint16(s);
114 uint8_t ttl = read_uint8(s);
115 uint8_t proto = read_uint8(s);
116 uint16_t chksum = read_uint16(s);
117 uint32_t saddr = read_uint32(s);
118 uint32_t daddr = read_uint32(s);
119
120 char saddr_s[20];
121 char daddr_s[20];
122
123 ip4_addr(saddr_s, saddr);
124 ip4_addr(daddr_s, daddr);
125
126 // Ignore options
127 sskip(s, 20 - ihl);
128
129 // Force stream length to IP payload length
130 s->len = length - ihl;
131
132 switch (proto) {
133 case IPPROTO_TCP:
134 process_tcp(s, saddr_s, daddr_s);
135 break;
136 case IPPROTO_UDP:
137 process_udp(s, saddr_s, daddr_s);
138 break;
139 case IPPROTO_ICMP:
140 process_icmp(s, saddr_s, daddr_s);
141 break;
142 default:
143 printf("P%d\t%s\t%s\t", proto, saddr_s, daddr_s);
144 break;
145 }
146
147 print_payload(s);
148}
149
150
151void
152print_ethernet(struct stream *s)
153{
154 uint8_t saddr[6];
155 uint8_t daddr[6];
156 uint16_t ethertype;
157
158 sread(s, &saddr, sizeof(saddr));
159 sread(s, &daddr, sizeof(daddr));
160 ethertype = read_uint16(s);
161
162 if (ethertype == 0x8100) {
163 // VLAN
164 read_uint16(s);
165 ethertype = read_uint16(s);
166 }
167
168 switch (ethertype) {
169 case 0x0800: // IPv4
170 process_ip4(s);
171 break;
172 }
173}
174
175void
176print_frame(struct pcap_file *p, struct pcap_pkthdr *hdr, char const *frame)
177{
178 struct stream streambuf;
179 struct stream *s = &streambuf;
180
181 sinit(s, frame, hdr->caplen, ENDIAN_NETWORK); // pcap.c always outputs network byte order
182 printf("%u.%u\t", hdr->ts.tv_sec, hdr->ts.tv_usec);
183 switch (p->linktype) {
184 case LINKTYPE_ETHERNET:
185 print_ethernet(s);
186 break;
187 case LINKTYPE_RAW:
188 process_ip4(s);
189 break;
190 }
191 printf("\n");
192}
193
194void
195pcat(FILE * f)
196{
197 struct pcap_file p;
198 struct pcap_pkthdr hdr;
199 char frame[MAXFRAME];
200
201 if (-1 == pcap_open_in(&p, f))
202 return;
203
204 for (;;) {
205
206 if (-1 == pcap_read_pkthdr(&p, &hdr)) {
207 break;
208 }
209
210 if (1 != fread(frame, hdr.caplen, 1, f)) {
211 break;
212 }
213
214 print_frame(&p, &hdr, frame);
215 }
216}
217
218
219int
220main(int argc, char *argv[])
221{
222 pcat(stdin);
223
224 return 0;
225}