1 /**
2 * HEXPCAP HEADER
3 *
4 * Utilities to sniff and inject packets (in raw or hexstring formats)
5 * via pcap libraries.
6 */
7
8 #ifndef HEXPCAP_H_
9 #define HEXPCAP_H_
10
11 #include <pcap.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdint.h>
15 #include <getopt.h>
16 #include <assert.h>
17 #include <arpa/inet.h>
18
19 #include "hexstring.h"
20
21 /**
22 * Required definitions
23 */
24 void do_cksum_ipv4 (uint8_t *, size_t);
25 void do_cksum_ipv6 (uint8_t *, size_t);
26 void do_size_ipv4 (uint8_t *, size_t);
27 void do_size_ipv6 (uint8_t *, size_t);
28
29 /**
30 * Checksum (simple)
31 */
cksum_simple(uint16_t * buff,size_t len)32 uint16_t cksum_simple (uint16_t *buff, size_t len)
33 {
34
35 uint32_t sum = 0;
36 uint16_t answer = 0;
37
38 while(len > 1) {
39 sum += *buff++;
40 len -= 2;
41 }
42
43 if (len) {
44 sum += * (uint8_t *) buff;
45 }
46
47 while (sum>>16)
48 sum = (sum & 0xffff) + (sum >> 16);
49
50 answer = ~sum;
51
52 return(answer);
53 }
54
55 /**
56 * Checksum (with pseudo header)
57 */
cksum_pseudo_header(uint16_t protocol_code,uint16_t * src_addr,uint16_t * dest_addr,uint8_t addr_len,uint16_t * buff,uint16_t len)58 uint16_t cksum_pseudo_header (uint16_t protocol_code, uint16_t *src_addr, uint16_t *dest_addr, uint8_t addr_len, uint16_t *buff, uint16_t len)
59 {
60
61 uint8_t i = 0;
62 uint32_t sum = 0;
63 uint16_t answer = 0;
64
65 for(i = 0; i < (addr_len/2); i++) {
66 sum += src_addr[i];
67 }
68
69 for(i = 0; i < (addr_len/2); i++) {
70 sum += dest_addr[i];
71 }
72
73 sum += htons(protocol_code);
74
75 sum += htons(len);
76
77 while(len > 1) {
78 sum += *buff++;
79 len -= 2;
80 }
81
82 if (len) {
83 sum += * (uint8_t *) buff;
84 }
85
86 while (sum>>16)
87 sum = (sum & 0xffff) + (sum >> 16);
88
89 answer = ~sum;
90
91 return(answer);
92 }
93
94 /**
95 * Do checksum of IPv4 and IPv6 data (next protocol dispatch)
96 */
do_cksum_ipv4_ipv6_next_protocol(uint8_t next_protocol,uint8_t * ip_header,uint8_t * raw,size_t size)97 void do_cksum_ipv4_ipv6_next_protocol (uint8_t next_protocol, uint8_t *ip_header, uint8_t *raw, size_t size)
98 {
99
100 uint8_t ip_version = 0;
101 uint16_t *cksum = NULL;
102
103 ip_version = ip_header[0] >> 4;
104
105 switch(next_protocol) {
106
107 // tcp
108 case 0x06:
109 if (size < 20) return; // size check
110 cksum = (uint16_t *) &raw[16];
111 goto PSEUDO_HEADER_CKSUM;
112
113 // udp
114 case 0x11:
115 if (size < 8) return; // size check
116 cksum = (uint16_t *) &raw[6];
117 goto PSEUDO_HEADER_CKSUM;
118
119 // icmpv6
120 case 0x3a:
121 if (size < 8) return; // size check
122 cksum = (uint16_t *) &raw[2];
123
124 PSEUDO_HEADER_CKSUM:
125 *cksum = 0;
126 if(ip_version == 4) {
127 *cksum = cksum_pseudo_header((uint16_t) next_protocol,
128 (uint16_t *) &ip_header[12],
129 (uint16_t *) &ip_header[16],
130 4, (uint16_t *) raw, size);
131 } else if (ip_version == 6) {
132 *cksum = cksum_pseudo_header((uint16_t) next_protocol,
133 (uint16_t *) &ip_header[8],
134 (uint16_t *) &ip_header[24],
135 16, (uint16_t *) raw, size);
136 }
137 break;
138
139 // icmp
140 case 0x01:
141 if (size < 8) return; // size check
142 cksum = (uint16_t *) &raw[2];
143 goto SIMPLE_CKSUM;
144
145 // igmp
146 case 0x02:
147 if (size < 8) return; // size check
148 cksum = (uint16_t *) &raw[2];
149
150 SIMPLE_CKSUM:
151 *cksum = 0;
152 *cksum = cksum_simple((uint16_t *) raw, size);
153 break;
154
155 // encapsulated ipv4
156 case 0x04:
157 do_cksum_ipv4(raw, size);
158 break;
159
160 // encapsulated ipv6
161 case 0x29:
162 do_cksum_ipv6(raw, size);
163 break;
164
165 }
166
167 }
168
169 /**
170 * Do checksum of IPv4 packet
171 */
do_cksum_ipv4(uint8_t * raw,size_t size)172 void do_cksum_ipv4 (uint8_t *raw, size_t size)
173 {
174
175 uint8_t hdr_size = 0, next_protocol = 0;
176 uint16_t *cksum = NULL;
177
178 // ipv4 header size
179 hdr_size = (raw[0] & 0x0F) * 4;
180 if(hdr_size > size) return;
181
182 // ipv4 checksum
183 cksum = (uint16_t *) &raw[10];
184 *cksum = 0;
185
186 *cksum = cksum_simple((uint16_t *) raw, hdr_size);
187
188 // do checksum of next protocol
189 next_protocol = raw[9];
190 do_cksum_ipv4_ipv6_next_protocol(next_protocol, raw, raw + hdr_size, size - hdr_size);
191
192 }
193
194 /**
195 * Do checksum of IPv6 packet
196 */
do_cksum_ipv6(uint8_t * raw,size_t size)197 void do_cksum_ipv6 (uint8_t *raw, size_t size)
198 {
199
200 uint8_t next_protocol = 0;
201 uint8_t *next_header = NULL;
202
203 next_protocol = raw[6];
204 next_header = raw + 40;
205
206 // skip ipv6 extension headers
207 while (1) {
208 switch (next_protocol) {
209
210 case 0: // hop-by-hop options
211 case 43: // routing options
212 case 44: // fragment options
213 case 50: // encapsulating security payload
214 case 51: // authentication header
215 case 60: // destination options
216 case 135: // mobility options
217 next_protocol = next_header[0];
218 next_header += 8 + (next_header[1] * 8);
219 if((next_header - raw) > (size - 8)) return; // check size
220 break;
221
222 default: // next protocol header
223 do_cksum_ipv4_ipv6_next_protocol(next_protocol, raw, next_header, size - (next_header - raw));
224 return;
225
226 }
227 }
228
229 }
230
231 /**
232 * Do checksum (if the packet requires it...)
233 */
do_cksum(uint8_t * raw,size_t size)234 void do_cksum (uint8_t *raw, size_t size)
235 {
236
237 // is ipv4?
238 if ( size >= 34 && raw[12]==0x08 && raw[13]==0x00 ) {
239 do_cksum_ipv4(raw + 14, size - 14);
240 }
241
242 // is ipv6?
243 else if ( size >= 54 && raw[12]==0x86 && raw[13]==0xDD ) {
244 do_cksum_ipv6(raw + 14, size - 14);
245 }
246
247 }
248
249 /**
250 * Adjust size fields of IPv4 and IPv6 data (next protocol dispatch)
251 */
do_size_ipv4_ipv6_next_protocol(uint8_t next_protocol,uint8_t * raw,size_t size)252 void do_size_ipv4_ipv6_next_protocol (uint8_t next_protocol, uint8_t *raw, size_t size)
253 {
254
255 uint16_t *len_field = NULL;
256
257 switch(next_protocol) {
258
259 // udp
260 case 0x11:
261 if (size < 8) return; // size check
262 len_field = (uint16_t *) &raw[4];
263 *len_field = htons(size);
264 break;
265
266 // encapsulated ipv4
267 case 0x04:
268 do_size_ipv4(raw, size);
269 break;
270
271 // encapsulated ipv6
272 case 0x29:
273 do_size_ipv6(raw, size);
274 break;
275
276 }
277
278 }
279
280 /**
281 * Adjust packet size fields of IPv4 packet
282 */
do_size_ipv4(uint8_t * raw,size_t size)283 void do_size_ipv4 (uint8_t *raw, size_t size)
284 {
285
286 uint8_t hdr_size = 0, next_protocol = 0;
287 uint16_t *len_field = NULL;
288
289 // ipv4 header size
290 hdr_size = (raw[0] & 0x0F) * 4;
291 if(hdr_size > size) return;
292
293 // ipv4 size field
294 len_field = (uint16_t *) &raw[2];
295 *len_field = htons(size);
296
297 // do size of next protocol
298 next_protocol = raw[9];
299 do_size_ipv4_ipv6_next_protocol(next_protocol, raw + hdr_size, size - hdr_size);
300
301 }
302
303 /**
304 * Adjust packet size fields of IPv6 packet
305 */
do_size_ipv6(uint8_t * raw,size_t size)306 void do_size_ipv6 (uint8_t *raw, size_t size)
307 {
308
309 uint8_t next_protocol = 0;
310 uint8_t *next_header = NULL;
311
312 uint16_t *len_field = NULL;
313
314 // set payload size
315 len_field = (uint16_t *) &raw[4];
316 *len_field = htons(size - 40);
317
318 // select next header
319 next_protocol = raw[6];
320 next_header = raw + 40;
321
322 // skip ipv6 extension headers
323 while (1) {
324 switch (next_protocol) {
325
326 case 0: // hop-by-hop options
327 case 43: // routing options
328 case 44: // fragment options
329 case 50: // encapsulating security payload
330 case 51: // authentication header
331 case 60: // destination options
332 case 135: // mobility options
333 next_protocol = next_header[0];
334 next_header += 8 + (next_header[1] * 8);
335 if((next_header - raw) > (size - 8)) return; // check size
336 break;
337
338 default: // next protocol header
339 do_size_ipv4_ipv6_next_protocol(next_protocol, next_header, size - (next_header - raw));
340 return;
341
342 }
343 }
344
345 }
346
347 /**
348 * Adjust packet size fields (if the packet requires it...)
349 */
do_size(uint8_t * raw,size_t size)350 void do_size (uint8_t *raw, size_t size)
351 {
352
353 // is ipv4?
354 if ( size >= 34 && raw[12]==0x08 && raw[13]==0x00 ) {
355 do_size_ipv4(raw + 14, size - 14);
356 }
357
358 // is ipv6?
359 else if ( size >= 54 && raw[12]==0x86 && raw[13]==0xDD ) {
360 do_size_ipv6(raw + 14, size - 14);
361 }
362
363 uint16_t *len_field = NULL;
364
365 // is ip?
366 if ( size >= 34 && raw[12]==0x08 && raw[13]==0x00 ) {
367
368 // ip total length
369 len_field = (uint16_t *) &raw[16];
370
371 *len_field = size - 14; // size - ethernet header
372 *len_field = htons(*len_field);
373
374 // next protocol
375 switch(raw[23]) {
376
377 // tcp
378 case 0x06:
379 if (size < 54) return; // size check
380 // tcp uses header length field
381 break;
382
383 // udp
384 case 0x11:
385 if (size < 42) return; // size check
386 len_field = (uint16_t *) &raw[38];
387 *len_field = size - 14 - ((raw[14] & 0xF) * 4); // size - ethernet header - ip header
388 *len_field = htons(*len_field);
389 break;
390
391 // icmp
392 case 0x01:
393 //if (size < 42) return; // size check
394 // no size field
395 break;
396
397 // igmp
398 case 0x02:
399 //if (size < 42) return; // size check
400 // no size field
401 break;
402 }
403 }
404 }
405
406 /**
407 * Inject a raw buffer to the network
408 */
inject_raw(pcap_t * fp,uint8_t * raw,size_t size,int disable_cksum,int disable_size)409 int inject_raw(pcap_t *fp, uint8_t *raw, size_t size, int disable_cksum, int disable_size)
410 {
411
412 assert(fp != NULL);
413 assert(raw != NULL);
414
415 int err = 0;
416
417 /* packet size (if enabled) */
418 if(!disable_size) do_size (raw, size);
419
420 /* checksum */
421 if(!disable_cksum) do_cksum (raw, size);
422
423 /* Send down the packet */
424 err = pcap_sendpacket(fp, (unsigned char *) raw, size);
425
426 return err;
427 }
428
429 /**
430 * Inject an hexstring to the network
431 */
inject_hexstr(pcap_t * fp,char * hexstr,int disable_cksum,int disable_size)432 int inject_hexstr(pcap_t *fp, char *hexstr, int disable_cksum, int disable_size)
433 {
434
435 assert(fp != NULL);
436 assert(hexstr != NULL);
437
438 int err = 0;
439 int size = 0;
440 uint8_t *raw = NULL;
441
442 raw = hexstr_to_raw(hexstr, &size);
443
444 /* Send down the packet */
445 err = inject_raw(fp, raw, size, disable_cksum, disable_size);
446
447 free(raw);
448
449 return err;
450 }
451
452 /**
453 * Sniff a packet from the network as an hexstring. The hexstring must be manually free()d.
454 */
sniff_hexstr(pcap_t * fp)455 char *sniff_hexstr(pcap_t *fp)
456 {
457
458 assert(fp != NULL);
459
460 struct pcap_pkthdr hdr;
461 char *hexstr = NULL;
462 uint8_t *raw = NULL;
463
464 /* Sniff the packet */
465 raw = (uint8_t *) pcap_next(fp, &hdr);
466
467 if(raw == NULL)
468 return NULL;
469
470 hexstr = raw_to_hexstr(raw, hdr.len);
471
472 return hexstr;
473 }
474
475 /**
476 * Sniff a packet from the network as a raw buffer. The buffer must NOT be modified or free()d.
477 */
sniff_raw(pcap_t * fp,size_t * size)478 const uint8_t *sniff_raw(pcap_t *fp, size_t *size)
479 {
480
481 assert(fp != NULL);
482 assert(size != NULL);
483
484 struct pcap_pkthdr hdr;
485 const uint8_t *raw = NULL;
486
487 /* Sniff the packet */
488 raw = (const uint8_t *) pcap_next(fp, &hdr);
489
490 *size = hdr.len;
491
492 return raw;
493 }
494
495 #endif /* HEXPCAP_H_ */
496