From b8c5c3b44362778c099531f7a905c56a0423bcef Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 15 May 2015 10:25:21 +0200 Subject: ripe-atlas-fw: imported version 4650 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- eperd/eooqd.c | 5 +- eperd/evtdig.c | 17 +- eperd/httpget.c | 21 +- eperd/ping.c | 350 +++++++++++++++------------- eperd/readresolv.c | 39 ++++ eperd/readresolv.h | 2 + eperd/sslgetcert.c | 11 +- eperd/tcputil.c | 44 +++- eperd/tcputil.h | 5 +- eperd/traceroute.c | 674 +++++++++++++++++++++++++++-------------------------- 10 files changed, 656 insertions(+), 512 deletions(-) (limited to 'eperd') diff --git a/eperd/eooqd.c b/eperd/eooqd.c index 7e071c0..41efa1b 100644 --- a/eperd/eooqd.c +++ b/eperd/eooqd.c @@ -616,7 +616,10 @@ static const char *get_session_id(void) cp= strchr(session_id, '\n'); if (cp) *cp= '\0'; - return session_id; + cp= strrchr(session_id, ' '); + if (!cp) + return NULL; + return cp+1; } static void skip_space(char *cp, char **ncpp) diff --git a/eperd/evtdig.c b/eperd/evtdig.c index b3813de..e0a8ae5 100644 --- a/eperd/evtdig.c +++ b/eperd/evtdig.c @@ -712,7 +712,7 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet) dns->aa = 0; //Not Authoritative dns->tc = 0; //This message is not truncated dns->rd = 0; //Recursion not Desired - dns->ra = 1; //Recursion not available! hey we dont have it (lol) + dns->ra = 0; //Recursion not available! hey we dont have it (lol) dns->z = 0; dns->ad = 0; dns->cd = 0; @@ -1895,7 +1895,8 @@ void tdig_start (struct query_state *qry) interval.tv_sec = CONN_TO; interval.tv_usec= 0; tu_connect_to_name (&qry->tu_env, qry->server_name, port_as_char, - &interval, &hints, tcp_timeout_callback, tcp_reporterr, + &interval, &hints, NULL, + tcp_timeout_callback, tcp_reporterr, tcp_dnscount, tcp_beforeconnect, tcp_connected, tcp_readcb, tcp_writecb); @@ -2194,7 +2195,9 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) int flagAnswer = 0; int data_len; int write_out = FALSE; - u_int32_t fw; + + int fw = get_atlas_fw_version(); + int lts = get_timesync(); if(! qry->result.size){ buf_init(&qry->result, -1); @@ -2206,19 +2209,21 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) JS(id, qry->str_Atlas); } - fw = get_atlas_fw_version(); - JU(fw, fw); - + JD(fw, fw); if (qry->opt_rset){ JS1(time, %ld, qry->xmit_time.tv_sec); + JD(lts,lts); AS("\"resultset\" : [ {"); } + } else if(qry->opt_rset) { AS (",{"); } JS1(time, %ld, qry->xmit_time.tv_sec); + JD(lts,lts); + if ( qry->opt_resolv_conf ) { JD (subid, (qry->resolv_i+1)); JD (submax, qry->base->resolv_max); diff --git a/eperd/httpget.c b/eperd/httpget.c index d0d3e4c..4b22bca 100644 --- a/eperd/httpget.c +++ b/eperd/httpget.c @@ -91,6 +91,7 @@ struct hgstate int etim; size_t read_limit; unsigned timeout; + char *infname; /* State */ char busy; @@ -368,7 +369,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], char *url, *check; char *post_file, *output_file, *post_footer, *post_header, *A_arg, *store_headers, *store_body, *read_limit_str, - *timeout_str; + *timeout_str, *infname; const char *user_agent; char *host, *port, *hostport, *path; struct hgstate *state; @@ -390,6 +391,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], read_limit_str= NULL; timeout_str= NULL; A_arg= NULL; + infname= NULL; only_v4= 0; only_v6= 0; do_etim= 0; @@ -406,7 +408,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], /* Allow us to be called directly by another program in busybox */ optind= 0; - while (c= getopt_long(argc, argv, "01aA:cO:46", longopts, NULL), c != -1) + while (c= getopt_long(argc, argv, "01aA:cI:O:46", longopts, NULL), c != -1) { switch(c) { @@ -455,6 +457,9 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], case 'h': /* --post-header */ post_header= optarg; break; + case 'I': + infname= optarg; + break; case 'O': output_file= optarg; break; @@ -622,6 +627,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], state->max_body= max_body; state->read_limit= read_limit; state->timeout= timeout; + state->infname= infname; state->only_v4= 2; @@ -701,8 +707,10 @@ static void report(struct hgstate *state) { fprintf(fh, DBQ(id) ":" DBQ(%s) ", " DBQ(fw) ":%d, " + DBQ(lts) ":%d, " DBQ(time) ":%ld, ", state->atlas, get_atlas_fw_version(), + get_timesync(), state->gstart); } fprintf(fh, DBQ(result) ":[ "); @@ -1822,6 +1830,13 @@ static void reporterr(struct tu_env *env, enum tu_err cause, err_reading(state); break; + case TU_SOCKET_ERR: + snprintf(line, sizeof(line), + "{ " DBQ(sockerr) ":" DBQ(%s) ", ", str); + add_str(state, line); + report(state); + break; + case TU_CONNECT_ERR: snprintf(line, sizeof(line), DBQ(err) ":" DBQ(connect: %s) ", ", str); @@ -1890,7 +1905,7 @@ static void httpget_start(void *state) interval.tv_sec= hgstate->timeout / 1000; interval.tv_usec= (hgstate->timeout % 1000) * 1000; tu_connect_to_name(&hgstate->tu_env, hgstate->host, hgstate->port, - &interval, &hints, timeout_callback, + &interval, &hints, hgstate->infname, timeout_callback, reporterr, dnscount, beforeconnect, connected, readcb, writecb); } diff --git a/eperd/ping.c b/eperd/ping.c index 16aa8fe..4d17317 100644 --- a/eperd/ping.c +++ b/eperd/ping.c @@ -26,7 +26,7 @@ #define DBQ(str) "\"" #str "\"" -#define PING_OPT_STRING ("!46rc:s:A:O:") +#define PING_OPT_STRING ("!46rc:s:A:O:i:I:") enum { @@ -71,25 +71,13 @@ struct pingbase { struct event_base *event_base; - evutil_socket_t rawfd4; /* Raw socket used to ping hosts (IPv4) - */ - evutil_socket_t rawfd6; /* Raw socket used to ping hosts (IPv6) - */ - pid_t pid; /* Identifier to send with each ICMP * Request */ - struct timeval tv_interval; /* Ping interval between two subsequent - * pings */ - /* A list of hosts to ping. */ struct pingstate **table; int tabsiz; - struct event event4; /* Used to detect read events on raw - * socket */ - struct event event6; /* Used to detect read events on raw - * socket */ void (*done)(void *state); /* Called when a ping is done */ u_char packet [MAX_DATA_SIZE]; @@ -100,9 +88,11 @@ struct pingstate /* Parameters */ char *atlas; char *hostname; + char *interface; int pingcount; char *out_filename; char delay_name_res; + unsigned interval; /* State */ struct sockaddr_in6 sin6; @@ -110,6 +100,7 @@ struct pingstate struct sockaddr_in6 loc_sin6; socklen_t loc_socklen; int busy; + int socket; char got_reply; char first; char no_dst; @@ -117,6 +108,9 @@ struct pingstate unsigned size; unsigned psize; + struct event event; /* Used to detect read events on raw + * socket */ + char *result; size_t reslen; size_t resmax; @@ -186,19 +180,6 @@ static void add_str(struct pingstate *state, const char *str) //printf("add_str: result = '%s'\n", state->result); } -static int get_timesync(void) -{ - FILE *fh; - int lastsync; - - fh= fopen(ATLAS_TIMESYNC_FILE, "r"); - if (!fh) - return -1; - fscanf(fh, "%d", &lastsync); - fclose(fh); - return time(NULL)-lastsync; -} - static void report(struct pingstate *state) { FILE *fh; @@ -259,13 +240,23 @@ static void report(struct pingstate *state) #endif /* DO_PSIZE */ fprintf(fh, ", \"result\": [ %s ] }\n", state->result); + free(state->result); state->result= NULL; - state->busy= 0; - if (state->out_filename) fclose(fh); + + /* Kill the event and close socket */ + event_del(&state->event); + if (state->socket != -1) + { + close(state->socket); + state->socket= -1; + } + + state->busy= 0; + } static void ping_cb(int result, int bytes, int psize, @@ -558,8 +549,9 @@ static void fmticmp6(u_char *buffer, size_t *sizep, static void ping_xmit(struct pingstate *host) { struct pingbase *base = host->base; + struct timeval tv_interval; - int nsent, fd4, fd6, t_errno, r; + int nsent; if (host->sentpkts >= host->maxpkts) { @@ -587,27 +579,14 @@ static void ping_xmit(struct pingstate *host) fmticmp6(base->packet, &host->cursize, host->seq, host->index, base->pid); - fd6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - if (fd6 != -1) - { - r= connect(fd6, (struct sockaddr *)&host->sin6, - host->socklen); - if (r == 0) - { - host->loc_socklen= - sizeof(host->loc_sin6); - getsockname(fd6, &host->loc_sin6, - &host->loc_socklen); - } - } + host->loc_socklen= sizeof(host->loc_sin6); + getsockname(host->socket, &host->loc_sin6, &host->loc_socklen); - nsent = sendto(fd6, base->packet, host->cursize+ICMP6_HDRSIZE, + nsent = sendto(host->socket, base->packet, + host->cursize+ICMP6_HDRSIZE, MSG_DONTWAIT, (struct sockaddr *)&host->sin6, host->socklen); - t_errno= errno; - close(fd6); - errno= t_errno; } else { @@ -615,28 +594,13 @@ static void ping_xmit(struct pingstate *host) fmticmp4(base->packet, &host->cursize, host->seq, host->index, base->pid); - fd4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - if (fd4 != -1) - { - r= connect(fd4, (struct sockaddr *)&host->sin6, - host->socklen); - if (r == 0) - { - host->loc_socklen= - sizeof(host->loc_sin6); - getsockname(fd4, &host->loc_sin6, - &host->loc_socklen); - } - } + host->loc_socklen= sizeof(host->loc_sin6); + getsockname(host->socket, &host->loc_sin6, &host->loc_socklen); - - nsent = sendto(fd4, base->packet, host->cursize+ICMP_MINLEN, + nsent = sendto(host->socket, base->packet, + host->cursize+ICMP_MINLEN, MSG_DONTWAIT, (struct sockaddr *)&host->sin6, host->socklen); - - t_errno= errno; - close(fd4); - errno= t_errno; } if (nsent > 0) @@ -660,7 +624,8 @@ static void ping_xmit(struct pingstate *host) /* Add the timer to handle no reply condition in the given timeout */ - evtimer_add(&host->ping_timer, &host->base->tv_interval); + msecstotv(host->interval, &tv_interval); + evtimer_add(&host->ping_timer, &tv_interval); } @@ -673,9 +638,7 @@ static void noreply_callback(int __attribute((unused)) unused, const short __att { ping_cb(PING_ERR_TIMEOUT, host->cursize, -1, (struct sockaddr *)&host->sin6, host->socklen, - NULL, 0, - host->seq, -1, &host->base->tv_interval, - host); + NULL, 0, host->seq, -1, NULL, host); /* Update the sequence number for the next run */ host->seq = (host->seq + 1) % 256; @@ -698,29 +661,32 @@ static void noreply_callback(int __attribute((unused)) unused, const short __att static void ready_callback4 (int __attribute((unused)) unused, const short __attribute((unused)) event, void * arg) { - struct pingbase *base = arg; - + struct pingstate *state; + struct pingbase *base; int nrecv, isDup; - struct sockaddr_in remote; /* responding internet address */ + struct sockaddr_in remote; /* responding internet address */ socklen_t slen = sizeof(struct sockaddr); struct sockaddr_in *sin4p; struct sockaddr_in loc_sin4; - - /* Pointer to relevant portions of the packet (IP, ICMP and user data) */ - struct ip * ip = (struct ip *) base->packet; + struct ip * ip; struct icmphdr * icmp; - struct evdata * data = (struct evdata *) (base->packet + IPHDR + ICMP_MINLEN); + struct evdata * data; int hlen = 0; - struct timeval now; - struct pingstate * host; + state= arg; + base = state->base; + + /* Pointer to relevant portions of the packet (IP, ICMP and user + * data) */ + ip = (struct ip *) base->packet; + data = (struct evdata *) (base->packet + IPHDR + ICMP_MINLEN); /* Time the packet has been received */ gettimeofday(&now, NULL); // printf("ready_callback4: before recvfrom\n"); /* Receive data from the network */ - nrecv = recvfrom(base->rawfd4, base->packet, sizeof(base->packet), MSG_DONTWAIT, (struct sockaddr *) &remote, &slen); + nrecv = recvfrom(state->socket, base->packet, sizeof(base->packet), MSG_DONTWAIT, (struct sockaddr *) &remote, &slen); if (nrecv < 0) { goto done; @@ -766,7 +732,8 @@ printf("ready_callback4: too short\n"); } /* Get the pointer to the host descriptor in our internal table */ - host= base->table[data->index]; + if (state != base->table[data->index]) + goto done; /* Not for us */ /* Check for Destination Host Unreachable */ if (icmp->type == ICMP_ECHO) @@ -786,31 +753,31 @@ printf("ready_callback4: too short\n"); memset(sin4p, '\0', sizeof(*sin4p)); sin4p->sin_family= AF_INET; sin4p->sin_addr= ip->ip_dst; - host->rcvd_ttl= ip->ip_ttl; + state->rcvd_ttl= ip->ip_ttl; /* Report everything with the wrong sequence number as a dup. * This is not quite right, it could be a late packet. Do we * care? */ - isDup= (ntohs(icmp->un.echo.sequence) != host->seq); + isDup= (ntohs(icmp->un.echo.sequence) != state->seq); ping_cb(isDup ? PING_ERR_DUP : PING_ERR_NONE, nrecv - IPHDR - ICMP_MINLEN, nrecv, - (struct sockaddr *)&host->sin6, host->socklen, + (struct sockaddr *)&state->sin6, state->socklen, (struct sockaddr *)&loc_sin4, sizeof(loc_sin4), ntohs(icmp->un.echo.sequence), ip->ip_ttl, &elapsed, - host); + state); /* Update the sequence number for the next run */ - host->seq = (host->seq + 1) % 256; + state->seq = (state->seq + 1) % 256; if (!isDup) - host->got_reply= 1; + state->got_reply= 1; } else { printf("ready_callback4: not an echo reply\n"); /* Handle this condition exactly as the request has expired */ - noreply_callback (-1, -1, host); + noreply_callback (-1, -1, state); } done: @@ -831,18 +798,16 @@ done: static void ready_callback6 (int __attribute((unused)) unused, const short __attribute((unused)) event, void * arg) { - struct pingbase *base = arg; + struct pingbase *base; + struct pingstate *state; int nrecv, isDup; struct sockaddr_in remote; /* responding internet address */ - /* Pointer to relevant portions of the packet (IP, ICMP and user data) */ - struct icmp6_hdr * icmp = (struct icmp6_hdr *) base->packet; - struct evdata * data = (struct evdata *) (base->packet + - offsetof(struct icmp6_hdr, icmp6_data16[2])); + struct icmp6_hdr *icmp; + struct evdata * data; struct timeval now; - struct pingstate * host; struct cmsghdr *cmsgptr; struct sockaddr_in6 *sin6p; struct msghdr msg; @@ -850,6 +815,15 @@ static void ready_callback6 (int __attribute((unused)) unused, struct iovec iov[1]; char cmsgbuf[256]; + state= arg; + base = state->base; + + /* Pointer to relevant portions of the packet (IP, ICMP and user + * data) */ + icmp = (struct icmp6_hdr *) base->packet; + data = (struct evdata *) (base->packet + + offsetof(struct icmp6_hdr, icmp6_data16[2])); + /* Time the packet has been received */ gettimeofday(&now, NULL); @@ -864,7 +838,7 @@ static void ready_callback6 (int __attribute((unused)) unused, msg.msg_flags= 0; /* Not really needed */ /* Receive data from the network */ - nrecv= recvmsg(base->rawfd6, &msg, MSG_DONTWAIT); + nrecv= recvmsg(state->socket, &msg, MSG_DONTWAIT); if (nrecv < 0) { goto done; @@ -885,7 +859,8 @@ static void ready_callback6 (int __attribute((unused)) unused, } /* Get the pointer to the host descriptor in our internal table */ - host= base->table[data->index]; + if (state != base->table[data->index]) + goto done; /* Not for us */ /* Check for Destination Host Unreachable */ if (icmp->icmp6_type == ICMP6_ECHO_REPLY) @@ -914,7 +889,7 @@ static void ready_callback6 (int __attribute((unused)) unused, if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) { - host->rcvd_ttl= *(int *)CMSG_DATA(cmsgptr); + state->rcvd_ttl= *(int *)CMSG_DATA(cmsgptr); } } @@ -922,23 +897,23 @@ static void ready_callback6 (int __attribute((unused)) unused, * This is not quite right, it could be a late packet. Do we * care? */ - isDup= (ntohs(icmp->icmp6_seq) != host->seq); + isDup= (ntohs(icmp->icmp6_seq) != state->seq); ping_cb(isDup ? PING_ERR_DUP : PING_ERR_NONE, nrecv - ICMP6_HDRSIZE, nrecv + sizeof(struct ip6_hdr), - (struct sockaddr *)&host->sin6, host->socklen, + (struct sockaddr *)&state->sin6, state->socklen, (struct sockaddr *)&loc_sin6, sizeof(loc_sin6), - ntohs(icmp->icmp6_seq), host->rcvd_ttl, &elapsed, - host); + ntohs(icmp->icmp6_seq), state->rcvd_ttl, &elapsed, + state); /* Update the sequence number for the next run */ - host->seq = (host->seq + 1) % 256; + state->seq = (state->seq + 1) % 256; if (!isDup) - host->got_reply= 1; + state->got_reply= 1; } else /* Handle this condition exactly as the request has expired */ - noreply_callback (-1, -1, host); + noreply_callback (-1, -1, state); done: ; @@ -953,53 +928,18 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], int i, newsiz, delay_name_res; uint32_t opt; unsigned pingcount; /* must be int-sized */ - unsigned size; + unsigned size, interval; sa_family_t af; const char *hostname; char *str_Atlas; char *out_filename; + char *interface; struct pingstate *state; len_and_sockaddr *lsa; FILE *fh; if (!ping_base) { - int p_proto, on; - struct protoent *protop; - evutil_socket_t fd4, fd6; - - /* Check if the ICMP protocol is available on this system */ - protop = getprotobyname("icmp"); - if (protop) - p_proto= protop->p_proto; - else - p_proto= IPPROTO_ICMP; - - /* Create an endpoint for communication using raw socket for ICMP calls */ - if ((fd4 = socket(AF_INET, SOCK_RAW, p_proto)) == -1) { - return NULL; - } - - /* Check if the ICMP6 protocol is available on this system */ - protop = getprotobyname("icmp6"); - if (protop) - p_proto= protop->p_proto; - else - p_proto= IPPROTO_ICMPV6; - - if ((fd6 = socket(AF_INET6, SOCK_RAW, p_proto)) == -1) { - close(fd4); - return NULL; - } - - on = 1; - setsockopt(fd6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, - sizeof(on)); - - on = 1; - setsockopt(fd6, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, - sizeof(on)); - ping_base = malloc(sizeof(*ping_base)); if (ping_base == NULL) return (NULL); @@ -1011,27 +951,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], ping_base->table= xzalloc(ping_base->tabsiz * sizeof(*ping_base->table)); - ping_base->rawfd4 = fd4; - ping_base->rawfd6 = fd6; - evutil_make_socket_nonblocking(ping_base->rawfd4); - evutil_make_socket_nonblocking(ping_base->rawfd6); - /* Set default values */ ping_base->pid = getpid(); - msecstotv(DEFAULT_PING_INTERVAL, &ping_base->tv_interval); - - /* Define the callback to handle ICMP Echo Reply and add the - * raw file descriptor to those monitored for read events */ - event_assign(&ping_base->event4, ping_base->event_base, - ping_base->rawfd4, EV_READ | EV_PERSIST, - ready_callback4, ping_base); - event_assign(&ping_base->event6, ping_base->event_base, - ping_base->rawfd6, EV_READ | EV_PERSIST, - ready_callback6, ping_base); - event_add(&ping_base->event4, NULL); - event_add(&ping_base->event6, NULL); - ping_base->done= 0; } @@ -1040,10 +962,12 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], size= 0; str_Atlas= NULL; out_filename= NULL; + interval= DEFAULT_PING_INTERVAL; + interface= NULL; /* exactly one argument needed; -c NUM */ - opt_complementary = "=1:c+:s+"; + opt_complementary = "=1:c+:s+:i+"; opt = getopt32(argv, PING_OPT_STRING, &pingcount, &size, - &str_Atlas, &out_filename); + &str_Atlas, &out_filename, &interval, &interface); hostname = argv[optind]; if (opt == 0xffffffff) @@ -1052,6 +976,12 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], return NULL; } + if (interval < 1 || interval > 60000) + { + crondlog(LVL8 "bad interval"); + return NULL; + } + if (out_filename) { if (!validate_filename(out_filename, SAFE_PREFIX)) @@ -1078,10 +1008,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], } } - af= AF_UNSPEC; if (opt & opt_4) af= AF_INET; - if (opt & opt_6) + else af= AF_INET6; delay_name_res= !!(opt & opt_r); @@ -1113,6 +1042,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], state->base = ping_base; state->af= af; state->delay_name_res= delay_name_res; + state->interval= interval; + state->interface= interface; + state->socket= -1; state->seq = 1; @@ -1157,7 +1089,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], static void ping_start2(void *state) { + int p_proto, on, fd; struct pingstate *pingstate; + char line[80]; pingstate= state; @@ -1167,6 +1101,98 @@ static void ping_start2(void *state) pingstate->send_error= 0; pingstate->got_reply= 0; + if (pingstate->af == AF_INET) + { + /* Check if the ICMP protocol is available on this system */ + p_proto= IPPROTO_ICMP; + + /* Create an endpoint for communication using raw socket for + * ICMP calls */ + if ((fd = socket(AF_INET, SOCK_RAW, p_proto)) == -1) { + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(socket failed: %s) + " }", strerror(errno)); + add_str(pingstate, line); + report(pingstate); + if (pingstate->base->done) + pingstate->base->done(pingstate); + return; + } + pingstate->socket= fd; + + /* Define the callback to handle ICMP Echo Reply and add the + * raw file descriptor to those monitored for read events */ + event_assign(&pingstate->event, pingstate->base->event_base, + pingstate->socket, EV_READ | EV_PERSIST, + ready_callback4, state); + } + else + { + /* Check if the ICMP6 protocol is available on this system */ + p_proto= IPPROTO_ICMPV6; + + if ((fd = socket(AF_INET6, SOCK_RAW, p_proto)) == -1) { + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(socket failed: %s) + " }", strerror(errno)); + add_str(pingstate, line); + report(pingstate); + if (pingstate->base->done) + pingstate->base->done(pingstate); + return; + } + + on = 1; + setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + sizeof(on)); + + on = 1; + setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + sizeof(on)); + + pingstate->socket= fd; + + /* Define the callback to handle ICMP Echo Reply and add the + * raw file descriptor to those monitored for read events */ + event_assign(&pingstate->event, pingstate->base->event_base, + pingstate->socket, EV_READ | EV_PERSIST, + ready_callback6, state); + } + + evutil_make_socket_nonblocking(pingstate->socket); + + if (pingstate->interface) + { + if (bind_interface(pingstate->socket, pingstate->af, + pingstate->interface) == -1) + { + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" + DBQ(bind to interface failed) + " }"); + add_str(pingstate, line); + report(pingstate); + if (pingstate->base->done) + pingstate->base->done(pingstate); + return; + } + } + + if (connect(pingstate->socket, &pingstate->sin6, + pingstate->socklen) == -1) + { + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(connect failed: %s) + " }", strerror(errno)); + add_str(pingstate, line); + report(pingstate); + if (pingstate->base->done) + pingstate->base->done(pingstate); + return; + } + + event_add(&pingstate->event, NULL); + ping_xmit(pingstate); } diff --git a/eperd/readresolv.c b/eperd/readresolv.c index cd43bd3..0f68a37 100644 --- a/eperd/readresolv.c +++ b/eperd/readresolv.c @@ -110,3 +110,42 @@ void get_local_resolvers(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], *resolv_max = i; return; } + +void get_local_resolvers_nocache(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], + int *resolv_max) +{ + +#ifndef RESOLV_CONF +#define RESOLV_CONF "/etc/resolv.conf" +#endif + FILE *R; + char buf[LINEL]; + char *buf_start; + int i = 0; + int r; + struct stat sb; + + r = stat(RESOLV_CONF, &sb); + if (r == -1) + { + crondlog(LVL8 "error accessing resolv.conf: %s", + strerror(errno)); + return; + } + + R = fopen (RESOLV_CONF, "r"); + if (R != NULL) { + while ( (fgets (buf, LINEL, R)) && (i < MAXNS)) { + buf_start = buf; + if(resolv_conf_parse_line(nslist[i], buf) ) { + crondlog(LVL5 "parsed file %s , line %s i=%d", RESOLV_CONF, buf_start, i); + i++; + } + else + crondlog(LVL5 "ERROR failed to parse from %s i=%d, line %s", RESOLV_CONF, i, buf_start); + } + fclose (R); + } + + *resolv_max = i; +} diff --git a/eperd/readresolv.h b/eperd/readresolv.h index 4c1fa83..b418d71 100644 --- a/eperd/readresolv.h +++ b/eperd/readresolv.h @@ -3,3 +3,5 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ void get_local_resolvers(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], int *resolv_max); +void get_local_resolvers_nocache(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], + int *resolv_max); diff --git a/eperd/sslgetcert.c b/eperd/sslgetcert.c index 2b71cc4..0a0f885 100644 --- a/eperd/sslgetcert.c +++ b/eperd/sslgetcert.c @@ -748,8 +748,9 @@ static void report(struct state *state) { fprintf(fh, DBQ(id) ":" DBQ(%s) ", " DBQ(fw) ":%d, " + DBQ(lts) ":%d, " DBQ(time) ":%ld, ", - state->atlas, get_atlas_fw_version(), + state->atlas, get_atlas_fw_version(), get_timesync(), state->gstart); } @@ -977,8 +978,10 @@ static int eat_certificate(struct state *state) if (state->atlas) { fprintf(fh, DBQ(id) ":" DBQ(%s) - ", " DBQ(fw) ":%d", - state->atlas, get_atlas_fw_version()); + ", " DBQ(fw) ":%d" + ", " DBQ(lts) ":%d", + state->atlas, get_atlas_fw_version(), + get_timesync()); } fprintf(fh, "%s" DBQ(time) ":%ld", @@ -1260,7 +1263,7 @@ static void sslgetcert_start(void *vstate) tu_connect_to_name(&state->tu_env, state->hostname, state->portname, - &interval, &hints, timeout_callback, + &interval, &hints, NULL, timeout_callback, reporterr, dnscount, beforeconnect, connected, readcb, writecb); } diff --git a/eperd/tcputil.c b/eperd/tcputil.c index d3d6134..355f42a 100644 --- a/eperd/tcputil.c +++ b/eperd/tcputil.c @@ -13,12 +13,13 @@ #include "tcputil.h" static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx); -static void create_bev(struct tu_env *env); +static int create_bev(struct tu_env *env); static void eventcb(struct bufferevent *bev, short events, void *ptr); void tu_connect_to_name(struct tu_env *env, char *host, char *port, struct timeval *interval, struct evutil_addrinfo *hints, + char *infname, void (*timeout_callback)(int unused, const short event, void *s), void (*reporterr)(struct tu_env *env, enum tu_err cause, const char *err), @@ -30,6 +31,7 @@ void tu_connect_to_name(struct tu_env *env, char *host, char *port, void (*writecb)(struct bufferevent *bev, void *ptr)) { env->interval= *interval; + env->infname= infname; env->reporterr= reporterr; env->reportcount= reportcount; env->beforeconnect= beforeconnect; @@ -49,6 +51,7 @@ void tu_connect_to_name(struct tu_env *env, char *host, char *port, void tu_restart_connect(struct tu_env *env) { + int r; struct bufferevent *bev; /* Delete old bev */ @@ -59,7 +62,11 @@ void tu_restart_connect(struct tu_env *env) } /* And create a new one */ - create_bev(env); + r= create_bev(env); + if (r == -1) + { + return; + } bev= env->bev; /* Connect failed, try next address */ @@ -118,7 +125,7 @@ void tu_cleanup(struct tu_env *env) static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) { - int count; + int r, count; struct tu_env *env; struct bufferevent *bev; struct evutil_addrinfo *cur; @@ -151,7 +158,11 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) env->reportcount(env, count); - create_bev(env); + r= create_bev(env); + if (r == -1) + { + return; + } while (env->dns_curr) { @@ -192,21 +203,44 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) env->reporterr(env, TU_OUT_OF_ADDRS, ""); } -static void create_bev(struct tu_env *env) +static int create_bev(struct tu_env *env) { + int af, fd; struct bufferevent *bev; + af= env->dns_curr->ai_addr->sa_family; + bev= bufferevent_socket_new(EventBase, -1, BEV_OPT_CLOSE_ON_FREE); if (!bev) { crondlog(DIE9 "bufferevent_socket_new failed"); } + if (env->infname) + { + fd= socket(af, SOCK_STREAM, 0); + if (fd == -1) + { + env->reporterr(env, TU_SOCKET_ERR, + "socket call failed"); + return -1; + } + + if (bind_interface(fd, af, env->infname) == -1) + { + env->reporterr(env, TU_SOCKET_ERR, + "bind_interface failed"); + close(fd); + return -1; + } + bufferevent_setfd(bev, fd); + } bufferevent_setcb(bev, env->readcb, env->writecb, eventcb, env); bufferevent_enable(bev, EV_WRITE); env->bev= bev; env->connecting= 1; + return 0; } static void eventcb(struct bufferevent *bev, short events, void *ptr) diff --git a/eperd/tcputil.h b/eperd/tcputil.h index d2b11ec..da26641 100644 --- a/eperd/tcputil.h +++ b/eperd/tcputil.h @@ -6,7 +6,8 @@ #include -enum tu_err { TU_DNS_ERR, TU_READ_ERR, TU_CONNECT_ERR, TU_OUT_OF_ADDRS }; +enum tu_err { TU_DNS_ERR, TU_READ_ERR, TU_SOCKET_ERR, TU_CONNECT_ERR, + TU_OUT_OF_ADDRS }; struct tu_env { char dnsip; @@ -15,6 +16,7 @@ struct tu_env struct evutil_addrinfo *dns_curr; struct bufferevent *bev; struct timeval interval; + char *infname; struct event timer; void (*reporterr)(struct tu_env *env, enum tu_err cause, const char *str); @@ -29,6 +31,7 @@ struct tu_env void tu_connect_to_name(struct tu_env *env, char *host, char *port, struct timeval *timeout, struct evutil_addrinfo *hints, + char *infname, void (*timeout_callback)(int unused, const short event, void *env), void (*reporterr)(struct tu_env *env, enum tu_err cause, const char *err), diff --git a/eperd/traceroute.c b/eperd/traceroute.c index d655e44..a3d0f24 100644 --- a/eperd/traceroute.c +++ b/eperd/traceroute.c @@ -28,7 +28,7 @@ #define uh_sum check #endif -#define TRACEROUTE_OPT_STRING ("!46IUFrTa:c:f:g:m:p:w:z:A:O:S:H:D:") +#define TRACEROUTE_OPT_STRING ("!46IUFrTa:c:f:g:i:m:p:w:z:A:O:S:H:D:") #define OPT_4 (1 << 0) #define OPT_6 (1 << 1) @@ -63,21 +63,8 @@ struct trtbase { struct event_base *event_base; - int v4icmp_rcv; - int v6icmp_rcv; - int v4icmp_snd; - int v6icmp_snd; - int v4tcp_rcv; - int v6tcp_rcv; - int v4udp_snd; - int my_pid; - struct event event4; - struct event tcp_event4; - struct event event6; - struct event tcp_event6; - struct trtstate **table; int tabsiz; @@ -95,9 +82,10 @@ struct trtstate /* Parameters */ char *atlas; char *hostname; - const char *destportstr; + char *destportstr; char *out_filename; - char do_Xicmp; + char *interface; + char do_icmp; char do_tcp; char do_udp; char do_v6; @@ -128,6 +116,13 @@ struct trtstate uint16_t paris; uint16_t seq; unsigned short curpacksize; + + int socket_icmp; /* Socket for sending and receiving + * ICMPs */ + struct event event_icmp; /* Event for this socket */ + int socket_tcp; /* Socket for sending and receiving + * raw TCP */ + struct event event_tcp; /* Event for this socket */ uint8_t last_response_hop; /* Hop at which we last got something * back. @@ -160,6 +155,7 @@ struct trtstate char *result; size_t reslen; size_t resmax; + char open_result; }; static struct trtbase *trt_base; @@ -191,6 +187,8 @@ struct v6info struct timeval tv; }; +static int create_socket(struct trtstate *state, int do_tcp); + #define OPT_PAD1 0 #define OPT_PADN 1 static void do_hbh_dest_opt(struct trtbase *base, int sock, int hbh_dest, @@ -387,9 +385,11 @@ static void report(struct trtstate *state) { fprintf(fh, DBQ(id) ":" DBQ(%s) ", " DBQ(fw) ":%d" + ", " DBQ(lts) ":%d" ", " DBQ(time) ":%ld" ", " DBQ(endtime) ":%ld, ", state->atlas, get_atlas_fw_version(), + get_timesync(), state->starttime, (long)time(NULL)); } @@ -412,7 +412,7 @@ static void report(struct trtstate *state) fprintf(fh, ", " DBQ(src_addr) ":" DBQ(%s), namebuf); } - if (state->do_Xicmp) + if (state->do_icmp) proto= "ICMP"; else if (state->do_tcp) proto= "TCP"; @@ -430,13 +430,29 @@ static void report(struct trtstate *state) state->paris % state->parismod); } fprintf(fh, ", \"result\": [ %s ] }\n", state->result); + free(state->result); state->result= NULL; - state->busy= 0; if (state->out_filename) fclose(fh); + /* Kill the event and close socket */ + if (state->socket_icmp != -1) + { + event_del(&state->event_icmp); + close(state->socket_icmp); + state->socket_icmp= -1; + } + if (state->socket_tcp != -1) + { + event_del(&state->event_tcp); + close(state->socket_tcp); + state->socket_tcp= -1; + } + + state->busy= 0; + if (state->base->done) state->base->done(state); } @@ -498,8 +514,9 @@ static void send_pkt(struct trtstate *state) } snprintf(line, sizeof(line), - ", { \"hop\":%d, \"result\": [ ", state->hop); + ", { " DBQ(hop) ":%d, " DBQ(result) ": [ ", state->hop); add_str(state, line); + state->open_result= 0; } state->seq++; @@ -628,21 +645,21 @@ static void send_pkt(struct trtstate *state) } } } - else if (state->do_Xicmp) + else if (state->do_icmp) { /* Set hop count */ - setsockopt(base->v6icmp_snd, SOL_IPV6, + setsockopt(state->socket_icmp, SOL_IPV6, IPV6_UNICAST_HOPS, &hop, sizeof(hop)); /* Set/clear don't fragment */ on= (state->dont_fragment ? IPV6_PMTUDISC_DO : IPV6_PMTUDISC_DONT); - setsockopt(base->v6icmp_snd, IPPROTO_IPV6, + setsockopt(state->socket_icmp, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on)); - do_hbh_dest_opt(base, base->v6icmp_snd, 0 /* hbh */, + do_hbh_dest_opt(base, state->socket_icmp, 0 /* hbh */, state->hbhoptsize); - do_hbh_dest_opt(base, base->v6icmp_snd, 1 /* dest */, + do_hbh_dest_opt(base, state->socket_icmp, 1 /* dest */, state->destoptsize); icmp6_hdr= (struct icmp6_hdr *)base->packet; @@ -708,7 +725,7 @@ static void send_pkt(struct trtstate *state) memset(&sin6copy, '\0', sizeof(sin6copy)); sin6copy.sin6_family= AF_INET6; sin6copy.sin6_addr= state->sin6.sin6_addr; - r= sendto(base->v6icmp_snd, base->packet, len, 0, + r= sendto(state->socket_icmp, base->packet, len, 0, (struct sockaddr *)&sin6copy, sizeof(sin6copy)); @@ -996,7 +1013,7 @@ static void send_pkt(struct trtstate *state) } } } - else if (state->do_Xicmp) + else if (state->do_icmp) { hop= state->hop; @@ -1044,16 +1061,16 @@ static void send_pkt(struct trtstate *state) #endif /* Set hop count */ - setsockopt(base->v4icmp_snd, IPPROTO_IP, IP_TTL, + setsockopt(state->socket_icmp, IPPROTO_IP, IP_TTL, &hop, sizeof(hop)); /* Set/clear don't fragment */ on= (state->dont_fragment ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT); - setsockopt(base->v4icmp_snd, IPPROTO_IP, + setsockopt(state->socket_icmp, IPPROTO_IP, IP_MTU_DISCOVER, &on, sizeof(on)); - r= sendto(base->v4icmp_snd, base->packet, len, 0, + r= sendto(state->socket_icmp, base->packet, len, 0, (struct sockaddr *)&state->sin6, state->socklen); @@ -1224,9 +1241,10 @@ static void send_pkt(struct trtstate *state) } } - if (state->sent) + if (state->open_result) add_str(state, " }, "); add_str(state, "{ "); + state->open_result= 0; /* Increment packets sent */ state->sent++; @@ -1344,10 +1362,11 @@ static void ready_callback4(int __attribute((unused)) unused, gettimeofday(&now, NULL); - base= s; + state= s; + base= state->base; slen= sizeof(remote); - nrecv= recvfrom(base->v4icmp_rcv, base->packet, sizeof(base->packet), + nrecv= recvfrom(state->socket_icmp, base->packet, sizeof(base->packet), MSG_DONTWAIT, (struct sockaddr *)&remote, &slen); if (nrecv == -1) { @@ -1412,9 +1431,8 @@ static void ready_callback4(int __attribute((unused)) unused, */ ind= ntohl(etcp->seq) >> 16; - state= NULL; - if (ind >= 0 && ind < base->tabsiz) - state= base->table[ind]; + if (ind != state->index) + state= NULL; if (state && state->sin6.sin6_family != AF_INET) state= NULL; if (state && !state->do_tcp) @@ -1453,6 +1471,9 @@ static void ready_callback4(int __attribute((unused)) unused, /* Sequence number is in seq field */ seq= ntohl(etcp->seq) & 0xffff; + if (state->open_result) + add_str(state, " }, { "); + if (seq != state->seq) { if (seq > state->seq) @@ -1467,14 +1488,14 @@ static void ready_callback4(int __attribute((unused)) unused, } late= 1; - snprintf(line, sizeof(line), "\"late\":%d", + snprintf(line, sizeof(line), DBQ(late) ":%d", state->seq-seq); add_str(state, line); } else if (state->gotresp) { isDup= 1; - add_str(state, " }, { \"dup\":true"); + add_str(state, " " DBQ(dup) ":true"); } if (!late && !isDup) @@ -1611,12 +1632,11 @@ printf("curpacksize: %d\n", state->curpacksize); */ ind= ntohs(eudp->uh_sport) - SRC_BASE_PORT; - state= NULL; - if (ind >= 0 && ind < base->tabsiz) - state= base->table[ind]; + if (ind != state->index) + state= NULL; if (state && state->sin6.sin6_family != AF_INET) state= NULL; - if (state && state->do_Xicmp) + if (state && state->do_icmp) state= NULL; if (!state) @@ -1665,6 +1685,9 @@ printf("curpacksize: %d\n", state->curpacksize); seq= ntohs(eudp->uh_dport)-BASE_PORT; } + if (state->open_result) + add_str(state, " }, { "); + if (seq != state->seq) { if (seq > state->seq) @@ -1679,14 +1702,14 @@ printf("curpacksize: %d\n", state->curpacksize); } late= 1; - snprintf(line, sizeof(line), "\"late\":%d", + snprintf(line, sizeof(line), DBQ(late) ":%d", state->seq-seq); add_str(state, line); } else if (state->gotresp) { isDup= 1; - add_str(state, " }, { \"dup\":true"); + add_str(state, " " DBQ(dup) ":true"); } if (!late && !isDup) @@ -1839,8 +1862,7 @@ printf("curpacksize: %d\n", state->curpacksize); return; } - state= base->table[ind]; - if (!state) + if (ind != state->index) { /* Nothing here */ printf( @@ -1855,7 +1877,7 @@ printf("curpacksize: %d\n", state->curpacksize); return; } - if (!state->do_Xicmp) + if (!state->do_icmp) { printf( "ready_callback4: index (%d) is not doing ICMP\n", @@ -1880,6 +1902,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family state->hostname); } + if (state->open_result) + add_str(state, " }, { "); + late= 0; isDup= 0; seq= ntohs(eicmp->icmp_seq); @@ -1897,14 +1922,14 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } late= 1; - snprintf(line, sizeof(line), "\"late\":%d", + snprintf(line, sizeof(line), DBQ(late) ":%d", state->seq-seq); add_str(state, line); } else if (state->gotresp) { isDup= 1; - add_str(state, " }, { \"dup\":true"); + add_str(state, DBQ(dup) ":true"); } if (!late && !isDup) @@ -2072,8 +2097,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } } - if (late) - add_str(state, " }, { "); + state->open_result= 1; if (!late && !isDup) { @@ -2109,8 +2133,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family return; } - state= base->table[ind]; - if (!state) + if (ind != state->index) { /* Nothing here */ printf( @@ -2134,6 +2157,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family return; } + if (state->open_result) + add_str(state, " }, { "); + late= 0; isDup= 0; seq= ntohs(icmp->icmp_seq); @@ -2150,14 +2176,14 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } late= 1; - snprintf(line, sizeof(line), "\"late\":%d", + snprintf(line, sizeof(line), DBQ(late) ":%d", state->seq-seq); add_str(state, line); } else if (state->gotresp) { isDup= 1; - add_str(state, " }, { \"dup\":true"); + add_str(state, DBQ(dup) ":true"); } if (memcmp(&ip->ip_dst, @@ -2195,8 +2221,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family /* Done */ state->done= 1; - if (late) - add_str(state, " }, { "); + state->open_result= 1; if (!late && !isDup) { @@ -2245,10 +2270,11 @@ static void ready_tcp4(int __attribute((unused)) unused, gettimeofday(&now, NULL); - base= s; + state= s; + base= state->base; slen= sizeof(remote); - nrecv= recvfrom(base->v4tcp_rcv, base->packet, sizeof(base->packet), + nrecv= recvfrom(state->socket_tcp, base->packet, sizeof(base->packet), MSG_DONTWAIT, (struct sockaddr *)&remote, &slen); if (nrecv == -1) { @@ -2279,9 +2305,8 @@ static void ready_tcp4(int __attribute((unused)) unused, /* We store the id in high order 16 bits of the sequence number */ ind= ntohl(tcphdr->ack_seq) >> 16; - state= NULL; - if (ind >= 0 && ind < base->tabsiz) - state= base->table[ind]; + if (ind != state->index) + state= NULL; if (state && state->sin6.sin6_family != AF_INET) state= NULL; if (state && !state->do_tcp) @@ -2306,6 +2331,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family late= 0; isDup= 0; + if (state->open_result) + add_str(state, " }, { "); + /* Only check if the ack is without 64k of what we expect */ seq= ntohl(tcphdr->ack_seq) & 0xffff; if (seq-state->seq > 0x2000) @@ -2322,14 +2350,14 @@ printf("got seq %d, expected %d\n", seq, state->seq); } late= 1; - snprintf(line, sizeof(line), "\"late\":%d", + snprintf(line, sizeof(line), DBQ(late) ":%d", state->seq-seq); add_str(state, line); } else if (state->gotresp) { isDup= 1; - add_str(state, " }, { \"dup\":true"); + add_str(state, DBQ(dup) ":true"); } ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + @@ -2368,8 +2396,7 @@ printf("got seq %d, expected %d\n", seq, state->seq); /* Done */ state->done= 1; - if (late) - add_str(state, " }, { "); + state->open_result= 1; if (!late && !isDup) { @@ -2411,7 +2438,8 @@ static void ready_tcp6(int __attribute((unused)) unused, gettimeofday(&now, NULL); - base= s; + state= s; + base= state->base; iov[0].iov_base= base->packet; iov[0].iov_len= sizeof(base->packet); @@ -2423,7 +2451,7 @@ static void ready_tcp6(int __attribute((unused)) unused, msg.msg_controllen= sizeof(cmsgbuf); msg.msg_flags= 0; /* Not really needed */ - nrecv= recvmsg(base->v6tcp_rcv, &msg, MSG_DONTWAIT); + nrecv= recvmsg(state->socket_tcp, &msg, MSG_DONTWAIT); if (nrecv == -1) { /* Strange, read error */ @@ -2463,9 +2491,8 @@ static void ready_tcp6(int __attribute((unused)) unused, /* We store the id in high order 16 bits of the sequence number */ ind= ntohl(tcphdr->ack_seq) >> 16; - state= NULL; - if (ind >= 0 && ind < base->tabsiz) - state= base->table[ind]; + if (ind != state->index) + state= NULL; if (state && state->sin6.sin6_family != AF_INET6) state= NULL; if (state && !state->do_tcp) @@ -2488,6 +2515,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family late= 0; isDup= 0; + if (state->open_result) + add_str(state, " }, { "); + /* Only check if the ack is within 64k of what we expect */ seq= ntohl(tcphdr->ack_seq) & 0xffff; if (seq-state->seq > 0x2000) @@ -2504,14 +2534,14 @@ printf("got seq %d, expected %d\n", seq, state->seq); } late= 1; - snprintf(line, sizeof(line), "\"late\":%d", + snprintf(line, sizeof(line), DBQ(late) ":%d", state->seq-seq); add_str(state, line); } else if (state->gotresp) { isDup= 1; - add_str(state, " }, { \"dup\":true"); + add_str(state, DBQ(dup) ":true"); } ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + @@ -2549,8 +2579,7 @@ printf("got seq %d, expected %d\n", seq, state->seq); /* Done */ state->done= 1; - if (late) - add_str(state, " }, { "); + state->open_result= 1; if (!late && !isDup) { @@ -2599,7 +2628,8 @@ static void ready_callback6(int __attribute((unused)) unused, gettimeofday(&now, NULL); - base= s; + state= s; + base= state->base; iov[0].iov_base= base->packet; iov[0].iov_len= sizeof(base->packet); @@ -2611,7 +2641,7 @@ static void ready_callback6(int __attribute((unused)) unused, msg.msg_controllen= sizeof(cmsgbuf); msg.msg_flags= 0; /* Not really needed */ - nrecv= recvmsg(base->v6icmp_rcv, &msg, MSG_DONTWAIT); + nrecv= recvmsg(state->socket_icmp, &msg, MSG_DONTWAIT); if (nrecv == -1) { /* Strange, read error */ @@ -2695,7 +2725,7 @@ static void ready_callback6(int __attribute((unused)) unused, #endif return; } - opthdr= (struct ip6_ext *)&eip[1]; + opthdr= (struct ip6_ext *)ptr; hbhoptsize= 8*opthdr->ip6e_len; optlen= hbhoptsize+8; if (nrecv < sizeof(*icmp) + sizeof(*eip) + @@ -2704,7 +2734,7 @@ static void ready_callback6(int __attribute((unused)) unused, /* Does not contain the full header */ return; } - ehdrsiz= optlen; + ehdrsiz += optlen; nxt= opthdr->ip6e_nxt; ptr= ((char *)opthdr)+optlen; } @@ -2723,7 +2753,7 @@ static void ready_callback6(int __attribute((unused)) unused, #endif return; } - frag= (struct ip6_frag *)&eip[1]; + frag= (struct ip6_frag *)ptr; if ((ntohs(frag->ip6f_offlg) & ~3) != 0) { /* Not first fragment, just ignore @@ -2731,7 +2761,7 @@ static void ready_callback6(int __attribute((unused)) unused, */ return; } - ehdrsiz= sizeof(*frag); + ehdrsiz += sizeof(*frag); nxt= frag->ip6f_nxt; ptr= &frag[1]; } @@ -2750,7 +2780,7 @@ static void ready_callback6(int __attribute((unused)) unused, #endif return; } - opthdr= (struct ip6_ext *)&eip[1]; + opthdr= (struct ip6_ext *)ptr; dstoptsize= 8*opthdr->ip6e_len; optlen= dstoptsize+8; if (nrecv < sizeof(*icmp) + sizeof(*eip) + @@ -2759,7 +2789,7 @@ static void ready_callback6(int __attribute((unused)) unused, /* Does not contain the full header */ return; } - ehdrsiz= optlen; + ehdrsiz += optlen; nxt= opthdr->ip6e_nxt; ptr= ((char *)opthdr)+optlen; } @@ -2838,9 +2868,8 @@ static void ready_callback6(int __attribute((unused)) unused, ind= ntohl(v6info->id); } - state= NULL; - if (ind >= 0 && ind < base->tabsiz) - state= base->table[ind]; + if (ind != state->index) + state= NULL; if (state && state->sin6.sin6_family != AF_INET6) state= NULL; @@ -2849,7 +2878,7 @@ static void ready_callback6(int __attribute((unused)) unused, { if ((etcp && !state->do_tcp) || (eudp && !state->do_udp) || - (eicmp && !state->do_Xicmp)) + (eicmp && !state->do_icmp)) { state= NULL; } @@ -2888,6 +2917,10 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } else seq= ntohl(v6info->seq); + + if (state->open_result) + add_str(state, " }, { "); + if (seq != state->seq) { if (seq > state->seq) @@ -2902,13 +2935,13 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } late= 1; - snprintf(line, sizeof(line), "\"late\":%d", + snprintf(line, sizeof(line), DBQ(late) ":%d", state->seq-seq); add_str(state, line); } else if (state->gotresp) { isDup= 1; - add_str(state, " }, { \"dup\":true"); + add_str(state, DBQ(dup) ":true"); } if (!late && !isDup) @@ -3042,16 +3075,19 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family state->done= 1; switch(icmp->icmp6_code) { - case ICMP6_DST_UNREACH_NOROUTE: + case ICMP6_DST_UNREACH_NOROUTE: /* 0 */ add_str(state, ", \"err\":\"N\""); break; - case ICMP6_DST_UNREACH_ADDR: - add_str(state, ", \"err\":\"H\""); + case ICMP6_DST_UNREACH_ADMIN: /* 1 */ + add_str(state, ", \"err\":\"A\""); break; - case ICMP6_DST_UNREACH_NOPORT: + case ICMP6_DST_UNREACH_BEYONDSCOPE: /* 2 */ + add_str(state, ", \"err\":\"h\""); break; - case ICMP6_DST_UNREACH_ADMIN: - add_str(state, ", \"err\":\"A\""); + case ICMP6_DST_UNREACH_ADDR: /* 3 */ + add_str(state, ", \"err\":\"H\""); + break; + case ICMP6_DST_UNREACH_NOPORT: /* 4 */ break; default: snprintf(line, sizeof(line), @@ -3110,8 +3146,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } } - if (late) - add_str(state, " }, { "); + state->open_result= 1; if (!late && !isDup) { @@ -3153,14 +3188,12 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family ind= ntohl(v6info->id); - state= NULL; - if (ind >= 0 && ind < base->tabsiz) - state= base->table[ind]; - + if (ind != state->index) + state= NULL; if (state && state->sin6.sin6_family != AF_INET6) state= NULL; - if (state && !state->do_Xicmp) + if (state && !state->do_icmp) { state= NULL; } @@ -3189,6 +3222,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family return; } + if (state->open_result) + add_str(state, " }, { "); + late= 0; isDup= 0; seq= ntohl(v6info->seq); @@ -3204,14 +3240,14 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } late= 1; - snprintf(line, sizeof(line), "\"late\":%d", + snprintf(line, sizeof(line), DBQ(late) ":%d", state->seq-seq); add_str(state, line); } else if (state->gotresp) { isDup= 1; - add_str(state, " }, { \"dup\":true"); + add_str(state, DBQ(dup) ":true"); } if (!late && !isDup) @@ -3260,8 +3296,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family sizeof(buf)), state->hop); #endif - if (late) - add_str(state, " }, { "); + state->open_result= 1; if (!late && !isDup) { @@ -3296,7 +3331,6 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family static struct trtbase *traceroute_base_new(struct event_base *event_base) { - int on; struct trtbase *base; base= xzalloc(sizeof(*base)); @@ -3306,40 +3340,8 @@ static struct trtbase *traceroute_base_new(struct event_base base->tabsiz= 10; base->table= xzalloc(base->tabsiz * sizeof(*base->table)); - base->v4icmp_rcv= xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - base->v6icmp_rcv= xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - base->v4icmp_snd= xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - base->v6icmp_snd= xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - base->v4tcp_rcv= xsocket(AF_INET, SOCK_RAW, IPPROTO_TCP); - base->v6tcp_rcv= xsocket(AF_INET6, SOCK_RAW, IPPROTO_TCP); - base->v4udp_snd= xsocket(AF_INET, SOCK_DGRAM, 0); - base->my_pid= getpid(); - on = 1; - setsockopt(base->v6icmp_rcv, IPPROTO_IPV6, IPV6_RECVPKTINFO, - &on, sizeof(on)); - - on = 1; - setsockopt(base->v6icmp_rcv, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, - &on, sizeof(on)); - on = 1; - setsockopt(base->v6tcp_rcv, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, - &on, sizeof(on)); - - event_assign(&base->event4, base->event_base, base->v4icmp_rcv, - EV_READ | EV_PERSIST, ready_callback4, base); - event_assign(&base->tcp_event4, base->event_base, base->v4tcp_rcv, - EV_READ | EV_PERSIST, ready_tcp4, base); - event_assign(&base->event6, base->event_base, base->v6icmp_rcv, - EV_READ | EV_PERSIST, ready_callback6, base); - event_assign(&base->tcp_event6, base->event_base, base->v6tcp_rcv, - EV_READ | EV_PERSIST, ready_tcp6, base); - event_add(&base->event4, NULL); - event_add(&base->tcp_event4, NULL); - event_add(&base->event6, NULL); - event_add(&base->tcp_event6, NULL); - return base; } @@ -3356,7 +3358,12 @@ static void noreply_callback(int __attribute((unused)) unused, #endif if (!state->gotresp) - add_str(state, "\"x\":\"*\""); + { + if (state->open_result) + add_str(state, " }, { "); + add_str(state, DBQ(x) ":" DBQ(*)); + state->open_result= 1; + } send_pkt(state); } @@ -3375,6 +3382,7 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], const char *hostname; char *out_filename; const char *destportstr; + char *interface; char *check; struct trtstate *state; sa_family_t af; @@ -3392,12 +3400,15 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], count= 3; firsthop= 1; gaplimit= 5; + interface= NULL; maxhops= 32; maxpacksize= 40; destportstr= "80"; duptimeout= 10; timeout= 1000; parismod= 16; + hbhoptsize= 0; + destoptsize= 0; str_Atlas= NULL; out_filename= NULL; opt_complementary = "=1:4--6:i--u:a+:c+:f+:g+:m+:w+:z+:S+:H+:D+"; @@ -3406,7 +3417,8 @@ for (i= 0; argv[i] != NULL; i++) printf("argv[%d] = '%s'\n", i, argv[i]); opt = getopt32(argv, TRACEROUTE_OPT_STRING, &parismod, &count, - &firsthop, &gaplimit, &maxhops, &destportstr, &timeout, + &firsthop, &gaplimit, &interface, &maxhops, &destportstr, + &timeout, &duptimeout, &str_Atlas, &out_filename, &maxpacksize, &hbhoptsize, &destoptsize); hostname = argv[optind]; @@ -3483,12 +3495,13 @@ for (i= 0; argv[i] != NULL; i++) state->maxpacksize= maxpacksize; state->maxhops= maxhops; state->gaplimit= gaplimit; - state->destportstr= destportstr; + state->interface= interface; + state->destportstr= strdup(destportstr); state->duptimeout= duptimeout*1000; state->timeout= timeout*1000; state->atlas= str_Atlas ? strdup(str_Atlas) : NULL; state->hostname= strdup(hostname); - state->do_Xicmp= do_icmp; + state->do_icmp= do_icmp; state->do_tcp= do_tcp; state->do_udp= do_udp; state->do_v6= do_v6; @@ -3548,15 +3561,10 @@ for (i= 0; argv[i] != NULL; i++) static void traceroute_start2(void *state) { - int r, serrno; struct trtstate *trtstate; - struct trtbase *trtbase; - struct sockaddr_in loc_sa4; - struct sockaddr_in6 loc_sa6; char line[80]; trtstate= state; - trtbase= trtstate->base; if (trtstate->busy) { @@ -3586,231 +3594,235 @@ static void traceroute_start2(void *state) trtstate->resmax= 80; trtstate->result= xmalloc(trtstate->resmax); trtstate->reslen= 0; + trtstate->open_result= 0; trtstate->starttime= time(NULL); + trtstate->socket_icmp= -1; + trtstate->socket_tcp= -1; + snprintf(line, sizeof(line), "{ \"hop\":%d", trtstate->hop); add_str(trtstate, line); - if (trtstate->do_Xicmp) + if (trtstate->do_icmp) { + if (create_socket(trtstate, 0 /*do_tcp*/) == -1) + return; + } + else if (trtstate->do_udp) + { + if (create_socket(trtstate, 0 /*do_tcp*/) == -1) + return; if (trtstate->do_v6) { - memset(&loc_sa6, '\0', sizeof(loc_sa6)); - loc_sa6.sin6_family= AF_INET; - - r= connect(trtbase->v6icmp_snd, - (struct sockaddr *)&trtstate->sin6, - trtstate->socklen); -#if 0 - { errno= ENOSYS; r= -1; } -#endif - if (r == -1) - { - serrno= errno; - - snprintf(line, sizeof(line), - ", " DBQ(error) ":" DBQ(connect failed: %s) " }", - strerror(serrno)); - add_str(trtstate, line); - report(trtstate); - return; - } - trtstate->loc_socklen= sizeof(trtstate->loc_sin6); - if (getsockname(trtbase->v6icmp_snd, - &trtstate->loc_sin6, - &trtstate->loc_socklen) == -1) - { - crondlog(DIE9 "getsockname failed"); - } -#if 0 - printf("Got localname: %s\n", - inet_ntop(AF_INET6, - &trtstate->loc_sin6.sin6_addr, - buf, sizeof(buf))); -#endif + trtstate->loc_sin6.sin6_port= htons(SRC_BASE_PORT + + trtstate->index); } else { - memset(&loc_sa4, '\0', sizeof(loc_sa4)); - loc_sa4.sin_family= AF_INET; - ((struct sockaddr_in *)&trtstate->sin6)->sin_port= - htons(0x8000); - - r= connect(trtbase->v4icmp_snd, - (struct sockaddr *)&trtstate->sin6, - trtstate->socklen); -#if 0 - { errno= ENOSYS; r= -1; } -#endif - if (r == -1) - { - serrno= errno; - - snprintf(line, sizeof(line), - ", " DBQ(error) ":" DBQ(connect failed: %s) " }", - strerror(serrno)); - add_str(trtstate, line); - report(trtstate); - return; - } - trtstate->loc_socklen= sizeof(trtstate->loc_sin6); - if (getsockname(trtbase->v4icmp_snd, - &trtstate->loc_sin6, - &trtstate->loc_socklen) == -1) - { - crondlog(DIE9 "getsockname failed"); - } -#if 0 - printf("Got localname: %s\n", - inet_ntoa(((struct sockaddr_in *) - &trtstate->loc_sin6)->sin_addr)); -#endif + ((struct sockaddr_in *)(&trtstate->loc_sin6))-> + sin_port= htons(SRC_BASE_PORT + + trtstate->index); } } - else + else if (trtstate->do_tcp) { + if (create_socket(trtstate, 1 /*do_tcp*/) == -1) + return; + if (trtstate->do_v6) { - int sock; + trtstate->loc_sin6.sin6_port= htons(SRC_BASE_PORT + + trtstate->index); + } + else + { + ((struct sockaddr_in *)(&trtstate->loc_sin6))-> + sin_port= htons(SRC_BASE_PORT + + trtstate->index); + } + } - memset(&loc_sa6, '\0', sizeof(loc_sa6)); - loc_sa6.sin6_family= AF_INET6; - loc_sa6.sin6_port= htons(SRC_BASE_PORT + - trtstate->index);; + add_str(trtstate, ", \"result\": [ "); - sock= socket(AF_INET6, SOCK_DGRAM, 0); - if (sock == -1) - { - crondlog(DIE9 "socket failed"); - } - r= bind(sock, (struct sockaddr *)&loc_sa6, - sizeof(loc_sa6)); - if (r == -1) - { - serrno= errno; + send_pkt(trtstate); +} - snprintf(line, sizeof(line), - ", " DBQ(error) ":" DBQ(bind failed: %s) " }", - strerror(serrno)); - add_str(trtstate, line); - report(trtstate); - close(sock); - return; - } +static int create_socket(struct trtstate *state, int do_tcp) +{ + int af, type, protocol; + int r, on, serrno; + char line[80]; + + af= (state->do_v6 ? AF_INET6 : AF_INET); + type= SOCK_RAW; + protocol= (af == AF_INET6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP); - r= connect(sock, (struct sockaddr *)&trtstate->sin6, - trtstate->socklen); + state->socket_icmp= xsocket(af, type, protocol); + if (state->socket_icmp == -1) + { + serrno= errno; + + snprintf(line, sizeof(line), + ", " DBQ(error) ":" DBQ(socket failed: %s) " }", + strerror(serrno)); + add_str(state, line); + report(state); + return -1; + } + + if (state->interface) + { + if (bind_interface(state->socket_icmp, + af, state->interface) == -1) + { + snprintf(line, sizeof(line), + ", " DBQ(error) ":" DBQ(bind_interface failed) " }"); + add_str(state, line); + report(state); + return -1; + } + } + + r= connect(state->socket_icmp, + (struct sockaddr *)&state->sin6, + state->socklen); #if 0 { errno= ENOSYS; r= -1; } #endif - if (r == -1) - { - serrno= errno; - - snprintf(line, sizeof(line), - ", " DBQ(error) ":" DBQ(connect failed: %s) " }", - strerror(serrno)); - add_str(trtstate, line); - report(trtstate); - return; - } - - trtstate->loc_socklen= sizeof(trtstate->loc_sin6); - if (getsockname(sock, - &trtstate->loc_sin6, - &trtstate->loc_socklen) == -1) - { - crondlog(DIE9 "getsockname failed"); - } + if (r == -1) + { + serrno= errno; - close(sock); + snprintf(line, sizeof(line), + ", " DBQ(error) ":" DBQ(connect failed: %s) " }", + strerror(serrno)); + add_str(state, line); + report(state); + return -1; + } + state->loc_socklen= sizeof(state->loc_sin6); + if (getsockname(state->socket_icmp, + &state->loc_sin6, + &state->loc_socklen) == -1) + { + crondlog(DIE9 "getsockname failed"); + } #if 0 - printf("Got localname: %s:%d\n", - inet_ntop(AF_INET6, - &trtstate->loc_sin6.sin6_addr, - buf, sizeof(buf)), - ntohs(((struct sockaddr_in *)&trtstate-> - loc_sin6)->sin_port)); + printf("Got localname: %s\n", + inet_ntop(AF_INET6, + &state->loc_sin6.sin6_addr, + buf, sizeof(buf))); #endif - } - else + + close(state->socket_icmp); + state->socket_icmp= xsocket(af, type, + protocol); + if (state->socket_icmp == -1) + { + serrno= errno; + + snprintf(line, sizeof(line), + ", " DBQ(error) ":" DBQ(socket failed: %s) " }", + strerror(serrno)); + add_str(state, line); + report(state); + return -1; + } + + if (af == AF_INET6) + { + on = 1; + setsockopt(state->socket_icmp, IPPROTO_IPV6, + IPV6_RECVPKTINFO, &on, sizeof(on)); + + on = 1; + setsockopt(state->socket_icmp, IPPROTO_IPV6, + IPV6_RECVHOPLIMIT, &on, sizeof(on)); + } + + if (state->interface) + { + if (bind_interface(state->socket_icmp, + af, state->interface) == -1) { - int sock; + snprintf(line, sizeof(line), + ", " DBQ(error) ":" DBQ(bind_interface failed) " }"); + add_str(state, line); + report(state); + return -1; + } + } - memset(&loc_sa4, '\0', sizeof(loc_sa4)); - loc_sa4.sin_family= AF_INET; + event_assign(&state->event_icmp, state->base->event_base, + state->socket_icmp, + EV_READ | EV_PERSIST, + (af == AF_INET6 ? ready_callback6 : ready_callback4), + state); + event_add(&state->event_icmp, NULL); - loc_sa4.sin_port= htons(SRC_BASE_PORT + - trtstate->index);; + if (do_tcp) + { + state->socket_tcp= xsocket(af, SOCK_RAW, + IPPROTO_TCP); + if (state->socket_tcp == -1) + { + serrno= errno; - if (!trtstate->do_tcp) - { - /* Also set destination port */ - ((struct sockaddr_in *)&trtstate->sin6)-> - sin_port= htons(BASE_PORT); - } + snprintf(line, sizeof(line), + ", " DBQ(error) ":" DBQ(socket failed: %s) " }", + strerror(serrno)); + add_str(state, line); + report(state); + return -1; + } - sock= socket(AF_INET, SOCK_DGRAM, 0); - if (sock == -1) - { - crondlog(DIE9 "socket failed"); - } - r= bind(sock, (struct sockaddr *)&loc_sa4, - sizeof(loc_sa4)); -#if 0 - { errno= ENOSYS; r= -1; } -#endif - if (r == -1) - { - serrno= errno; + if (af == AF_INET6) + { + on = 1; + setsockopt(state->socket_tcp, IPPROTO_IPV6, + IPV6_RECVHOPLIMIT, &on, sizeof(on)); + } + if (state->interface) + { + if (bind_interface(state->socket_tcp, + af, state->interface) == -1) + { snprintf(line, sizeof(line), - ", " DBQ(error) ":" DBQ(bind failed: %s) " }", - strerror(serrno)); - add_str(trtstate, line); - report(trtstate); - close(sock); - return; + ", " DBQ(error) ":" DBQ(bind_interface failed) " }"); + add_str(state, line); + report(state); + return -1; } + } - r= connect(sock, (struct sockaddr *) &trtstate->sin6, - trtstate->socklen); + r= connect(state->socket_tcp, + (struct sockaddr *)&state->sin6, + state->socklen); #if 0 { errno= ENOSYS; r= -1; } #endif - if (r == -1) - { - serrno= errno; + if (r == -1) + { + serrno= errno; - snprintf(line, sizeof(line), - ", " DBQ(error) ":" DBQ(connect failed: %s) " }", - strerror(serrno)); - add_str(trtstate, line); - report(trtstate); - close(sock); - return; - } - trtstate->loc_socklen= sizeof(trtstate->loc_sin6); - if (getsockname(sock, - &trtstate->loc_sin6, - &trtstate->loc_socklen) == -1) - { - crondlog(DIE9 "getsockname failed"); - } - close(sock); -#if 0 - printf("Got localname: %s:%d\n", - inet_ntoa(((struct sockaddr_in *) - &trtstate->loc_sin6)->sin_addr), - ntohs(((struct sockaddr_in *)&trtstate-> - loc_sin6)->sin_port)); -#endif + snprintf(line, sizeof(line), + ", " DBQ(error) ":" DBQ(connect failed: %s) " }", + strerror(serrno)); + add_str(state, line); + report(state); + return -1; } - } - add_str(trtstate, ", \"result\": [ "); + event_assign(&state->event_tcp, state->base->event_base, + state->socket_tcp, + EV_READ | EV_PERSIST, + (af == AF_INET6 ? ready_tcp6 : ready_tcp4), + state); + event_add(&state->event_tcp, NULL); + } - send_pkt(trtstate); + return 0; } static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) @@ -3934,6 +3946,8 @@ static int traceroute_delete(void *state) trtstate->atlas= NULL; free(trtstate->hostname); trtstate->hostname= NULL; + free(trtstate->destportstr); + trtstate->destportstr= NULL; free(trtstate->out_filename); trtstate->out_filename= NULL; -- cgit v1.2.3