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#include <stdio.h> 30#include <err.h> 31#include <sysexits.h> 32#include <string.h> 33#include <strings.h> 34#include <stdlib.h> 35#include <fcntl.h> 36#include <unistd.h> 37#include <sys/socket.h> 38#include <netinet/in.h> 39#include <arpa/inet.h> 40 41#include "bpf.h" 42 43#include "pcap-ng.h" 44 45enum { 46 SIMPLE_PACKET = 0, 47 ENHANCED_PACKET = 1, 48 OBSOLETE_PACKET = 2 49}; 50 51const char *if_name = NULL; 52int type_of_packet = ENHANCED_PACKET; 53const char *proc_name = NULL; 54uint32_t proc_pid = 0; 55int32_t proc_index = -1; 56const char *comment = NULL; 57pcap_dumper_t *dumper = NULL; 58size_t ext_len = 65536; 59void *ext_buffer = NULL; 60int first_comment = 0; 61unsigned char *packet_data = NULL; 62size_t packet_length = 0; 63unsigned long num_data_blocks = 1; 64int copy_data_buffer = 0; 65 66void hex_and_ascii_print(const char *, const void *, size_t, const char *); 67 68void 69help(const char *str) 70{ 71 printf("# usage: %s options...\n", str); 72 printf("# options in order of dependency:\n"); 73 printf(" %-20s # %s\n", "-4 ipv4:name[:name...]", "IPv4 name resolution record"); 74 printf(" %-20s # %s\n", "-6 ipv6:name[:name...]", "IPv6 name resolution record"); 75 printf(" %-20s # %s\n", "-C", "copy data packet from data buffer"); 76 printf(" %-20s # %s\n", "-c string", "comment option"); 77 printf(" %-20s # %s\n", "-D length", "packet data length"); 78 printf(" %-20s # %s\n", "-d string", "packet data as a string"); 79 printf(" %-20s # %s\n", "-f", "first comment option"); 80 printf(" %-20s # %s\n", "-i name", "interface name"); 81 printf(" %-20s # %s\n", "-n num_data", "number of data blocks"); 82 printf(" %-20s # %s\n", "-p name:pid", "process name and pid"); 83 printf(" %-20s # %s\n", "-e", "enhanced packet block (default)"); 84 printf(" %-20s # %s\n", "-o", "(obsolete) packet block -- not implemented"); 85 printf(" %-20s # %s\n", "-s", "simple packet block"); 86 printf(" %-20s # %s\n", "-w name", "packet capture file name"); 87 printf(" %-20s # %s\n", "-x [buffer_length]", "externalize in buffer of given length"); 88} 89 90void 91write_block(pcapng_block_t block) 92{ 93 bpf_u_int32 n; 94 95 if (dumper != NULL) { 96 n = pcap_ng_dump_block(dumper, block); 97 if (n != pcap_ng_block_get_len(block)) 98 printf("%s: block len %u != pcap_ng_block_get_len() %u\n", 99 __func__, pcap_ng_block_get_len(block), n); 100 } 101 if (ext_buffer != NULL) { 102 n = pcap_ng_externalize_block(ext_buffer, ext_len, block); 103 hex_and_ascii_print("", ext_buffer, pcap_ng_block_get_len(block), ""); 104 if (n != pcap_ng_block_get_len(block)) 105 printf("%s: block len %u != pcap_ng_externalize_block() %u\n", 106 __func__, pcap_ng_block_get_len(block), n); 107 } 108} 109 110pcapng_block_t 111make_interface_description_block(pcapng_block_t block, const char *name) 112{ 113 struct pcapng_interface_description_fields *idb_fields; 114 115 pcap_ng_block_reset(block, PCAPNG_BT_IDB); 116 117 if (first_comment && comment) 118 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 119 120 idb_fields = pcap_ng_get_interface_description_fields(block); 121 idb_fields->linktype = DLT_RAW; 122 idb_fields->snaplen = 65536; 123 124 if (!first_comment && comment) 125 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 126 127 pcap_ng_block_add_option_with_string(block, PCAPNG_IF_NAME, name); 128 129 write_block(block); 130 131 return (block); 132} 133 134pcapng_block_t 135make_process_information_block(pcapng_block_t block, const char *name, uint32_t pid) 136{ 137 struct pcapng_process_information_fields *pib_fields; 138 139 pcap_ng_block_reset(block, PCAPNG_BT_PIB); 140 141 if (first_comment && comment) 142 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 143 144 pib_fields = pcap_ng_get_process_information_fields(block); 145 pib_fields->process_id = pid; 146 147 if (!first_comment && comment) 148 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 149 150 pcap_ng_block_add_option_with_string(block, PCAPNG_PIB_NAME, name); 151 152 write_block(block); 153 154 return (block); 155} 156 157pcapng_block_t 158make_data_block(pcapng_block_t block, const void *data, size_t len) 159{ 160 unsigned int i; 161 162 for (i = 0; i < num_data_blocks; i++) { 163 switch (type_of_packet) { 164 case SIMPLE_PACKET: { 165 pcap_ng_block_reset(block, PCAPNG_BT_SPB); 166 167 if (first_comment && comment) 168 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 169 170 if (copy_data_buffer) 171 pcap_ng_block_packet_copy_data(block, data, len); 172 else 173 pcap_ng_block_packet_set_data(block, data, len); 174 175 if (!first_comment && comment) 176 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 177 178 write_block(block); 179 break; 180 } 181 case ENHANCED_PACKET: { 182 struct pcapng_enhanced_packet_fields *epb_fields; 183 184 pcap_ng_block_reset(block, PCAPNG_BT_EPB); 185 186 if (first_comment && comment) 187 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 188 189 epb_fields = pcap_ng_get_enhanced_packet_fields(block); 190 epb_fields->caplen = len; 191 epb_fields->len = len; 192 epb_fields->interface_id = 0; 193 epb_fields->timestamp_high = 10000; 194 epb_fields->timestamp_low = 2000; 195 196 if (copy_data_buffer) 197 pcap_ng_block_packet_copy_data(block, data, len); 198 else 199 pcap_ng_block_packet_set_data(block, data, len); 200 201 if (proc_name != NULL) { 202 pcap_ng_block_add_option_with_value(block, PCAPNG_EPB_PIB_INDEX, &proc_index, sizeof(proc_index)); 203 } 204 if (!first_comment && comment) 205 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 206 207 write_block(block); 208 break; 209 } 210 default: 211 break; 212 } 213 } 214 return (block); 215} 216 217void 218make_section_header_block() 219{ 220 pcapng_block_t block = pcap_ng_block_alloc(65536); 221 222 pcap_ng_block_reset(block, PCAPNG_BT_SHB); 223 224 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, 225 "section header block"); 226 227 write_block(block); 228 229 pcap_ng_free_block(block); 230 231 return; 232} 233 234pcapng_block_t 235make_name_resolution_record(pcapng_block_t block, int af, void *addr, char **names) 236{ 237 pcap_ng_block_reset(block, PCAPNG_BT_NRB); 238 239 if (first_comment && comment) 240 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 241 242 if (af == AF_INET) { 243 pcap_ng_block_add_name_record_with_ip4(block, (struct in_addr *)addr, (const char **)names); 244 } else { 245 pcap_ng_block_add_name_record_with_ip6(block, (struct in6_addr *)addr, (const char **)names); 246 } 247 248 if (!first_comment && comment) 249 pcap_ng_block_add_option_with_string(block, PCAPNG_OPT_COMMENT, comment); 250 251 write_block(block); 252 253 return (block); 254} 255 256int 257main(int argc, char * const argv[]) 258{ 259 int ch; 260 const char *file_name = NULL; 261 pcapng_block_t block; 262 263 /* 264 * Loop through argument to build PCAP-NG block 265 * Optionally write to file 266 */ 267 while ((ch = getopt(argc, argv, "4:6:Cc:D:d:efhi:n:o:p:sw:x")) != -1) { 268 switch (ch) { 269 case 'C': 270 copy_data_buffer = 1; 271 break; 272 273 case 'c': 274 comment = optarg; 275 break; 276 277 case 'D': { 278 int i; 279 280 packet_length = strtoul(optarg, NULL, 0); 281 packet_data = malloc(packet_length); 282 for (i = 0; i < packet_length; i++) { 283 packet_data[i] = i % 256; 284 } 285 286 block = pcap_ng_block_alloc(65536); 287 make_data_block(block, packet_data, packet_length); 288 pcap_ng_free_block(block); 289 break; 290 } 291 case 'd': 292 packet_length = strlen(optarg); 293 packet_data = (unsigned char *)optarg; 294 block = pcap_ng_block_alloc(65536); 295 make_data_block(block, packet_data, packet_length); 296 pcap_ng_free_block(block); 297 break; 298 299 case 'e': 300 type_of_packet = ENHANCED_PACKET; 301 break; 302 303 case 'f': 304 first_comment = 1; 305 break; 306 307 case 'h': 308 help(argv[0]); 309 return (0); 310 311 case 'i': 312 if_name = optarg; 313 314 block = pcap_ng_block_alloc(65536); 315 make_interface_description_block(block, if_name); 316 pcap_ng_free_block(block); 317 318 break; 319 320 case '4': 321 case '6': { 322 int af; 323 int name_count = 0; 324 char *ptr = strchr(optarg, ':'); 325 char **names = NULL; 326 int i; 327 struct in_addr ina; 328 struct in6_addr in6a; 329 int retval; 330 331 332 if (ptr == NULL) { 333 fprintf(stderr, "malformed arguments for option 'n'\n"); 334 help(argv[0]); 335 return (0); 336 } 337 do { 338 ptr++; 339 name_count += 1; 340 } while ((ptr = strchr(ptr, ':')) != NULL); 341 342 names = calloc(name_count +1, sizeof(char *)); 343 344 ptr = strchr(optarg, ':'); 345 *ptr = '\0'; 346 347 if (ch == '4') { 348 af = AF_INET; 349 retval = inet_pton(af, optarg, &ina); 350 } else { 351 af = AF_INET6; 352 retval = inet_pton(af, optarg, &in6a); 353 } 354 if (retval == 0) 355 errx(1, "This is not an %s address: '%s'\n", 356 af == AF_INET ? "IPv4" : "IPv6", 357 optarg); 358 else if (retval == -1) 359 err(1, "inet_pton(%s) failed\n", optarg); 360 361 for (i = 0; i < name_count; i++) { 362 char *end; 363 ptr++; 364 end = strchr(ptr, ':'); 365 if (end != NULL) 366 *end = '\0'; 367 368 names[i] = strdup(ptr); 369 if (end != NULL) 370 ptr = end; 371 } 372 373 block = pcap_ng_block_alloc(65536); 374 if (af == AF_INET) 375 make_name_resolution_record(block, af, &ina, names); 376 else 377 make_name_resolution_record(block, af, &in6a, names); 378 pcap_ng_free_block(block); 379 break; 380 } 381 382 case 'n': { 383 num_data_blocks = strtoul(optarg, NULL, 0); 384 break; 385 } 386 387 case 'o': 388 type_of_packet = OBSOLETE_PACKET; 389 break; 390 391 case 'p': { 392 char *ptr = strchr(optarg, ':'); 393 char *endptr; 394 395 if (ptr == NULL) { 396 fprintf(stderr, "malformed arguments for option 'p'\n"); 397 help(argv[0]); 398 return (0); 399 } 400 proc_name = strndup(optarg, (ptr - optarg)); 401 ptr += 1; 402 if (*ptr == '\0') { 403 fprintf(stderr, "malformed arguments for option 'p'\n"); 404 help(argv[0]); 405 return (0); 406 } 407 proc_pid = (uint32_t)strtoul(ptr, &endptr, 0); 408 if (endptr != NULL && *endptr != '\0') { 409 fprintf(stderr, "malformed arguments for option 'p'\n"); 410 help(argv[0]); 411 return (0); 412 } 413 proc_index += 1; 414 415 block = pcap_ng_block_alloc(65536); 416 make_process_information_block(block, proc_name, proc_pid); 417 pcap_ng_free_block(block); 418 break; 419 } 420 case 's': 421 type_of_packet = SIMPLE_PACKET; 422 break; 423 424 case 'w': 425 file_name = optarg; 426 427 if (dumper != NULL) 428 pcap_ng_dump_close(dumper); 429 430 pcap_t *pcap = pcap_open_dead(DLT_PCAPNG, 65536); 431 if (pcap == NULL) 432 err(EX_OSERR, "pcap_open_dead(DLT_PCAPNG, 65536) failed\n"); 433 434 dumper = pcap_ng_dump_open(pcap, file_name); 435 if (pcap == NULL) 436 err(EX_OSERR, "pcap_ng_dump_open(%s) failed\n", file_name); 437 438 439 make_section_header_block(); 440 break; 441 442 case 'x': 443 if (optind < argc) { 444 if (argv[optind][0] != '-') { 445 char *endptr; 446 unsigned long num = strtoul(argv[optind], &endptr, 0); 447 if (endptr != NULL && *endptr == '\0') { 448 optind++; 449 ext_len = num; 450 } 451 } 452 } 453 ext_buffer = malloc(ext_len); 454 if (ext_buffer == NULL) 455 errx(EX_OSERR, "malloc(%lu) failed", ext_len); 456 break; 457 default: 458 help(argv[0]); 459 return (0); 460 } 461 } 462 463 if (dumper != NULL) 464 pcap_ng_dump_close(dumper); 465 466 return (0); 467}