1/*
2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30#include "pcap-ng.h"
31#include <stdio.h>
32#include <err.h>
33#include <stdlib.h>
34#include <string.h>
35
36struct section_info {
37	struct section_info *next;
38	struct pcapng_section_header_fields shb;
39	pcap_t *pcap;
40	u_int32_t if_count;
41	struct interface_info *if_list;
42};
43
44struct interface_info {
45	struct interface_info *next;
46	struct pcapng_interface_description_fields idb;
47	struct section_info *section_info;
48	u_int32_t interface_id;
49	char *if_name;
50	char *if_desc;
51};
52
53struct section_info *section_list = NULL;
54struct section_info *current_section = NULL;
55
56int mode_raw = 0;
57int mode_block = 0;
58
59#define PAD32(x) (((x) + 3) & ~3)
60
61void hex_and_ascii_print(const char *, const void *, unsigned int , const char *);
62
63struct section_info *
64new_section_info(pcap_t *pcap, struct pcapng_section_header_fields *shb)
65{
66	struct section_info *section_info = calloc(1, sizeof(struct section_info));
67
68	if (section_info == NULL)
69		return NULL;
70
71	section_info->pcap = pcap;
72	section_info->shb = *shb;
73
74	if (section_list == NULL) {
75		section_list = section_info;
76	} else {
77		section_info->next = section_list;
78		section_list = section_info;
79	}
80	current_section = section_info;
81
82	return section_info;
83}
84
85
86void
87interface_option_iterator(pcapng_block_t block, struct pcapng_option_info *option_info, void *context)
88{
89	struct interface_info *interface_info = (struct interface_info *)context;
90
91	switch (option_info->code) {
92		case 0:
93			break;
94
95		case 1:
96			break;
97
98		case 2:
99			interface_info->if_name = malloc(option_info->length + 1);
100			if (interface_info->if_name == NULL)
101				break;
102			snprintf(interface_info->if_name, option_info->length + 1, "%s", option_info->value);
103			break;
104		case 3:
105			interface_info->if_desc = malloc(option_info->length + 1);
106			if (interface_info->if_desc == NULL)
107				break;
108			snprintf(interface_info->if_desc, option_info->length + 1, "%s", option_info->value);
109			break;
110		case 4:
111			break;
112		case 5:
113			break;
114		case 6:
115			break;
116		case 7:
117			break;
118		case 8:
119			break;
120		case 9:
121			break;
122		case 10:
123			break;
124		case 11:
125			break;
126		case 12:
127			break;
128		case 13:
129			break;
130		case 14:
131			break;
132		default:
133			break;
134	}
135}
136
137struct interface_info *
138new_interface_info(struct section_info *section_info, pcapng_block_t block)
139{
140	struct interface_info *interface_info = calloc(1, sizeof(struct interface_info));
141
142	if (interface_info == NULL)
143		return NULL;
144
145	interface_info->section_info = section_info;
146	interface_info->interface_id = section_info->if_count;
147	section_info->if_count++;
148	if (section_info->if_list == NULL) {
149		section_info->if_list = interface_info;
150	} else {
151		interface_info->next = section_info->if_list;
152		section_info->if_list = interface_info;
153	}
154	(void) pcnapng_block_iterate_options(block,
155										 interface_option_iterator,
156										 interface_info);
157
158	return interface_info;
159}
160
161struct interface_info *
162find_interface_info_by_id(u_int16_t interface_id)
163{
164	struct interface_info *interface_info;
165
166	if (current_section == NULL)
167		return (NULL);
168
169	if (interface_id + 1 > current_section->if_count)
170		return (NULL);
171
172	for (interface_info = current_section->if_list;
173		 interface_info != NULL;
174		 interface_info = interface_info->next) {
175		if (interface_info->interface_id == interface_id)
176			return (interface_info);
177	}
178	return (NULL);
179}
180
181void
182block_option_iterator(pcapng_block_t block, struct pcapng_option_info *option_info, void *context)
183{
184	printf("    block_type %u context %p option_code %u value_len %u value_ptr %p\n",
185		   pcap_ng_block_get_type(block), context,
186		   option_info->code, option_info->length,
187		   option_info->value
188		   );
189	switch (option_info->code) {
190		case 0:
191			printf("      opt_endofopt\n");
192			break;
193
194		case 1:
195			printf("      opt_comment: %-*s\n",
196				   option_info->length, option_info->value);
197			break;
198
199		default:
200			/*
201			 * Each block type has its own option code space
202			 */
203			switch (pcap_ng_block_get_type(block)) {
204				case PCAPNG_BT_SHB:
205					switch (option_info->code) {
206						case 2:
207							printf("      shb_hardware: %-*s\n",
208								   option_info->length, option_info->value);
209							break;
210						case 3:
211							printf("      shb_os: %-*s\n",
212								   option_info->length, option_info->value);
213							break;
214						case 4:
215							printf("      shb_userappl: %-*s\n",
216								   option_info->length, option_info->value);
217							break;
218						default:
219							printf("      <unkown shb option>\n");
220							break;
221					}
222					break;
223
224				case PCAPNG_BT_IDB:
225					switch (option_info->code) {
226						case 2:
227							printf("      if_name: %-*s\n",
228								   option_info->length, option_info->value);
229							break;
230						case 3:
231							printf("      if_desc: %-*s\n",
232								   option_info->length, option_info->value);
233							break;
234						case 4:
235							printf("      if_IPv4addr\n");
236							break;
237						case 5:
238							printf("      if_IPv6addr\n");
239							break;
240						case 6:
241							printf("      if_MACaddr\n");
242							break;
243						case 7:
244							printf("      if_EUIaddr\n");
245							break;
246						case 8:
247							printf("      if_speed\n");
248							break;
249						case 9:
250							printf("      if_tsresol\n");
251							break;
252						case 10:
253							printf("      if_tzone\n");
254							break;
255						case 11:
256							printf("      if_filter %-*s\n",
257								   option_info->length, option_info->value);
258							break;
259						case 12:
260							printf("      if_os %-*s\n",
261								   option_info->length, option_info->value);
262							break;
263						case 13:
264							printf("      if_fcslen\n");
265							break;
266						case 14:
267							printf("      if_tsoffset\n");
268							break;
269						default:
270							printf("      <unkown idb option>\n");
271							break;
272					}
273					break;
274
275				case PCAPNG_BT_EPB:
276					switch (option_info->code) {
277						case 2:
278							printf("      epb_flags\n");
279							break;
280						case 3:
281							printf("      epb_hash\n");
282							break;
283						case 4:
284							printf("      epb_dropcount\n");
285							break;
286						case PCAPNG_EPB_PIB_INDEX:
287							printf("      epb_pib\n");
288							break;
289						case PCAPNG_EPB_SVC:
290							printf("      epb_svc\n");
291							break;
292						default:
293							printf("      <unkown epb option>\n");
294							break;
295					}
296					break;
297
298				case PCAPNG_BT_SPB:
299					printf("      <invalid spb option>\n");
300					break;
301
302				case PCAPNG_BT_PB:
303					switch (option_info->code) {
304						case 2:
305							printf("      pack_flags\n");
306							break;
307						case 3:
308							printf("      pack_hash\n");
309							break;
310						default:
311							printf("      <unkown pb option>\n");
312							break;
313					}
314					break;
315
316				case PCAPNG_BT_PIB: {
317					switch (option_info->code) {
318						case 2:
319							printf("      proc_name\n");
320							break;
321						case 3:
322							printf("      proc_path\n");
323							break;
324						default:
325							printf("      <unkown pib option>\n");
326							break;
327					}
328					break;
329				}
330				case PCAPNG_BT_ISB: {
331					break;
332				}
333				case PCAPNG_BT_NRB: {
334					break;
335				}
336				default:
337					break;
338			}
339			break;
340	}
341	if (option_info->value) {
342		hex_and_ascii_print("      ", option_info->value, option_info->length, "\n");
343	}
344}
345
346void
347read_callback(u_char *user, const struct pcap_pkthdr *hdr, const u_char *bytes)
348{
349	pcap_t *pcap = (pcap_t *)user;
350	struct pcapng_option_info option_info;
351	u_char *optptr = NULL;
352
353	/* Access the raw block */
354	if (mode_raw) {
355		struct pcapng_block_header *block_header = (struct pcapng_block_header*)bytes;
356
357		printf("raw  hdr caplen %u len %u\n", hdr->caplen, hdr->len);
358
359		printf("#\n# user %p hdr.caplen %u hdr.len %u block_header.blocktype 0x%x block_header.totallength %u\n",
360			   user, hdr->caplen, hdr->len,
361			   block_header->block_type, block_header->total_length);
362
363		hex_and_ascii_print("", bytes, block_header->total_length, "\n");
364
365		switch (block_header->block_type) {
366			case PCAPNG_BT_SHB: {
367				struct pcapng_section_header_fields *shb = (struct pcapng_section_header_fields *)(block_header + 1);
368				printf("# Section Header Block\n");
369				printf("  byte_order_magic 0x%x major_version %u minor_version %u section_length %llu\n",
370					   shb->byte_order_magic, shb->major_version, shb->minor_version, shb->section_length);
371
372				hex_and_ascii_print("", shb, sizeof(struct pcapng_section_header_fields), "\n");
373
374				optptr = (u_char *)(shb + 1);
375
376				break;
377			}
378			case PCAPNG_BT_IDB: {
379				struct pcapng_interface_description_fields *idb = (struct pcapng_interface_description_fields *)(block_header + 1);
380				printf("# Interface Description Block\n");
381				printf("  linktype %u reserved %u snaplen %u\n",
382					   idb->linktype, idb->reserved, idb->snaplen);
383
384				hex_and_ascii_print("", idb, sizeof(struct pcapng_interface_description_fields), "\n");
385				optptr = (u_char *)(idb + 1);
386
387				break;
388			}
389			case PCAPNG_BT_EPB: {
390				struct pcapng_enhanced_packet_fields *epb = (struct pcapng_enhanced_packet_fields *)(block_header + 1);
391				printf("# Enhanced Packet Block\n");
392				printf("  interface_id %u timestamp_high %u timestamp_low %u caplen %u len %u\n",
393					   epb->interface_id, epb->timestamp_high, epb->timestamp_low, epb->caplen, epb->len);
394
395				hex_and_ascii_print("", epb, sizeof(struct pcapng_enhanced_packet_fields), "\n");
396				hex_and_ascii_print("", epb + 1, epb->caplen, "\n");
397
398				optptr = (u_char *)(epb + 1);
399				optptr += PAD32(epb->caplen);
400
401				break;
402			}
403			case PCAPNG_BT_SPB: {
404				struct pcapng_simple_packet_fields *spb = (struct pcapng_simple_packet_fields *)(block_header + 1);
405				printf("# Simple Packet Block\n");
406				printf("  len %u\n",
407					   spb->len);
408
409				hex_and_ascii_print("", spb, sizeof(struct pcapng_simple_packet_fields), "\n");
410				hex_and_ascii_print("", spb + 1, spb->len, "\n");
411				break;
412			}
413			case PCAPNG_BT_PB: {
414				struct pcapng_packet_fields *pb = (struct pcapng_packet_fields *)(block_header + 1);
415				printf("# Packet Block\n");
416				printf("  interface_id %u drops_count %u timestamp_high %u timestamp_low %u caplen %u len %u\n",
417					   pb->interface_id, pb->drops_count, pb->timestamp_high, pb->timestamp_low, pb->caplen, pb->len);
418
419				hex_and_ascii_print("", pb, sizeof(struct pcapng_packet_fields), "\n");
420
421				hex_and_ascii_print("", pb + 1, pb->caplen, "\n");
422
423				break;
424			}
425			case PCAPNG_BT_PIB: {
426				struct pcapng_process_information_fields *pib =  (struct pcapng_process_information_fields *)(block_header + 1);
427				printf("# Process Information Block\n");
428				printf("  process_id %u\n",
429					   pib->process_id);
430				hex_and_ascii_print("", pib, sizeof(struct pcapng_process_information_fields), "\n");
431				break;
432			}
433			case PCAPNG_BT_ISB: {
434				printf("# Interface Statistics Block\n");
435				break;
436			}
437			case PCAPNG_BT_NRB: {
438				printf("# Name Record Block\n");
439				break;
440			}
441			default:
442				printf("# Unknown Block\n");
443				break;
444		}
445		if (optptr) {
446			size_t optlen = block_header->total_length - (optptr - bytes);
447
448			hex_and_ascii_print("", optptr, optlen, "\n");
449		}
450
451	}
452	/* Create block object */
453	if (mode_block) {
454		pcapng_block_t block = pcap_ng_block_alloc_with_raw_block(pcap, (u_char *)bytes);
455
456		if (block == NULL) {
457			printf("  pcap_ng_block_alloc_with_raw_block() failed: %s\n", pcap_geterr(pcap));
458			return;
459		}
460
461		switch (pcap_ng_block_get_type(block)) {
462			case PCAPNG_BT_SHB: {
463				struct pcapng_section_header_fields *shb = pcap_ng_get_section_header_fields(block);
464				printf("# Section Header Block\n");
465				printf("  byte_order_magic 0x%x major_version %u minor_version %u section_length %llu\n",
466					   shb->byte_order_magic, shb->major_version, shb->minor_version, shb->section_length);
467
468				(void)new_section_info(pcap, shb);
469				break;
470			}
471			case PCAPNG_BT_IDB: {
472				struct pcapng_interface_description_fields *idb = pcap_ng_get_interface_description_fields(block);
473				printf("# Interface Description Block\n");
474				printf("  linktype %u reserved %u snaplen %u\n",
475					   idb->linktype, idb->reserved, idb->snaplen);
476				if (pcap_ng_block_get_option(block, PCAPNG_IF_NAME, &option_info) == 1)
477					if (option_info.value)
478						printf("  interface name: %s\n", option_info.value);
479
480				(void)new_interface_info(current_section, block);
481				break;
482			}
483			case PCAPNG_BT_EPB: {
484				struct pcapng_enhanced_packet_fields *epb = pcap_ng_get_enhanced_packet_fields(block);
485				printf("# Enhanced Packet Block\n");
486				printf("  interface_id %u timestamp_high %u timestamp_low %u caplen %u len %u\n",
487					   epb->interface_id, epb->timestamp_high, epb->timestamp_low, epb->caplen, epb->len);
488				break;
489			}
490			case PCAPNG_BT_SPB: {
491				struct pcapng_simple_packet_fields *spb = pcap_ng_get_simple_packet_fields(block);
492				printf("# Simple Packet Block\n");
493				printf("  len %u\n",
494					   spb->len);
495				break;
496			}
497			case PCAPNG_BT_PB: {
498				struct pcapng_packet_fields *pb = pcap_ng_get_packet_fields(block);
499				printf("# Packet Block\n");
500				printf("  interface_id %u drops_count %u timestamp_high %u timestamp_low %u caplen %u len %u\n",
501					   pb->interface_id, pb->drops_count, pb->timestamp_high, pb->timestamp_low, pb->caplen, pb->len);
502				break;
503			}
504			case PCAPNG_BT_PIB: {
505				struct pcapng_process_information_fields *pib = pcap_ng_get_process_information_fields(block);
506				printf("# Process Information Block\n");
507				printf("  process_id %u\n",
508					   pib->process_id);
509
510				if (pcap_ng_block_get_option(block, PCAPNG_PIB_NAME, &option_info) == 1)
511					if (option_info.value)
512						printf("  process name: %s\n", option_info.value);
513				break;
514			}
515			case PCAPNG_BT_ISB: {
516				printf("# Interface Statistics Block\n");
517				break;
518			}
519			case PCAPNG_BT_NRB: {
520				printf("# Name Record Block\n");
521				break;
522			}
523			default:
524				printf("# Unknown Block\n");
525				break;
526		}
527		pcnapng_block_iterate_options(block, block_option_iterator, NULL);
528	}
529}
530
531#define	SWAPLONG(y) \
532((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
533#define	SWAPSHORT(y) \
534( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) )
535#define	SWAPLONGLONG(y) \
536(SWAPLONG((unsigned long)(y)) << 32 | SWAPLONG((unsigned long)((y) >> 32)))
537
538int main(int argc, const char * argv[])
539{
540	int i;
541	char errbuf[PCAP_ERRBUF_SIZE];
542#if 0
543	u_int64_t	section_length;
544
545	section_length = 0x0004000300020001;
546	printf("section_length %llx\n", section_length);
547
548	u_int32_t lowlong = (u_int32_t)section_length;
549	printf("lowlong %x\n", lowlong);
550
551	u_int32_t hilong = (u_int32_t)(section_length >> 32);
552	printf("hilong %x\n", hilong);
553
554	u_int64_t swapped = SWAPLONGLONG(section_length);
555	printf("swapped %llx\n", swapped);
556
557	int nums[11] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5 };
558	for (i = 0; i < 11; i++) {
559		printf("PCAPNG_ROUNDUP32(%d): %d\n", nums[i], PCAPNG_ROUNDUP32(nums[i]));
560	}
561#endif
562	for (i = 1; i < argc; i++) {
563		if (strcmp(argv[i], "-raw") == 0) {
564			mode_raw = 1;
565			continue;
566		}
567		if (strcmp(argv[i], "-block") == 0) {
568			mode_block = 1;
569			continue;
570		}
571		if (mode_block == 0 && mode_raw == 0)
572			mode_block = 1;
573
574		printf("#\n# opening %s\n#\n", argv[i]);
575
576		pcap_t *pcap = pcap_ng_open_offline(argv[i], errbuf);
577		if (pcap == NULL) {
578			warnx("pcap_ng_open_offline(%s) failed: %s\n",
579				  argv[i], errbuf);
580			continue;
581		}
582		int result = pcap_dispatch(pcap, -1, read_callback, (u_char *)pcap);
583		if (result < 0) {
584			warnx("pcap_dispatch failed: %s\n",
585				  pcap_statustostr(result));
586		} else {
587			printf("# read %d packets\n", result);
588		}
589		pcap_close(pcap);
590	}
591	return 0;
592}
593
594