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