1/*
2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <sys/param.h>
29#include <netinet/in.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdio.h>
33#include <err.h>
34#include <sysexits.h>
35#include <unistd.h>
36#include <sys/uio.h>
37#include "pcapng_private.h"
38
39#include "pcap-int.h"
40#include "pcap-common.h"
41#include "sf-pcap-ng.h"
42#include "pcap-util.h"
43
44
45#define PAD_32BIT(x) ((x + 3) & ~3)
46#define PAD_64BIT(x) ((x + 7) & ~7)
47#define PADDED_OPTION_LEN(x) ((x) ? PAD_32BIT(x) + sizeof(struct pcapng_option_header) : 0)
48
49
50void *
51pcap_ng_block_header_ptr(pcapng_block_t block)
52{
53	return (block->pcapng_bufptr);
54}
55
56void *
57pcap_ng_block_fields_ptr(pcapng_block_t block)
58{
59	return (block->pcapng_bufptr +
60		sizeof(struct pcapng_block_header));
61}
62
63void *
64pcap_ng_block_data_ptr(pcapng_block_t block)
65{
66	if (block->pcapng_data_is_external)
67		return (block->pcapng_data_ptr);
68	else
69		return (block->pcapng_bufptr +
70			sizeof(struct pcapng_block_header) +
71			block->pcapng_fields_len);
72}
73
74void *
75pcap_ng_block_records_ptr(pcapng_block_t block)
76{
77	if (block->pcapng_block_type != PCAPNG_BT_NRB)
78		return (NULL);
79
80	if (block->pcapng_data_is_external)
81		return (block->pcapng_bufptr +
82			sizeof(struct pcapng_block_header) +
83			block->pcapng_fields_len);
84	else
85		return (block->pcapng_bufptr +
86			sizeof(struct pcapng_block_header) +
87			block->pcapng_fields_len +
88			block->pcapng_data_len);
89}
90
91void *
92pcap_ng_block_options_ptr(pcapng_block_t block)
93{
94	if (block->pcapng_block_type == PCAPNG_BT_SPB)
95		return (NULL);
96
97	if (block->pcapng_data_is_external)
98		return (block->pcapng_bufptr +
99			sizeof(struct pcapng_block_header) +
100			block->pcapng_fields_len +
101			block->pcapng_records_len);
102	else
103		return (block->pcapng_bufptr +
104			sizeof(struct pcapng_block_header) +
105			block->pcapng_fields_len +
106			block->pcapng_data_len +
107			block->pcapng_records_len);
108}
109
110void *
111pcap_ng_block_trailer_ptr(pcapng_block_t block)
112{
113	if (block->pcapng_data_is_external)
114		return (block->pcapng_bufptr +
115			sizeof(struct pcapng_block_header) +
116			block->pcapng_fields_len +
117			block->pcapng_records_len +
118			block->pcapng_options_len);
119	else
120		return (block->pcapng_bufptr +
121			sizeof(struct pcapng_block_header) +
122			block->pcapng_fields_len +
123			block->pcapng_data_len +
124			block->pcapng_records_len +
125			block->pcapng_options_len);
126}
127
128pcapng_block_t
129pcap_ng_block_alloc(size_t len)
130{
131	size_t totallen;
132	u_char *ptr;
133	struct pcapng_block *block;
134
135	/*
136	 * The internal block structure is prepended
137	 */
138	totallen = PAD_64BIT(sizeof(struct pcapng_block)) + len;
139	ptr = malloc(totallen);
140	if (ptr == NULL)
141		return (NULL);
142
143	block = (struct pcapng_block *)ptr;
144	bzero(block, sizeof(struct pcapng_block));
145
146	block->pcapng_bufptr = ptr + PAD_64BIT(sizeof(struct pcapng_block));
147	block->pcapng_buflen = len;
148
149
150	return (block);
151}
152
153void
154pcap_ng_free_block(pcapng_block_t block)
155{
156	free(block);
157}
158
159bpf_u_int32
160pcap_ng_block_get_type(pcapng_block_t block)
161{
162	return (block->pcapng_block_type);
163}
164
165bpf_u_int32
166pcap_ng_block_get_len(pcapng_block_t block)
167{
168	return (block->pcapng_block_len);
169}
170
171int
172pcap_ng_block_is_swapped(pcapng_block_t block)
173{
174	return (block->pcapng_block_swapped);
175}
176
177int
178pcapng_update_block_length(pcapng_block_t block)
179{
180	block->pcapng_block_len = sizeof(struct pcapng_block_header) +
181		block->pcapng_fields_len +
182		block->pcapng_data_len +
183		block->pcapng_records_len +
184		block->pcapng_options_len +
185		sizeof(struct pcapng_block_trailer);
186
187	if (block->pcapng_block_len > block->pcapng_buflen) {
188		errx(EX_SOFTWARE, "%s block len %lu greater than buffer size %lu",
189		     __func__, block->pcapng_block_len, block->pcapng_buflen);
190
191	}
192
193	return (0);
194}
195
196int
197pcap_ng_block_reset(pcapng_block_t block, bpf_u_int32 type)
198{
199	bzero(&block->block_fields_, sizeof(block->block_fields_));
200
201	switch (type) {
202		case PCAPNG_BT_SHB:
203			block->pcapng_block_type = type;
204
205			block->pcap_ng_shb_fields.byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC;
206			block->pcap_ng_shb_fields.major_version = PCAPNG_VERSION_MAJOR;
207			block->pcap_ng_shb_fields.minor_version = PCAPNG_VERSION_MINOR;
208			block->pcap_ng_shb_fields.section_length = (uint64_t)-1;
209
210			block->pcapng_fields_len = sizeof(struct pcapng_section_header_fields);
211			break;
212
213		case PCAPNG_BT_IDB:
214			block->pcapng_block_type = type;
215
216			block->pcapng_fields_len = sizeof(struct pcapng_interface_description_fields);
217			break;
218
219		case PCAPNG_BT_PB:
220			block->pcapng_block_type = type;
221
222			block->pcapng_fields_len = sizeof(struct pcapng_packet_fields);
223
224			break;
225
226		case PCAPNG_BT_SPB:
227			block->pcapng_block_type = type;
228
229			block->pcapng_fields_len = sizeof(struct pcapng_simple_packet_fields);
230
231			break;
232
233		case PCAPNG_BT_NRB:
234			block->pcapng_block_type = type;
235
236			block->pcapng_fields_len = 0;
237			break;
238
239		case PCAPNG_BT_ISB:
240			block->pcapng_block_type = type;
241
242			block->pcapng_fields_len = sizeof(struct pcapng_interface_statistics_fields);
243			break;
244
245		case PCAPNG_BT_EPB:
246			block->pcapng_block_type = type;
247
248			block->pcapng_fields_len = sizeof(struct pcapng_enhanced_packet_fields);
249			break;
250
251		case PCAPNG_BT_PIB:
252			block->pcapng_block_type = type;
253
254			block->pcapng_fields_len = sizeof(struct pcapng_process_information_fields);
255			break;
256
257		default:
258			return (PCAP_ERROR);
259	}
260
261	block->pcapng_data_ptr = NULL;
262	block->pcapng_data_len = 0;
263	block->pcapng_cap_len = 0;
264	block->pcapng_data_is_external = 0;
265
266	block->pcapng_records_len = 0;
267
268	block->pcapng_options_len = 0;
269
270	pcapng_update_block_length(block);
271
272	return (0);
273}
274
275struct pcapng_section_header_fields *
276pcap_ng_get_section_header_fields(pcapng_block_t block)
277{
278	if (block != NULL && block->pcapng_block_type == PCAPNG_BT_SHB)
279		return &block->pcap_ng_shb_fields;
280	else
281		return NULL;
282}
283
284struct pcapng_interface_description_fields *
285pcap_ng_get_interface_description_fields(pcapng_block_t block)
286{
287	if (block != NULL && block->pcapng_block_type == PCAPNG_BT_IDB)
288		return &block->pcap_ng_idb_fields;
289	else
290		return NULL;
291}
292
293struct pcapng_enhanced_packet_fields *
294pcap_ng_get_enhanced_packet_fields(pcapng_block_t block)
295{
296	if (block != NULL && block->pcapng_block_type == PCAPNG_BT_EPB)
297		return &block->pcap_ng_epb_fields;
298	else
299		return NULL;
300}
301
302struct pcapng_simple_packet_fields *
303pcap_ng_get_simple_packet_fields(pcapng_block_t block)
304{
305	if (block != NULL && block->pcapng_block_type == PCAPNG_BT_SPB)
306		return &block->pcap_ng_spb_fields;
307	else
308		return NULL;
309}
310
311struct pcapng_packet_fields *
312pcap_ng_get_packet_fields(pcapng_block_t block)
313{
314	if (block != NULL && block->pcapng_block_type == PCAPNG_BT_PB)
315		return &block->pcap_ng_opb_fields;
316	else
317		return NULL;
318}
319
320struct pcapng_interface_statistics_fields *
321pcap_ng_get_interface_statistics_fields(pcapng_block_t block)
322{
323	if (block != NULL && block->pcapng_block_type == PCAPNG_BT_ISB)
324		return &block->pcap_ng_isb_fields;
325	else
326		return NULL;
327}
328
329struct pcapng_process_information_fields *
330pcap_ng_get_process_information_fields(pcapng_block_t block)
331{
332	if (block != NULL && block->pcapng_block_type == PCAPNG_BT_PIB)
333		return &block->pcap_ng_pib_fields;
334	else
335		return NULL;
336}
337
338int
339pcap_ng_block_does_support_data(pcapng_block_t block)
340{
341	switch (block->pcapng_block_type) {
342		case PCAPNG_BT_PB:
343		case PCAPNG_BT_SPB:
344		case PCAPNG_BT_EPB:
345			return (1);
346			/* NOT REACHED */
347
348		default:
349			break;
350	}
351	return (0);
352}
353
354void *
355pcap_ng_block_packet_get_data_ptr(pcapng_block_t block)
356{
357	if (pcap_ng_block_does_support_data(block) == 0)
358		return (NULL);
359
360	return (block->pcapng_data_ptr);
361}
362
363bpf_u_int32
364pcap_ng_block_packet_get_data_len(pcapng_block_t block)
365{
366	if (pcap_ng_block_does_support_data(block) == 0)
367		return (0);
368
369	return (block->pcapng_cap_len);
370}
371
372bpf_u_int32
373pcap_ng_block_packet_copy_data(pcapng_block_t block, const void *ptr,
374                               bpf_u_int32 caplen)
375{
376	bpf_u_int32 padding_len = PAD_32BIT(caplen) - caplen;
377
378	if (pcap_ng_block_does_support_data(block) == 0)
379		return (PCAP_ERROR);
380
381	if (block->pcapng_block_len + PAD_32BIT(caplen) > block->pcapng_buflen) {
382		warnx("%s block len %lu greater than buffer size %lu",
383			  __func__, block->pcapng_block_len, block->pcapng_buflen);
384		return (PCAP_ERROR);
385	}
386	/*
387	 * Move the name records and options if necessary
388	 */
389	if (block->pcapng_records_len > 0 || block->pcapng_options_len > 0) {
390		u_char *tmp = pcap_ng_block_records_ptr(block) ?
391			pcap_ng_block_records_ptr(block) :
392			pcap_ng_block_options_ptr(block);
393		size_t len = block->pcapng_records_len + block->pcapng_options_len;
394		int32_t offset = PAD_32BIT(caplen) - block->pcapng_data_len;
395
396		bcopy(tmp, tmp + offset, len);
397	}
398
399	/*
400	 * TBD: if records or options exist, should move them or error out
401	 */
402	block->pcapng_data_is_external = 0;
403	block->pcapng_data_ptr = pcap_ng_block_data_ptr(block);
404	bcopy(ptr, block->pcapng_data_ptr, caplen);
405	if (padding_len > 0)
406		bzero(block->pcapng_data_ptr + caplen, padding_len);
407	block->pcapng_cap_len = caplen;
408	block->pcapng_data_len = PAD_32BIT(caplen);
409
410	pcapng_update_block_length(block);
411
412	return (0);
413}
414
415bpf_u_int32
416pcap_ng_block_packet_set_data(pcapng_block_t block, const void *ptr,
417                              bpf_u_int32 caplen)
418{
419	if (pcap_ng_block_does_support_data(block) == 0)
420		return (PCAP_ERROR);
421
422	block->pcapng_data_is_external = 1;
423	block->pcapng_data_ptr = (u_char *)ptr;
424	block->pcapng_cap_len = caplen;
425	block->pcapng_data_len = PAD_32BIT(caplen);
426
427	pcapng_update_block_length(block);
428
429	return (0);
430}
431
432int
433pcap_ng_block_add_option_with_value(pcapng_block_t block, u_short code,
434                                    const void *value, u_short value_len)
435{
436	size_t optlen = sizeof(struct pcapng_option_header) + PAD_32BIT(value_len);
437	struct pcapng_option_header *opt_header;
438	bpf_u_int32 padding_len = PAD_32BIT(value_len) - value_len;
439	u_char *buffer;
440	u_char *block_option_ptr = pcap_ng_block_options_ptr(block);
441
442	if (block_option_ptr == NULL) {
443		warnx("%s options not supported for block type %u",
444			  __func__, block->pcapng_block_type);
445		return (PCAP_ERROR);
446	}
447
448	if (optlen + block->pcapng_block_len > block->pcapng_buflen) {
449		warnx("%s block len %lu greater than buffer size %lu",
450			  __func__, block->pcapng_block_len, block->pcapng_buflen);
451		return (PCAP_ERROR);
452	}
453
454	opt_header = (struct pcapng_option_header *)(block_option_ptr + block->pcapng_options_len);
455	/* Insert before the end of option */
456	if (block->pcapng_options_len > 0)
457		opt_header -= 1;
458	opt_header->option_code = code;
459	opt_header->option_length = value_len;
460
461	buffer = (u_char *)(opt_header + 1);
462
463	bcopy(value, buffer, value_len);
464
465	if (padding_len > 0)
466		bzero(buffer + value_len, padding_len);
467
468	/* Add end of option when first option added */
469	if (block->pcapng_options_len == 0)
470		block->pcapng_options_len = sizeof(struct pcapng_option_header);
471
472	block->pcapng_options_len += optlen;
473
474	/* Set the end of option at the end of the options */
475	opt_header = (struct pcapng_option_header *)(block_option_ptr + block->pcapng_options_len);
476	opt_header -= 1;
477	opt_header->option_code = PCAPNG_OPT_ENDOFOPT;
478	opt_header->option_length = 0;
479
480	pcapng_update_block_length(block);
481
482	return (0);
483}
484
485int
486pcap_ng_block_add_option_with_string(pcapng_block_t block, u_short code, const char *str)
487{
488	return (pcap_ng_block_add_option_with_value(block, code, str, strlen(str) + 1));
489}
490
491int
492pcap_ng_block_get_option(pcapng_block_t block, u_short code, struct pcapng_option_info *option_info)
493{
494	struct pcapng_option_header opthdr;
495	int swapped;
496	int num_of_options = 0;
497	struct block_cursor cursor;
498
499	if (option_info == NULL)
500		return (PCAP_ERROR);
501	if (block->pcapng_options_len == 0)
502		goto done;
503
504	swapped = block->pcapng_block_swapped;
505
506	cursor.block_type = block->pcapng_block_type;
507	cursor.data = pcap_ng_block_options_ptr(block);
508	cursor.data_remaining = block->pcapng_options_len;
509
510	while (get_opthdr_from_block_data(&opthdr, swapped, &cursor, NULL)) {
511		void *value = get_optvalue_from_block_data(&cursor, &opthdr, NULL);
512
513		/*
514		 * If option is cut short we cannot parse it, give up
515		 */
516		if (opthdr.option_length != 0 && value == NULL)
517			break;
518
519		if (code == opthdr.option_code) {
520			option_info->code = opthdr.option_code;
521			option_info->length = opthdr.option_length;
522			option_info->value = value;
523
524			num_of_options = 1;
525			break;
526		}
527		/*
528		 * Detect end of option delimiter
529		 */
530		if (opthdr.option_code == PCAPNG_OPT_ENDOFOPT)
531			break;
532	}
533
534done:
535	return (num_of_options);
536}
537
538int
539pcnapng_block_iterate_options(pcapng_block_t block,
540                              pcapng_option_iterator_func opt_iterator_func,
541                              void *context)
542{
543	struct pcapng_option_header opthdr;
544	int swapped;
545	int num_of_options = 0;
546	struct block_cursor cursor;
547
548	if (block == NULL || opt_iterator_func == NULL)
549		return (PCAP_ERROR);
550	swapped = block->pcapng_block_swapped;
551
552	cursor.block_type = block->pcapng_block_type;
553	cursor.data = pcap_ng_block_options_ptr(block);
554	cursor.data_remaining = block->pcapng_options_len;
555
556	while (get_opthdr_from_block_data(&opthdr, swapped, &cursor, NULL)) {
557		void *value = get_optvalue_from_block_data(&cursor, &opthdr, NULL);
558		struct pcapng_option_info option_info;
559
560		/*
561		 * If option is cut short we cannot parse it, give up
562		 */
563		if (opthdr.option_length != 0 && value == NULL)
564			break;
565
566		option_info.code = opthdr.option_code;
567		option_info.length = opthdr.option_length;
568		option_info.value = value;
569
570		num_of_options++;
571
572		opt_iterator_func(block, &option_info, context);
573
574		/*
575		 * Detect end of option delimiter
576		 */
577		if (opthdr.option_code == PCAPNG_OPT_ENDOFOPT)
578			break;
579	}
580
581done:
582	return (num_of_options);
583}
584
585int
586pcnapng_block_iterate_name_records(pcapng_block_t block,
587                                   pcapng_name_record_iterator_func record_iterator_func,
588                                   void *context)
589{
590	struct pcapng_record_header recordhdr;
591	int swapped;
592	int num_of_records = 0;
593	struct block_cursor cursor;
594
595	if (block == NULL || record_iterator_func == NULL)
596		return (PCAP_ERROR);
597	swapped = block->pcapng_block_swapped;
598
599	cursor.block_type = block->pcapng_block_type;
600	cursor.data = pcap_ng_block_records_ptr(block);
601	cursor.data_remaining = block->pcapng_records_len;
602
603	/*
604	 * Note that we take advantage of the fact that name record headers
605	 * have the same layout as option headers
606	 */
607	while (get_opthdr_from_block_data((struct pcapng_option_header *)&recordhdr,
608									  swapped, &cursor, NULL)) {
609		struct pcapng_name_record_info record_info;
610		void *value =
611			get_optvalue_from_block_data(&cursor,
612			                             (struct pcapng_option_header *)&recordhdr,
613			                             NULL);
614
615		/*
616		 * If record is cut short we cannot parse it, give up
617		 */
618		if (recordhdr.record_length != 0 && value == NULL)
619			break;
620
621		record_info.code = recordhdr.record_type;
622		record_info.length = recordhdr.record_length;
623		record_info.value = value;
624
625		num_of_records++;
626
627		/*
628		 * Detect end of option delimiter
629		 */
630		if (record_info.code == PCAPNG_NRES_ENDOFRECORD)
631			break;
632	}
633
634done:
635	return (num_of_records);
636}
637
638int
639pcap_ng_block_add_name_record_common(pcapng_block_t block, uint32_t type,
640                                     size_t addrlen, void *addr, const char **names)
641{
642	size_t names_len = 0;
643	int i;
644	const char *p;
645	size_t record_len = 0;
646	struct pcapng_record_header	*record_hdr;
647	size_t padding_len;
648	u_char *buffer;
649	size_t offset;
650	u_char *block_records_ptr = pcap_ng_block_records_ptr(block);
651
652	if (block_records_ptr == NULL)
653		return (PCAP_ERROR);
654
655	for (i = 0; ; i++) {
656		p = names[i];
657		if (p == NULL || *p == 0)
658			break;
659		names_len += strlen(p) + 1;
660	}
661
662	record_len = sizeof(struct pcapng_record_header) + addrlen + PAD_32BIT(names_len);
663	if (record_len + block->pcapng_block_len > block->pcapng_buflen) {
664		warnx("%s block len %lu greater than buffer size %lu",
665		      __func__, block->pcapng_block_len, block->pcapng_buflen);
666		return (PCAP_ERROR);
667	}
668
669	/*
670	 * Move the options if necessary
671	 */
672	if (block->pcapng_options_len > 0) {
673		u_char *tmp = pcap_ng_block_options_ptr(block);
674
675		bcopy(tmp, tmp + record_len, block->pcapng_options_len);
676	}
677
678	padding_len = PAD_32BIT(names_len) - names_len;
679
680	record_hdr = (struct pcapng_record_header*)(block_records_ptr + block->pcapng_records_len);
681	if (block->pcapng_records_len > 0)
682		record_hdr -= 1;
683	record_hdr->record_type = type;
684	record_hdr->record_length = addrlen + PAD_32BIT(names_len);
685
686	buffer = (u_char *)(record_hdr + 1);
687	bcopy(addr, buffer, addrlen);
688	offset = addrlen;
689	for (i = 0; ; i++) {
690		p = names[i];
691		if (p == NULL || *p == 0)
692			break;
693		u_short slen = strlen(p) + 1;
694		bcopy(p, buffer, slen);
695		offset += slen;
696	}
697	if (padding_len > 0)
698		bzero(buffer + offset, padding_len);
699
700	block->pcapng_records_len += record_len;
701
702	pcapng_update_block_length(block);
703
704	return (0);
705}
706
707int
708pcap_ng_block_add_name_record_with_ip4(pcapng_block_t block,
709                                       struct in_addr *in4,
710                                       const char **names)
711{
712	if (block->pcapng_block_type != PCAPNG_BT_NRB)
713		return (PCAP_ERROR);
714
715	return pcap_ng_block_add_name_record_common(block,
716	                                            PCAPNG_NRES_IP4RECORD,
717	                                            sizeof(struct in_addr),
718	                                            in4,
719	                                            names);
720}
721
722int
723pcap_ng_block_add_name_record_with_ip6(pcapng_block_t block,
724                                       struct in6_addr *in6,
725                                       const char **names)
726{
727	if (block->pcapng_block_type != PCAPNG_BT_NRB)
728		return (PCAP_ERROR);
729
730	return pcap_ng_block_add_name_record_common(block,
731	                                            PCAPNG_NRES_IP4RECORD,
732	                                            sizeof(struct in6_addr),
733	                                            in6,
734	                                            names);
735}
736
737bpf_u_int32
738pcap_ng_externalize_block(void *buffer, size_t buflen, pcapng_block_t block)
739{
740	struct pcapng_block_header block_header;
741	struct pcapng_block_trailer block_trailer;
742	bpf_u_int32 bytes_written = 0;
743	u_char *ptr;
744
745	if (buffer == NULL || buflen < block->pcapng_block_len)
746		return (0);
747
748	ptr = buffer;
749	block_header.block_type = block->pcapng_block_type;
750	block_header.total_length = block->pcapng_block_len;
751	bcopy(&block_header, ptr + bytes_written, sizeof(struct pcapng_block_header));
752	bytes_written += sizeof(struct pcapng_block_header);
753
754	switch (block->pcapng_block_type) {
755		case PCAPNG_BT_SHB:
756		case PCAPNG_BT_IDB:
757		case PCAPNG_BT_PB:
758		case PCAPNG_BT_SPB:
759		case PCAPNG_BT_NRB:
760		case PCAPNG_BT_ISB:
761		case PCAPNG_BT_EPB:
762		case PCAPNG_BT_PIB:
763			if (block->pcapng_block_type == PCAPNG_BT_PB) {
764				if(block->pcap_ng_opb_fields.caplen == 0)
765					block->pcap_ng_opb_fields.caplen = block->pcapng_cap_len;
766				if(block->pcap_ng_opb_fields.len == 0)
767					block->pcap_ng_opb_fields.len = block->pcapng_cap_len;
768			}
769			if (block->pcapng_block_type == PCAPNG_BT_SPB) {
770				if(block->pcap_ng_spb_fields.len == 0)
771					block->pcap_ng_spb_fields.len = block->pcapng_cap_len;
772			}
773			if (block->pcapng_block_type == PCAPNG_BT_EPB) {
774				if(block->pcap_ng_epb_fields.caplen == 0)
775					block->pcap_ng_epb_fields.caplen = block->pcapng_cap_len;
776				if(block->pcap_ng_epb_fields.len == 0)
777					block->pcap_ng_epb_fields.len = block->pcapng_cap_len;
778			}
779
780			if (block->pcapng_fields_len > 0) {
781				bcopy(&block->pcap_ng_shb_fields, ptr + bytes_written, block->pcapng_fields_len);
782				bytes_written += block->pcapng_fields_len;
783			}
784			break;
785		default:
786			/* Unknown block */
787			return (0);
788			break;
789	}
790
791
792	if (block->pcapng_data_len > 0) {
793		bpf_u_int32 padding_len = PAD_32BIT(block->pcapng_cap_len) - block->pcapng_cap_len;
794
795		bcopy(block->pcapng_data_ptr, ptr + bytes_written, block->pcapng_cap_len);
796		bytes_written += block->pcapng_cap_len;
797
798		if (padding_len > 0) {
799			bzero(ptr + bytes_written, padding_len);
800			bytes_written += padding_len;
801		}
802	}
803
804	if (block->pcapng_records_len > 0) {
805		bcopy(pcap_ng_block_records_ptr(block), ptr + bytes_written, block->pcapng_records_len);
806		bytes_written += block->pcapng_records_len;
807	}
808	if (block->pcapng_options_len > 0) {
809		bcopy(pcap_ng_block_options_ptr(block), ptr + bytes_written, block->pcapng_options_len);
810		bytes_written += block->pcapng_options_len;
811	}
812
813	block_trailer.total_length = block->pcapng_block_len;
814	bcopy(&block_trailer, ptr + bytes_written, bytes_written);
815	bytes_written += sizeof(struct pcapng_block_trailer);
816
817	return (bytes_written);
818}
819
820bpf_u_int32
821pcap_ng_dump_block(pcap_dumper_t *p, pcapng_block_t block)
822{
823	struct pcapng_block_header *block_header;
824	struct pcapng_block_trailer *block_trailer;
825	bpf_u_int32 bytes_written = 0;
826	struct iovec iov[4];
827	int iovcnt;
828	char data_padding[3] = { 0, 0, 0 };
829
830	block_header = (struct pcapng_block_header *)pcap_ng_block_header_ptr(block);
831	block_header->block_type = block->pcapng_block_type;
832	block_header->total_length = block->pcapng_block_len;
833
834	switch (block->pcapng_block_type) {
835		case PCAPNG_BT_SHB:
836		case PCAPNG_BT_IDB:
837		case PCAPNG_BT_PB:
838		case PCAPNG_BT_SPB:
839		case PCAPNG_BT_NRB:
840		case PCAPNG_BT_ISB:
841		case PCAPNG_BT_EPB:
842		case PCAPNG_BT_PIB:
843			if (block->pcapng_block_type == PCAPNG_BT_PB) {
844				if(block->pcap_ng_opb_fields.caplen == 0)
845					block->pcap_ng_opb_fields.caplen = block->pcapng_cap_len;
846				if(block->pcap_ng_opb_fields.len == 0)
847					block->pcap_ng_opb_fields.len = block->pcapng_cap_len;
848			}
849			if (block->pcapng_block_type == PCAPNG_BT_SPB) {
850				if(block->pcap_ng_spb_fields.len == 0)
851					block->pcap_ng_spb_fields.len = block->pcapng_cap_len;
852			}
853			if (block->pcapng_block_type == PCAPNG_BT_EPB) {
854				if(block->pcap_ng_epb_fields.caplen == 0)
855					block->pcap_ng_epb_fields.caplen = block->pcapng_cap_len;
856				if(block->pcap_ng_epb_fields.len == 0)
857					block->pcap_ng_epb_fields.len = block->pcapng_cap_len;
858			}
859
860			if (block->pcapng_fields_len > 0)
861				bcopy(&block->pcap_ng_shb_fields, pcap_ng_block_fields_ptr(block), block->pcapng_fields_len);
862			break;
863		default:
864			/* Unknown block */
865			return (0);
866			break;
867	}
868
869	block_trailer = pcap_ng_block_trailer_ptr(block);
870	block_trailer->total_length = block_header->total_length;
871
872	iovcnt = 0;
873	iov[iovcnt].iov_len = sizeof(struct pcapng_block_header) + block->pcapng_fields_len;
874	iov[iovcnt].iov_base = block->pcapng_bufptr;
875	iovcnt++;
876
877	if (block->pcapng_data_len > 0) {
878		bpf_u_int32 padding_len = PAD_32BIT(block->pcapng_cap_len) - block->pcapng_cap_len;
879
880		iov[iovcnt].iov_len = block->pcapng_cap_len;
881		iov[iovcnt].iov_base = block->pcapng_data_ptr;
882		iovcnt++;
883
884		/* This is suboptimal... */
885		if (padding_len > 0) {
886			iov[iovcnt].iov_len = padding_len;
887			iov[iovcnt].iov_base = data_padding;
888			iovcnt++;
889		}
890	}
891	/*
892	 * The name records, options and block trailer are contiguous
893	 */
894	iov[iovcnt].iov_len = block->pcapng_records_len +
895		block->pcapng_options_len +
896		sizeof(struct pcapng_block_trailer);
897	if (block->pcapng_records_len > 0)
898		iov[iovcnt].iov_base = pcap_ng_block_records_ptr(block);
899	else if (block->pcapng_options_len > 0)
900		iov[iovcnt].iov_base = pcap_ng_block_options_ptr(block);
901	else
902		iov[iovcnt].iov_base = block_trailer;
903	iovcnt++;
904
905	bytes_written += writev(((FILE *)p)->_file, iov, iovcnt);
906
907	return (bytes_written);
908}
909
910int
911pcap_ng_block_internalize_common(pcapng_block_t *pblock, pcap_t *p, u_char *raw_block)
912{
913	pcapng_block_t block = NULL;
914	struct pcapng_block_header bh = *(struct pcapng_block_header *)raw_block;
915	struct block_cursor cursor;
916	int swapped = 0;
917
918	if (pblock == NULL || raw_block == NULL)
919		return (PCAP_ERROR);
920
921	if (p != NULL)
922		swapped = p->sf.swapped;
923
924	if (swapped) {
925		bh.block_type = SWAPLONG(bh.block_type);
926		bh.total_length = SWAPLONG(bh.total_length);
927	}
928
929	switch (bh.block_type) {
930		case PCAPNG_BT_SHB:
931		    pcap_ng_init_section_info(p);
932		    break;
933		case PCAPNG_BT_IDB:
934		case PCAPNG_BT_PB:
935		case PCAPNG_BT_SPB:
936		case PCAPNG_BT_NRB:
937		case PCAPNG_BT_ISB:
938		case PCAPNG_BT_EPB:
939		case PCAPNG_BT_PIB:
940			break;
941		default:
942			(void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
943			                "%s: Unknown block type length %u",
944			                __func__, bh.block_type);
945			goto fail;
946	}
947	/* Check the length is reasonable, limit to 1 MBytes */
948	if (bh.total_length > 1024 * 1024) {
949		(void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
950		                "%s: Block total length %u is greater than 16 MB",
951		                __func__, bh.total_length);
952		goto fail;
953	}
954
955	/*
956	 * Some ntar files from wireshark.org do not round up the total block length to
957	 * a multiple of 4 bytes -- they must ignore the 32 bit alignment of the block body!
958	 */
959	bh.total_length = PAD_32BIT(bh.total_length);
960
961	if (*pblock == NULL) {
962		block = pcap_ng_block_alloc(bh.total_length);
963		if (block == NULL) {
964			(void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
965			                "%s: Unknown block type %u",
966			                __func__, bh.block_type);
967			goto fail;
968		}
969	} else {
970		block = *pblock;
971	}
972	block->pcapng_bufptr = raw_block;
973	block->pcapng_buflen = bh.total_length;
974	block->pcapng_buf_is_external = 1;
975	pcap_ng_block_reset(block, bh.block_type);
976	block->pcapng_block_len = bh.total_length;
977	block->pcapng_block_swapped = swapped;
978
979	cursor.data = raw_block + sizeof(struct pcapng_block_header);
980	cursor.data_remaining = bh.total_length -
981		sizeof(struct pcapng_block_header) -
982		sizeof(struct pcapng_block_trailer);
983	cursor.block_type = bh.block_type;
984
985	switch (bh.block_type) {
986		case PCAPNG_BT_SHB: {
987			struct pcapng_section_header_fields *shbp = pcap_ng_get_section_header_fields(block);
988			struct pcapng_section_header_fields *rawshb;
989
990			rawshb = get_from_block_data(&cursor, sizeof(struct pcapng_section_header_fields), p->errbuf);
991			if (rawshb == NULL)
992				goto fail;
993
994			shbp->byte_order_magic = rawshb->byte_order_magic;
995			shbp->major_version = rawshb->major_version;
996			shbp->minor_version = rawshb->minor_version;
997			shbp->section_length = rawshb->section_length;
998			if (swapped) {
999				shbp->byte_order_magic = SWAPLONG(shbp->byte_order_magic);
1000				shbp->major_version = SWAPSHORT(shbp->major_version);
1001				shbp->minor_version = SWAPSHORT(shbp->minor_version);
1002				shbp->section_length = SWAPLONGLONG(shbp->section_length);
1003			}
1004
1005			break;
1006		}
1007		case PCAPNG_BT_IDB: {
1008			struct pcapng_interface_description_fields *idbp = pcap_ng_get_interface_description_fields(block);
1009			struct pcapng_interface_description_fields *rawidb;
1010
1011			rawidb = get_from_block_data(&cursor, sizeof(struct pcapng_interface_description_fields), p->errbuf);
1012			if (rawidb == NULL)
1013				goto fail;
1014
1015			idbp->linktype = rawidb->linktype;
1016			idbp->reserved = rawidb->reserved;
1017			idbp->snaplen = rawidb->snaplen;
1018			if (swapped) {
1019				idbp->linktype = SWAPSHORT(idbp->linktype);
1020				idbp->reserved = SWAPSHORT(idbp->reserved);
1021				idbp->snaplen = SWAPLONG(idbp->snaplen);
1022			}
1023
1024			break;
1025		}
1026		case PCAPNG_BT_ISB: {
1027			struct pcapng_interface_statistics_fields *isbp = pcap_ng_get_interface_statistics_fields(block);
1028			struct pcapng_interface_statistics_fields *rawisb;
1029
1030			rawisb = get_from_block_data(&cursor, sizeof(struct pcapng_interface_statistics_fields), p->errbuf);
1031			if (rawisb == NULL)
1032				goto fail;
1033
1034			isbp->interface_id = rawisb->interface_id;
1035			isbp->timestamp_high = rawisb->timestamp_high;
1036			isbp->timestamp_low = rawisb->timestamp_low;
1037			if (swapped) {
1038				isbp->interface_id = SWAPSHORT(isbp->interface_id);
1039				isbp->timestamp_high = SWAPLONG(isbp->timestamp_high);
1040				isbp->timestamp_low = SWAPLONG(isbp->timestamp_low);
1041			}
1042
1043			break;
1044		}
1045		case PCAPNG_BT_EPB: {
1046			struct pcapng_enhanced_packet_fields *epbp = pcap_ng_get_enhanced_packet_fields(block);
1047			struct pcapng_enhanced_packet_fields *rawepb;
1048			void *data;
1049
1050			rawepb = get_from_block_data(&cursor, sizeof(struct pcapng_enhanced_packet_fields), p->errbuf);
1051			if (rawepb == NULL)
1052				goto fail;
1053
1054			epbp->interface_id = rawepb->interface_id;
1055			epbp->timestamp_high = rawepb->timestamp_high;
1056			epbp->timestamp_low = rawepb->timestamp_low;
1057			epbp->caplen = rawepb->caplen;
1058			epbp->len = rawepb->len;
1059			if (swapped) {
1060				epbp->interface_id = SWAPLONG(epbp->interface_id);
1061				epbp->timestamp_high = SWAPLONG(epbp->timestamp_high);
1062				epbp->timestamp_low = SWAPLONG(epbp->timestamp_low);
1063				epbp->caplen = SWAPLONG(epbp->caplen);
1064				epbp->len = SWAPLONG(epbp->len);
1065			}
1066			data = get_from_block_data(&cursor, PAD_32BIT(epbp->caplen), p->errbuf);
1067			if (data == NULL)
1068				goto fail;
1069			block->pcapng_data_is_external = 0;
1070			block->pcapng_data_ptr = (u_char *)data;
1071			block->pcapng_cap_len = epbp->caplen;
1072			block->pcapng_data_len = PAD_32BIT(epbp->caplen);
1073
1074			break;
1075		}
1076		case PCAPNG_BT_SPB: {
1077			struct pcapng_simple_packet_fields *spbp = pcap_ng_get_simple_packet_fields(block);
1078			struct pcapng_simple_packet_fields *rawspb;
1079			void *data;
1080			uint32_t caplen;
1081
1082			rawspb = get_from_block_data(&cursor, sizeof(struct pcapng_simple_packet_fields), p->errbuf);
1083			if (rawspb == NULL)
1084				goto fail;
1085
1086			spbp->len = rawspb->len;
1087			if (swapped) {
1088				spbp->len = SWAPLONG(spbp->len);
1089			}
1090			caplen = bh.total_length - sizeof(struct pcapng_simple_packet_fields) -
1091			sizeof(struct pcapng_block_header) - sizeof(struct pcapng_block_trailer);
1092			if (caplen > spbp->len)
1093				caplen = spbp->len;
1094			data = get_from_block_data(&cursor, PAD_32BIT(caplen), p->errbuf);
1095			if (data == NULL)
1096				goto fail;
1097			block->pcapng_data_is_external = 0;
1098			block->pcapng_data_ptr = (u_char *)data;
1099			block->pcapng_cap_len = caplen;
1100			block->pcapng_data_len = PAD_32BIT(caplen);
1101
1102			break;
1103		}
1104		case PCAPNG_BT_PB: {
1105			struct pcapng_packet_fields *pbp = pcap_ng_get_packet_fields(block);
1106			struct pcapng_packet_fields *rawpb;
1107			void *data;
1108
1109			rawpb = get_from_block_data(&cursor, sizeof(struct pcapng_packet_fields), p->errbuf);
1110			if (rawpb == NULL)
1111				goto fail;
1112
1113			pbp->interface_id = rawpb->interface_id;
1114			pbp->drops_count = rawpb->drops_count;
1115			pbp->timestamp_high = rawpb->timestamp_high;
1116			pbp->timestamp_low = rawpb->timestamp_low;
1117			pbp->caplen = rawpb->caplen;
1118			pbp->len = rawpb->len;
1119			if (swapped) {
1120				/* these were written in opposite byte order */
1121				pbp->interface_id = SWAPSHORT(pbp->interface_id);
1122				pbp->drops_count = SWAPSHORT(pbp->drops_count);
1123				pbp->timestamp_high = SWAPLONG(pbp->timestamp_high);
1124				pbp->timestamp_low = SWAPLONG(pbp->timestamp_low);
1125				pbp->caplen = SWAPLONG(pbp->caplen);
1126				pbp->len = SWAPLONG(pbp->len);
1127			}
1128
1129			data = get_from_block_data(&cursor, PAD_32BIT(pbp->caplen), p->errbuf);
1130			if (data == NULL)
1131				goto fail;
1132			block->pcapng_data_is_external = 0;
1133			block->pcapng_data_ptr = (u_char *)data;
1134			block->pcapng_cap_len = pbp->caplen;
1135			block->pcapng_data_len = PAD_32BIT(pbp->caplen);
1136
1137			break;
1138		}
1139		case PCAPNG_BT_PIB: {
1140			struct pcapng_process_information_fields *pibp = pcap_ng_get_process_information_fields(block);
1141			struct pcapng_process_information_fields *rawpib;
1142
1143			rawpib = get_from_block_data(&cursor, sizeof(struct pcapng_process_information_fields), p->errbuf);
1144			if (rawpib == NULL)
1145				goto fail;
1146
1147			pibp->process_id = rawpib->process_id;
1148			if (swapped) {
1149				pibp->process_id = SWAPSHORT(rawpib->process_id);
1150			}
1151			break;
1152		}
1153		case PCAPNG_BT_NRB: {
1154			struct pcapng_record_header *rh = (struct pcapng_record_header *)(block + 1);
1155
1156			while (1) {
1157				size_t record_len;
1158
1159				rh = get_from_block_data(&cursor, sizeof(struct pcapng_record_header), p->errbuf);
1160				if (rh == NULL)
1161					goto fail;
1162
1163				if (swapped)
1164					record_len = SWAPSHORT(rh->record_length);
1165				else
1166					record_len = rh->record_length;
1167
1168				if (get_from_block_data(&cursor, PCAPNG_ROUNDUP32(record_len), p->errbuf) == NULL)
1169					goto fail;
1170
1171				block->pcapng_records_len += sizeof(struct pcapng_record_header) +
1172					PCAPNG_ROUNDUP32(record_len);
1173
1174				if (rh->record_type == PCAPNG_NRES_ENDOFRECORD)
1175					break;
1176			}
1177			break;
1178		}
1179		default:
1180			goto fail;
1181	}
1182
1183	/*
1184	 * Finally compute the length of the options as options come last in blocks
1185	 */
1186	while (1) {
1187		size_t optlen;
1188		struct pcapng_option_header *opt;
1189
1190		opt = get_from_block_data(&cursor, sizeof(struct pcapng_option_header), p->errbuf);
1191		/*
1192		 * No, or no more options
1193		 */
1194		if (opt == NULL)
1195			break;
1196
1197		if (swapped)
1198			optlen = SWAPSHORT(opt->option_length);
1199		else
1200			optlen = opt->option_length;
1201
1202		if (get_from_block_data(&cursor, PCAPNG_ROUNDUP32(optlen), p->errbuf) == NULL)
1203			goto fail;
1204
1205		block->pcapng_options_len += sizeof(struct pcapng_option_header) + PCAPNG_ROUNDUP32(optlen);
1206
1207		if (opt->option_code == PCAPNG_OPT_ENDOFOPT)
1208			break;
1209	}
1210
1211	/* Success */
1212	if (*pblock == NULL)
1213		*pblock = block;
1214	return (0);
1215
1216fail:
1217	if (*pblock == NULL && block != NULL)
1218		pcap_ng_free_block(block);
1219	return (PCAP_ERROR);
1220}
1221
1222int
1223pcap_ng_block_init_with_raw_block(pcapng_block_t block, pcap_t *p, u_char *raw_block)
1224{
1225	return pcap_ng_block_internalize_common(&block, p, raw_block);
1226}
1227
1228pcapng_block_t
1229pcap_ng_block_alloc_with_raw_block(pcap_t *p, u_char *raw_block)
1230{
1231	pcapng_block_t block = NULL;
1232
1233	if (pcap_ng_block_internalize_common(&block, p, raw_block) == 0)
1234		return (block);
1235	else
1236		return (NULL);
1237}
1238