diff --git a/src/fieldset.c b/src/fieldset.c index 5c105cb..25752fa 100644 --- a/src/fieldset.c +++ b/src/fieldset.c @@ -7,31 +7,14 @@ #include "../lib/logger.h" -int fs_split_string(char* in, int *len, char**results) +void gen_fielddef_set(fielddefset_t *fds, fieldset_t fs[], int len) { - - char** fields = calloc(MAX_FIELDS, sizeof(char*)); - memset(fields, 0, sizeof(fields)); - int retvlen = 0; - char *currloc = in; - // parse csv into a set of strings - while (1) { - size_t len = strcspn(currloc, ", "); - char *new = malloc(len+1); - - + if (fds->len + len > MAX_FIELDS) { + log_fatal("fieldset", "out of room in field def set"); } - - (void)len; - *results = fields; - *len = retvlen; - (void)results; - return 0; -} - -void combine_definitions() -{ - + fielddef_t *open = &(fds->fielddefs[fds->len]); + memcpy(open, fs, len*sizeof(fielddef_t)); + fds->len += len; } fieldset_t *fs_new_fieldset(void) @@ -75,8 +58,27 @@ void fs_add_binary(fieldset_t *fs, const char *name, size_t len, fs_add_word(fs, name, FS_BINARY, free_, len, value); } -void fs_free(fieldset_t *fs) +uint64_t fs_get_uint64_by_index(fieldset_t *fs, int index) { + return (uint64_t) fs->fields[i].value; +} + +char* fs_get_string_by_index(fieldset_t *fs, int index) +{ + return (char*) fs->fields[i].value; +} + +int fds_get_index_by_name(fielddefset_t *fds, char *name) +{ + for (int i=0; i < fds->len; i++) { + if (!strcmp(fds->fielddefs[i].name, name)) { + return i; + } + } + return -1; +} + +void fs_free(fieldset_t *fs) for (int i=0; i < fs->len; i++) { field_t *f = &(fs->fields[i]); if (f->free_) { diff --git a/src/fieldset.h b/src/fieldset.h index 5c47990..d733dee 100644 --- a/src/fieldset.h +++ b/src/fieldset.h @@ -8,6 +8,7 @@ #include #include +#include "types.h" #ifndef _FIELDSET_H #define _FIELDSET_H @@ -29,6 +30,11 @@ typedef struct field_def { const char *desc; } fielddef_t; +typedef struct fielddef_set { + fielddef_t fielddefs[MAX_FIELDS]; + int len; +} fielddefset_t; + // the internal field type used by fieldset typedef struct field { const char *name; @@ -61,6 +67,14 @@ typedef struct translation { fieldset_t *fs_new_fieldset(void); +uint64_t fs_get_uint64_by_index(fieldset_t *fs, int index); + +char* fs_get_string_by_index(fieldset_t *fs, int index); + +int fds_get_index_by_name(fielddefset_t *fds, char *name); + +void gen_fielddef_set(fielddefset_t *fds, fieldset_t fs[], int len); + void fs_add_uint64(fieldset_t *fs, const char *name, uint64_t value); void fs_add_string(fieldset_t *fs, const char *name, char *value, int free_); diff --git a/src/probe_modules/module_icmp_echo.c b/src/probe_modules/module_icmp_echo.c index 50907ad..cb6e9a4 100644 --- a/src/probe_modules/module_icmp_echo.c +++ b/src/probe_modules/module_icmp_echo.c @@ -82,33 +82,8 @@ void icmp_echo_print_packet(FILE *fp, void* packet) ntohs(icmp_header->icmp_cksum), ntohs(icmp_header->icmp_id), ntohs(icmp_header->icmp_seq)); - struct in_addr *s = (struct in_addr *) &(iph->saddr); - struct in_addr *d = (struct in_addr *) &(iph->daddr); - char srcip[20]; - char dstip[20]; - // inet_ntoa is a const char * so we if just call it in - // fprintf, you'll get back wrong results since we're - // calling it twice. - strncpy(srcip, inet_ntoa(*s), 19); - strncpy(dstip, inet_ntoa(*d), 19); - fprintf(fp, "ip { saddr: %s | daddr: %s | checksum: %u }\n", - srcip, - dstip, - ntohl(iph->check)); - fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | " - "dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n", - (int) ((unsigned char *) ethh->h_source)[0], - (int) ((unsigned char *) ethh->h_source)[1], - (int) ((unsigned char *) ethh->h_source)[2], - (int) ((unsigned char *) ethh->h_source)[3], - (int) ((unsigned char *) ethh->h_source)[4], - (int) ((unsigned char *) ethh->h_source)[5], - (int) ((unsigned char *) ethh->h_dest)[0], - (int) ((unsigned char *) ethh->h_dest)[1], - (int) ((unsigned char *) ethh->h_dest)[2], - (int) ((unsigned char *) ethh->h_dest)[3], - (int) ((unsigned char *) ethh->h_dest)[4], - (int) ((unsigned char *) ethh->h_dest)[5]); + fprintf_ip_header(fp, iph); + fprintf_eth_header(fp, ethh); fprintf(fp, "------------------------------------------------------\n"); } diff --git a/src/probe_modules/module_tcp_synscan.c b/src/probe_modules/module_tcp_synscan.c index 448a678..a8f2e23 100644 --- a/src/probe_modules/module_tcp_synscan.c +++ b/src/probe_modules/module_tcp_synscan.c @@ -84,45 +84,18 @@ void synscan_print_packet(FILE *fp, void* packet) ntohs(tcph->dest), ntohl(tcph->seq), ntohl(tcph->check)); - struct in_addr *s = (struct in_addr *) &(iph->saddr); - struct in_addr *d = (struct in_addr *) &(iph->daddr); - char srcip[20]; - char dstip[20]; - // inet_ntoa is a const char * so we if just call it in - // fprintf, you'll get back wrong results since we're - // calling it twice. - strncpy(srcip, inet_ntoa(*s), 19); - strncpy(dstip, inet_ntoa(*d), 19); - fprintf(fp, "ip { saddr: %s | daddr: %s | checksum: %u }\n", - srcip, - dstip, - ntohl(iph->check)); - fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | " - "dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n", - (int) ((unsigned char *) ethh->h_source)[0], - (int) ((unsigned char *) ethh->h_source)[1], - (int) ((unsigned char *) ethh->h_source)[2], - (int) ((unsigned char *) ethh->h_source)[3], - (int) ((unsigned char *) ethh->h_source)[4], - (int) ((unsigned char *) ethh->h_source)[5], - (int) ((unsigned char *) ethh->h_dest)[0], - (int) ((unsigned char *) ethh->h_dest)[1], - (int) ((unsigned char *) ethh->h_dest)[2], - (int) ((unsigned char *) ethh->h_dest)[3], - (int) ((unsigned char *) ethh->h_dest)[4], - (int) ((unsigned char *) ethh->h_dest)[5]); + fprintf_ip_header(fp, iph); + fprintf_eth_header(fp, ethh); fprintf(fp, "------------------------------------------------------\n"); } - - int synscan_validate_packet(const struct iphdr *ip_hdr, uint32_t len, - __attribute__((unused))uint32_t *src_ip, uint32_t *validation) + __attribute__((unused))uint32_t *src_ip, + uint32_t *validation) { if (ip_hdr->protocol != IPPROTO_TCP) { return 0; } - if ((4*ip_hdr->ihl + sizeof(struct tcphdr)) > len) { // buffer not large enough to contain expected tcp header return 0; @@ -130,27 +103,21 @@ int synscan_validate_packet(const struct iphdr *ip_hdr, uint32_t len, struct tcphdr *tcp = (struct tcphdr*)((char *)ip_hdr + 4*ip_hdr->ihl); uint16_t sport = tcp->source; uint16_t dport = tcp->dest; - // validate source port if (ntohs(sport) != zconf.target_port) { return 0; } - // validate destination port if (!check_dst_port(ntohs(dport), num_ports, validation)) { return 0; } - // validate tcp acknowledgement number if (htonl(tcp->ack_seq) != htonl(validation[0])+1) { return 0; } - return 1; } - - void synscan_process_packet(const u_char *packet, __attribute__((unused)) uint32_t len, fieldset_t *fs) { @@ -174,13 +141,18 @@ void synscan_process_packet(const u_char *packet, } static fielddef_t fields[] = { - {.name = "sport", .type = "int", .desc = "TCP source port"}, - {.name = "dport", .type = "int", .desc = "TCP destination port"}, + {.name = "sport", .type = "int", .desc = "TCP source port"}, + {.name = "dport", .type = "int", .desc = "TCP destination port"}, {.name = "seqnum", .type = "int", .desc = "TCP sequence number"}, {.name = "acknum", .type = "int", .desc = "TCP acknowledgement number"}, {.name = "window", .type = "int", .desc = "TCP window"}, }; +const char *help = + "Probe module that sends a TCP SYN packet to a specific " + "port. Possible classifications are: synack and rst. A " + "SYN-ACK packet is considered a success and a reset packet " + "is considered a failed response."; probe_module_t module_tcp_synscan = { .name = "tcp_synscan", @@ -195,5 +167,6 @@ probe_module_t module_tcp_synscan = { .process_packet = &synscan_process_packet, .validate_packet = &synscan_validate_packet, .close = NULL, + .helptext = help, .fields = fields}; diff --git a/src/probe_modules/module_udp.c b/src/probe_modules/module_udp.c index be02adb..e048b64 100644 --- a/src/probe_modules/module_udp.c +++ b/src/probe_modules/module_udp.c @@ -109,14 +109,17 @@ int udp_global_initialize(struct state_conf *conf) { udp_send_msg[i] = (n & 0xff); } } else { - log_fatal("udp", "unknown UDP probe specification (expected file:/path, text:STRING, or hex:01020304)"); + log_fatal("udp", "unknown UDP probe specification " + "(expected file:/path, text:STRING, " + "or hex:01020304)"); free(udp_send_msg); free(args); exit(1); } if (udp_send_msg_len > MAX_UDP_PAYLOAD_LEN) { - log_warn("udp", "warning: reducing UDP payload to %d bytes (from %d) to fit on the wire\n", + log_warn("udp", "warning: reducing UDP payload to %d " + "bytes (from %d) to fit on the wire\n", MAX_UDP_PAYLOAD_LEN, udp_send_msg_len); udp_send_msg_len = MAX_UDP_PAYLOAD_LEN; } @@ -132,7 +135,6 @@ int udp_global_cleanup(__attribute__((unused)) struct state_conf *zconf, return(0); } - int udp_init_perthread(void* buf, macaddr_t *src, macaddr_t *gw, __attribute__((unused)) port_h_t dst_port) { @@ -158,9 +160,6 @@ int udp_init_perthread(void* buf, macaddr_t *src, return EXIT_SUCCESS; } - - - int udp_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, uint32_t *validation, int probe_num) { @@ -188,34 +187,8 @@ void udp_print_packet(FILE *fp, void* packet) ntohs(udph->source), ntohs(udph->dest), ntohl(udph->check)); - //ip_header = (struct iphdr*)(ð_header[1]) - struct in_addr *s = (struct in_addr *) &(iph->saddr); - struct in_addr *d = (struct in_addr *) &(iph->daddr); - char srcip[20]; - char dstip[20]; - // inet_ntoa is a const char * so we if just call it in - // fprintf, you'll get back wrong results since we're - // calling it twice. - strncpy(srcip, inet_ntoa(*s), 19); - strncpy(dstip, inet_ntoa(*d), 19); - fprintf(fp, "ip { saddr: %s | daddr: %s | checksum: %u }\n", - srcip, - dstip, - ntohl(iph->check)); - fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | " - "dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n", - (int) ((unsigned char *) ethh->h_source)[0], - (int) ((unsigned char *) ethh->h_source)[1], - (int) ((unsigned char *) ethh->h_source)[2], - (int) ((unsigned char *) ethh->h_source)[3], - (int) ((unsigned char *) ethh->h_source)[4], - (int) ((unsigned char *) ethh->h_source)[5], - (int) ((unsigned char *) ethh->h_dest)[0], - (int) ((unsigned char *) ethh->h_dest)[1], - (int) ((unsigned char *) ethh->h_dest)[2], - (int) ((unsigned char *) ethh->h_dest)[3], - (int) ((unsigned char *) ethh->h_dest)[4], - (int) ((unsigned char *) ethh->h_dest)[5]); + fprintf_ip_header(fp, iph); + fprintf_eth_header(fp, ethh); fprintf(fp, "------------------------------------------------------\n"); } diff --git a/src/probe_modules/packet.c b/src/probe_modules/packet.c index 7e2ee42..0ff752a 100644 --- a/src/probe_modules/packet.c +++ b/src/probe_modules/packet.c @@ -6,7 +6,6 @@ * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ - #include "packet.h" #include @@ -36,6 +35,41 @@ void print_macaddr(struct ifreq* i) (int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[5]); } +void fprintf_ip_header(FILE *fp, struct iphdr *iph) +{ + struct in_addr *s = (struct in_addr *) &(iph->saddr); + struct in_addr *d = (struct in_addr *) &(iph->daddr); + char srcip[20]; + char dstip[20]; + // inet_ntoa is a const char * so we if just call it in + // fprintf, you'll get back wrong results since we're + // calling it twice. + strncpy(srcip, inet_ntoa(*s), 19); + strncpy(dstip, inet_ntoa(*d), 19); + fprintf(fp, "ip { saddr: %s | daddr: %s | checksum: %u }\n", + srcip, + dstip, + ntohl(iph->check)); +} + +void fprintf_eth_header(FILE *fp, struct ethhdr *ethh) +{ + fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | " + "dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n", + (int) ((unsigned char *) ethh->h_source)[0], + (int) ((unsigned char *) ethh->h_source)[1], + (int) ((unsigned char *) ethh->h_source)[2], + (int) ((unsigned char *) ethh->h_source)[3], + (int) ((unsigned char *) ethh->h_source)[4], + (int) ((unsigned char *) ethh->h_source)[5], + (int) ((unsigned char *) ethh->h_dest)[0], + (int) ((unsigned char *) ethh->h_dest)[1], + (int) ((unsigned char *) ethh->h_dest)[2], + (int) ((unsigned char *) ethh->h_dest)[3], + (int) ((unsigned char *) ethh->h_dest)[4], + (int) ((unsigned char *) ethh->h_dest)[5]); +} + void make_eth_header(struct ethhdr *ethh, macaddr_t *src, macaddr_t *dst) { memcpy(ethh->h_source, src, ETH_ALEN); diff --git a/src/probe_modules/probe_modules.c b/src/probe_modules/probe_modules.c index f87ebeb..27a3238 100644 --- a/src/probe_modules/probe_modules.c +++ b/src/probe_modules/probe_modules.c @@ -31,7 +31,6 @@ probe_module_t* probe_modules[] = { // ADD YOUR MODULE HERE }; - probe_module_t* get_probe_module_by_name(const char* name) { for (int i=0; i < (int) (sizeof(probe_modules)/sizeof(probe_modules[0])); i++) { @@ -76,6 +75,8 @@ fielddef_t ip_fields[] = { fielddef_t sys_fields[] = { {.name="repeat", .type="int", .desc="Is response a repeat response from host"}, + {.name="cooldown", .type="int", .desc="Was response received during the cooldown period"}, + {.name="timestamp-str", .type="string", .desc="timestamp of when response arrived in ISO8601 format."} } @@ -87,9 +88,8 @@ void fs_add_ip_fields(fieldset_t *fs, struct iphdr *ip) fs_add_uint64(fs, "ttl", ntohl(ip->ttl)); } -void fs_add_system_fields(fieldset_t *fs) +void fs_add_system_fields(fieldset_t *fs, int is_repeat, int in_cooldown) { - } diff --git a/src/probe_modules/probe_modules.h b/src/probe_modules/probe_modules.h index 613c1e2..b077af7 100644 --- a/src/probe_modules/probe_modules.h +++ b/src/probe_modules/probe_modules.h @@ -37,12 +37,14 @@ typedef struct probe_module { probe_classify_packet_cb process_packet; probe_close_cb close; fielddef_t *fields; - + const char *helptext; } probe_module_t; probe_module_t* get_probe_module_by_name(const char*); +void fs_add_ip_fields(fieldset_t *fs, struct iphdr *ip); +void fs_add_system_fields(fieldset_t *fs, int is_repeat, int in_cooldown); void print_probe_modules(void); #endif // HEADER_PROBE_MODULES_H diff --git a/src/recv.c b/src/recv.c index 1afa9ee..76370cd 100644 --- a/src/recv.c +++ b/src/recv.c @@ -27,11 +27,13 @@ #include #include #include +#include #include "../lib/logger.h" #include "state.h" #include "validate.h" +#include "fieldset.h" #include "probe_modules/probe_modules.h" #include "output_modules/output_modules.h" @@ -92,9 +94,16 @@ void packet_cb(u_char __attribute__((__unused__)) *user, } int is_repeat = check_ip(src_ip); - response_type_t *r = zconf.probe_module->classify_packet(bytes, buflen); - if (r->is_success) { + fieldset_t *fs = fs_new_fieldset(); + fs_add_ip_fields(fs, ip_hdr); + zconf.probe_module->process_packet(bytes, buflen, fs); + fs_add_system_fields(fs, is_repeat, zsend.complete); + int success_index = zconf.fsconf.success_index; + assert(success_index < fs->len); + int is_success = fs_get_uint64_byindex(success_index); + + if (is_success) { zrecv.success_total++; if (!is_repeat) { zrecv.success_unique++; @@ -106,19 +115,15 @@ void packet_cb(u_char __attribute__((__unused__)) *user, zrecv.cooldown_unique++; } } - if (zconf.output_module && zconf.output_module->success_ip) { - zconf.output_module->success_ip( - ip_hdr->saddr, ip_hdr->daddr, - r->name, is_repeat, zsend.complete, bytes, buflen); - } + } else { zrecv.failure_total++; - if (zconf.output_module && zconf.output_module->other_ip) { - zconf.output_module->other_ip( - ip_hdr->saddr, ip_hdr->daddr, - r->name, is_repeat, zsend.complete, bytes, buflen); - } } + //if (zconf.output_module && zconf.output_module->process_record) { + // //zconf.output_module->success_ip( + // // ip_hdr->saddr, ip_hdr->daddr, + // // r->name, is_repeat, zsend.complete, bytes, buflen); + //} if (zconf.output_module && zconf.output_module->update && !(zrecv.success_unique % zconf.output_module->update_interval)) { diff --git a/src/state.h b/src/state.h index 7730b99..efba852 100644 --- a/src/state.h +++ b/src/state.h @@ -13,20 +13,26 @@ #include #include +#include "types.h" +#include "fieldset.h" + #ifndef _STATE_H #define _STATE_H #define MAX_PACKET_SIZE 4096 -typedef uint32_t ipaddr_n_t; // IPv4 address network order -typedef uint32_t ipaddr_h_t; // IPv4 address host order -typedef uint16_t port_n_t; // port network order -typedef uint16_t port_h_t; // port host order -typedef unsigned char macaddr_t; - struct probe_module; struct output_module; +struct fieldset_conf { + fielddefset_t defs; + int *translation; + int translation_len; + int success_index; + int classification_index; +}; + + // global configuration struct state_conf { int log_level; @@ -73,6 +79,7 @@ struct state_conf { char *whitelist_filename; char *raw_output_fields; char **output_fields; + struct fieldset_conf fs_conf; int output_fields_len; int dryrun; int summary; @@ -81,6 +88,7 @@ struct state_conf { }; extern struct state_conf zconf; + // global sender stats struct state_send { double start; diff --git a/src/zmap.c b/src/zmap.c index 79a0f7c..3766d33 100644 --- a/src/zmap.c +++ b/src/zmap.c @@ -367,6 +367,59 @@ int main(int argc, char *argv[]) if (cmdline_parser_required(&args, CMDLINE_PARSER_PACKAGE) != 0) { exit(EXIT_FAILURE); } + // parse the provided probe and output module s.t. that we can support + // other command-line helpers (e.g. probe help) + zconf.output_module = get_output_module_by_name(args.output_module_arg); + if (!zconf.output_module) { + fprintf(stderr, "%s: specified output module (%s) does not exist\n", + CMDLINE_PARSER_PACKAGE, args.output_module_arg); + exit(EXIT_FAILURE); + } + zconf.probe_module = get_probe_module_by_name(args.probe_module_arg); + if (!zconf.probe_module) { + fprintf(stderr, "%s: specified probe module (%s) does not exist\n", + CMDLINE_PARSER_PACKAGE, args.probe_module_arg); + exit(EXIT_FAILURE); + } + + // now that we know the probe module, let's find what it supports + memset(zconf.fs_conf, 0, sizeof(struct fieldset_conf)); + // the set of fields made available to a user is constructed + // of IP header fields + probe module fields + system fields + fielddefset_t *fds = &(zconf.fs_conf.defs); + gen_fieldset_def(fds, &(ip_fields), + sizeof(ip_fields)/sizeof(fielddef_t)); + gen_fieldset_def(fds, &(zconf.probe_module->fields), + sizeof(zconf.probe_module->fields)/sizeof(fielddef_t)); + gen_fieldset_def(fds, &(sys_fields), + sizeof(sys_fields)/sizeof(fielddef_t)); + // find the fields we need for the framework + zconf.fs_conf.success_index = + fs_get_index_by_name(fds, "success"); + if (zconf.fs_conf.success_index < 0) { + log_fatal("fieldset", "probe module does not supply " + "required success field."); + } + zconf.fs_conf.classification_index = + fs_get_index_by_name(fds, "classification"); + if (zconf.fs_conf.classification_index < 0) { + log_fatal("fieldset", "probe module does not supply " + "required packet classification field."); + } + // process the list of requested output fields. + if (args.output_fields_given) { + zconf.raw_output_fields = args.output_fields_arg; + } else { + zconf.raw_output_fields = (char*) "saddr"; + } + fs_split_string(args.output_fields_arg, &(zconf.output_fields_len), + &(zconf.output_fields)); + for (int i=0; i < zconf.output_fields_len; i++) { + log_trace("zmap", "requested output field (%i): %s", + zconf.output_fields[i]); + } + // generate a translation that can be used to convert output + // from a probe module to the input for an output module SET_IF_GIVEN(zconf.output_filename, output_file); SET_IF_GIVEN(zconf.blacklist_filename, blacklist_file); @@ -385,36 +438,7 @@ int main(int argc, char *argv[]) zconf.senders = args.sender_threads_arg; zconf.log_level = args.verbosity_arg; - zconf.output_module = get_output_module_by_name(args.output_module_arg); - if (!zconf.output_module) { - fprintf(stderr, "%s: specified output module (%s) does not exist\n", - CMDLINE_PARSER_PACKAGE, args.output_module_arg); - exit(EXIT_FAILURE); - } - zconf.probe_module = get_probe_module_by_name(args.probe_module_arg); - if (!zconf.probe_module) { - fprintf(stderr, "%s: specified probe module (%s) does not exist\n", - CMDLINE_PARSER_PACKAGE, args.probe_module_arg); - exit(EXIT_FAILURE); - } - // we need to generate a master fielddef list - - // process the list of output fields. - if (args.output_fields_given) { - zconf.raw_output_fields = zopt.output_fields; - fs_split_string(zopt.output_fields, &(zconf.output_fields), - &(zconf.output_fields_len)); - } else { - zconf.output_fields = {"saddr"}; - zconf.num_output_fields = 1; - } - // check the list of requested fields to see if they are available - // with the selected probe module. - for (int i=0; i < zonf.num_output_fields; i++) { - fs_check - - } - + if (zconf.probe_module->port_args) { if (args.source_port_given) {