diff options
author | Aaron Huang <huangaaron@google.com> | 2018-12-09 19:23:41 -0800 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-12-09 19:23:41 -0800 |
commit | 831564c0f9748b4fc98ab789f0d05f26b7997b0d (patch) | |
tree | 886394ac0938fa4dd76841e44a562ee45f653fe3 | |
parent | 7b498b9dc6ec9170f80900661978638dca7352f4 (diff) | |
parent | 23d87f340716fa81f9c3bce77dc4f97070b7b877 (diff) | |
download | apf-831564c0f9748b4fc98ab789f0d05f26b7997b0d.tar.gz |
Make apf_run support reading a pcap file am: 5ef76bdf49 am: fa912162e9
am: 23d87f3407
Change-Id: I289adaefcb03913abfadfcab0a4d980c7d6cec81
-rw-r--r-- | Android.bp | 3 | ||||
-rw-r--r-- | apf_run.c | 210 |
2 files changed, 192 insertions, 21 deletions
@@ -26,6 +26,9 @@ cc_binary_host { cc_binary_host { name: "apf_run", defaults: ["apf_defaults"], + static_libs: [ + "libpcap", + ], srcs: [ "apf_run.c", "apf_interpreter.c", @@ -16,7 +16,11 @@ // Simple program to try running an APF program against a packet. +#include <errno.h> +#include <getopt.h> #include <libgen.h> +#include <limits.h> +#include <pcap.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -24,9 +28,27 @@ #include "apf_interpreter.h" +enum { + OPT_PROGRAM, + OPT_PACKET, + OPT_PCAP, + OPT_DATA, + OPT_AGE +}; + +const struct option long_options[] = { + {"program", 1, NULL, OPT_PROGRAM}, + {"packet", 1, NULL, OPT_PACKET}, + {"pcap", 1, NULL, OPT_PCAP}, + {"data", 1, NULL, OPT_DATA}, + {"age", 1, NULL, OPT_AGE}, + {"help", 0, NULL, 'h'}, + {NULL, 0, NULL, 0} +}; + // Parses hex in "input". Allocates and fills "*output" with parsed bytes. // Returns length in bytes of "*output". -int parse_hex(char* input, uint8_t** output) { +size_t parse_hex(const char* input, uint8_t** output) { int length = strlen(input); if (length & 1) { fprintf(stderr, "Argument not even number of characters: %s\n", input); @@ -50,30 +72,173 @@ int parse_hex(char* input, uint8_t** output) { return length; } -void print_hex(uint8_t* input, int len) { +void print_hex(const uint8_t* input, int len) { for (int i = 0; i < len; ++i) { printf("%02x", input[i]); } } +// Process packet through APF filter +void packet_handler(uint8_t* program, uint32_t program_len, uint32_t ram_len, + const char* pkt, uint32_t filter_age) { + uint8_t* packet; + uint32_t packet_len = parse_hex(pkt, &packet); + + int ret = accept_packet(program, program_len, ram_len, packet, packet_len, + filter_age); + printf("Packet %sed\n", ret ? "pass" : "dropp"); + + free(packet); +} + +// Process pcap file through APF filter and generate output files +void file_handler(uint8_t* program, uint32_t program_len, uint32_t ram_len, + char* filename, uint32_t filter_age){ + char errbuf[PCAP_ERRBUF_SIZE]; + pcap_t *pcap; + struct pcap_pkthdr apf_header; + const uint8_t* apf_packet; + pcap_dumper_t *passed_dumper, *dropped_dumper; + const char passed_file[] = "passed.pcap"; + const char dropped_file[] = "dropped.pcap"; + int pass = 0; + int drop = 0; + + pcap = pcap_open_offline(filename, errbuf); + if (pcap == NULL) { + printf("Open pcap file failed.\n"); + exit(1); + } + + passed_dumper = pcap_dump_open(pcap, passed_file); + dropped_dumper = pcap_dump_open(pcap, dropped_file); + + if (!passed_dumper || !dropped_dumper) { + printf("pcap_dump_open(): open output file failed.\n"); + pcap_close(pcap); + exit(1); + } + + while ((apf_packet = pcap_next(pcap, &apf_header)) != NULL) { + int result = accept_packet(program, program_len, ram_len, apf_packet, + apf_header.len, filter_age); + + if (!result){ + drop++; + pcap_dump((u_char*)dropped_dumper, &apf_header, apf_packet); + } else { + pass++; + pcap_dump((u_char*)passed_dumper, &apf_header, apf_packet); + } + } + + printf("%d packets dropped\n", drop); + printf("%d packets passed\n", pass); + pcap_dump_close(passed_dumper); + pcap_dump_close(dropped_dumper); + pcap_close(pcap); +} + +void print_usage(char* cmd) { + fprintf(stderr, + "Usage: %s --program <program> --pcap <file>|--packet <packet> " + "[--data <content>] [--age <number>]\n" + " --program APF program, in hex.\n" + " --pcap Pcap file to run through program.\n" + " --packet Packet to run through program.\n" + " --data Data memory contents, in hex.\n" + " --age Age of program in seconds (default: 0).\n" + " -h, --help Show this message.\n", + basename(cmd)); +} + int main(int argc, char* argv[]) { - if (argc < 3 || argc > 5) { - fprintf(stderr, - "Usage: %s <program> <packet> [<data>] [<age>]\n" - " program: APF program, in hex\n" - " packet: Packet to run through program, in hex\n" - " data: Data memory contents, in hex\n" - " age: Age of program in seconds (default: 0)\n", - basename(argv[0])); + if (argc > 9) { + print_usage(argv[0]); exit(1); } - uint8_t* program; - uint32_t program_len = parse_hex(argv[1], &program); - uint8_t* packet; - uint32_t packet_len = parse_hex(argv[2], &packet); + + uint8_t* program = NULL; + uint32_t program_len; + char *filename = NULL; + char* packet = NULL; uint8_t* data = NULL; - uint32_t data_len = argc > 3 ? parse_hex(argv[3], &data) : 0; - uint32_t filter_age = argc > 4 ? atoi(argv[4]) : 0; + uint32_t data_len = 0; + int32_t filter_age = 0; + + int opt; + char *endptr; + + while ((opt = getopt_long_only(argc, argv, "h", long_options, NULL)) != -1) { + switch (opt) { + case OPT_PROGRAM: + program_len = parse_hex(optarg, &program); + break; + case OPT_PACKET: + if (!program) { + printf("<packet> requires <program> first\n\'%s -h or --help\' " + "for more information\n", basename(argv[0])); + exit(1); + } + if (filename) { + printf("Cannot use <file> with <packet> \n\'%s -h or --help\' " + "for more information\n", basename(argv[0])); + + exit(1); + } + packet = optarg; + break; + case OPT_PCAP: + if (!program) { + printf("<file> requires <program> first\n\'%s -h or --help\' " + "for more information\n", basename(argv[0])); + + exit(1); + } + if (packet) { + printf("Cannot use <packet> with <file>\n\'%s -h or --help\' " + "for more information\n", basename(argv[0])); + + exit(1); + } + filename = optarg; + break; + case OPT_DATA: + data_len = parse_hex(optarg, &data); + break; + case OPT_AGE: + errno = 0; + filter_age = strtoul(optarg, &endptr, 10); + if ((errno == ERANGE && filter_age == ULONG_MAX) + || (errno != 0 && filter_age == 0)) { + perror("Error on age option: strtoul"); + exit(1); + } + if (endptr == optarg) { + printf("No digit found in age.\n"); + exit(1); + } + break; + case 'h': + print_usage(argv[0]); + exit(0); + break; + default: + print_usage(argv[0]); + exit(1); + break; + } + } + + if (!program) { + printf("Must have APF program in option.\n"); + exit(1); + } + + if (!filename && !packet) { + printf("Missing file or packet after program.\n"); + exit(1); + } // Combine the program and data into the unified APF buffer. if (data) { @@ -83,15 +248,18 @@ int main(int argc, char* argv[]) { } uint32_t ram_len = program_len + data_len; - int ret = accept_packet(program, program_len, ram_len, packet, packet_len, - filter_age); - printf("Packet %sed\n", ret ? "pass" : "dropp"); + + if (filename) + file_handler(program, program_len, ram_len, filename, filter_age); + else + packet_handler(program, program_len, ram_len, packet, filter_age); + if (data_len) { printf("Data: "); print_hex(program + program_len, data_len); printf("\n"); } + free(program); - free(packet); - return ret; + return 0; } |