From 729eb50738777d6dbc27f81d854c824b32bebb05 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 6 May 2016 15:14:16 +0200 Subject: ripe-atlas-fw: imported version 4730 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- eperd/evtdig.c | 283 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 227 insertions(+), 56 deletions(-) (limited to 'eperd/evtdig.c') diff --git a/eperd/evtdig.c b/eperd/evtdig.c index 299a79e..0303cfd 100644 --- a/eperd/evtdig.c +++ b/eperd/evtdig.c @@ -122,9 +122,6 @@ #define T_DNAME ns_t_dname #endif - - - #ifndef ns_t_dlv #define ns_t_dlv 32769 #endif @@ -133,7 +130,6 @@ #define T_DLV ns_t_dlv #endif - #ifndef ns_t_ds #define ns_t_ds 43 #endif @@ -231,8 +227,6 @@ typedef uint32_t counter_t; struct tdig_base { struct event_base *event_base; - struct timeval tv_noreply; /* DNS query Reply timeout */ - /* A circular list of user queries */ struct query_state *qry_head; @@ -264,14 +258,10 @@ struct query_state { struct tdig_base *base; char * name; /* Host identifier as given by the user */ - char * fqname; /* Full qualified hostname */ - char * ipname; /* Remote address in dot notation */ char * infname; /* Bind to this interface (or address) */ u_int16_t qryid; /* query id 16 bit */ struct event event; /* Used to detect read events on udp socket */ - int udp_fd; /* udp_fd and tcp_fd should be merged */ - int tcp_fd; - FILE *tcp_file; + int udp_fd; /* udp_fd */ int wire_size; struct bufferevent *bev_tcp; @@ -294,6 +284,7 @@ struct query_state { int opt_rset; int opt_retry_max; int opt_query_arg; + unsigned opt_timeout; int retry; int resolv_i; @@ -305,6 +296,10 @@ struct query_state { char * server_name; char *out_filename ; + /* For fuzzing */ + char *response_out; + char *response_in; + uint32_t pktsize; /* Packet size in bytes */ struct addrinfo *res, *ressave, *ressent; @@ -338,9 +333,10 @@ struct query_state { unsigned short loc_ai_family ; struct sockaddr_in6 loc_sin6; socklen_t loc_socklen; - u_char *outbuff; + + FILE *resp_file; /* Fuzzing */ }; //DNS header structure struct DNS_HEADER @@ -483,12 +479,16 @@ static struct option longopts[]= { "resolv", no_argument, NULL, O_RESOLV_CONF }, { "qbuf", no_argument, NULL, 1001 }, { "noabuf", no_argument, NULL, 1002 }, + { "timeout", required_argument, NULL, 'T' }, { "evdns", no_argument, NULL, O_EVDNS }, { "out-file", required_argument, NULL, 'O' }, { "p_probe_id", no_argument, NULL, O_PREPEND_PROBE_ID }, { "c_output", no_argument, NULL, O_OUTPUT_COBINED}, - + + { "write-response", required_argument, NULL, 200000 + 'W'}, + { "read-response", required_argument, NULL, 200000 + 'R'}, + { NULL, } }; static char line[(DEFAULT_LINE_LENGTH+1)]; @@ -797,7 +797,7 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet) -/* Attempt to transmit a UDP DNS Request to a serveri. TCP is else where */ +/* Attempt to transmit a UDP DNS Request to a server. TCP is else where */ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event UNUSED_PARAM, void *h) { int r, fd; @@ -807,6 +807,7 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event uint32_t nsent = 0; u_char *outbuff= NULL; int err = 0; + struct timeval tv_noreply; /* Clean the no reply timer (if any was previously set) */ evtimer_del(&qry->noreply_timer); @@ -828,7 +829,16 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event af = ((struct sockaddr *)(qry->res->ai_addr))->sa_family; - if ((fd = socket(af, SOCK_DGRAM, 0) ) < 0 ) + if (qry->response_in) + { + fd= open(qry->response_in, O_RDONLY); + if (fd == -1) + { + crondlog(DIE9 "unable to open '%s': %s", + qry->response_in, strerror(errno)); + } + } + else if ((fd = socket(af, SOCK_DGRAM, 0) ) < 0 ) { snprintf(line, DEFAULT_LINE_LENGTH, "%s \"socket\" : \"socket failed %s\"", qry->err.size ? ", " : "", strerror(errno)); buf_add(&qry->err, line, strlen(line)); @@ -878,7 +888,9 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event } } qry->loc_socklen = sizeof(qry->loc_sin6); - if (connect(qry->udp_fd, qry->res->ai_addr, qry->res->ai_addrlen) == -1) + if (qry->response_in) + ; /* No need to connect */ + else if (connect(qry->udp_fd, qry->res->ai_addr, qry->res->ai_addrlen) == -1) { snprintf(line, DEFAULT_LINE_LENGTH, "%s \"socket\" : \"connect failed %s\"", @@ -891,12 +903,18 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event return; } - nsent = send(qry->udp_fd, outbuff,qry->pktsize, MSG_DONTWAIT); + if (qry->response_in) + nsent= qry->pktsize; + else + { + nsent = send(qry->udp_fd, outbuff,qry->pktsize, + MSG_DONTWAIT); + } qry->ressent = qry->res; if (nsent == qry->pktsize) { - if (getsockname(qry->udp_fd, (struct sockaddr *)&qry->loc_sin6, &qry->loc_socklen) == -1) { - snprintf(line, DEFAULT_LINE_LENGTH, "%s \"getscokname\" : \"%s\"", qry->err.size ? ", " : "", strerror(errno)); + if (!qry->response_in && getsockname(qry->udp_fd, (struct sockaddr *)&qry->loc_sin6, &qry->loc_socklen) == -1) { + snprintf(line, DEFAULT_LINE_LENGTH, "%s \"getsockname\" : \"%s\"", qry->err.size ? ", " : "", strerror(errno)); buf_add(&qry->err, line, strlen(line)); } @@ -905,7 +923,8 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event base->sentbytes += nsent; err = 0; /* Add the timer to handle no reply condition in the given timeout */ - evtimer_add(&qry->noreply_timer, &base->tv_noreply); + msecstotv(qry->opt_timeout, &tv_noreply); + evtimer_add(&qry->noreply_timer, &tv_noreply); if(qry->opt_qbuf) { buf_init(&qry->qbuf, -1); buf_add_b64(&qry->qbuf, outbuff, qry->pktsize, 0); @@ -919,6 +938,8 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event , strerror(errno) , qry->res->ai_family == AF_INET ? "AF_INET" :"NOT AF_INET"); buf_add(&qry->err, line, strlen(line)); } + if (qry->response_in) + ready_callback(0, 0, qry); } while ((qry->res = qry->res->ai_next) != NULL); free (outbuff); outbuff = NULL; @@ -946,8 +967,9 @@ static void noreply_callback(int unused UNUSED_PARAM, const short event UNUSED_ { struct timeval asap = { 1, 1 }; struct query_state *qry = h; + qry->base->timeout++; - snprintf(line, DEFAULT_LINE_LENGTH, "%s \"timeout\" : %d", qry->err.size ? ", " : "", DEFAULT_NOREPLY_TIMEOUT); + snprintf(line, DEFAULT_LINE_LENGTH, "%s \"timeout\" : %d", qry->err.size ? ", " : "", qry->opt_timeout); buf_add(&qry->err, line, strlen(line)); BLURT(LVL5 "AAA timeout for %s retry %d/%d ", qry->server_name, qry->retry, qry->opt_retry_max); @@ -1062,7 +1084,8 @@ static void tcp_connected(struct tu_env *env, struct bufferevent *bev) qry = ENV2QRY(env); qry->loc_socklen= sizeof(qry->loc_sin6); - getsockname(bufferevent_getfd(bev), &qry->loc_sin6, &qry->loc_socklen); + if (!qry->response_in) + getsockname(bufferevent_getfd(bev), &qry->loc_sin6, &qry->loc_socklen); qry->bev_tcp = bev; outbuff = xzalloc(MAX_DNS_BUF_SIZE); @@ -1072,7 +1095,11 @@ static void tcp_connected(struct tu_env *env, struct bufferevent *bev) wire = xzalloc (payload_len + 4); ldns_write_uint16(wire, qry->pktsize); memcpy(wire + 2, outbuff, qry->pktsize); - evbuffer_add(bufferevent_get_output(qry->bev_tcp), wire, (qry->pktsize +2)); + if (!qry->response_in) + { + evbuffer_add(bufferevent_get_output(qry->bev_tcp), wire, + (qry->pktsize +2)); + } qry->base->sentok++; qry->base->sentbytes+= (qry->pktsize +2); BLURT(LVL5 "send %u bytes", payload_len ); @@ -1111,10 +1138,17 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) clock_gettime(CLOCK_MONOTONIC_RAW, &rectime); bzero(qry->base->packet, MAX_DNS_BUF_SIZE); - input = bufferevent_get_input(bev); + if (!qry->response_in) + input = bufferevent_get_input(bev); if(qry->wire_size == 0) { - n = evbuffer_remove(input, b2, 2 ); + if (qry->response_in) + n= fread(b2, 1, 2, qry->resp_file); + else + n = evbuffer_remove(input, b2, 2 ); + printf("got %d bytes for response size\n", n); if(n == 2){ + if (qry->response_out) + fwrite(b2, 2, 1, qry->resp_file); qry->wire_size = ldns_read_uint16(b2); buf_init(&qry->packet, -1); } @@ -1124,7 +1158,20 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) buf_add(&qry->err, line, strlen(line)); } } - while ((n = evbuffer_remove(input,line , DEFAULT_LINE_LENGTH )) > 0) { + for (;;) { + if (qry->response_in) + n= fread(line, 1, 1, qry->resp_file); + else + n = evbuffer_remove(input,line , DEFAULT_LINE_LENGTH ); + printf("got %d bytes for data size\n", n); + if (n <= 0) + { + if (qry->response_in) + noreply_callback(0,0,qry); + break; + } + if (qry->response_out) + fwrite(line, n, 1, qry->resp_file); buf_add(&qry->packet, line, n); if(qry->wire_size == qry->packet.size) { crondlog(LVL5 "in readcb %s %s red %d bytes ", qry->str_Atlas, qry->server_name, qry->wire_size); @@ -1213,6 +1260,7 @@ static void ready_callback (int unused UNUSED_PARAM, const short event UNUSED_PA struct query_state * qry; int nrecv; struct timespec rectime; + FILE *fh; // printf("in ready_callback\n"); @@ -1223,13 +1271,30 @@ static void ready_callback (int unused UNUSED_PARAM, const short event UNUSED_PA clock_gettime(CLOCK_MONOTONIC_RAW, &rectime); /* Receive data from the network */ - nrecv = recv(qry->udp_fd, qry->base->packet, - sizeof(qry->base->packet), MSG_DONTWAIT); + if (qry->response_in) + { + nrecv= read(qry->udp_fd, qry->base->packet, + sizeof(qry->base->packet)); + } + else + { + nrecv = recv(qry->udp_fd, qry->base->packet, + sizeof(qry->base->packet), MSG_DONTWAIT); + } if (nrecv < 0) { /* One more failure */ qry->base->recvfail++; return ; } + if (qry->response_out) + { + fh= fopen(qry->response_out, "w"); + if (fh) + { + fwrite(qry->base->packet, nrecv, 1, fh); + fclose(fh); + } + } process_reply(arg, nrecv, rectime); return; } @@ -1309,6 +1374,25 @@ static bool argProcess (int argc, char *argv[], struct query_state *qry ) tdig_delete(qry); return TRUE; } + if (qry->response_in) + { + if (!validate_filename(qry->response_in, ATLAS_FUZZING)) + { + crondlog(LVL8 "insecure fuzzing file '%s'", qry->response_in); + tdig_delete(qry); + return TRUE; + } + } + if (qry->response_out) + { + if (!validate_filename(qry->response_out, ATLAS_FUZZING)) + { + crondlog(LVL8 "insecure fuzzing file '%s'", qry->response_out); + tdig_delete(qry); + return TRUE; + } + } + if(qry->opt_v6_only == 0) @@ -1346,9 +1430,7 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) qry->str_Atlas = NULL; qry->out_filename = NULL; qry->opt_proto = 17; - qry->tcp_file = NULL; qry->udp_fd = -1; - qry->tcp_fd = -1; qry->server_name = NULL; qry->str_Atlas = NULL; qry->infname = NULL; @@ -1381,6 +1463,7 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) qry->result.offset = qry->result.size = qry->result.maxsize= 0; qry->result.buf = NULL; qry->opt_query_arg = 0; + qry->opt_timeout= DEFAULT_NOREPLY_TIMEOUT; /* initialize callbacks : */ /* sendpacket called by UDP send */ @@ -1471,6 +1554,10 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) qry->opt_proto = 6; break; + case 'T' : + qry->opt_timeout = strtoul(optarg, NULL, 10); + break; + case 1001: qry->opt_qbuf = 1; break; @@ -1733,6 +1820,18 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) qry->lookupname = strdup(optarg); break; + case 200000 + 'W': + printf("write-response: to %s\n", optarg); + if (qry->response_out) free(qry->response_out); + qry->response_out= strdup(optarg); + break; + + case 200000 + 'R': + printf("read-response: from %s\n", optarg); + if (qry->response_in) free(qry->response_in); + qry->response_in= strdup(optarg); + break; + default: fprintf(stderr, "ERROR unknown option %d ??\n", c); tdig_delete(qry); @@ -1744,6 +1843,10 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) if(argProcess(argc, argv, qry)) return NULL; + qry->opt_evdns = 1; /* Always enabled, leave the old code in + * place for now. + */ + qry->base = tdig_base; /* insert this qry into the list of queries */ @@ -1805,8 +1908,6 @@ struct tdig_base * tdig_base_new(struct event_base *event_base) evtimer_assign(&tdig_base->statsReportEvent, tdig_base->event_base, tdig_stats, tdig_base); - msecstotv(DEFAULT_NOREPLY_TIMEOUT, &tdig_base->tv_noreply); - // Define the callback to handle UDP Reply // add the raw file descriptor to those monitored for read events @@ -1933,15 +2034,44 @@ void tdig_start (void *arg) } else { // TCP Query + if (qry->response_out) + { + qry->resp_file= fopen(qry->response_out, "w"); + if (!qry->resp_file) + { + crondlog(DIE9 "unable to write to '%s'", + qry->response_out); + } + } + qry->wire_size = 0; crondlog(LVL5 "TCP QUERY %s", qry->server_name); interval.tv_sec = CONN_TO; interval.tv_usec= 0; - tu_connect_to_name (&qry->tu_env, qry->server_name, port_as_char, - &interval, &hints, qry->infname, - tcp_timeout_callback, tcp_reporterr, - tcp_dnscount, tcp_beforeconnect, - tcp_connected, tcp_readcb, tcp_writecb); + + if (qry->response_in) + { + qry->resp_file= fopen(qry->response_in, "r"); + if (!qry->resp_file) + { + crondlog(DIE9 "unable to read from '%s'", + qry->response_in); + } + tcp_connected(&qry->tu_env, NULL); + tcp_writecb(NULL, &qry->tu_env); + while(qry->resp_file != NULL) + tcp_readcb(NULL, &qry->tu_env); + // report(qry); + } + else + { + tu_connect_to_name (&qry->tu_env, qry->server_name, + port_as_char, + &interval, &hints, qry->infname, + tcp_timeout_callback, tcp_reporterr, + tcp_dnscount, tcp_beforeconnect, + tcp_connected, tcp_readcb, tcp_writecb); + } } return ; @@ -2061,6 +2191,12 @@ static void free_qry_inst(struct query_state *qry) struct timeval asap = { 1, 0 }; BLURT(LVL5 "freeing instance of %s ", qry->server_name); + if (qry->response_in) + { + asap.tv_sec= 0; + asap.tv_usec= 1; + } + if(qry->err.size) { buf_cleanup(&qry->err); @@ -2120,6 +2256,11 @@ static void free_qry_inst(struct query_state *qry) if(qry->base->done) { evtimer_add(&qry->done_qry_timer, &asap); } + if (qry->response_in && qry->resp_file) + { + fclose(qry->resp_file); + qry->resp_file= NULL; + } break; } } @@ -2254,7 +2395,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) u_int32_t serial; int iMax ; int flagAnswer = 0; - int data_len; + int data_len, offset; int write_out = FALSE; int fw = get_atlas_fw_version(); @@ -2380,12 +2521,21 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) { iMax = MIN(2, ntohs(dnsR->ans_count)); + memset(answers, '\0', sizeof(answers)); + for(i=0;i + result + wire_size) + { + /* Report error? */ + break; + } + answers[i].resource = (struct R_DATA*)(reader); reader = reader + sizeof(struct R_DATA); @@ -2404,7 +2554,11 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) flagAnswer++; JS (TYPE, "TXT"); JS (NAME, answers[i].name); - print_txt_json(&result[reader-result], data_len, qry); + offset= reader-result; + if (offset+data_len > wire_size) + data_len= wire_size-offset; + print_txt_json(reader, + data_len, qry); reader = reader + ntohs(answers[i].resource->data_len); AS("}"); @@ -2514,7 +2668,8 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset, int* count) { unsigned char *name; - unsigned int p=0,jumped=0, len; + unsigned int p=0,jumped=0, jump_count=0, len; + size_t noffset; *count = 0; name = (unsigned char*)malloc(256); @@ -2522,28 +2677,41 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset, name[0]= '\0'; //read the names in 3www6google3com format - while(len= base[offset], len !=0) + while(offset < size && (len= base[offset], len !=0)) { if (len & 0xc0) { if ((len & 0xc0) != 0xc0) { /* Bad format */ - strcpy((char *)name, "format-error"); - printf("format-error: len = %d\n", - len); - abort(); + snprintf((char *)name, sizeof(name), + "format-error at %lu: value 0x%x", + offset, len); + //abort(); return name; } - offset= ((len & ~0xc0) << 8) | base[offset+1]; - if (offset >= size) + noffset= ((len & ~0xc0) << 8) | base[offset+1]; + if (noffset >= size) { - strcpy((char *)name, "offset-error"); - printf("offset-error\n"); - abort(); + snprintf((char *)name, sizeof(name), + "offset-error at %lu: offset %lu", + offset, noffset); + //abort(); return name; } + + if (jump_count > 256) + { + /* Too many */ + snprintf((char *)name, sizeof(name), + "too many redirects at %lu", + offset); + //abort(); + return name; + } + + offset= noffset; if(jumped==0) { /* if we havent jumped to another location @@ -2552,21 +2720,24 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset, *count += 2; } jumped= 1; + jump_count++; continue; } if (offset+len+1 > size) { - strcpy((char *)name, "buf-bounds-error"); - printf("buf-bounds-error\n"); - abort(); + snprintf((char *)name, sizeof(name), + "buf-bounds-error at %lu: len %d", + offset, len); + //abort(); return name; } if (p+len+1 > 255) { - strcpy((char *)name, "name-length-error"); - printf("name-length-error\n"); - abort(); + snprintf((char *)name, sizeof(name), + "name-length-error at %lu: len %d", + offset, p+len+1); + //abort(); return name; } memcpy(name+p, base+offset+1, len); -- cgit v1.2.3