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