From c9c35747c0d20cff54561c0b8fe15813c7a8e0ff Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 15 May 2015 10:25:14 +0200 Subject: ripe-atlas-fw: imported version 4570 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- .config | 2 +- checksum | 4 +- eperd/eooqd.c | 52 +- eperd/eperd.c | 46 ++ eperd/evtdig.c | 76 +- eperd/ping.c | 90 ++- eperd/traceroute.c | 1049 ++++++++++++++++++++++++-- include/usage.h | 25 +- libevent-2.0.20-stable/evdns.c | 22 +- libevent-2.0.20-stable/evutil.c | 6 + libevent-2.0.20-stable/include/event2/util.h | 3 + networking/telnetd.c | 1 + 12 files changed, 1249 insertions(+), 127 deletions(-) diff --git a/.config b/.config index cea4e44..1e06edb 100644 --- a/.config +++ b/.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.13.3 -# Thu Aug 22 15:10:00 2013 +# Thu Oct 31 21:51:23 2013 # CONFIG_HAVE_DOT_CONFIG=y diff --git a/checksum b/checksum index 576cf08..507305c 100644 --- a/checksum +++ b/checksum @@ -1,2 +1,2 @@ -SHA256 f98e46d69fe1f79d955bba73e78d1299193c1af56094a2b6f70802cd77af2730 ripe-atlas-fw-4550.tar.gz -SHA512 c4c716a573897903759af66bef70c0fba9c2bf04961e1bd3725aca9dd49ff81fc3cd8bc7c3781082cbcb83b4c9229bf8f0b5b916c183a9b83d13e7a35437e99b ripe-atlas-fw-4550.tar.gz +SHA256 50cbf293f78251170c3afbba74850ac3a17836f30542775ecad78f660ee6f68c ripe-atlas-fw-4560.tar.gz +SHA512 27eab255f332dc0fc88036657243de806dff938d954d7bab538f3e7a4c3c55f777c0384236a17c3a1f47b76b140e266c0335d52f8e113b2de25ef9031642c387 ripe-atlas-fw-4560.tar.gz diff --git a/eperd/eooqd.c b/eperd/eooqd.c index 49371ad..ea7162f 100644 --- a/eperd/eooqd.c +++ b/eperd/eooqd.c @@ -57,6 +57,7 @@ static struct builtin { NULL, NULL } }; +static const char *atlas_id; static void process(FILE *file); static void report(const char *fmt, ...); @@ -76,7 +77,7 @@ int eooqd_main(int argc, char *argv[]) { int r; uint32_t opt; - char *atlas_id, *pid_file_name; + char *pid_file_name; struct event *checkQueueEvent, *rePostEvent; struct timeval tv; @@ -468,6 +469,55 @@ static void cmddone(void *cmdstate) } } +#define RESOLV_CONF "/etc/resolv.conf" +static void check_resolv_conf2(const char *out_file, const char *atlasid) +{ + static time_t last_time= -1; + + int r; + FILE *fn; + struct stat sb; + + r= stat(RESOLV_CONF, &sb); + if (r == -1) + { + crondlog(LVL8 "error accessing resolv.conf: %s", + strerror(errno)); + return; + } + + if (sb.st_mtime == last_time) + return; /* resolv.conf did not change */ + evdns_base_clear_nameservers_and_suspend(DnsBase); + r= evdns_base_resolv_conf_parse(DnsBase, DNS_OPTIONS_ALL, + RESOLV_CONF); + evdns_base_resume(DnsBase); + + if (r != 0 || last_time != -1) + { + fn= fopen(out_file, "a"); + if (!fn) + crondlog(DIE9 "unable to append to '%s'", out_file); + fprintf(fn, "RESULT { "); + if (atlasid) + fprintf(fn, DBQ(id) ":" DBQ(%s) ", ", atlasid); + fprintf(fn, DBQ(fw) ":" DBQ(%d) ", " DBQ(time) ":%ld, ", + get_atlas_fw_version(), (long)time(NULL)); + fprintf(fn, DBQ(event) ": " DBQ(load resolv.conf) + ", " DBQ(result) ": %d", r); + + fprintf(fn, " }\n"); + fclose(fn); + } + + last_time= sb.st_mtime; +} + +static void check_resolv_conf(void) +{ + check_resolv_conf1(); +} + static void re_post(evutil_socket_t fd UNUSED_PARAM, short what UNUSED_PARAM, void *arg UNUSED_PARAM) { diff --git a/eperd/eperd.c b/eperd/eperd.c index b240e6e..bfa3615 100644 --- a/eperd/eperd.c +++ b/eperd/eperd.c @@ -568,6 +568,50 @@ static void SynchronizeFile(const char *fileName) DeleteFile(); } +#define RESOLV_CONF "/etc/resolv.conf" +static void check_resolv_conf(void) +{ + static time_t last_time= -1; + + int r; + FILE *fn; + struct stat sb; + + r= stat(RESOLV_CONF, &sb); + if (r == -1) + { + crondlog(LVL8 "error accessing resolv.conf: %s", + strerror(errno)); + return; + } + + if (sb.st_mtime == last_time) + return; /* resolv.conf did not change */ + evdns_base_clear_nameservers_and_suspend(DnsBase); + r= evdns_base_resolv_conf_parse(DnsBase, DNS_OPTIONS_ALL, + RESOLV_CONF); + evdns_base_resume(DnsBase); + + if ((r != 0 || last_time != -1) && out_filename) + { + fn= fopen(out_filename, "a"); + if (!fn) + crondlog(DIE9 "unable to append to '%s'", out_filename); + fprintf(fn, "RESULT { "); + if (atlas_id) + fprintf(fn, DBQ(id) ":" DBQ(%s) ", ", atlas_id); + fprintf(fn, DBQ(fw) ":" DBQ(%d) ", " DBQ(time) ":%ld, ", + get_atlas_fw_version(), (long)time(NULL)); + fprintf(fn, DBQ(event) ": " DBQ(load resolv.conf) + ", " DBQ(result) ": %d", r); + + fprintf(fn, " }\n"); + fclose(fn); + } + + last_time= sb.st_mtime; +} + static void CheckUpdates(evutil_socket_t __attribute__ ((unused)) fd, short __attribute__ ((unused)) what, void __attribute__ ((unused)) *arg) @@ -584,6 +628,8 @@ static void CheckUpdates(evutil_socket_t __attribute__ ((unused)) fd, } fclose(fi); } + + check_resolv_conf(); } static void CheckUpdatesHour(evutil_socket_t __attribute__ ((unused)) fd, diff --git a/eperd/evtdig.c b/eperd/evtdig.c index c0d606c..da67a2a 100644 --- a/eperd/evtdig.c +++ b/eperd/evtdig.c @@ -50,6 +50,7 @@ #define O_RESOLV_CONF 1003 #define O_PREPEND_PROBE_ID 1004 #define O_EVDNS 1005 +#define O_RETRY 1006 #define DNS_FLAG_RD 0x0100 @@ -63,10 +64,11 @@ #define MAX_DNS_OUT_BUF_SIZE 512 /* Intervals and timeouts (all are in milliseconds unless otherwise specified) */ -#define DEFAULT_NOREPLY_TIMEOUT 5000 /* 1000 msec - 0 is illegal */ +#define DEFAULT_NOREPLY_TIMEOUT 5000 /* 5000 msec - 0 is illegal */ #define DEFAULT_LINE_LENGTH 80 #define DEFAULT_STATS_REPORT_INTERVEL 180 /* in seconds */ #define CONN_TO 5 /* TCP connection time out in seconds */ +#define DEFAULT_RETRY_MAX 10 /* state of the dns query */ #define STATUS_DNS_RESOLV 1001 @@ -74,6 +76,7 @@ #define STATUS_TCP_CONNECTED 1003 #define STATUS_TCP_WRITE 1004 #define STATUS_NEXT_QUERY 1005 +#define STATUS_RETRANSMIT_QUERY 1006 #define STATUS_FREE 0 // seems T_DNSKEY is not defined header files of lenny and sdk @@ -187,6 +190,8 @@ struct query_state { int opt_rd; int opt_prepend_probe_id; int opt_evdns; + int opt_retry_max; + int retry; char * str_Atlas; u_int16_t qtype; @@ -319,6 +324,8 @@ static struct option longopts[]= { "ds", required_argument, NULL, (100000 + T_DS) }, { "rrsig", required_argument, NULL, (100000 + T_RRSIG) }, { "soa", required_argument, NULL, 's' }, + { "srv", required_argument, NULL, (100000 + T_SRV) }, + { "naptr", required_argument, NULL, (100000 + T_NAPTR) }, // clas CHAOS { "hostname.bind", no_argument, NULL, 'h' }, @@ -331,6 +338,7 @@ static struct option longopts[]= { "nsid", no_argument, NULL, 'n' }, { "d0", no_argument, NULL, 'd' }, + { "retry", required_argument, NULL, O_RETRY }, { "resolv", no_argument, NULL, O_RESOLV_CONF }, { "qbuf", no_argument, NULL, 1001 }, { "noabuf", no_argument, NULL, 1002 }, @@ -355,6 +363,8 @@ static void process_reply(void * arg, int nrecv, struct timeval now, int af, voi static void mk_dns_buff(struct query_state *qry, u_char *packet); int ip_addr_cmp (u_int16_t af_a, void *a, u_int16_t af_b, void *b); static void udp_dns_cb(int err, struct evutil_addrinfo *ev_res, struct query_state *qry); +static void noreply_callback(int unused UNUSED_PARAM, const short event UNUSED_PARAM, void *h); +static void free_qry_inst(struct query_state *qry); /* move the next functions from tdig.c */ u_int32_t get32b (char *p); @@ -724,15 +734,26 @@ static void next_qry_cb(int unused UNUSED_PARAM, const short event UNUSED_PARAM /* The callback to handle timeouts due to destination host unreachable condition */ static void noreply_callback(int unused UNUSED_PARAM, const short event UNUSED_PARAM, void *h) { + struct timeval asap = { 0, 0 }; struct query_state *qry = h; qry->base->timeout++; snprintf(line, DEFAULT_LINE_LENGTH, "%s \"timeout\" : %d", qry->err.size ? ", " : "", DEFAULT_NOREPLY_TIMEOUT); buf_add(&qry->err, line, strlen(line)); - BLURT(LVL5 "AAA timeout for %s ", qry->server_name); - printReply (qry, 0, NULL); + BLURT(LVL5 "AAA timeout for %s retry %d/%d ", qry->server_name, qry->retry, qry->opt_retry_max); + if (qry->retry < qry->opt_retry_max) { + qry->retry++; + free_qry_inst(qry); + qry->qst = STATUS_RETRANSMIT_QUERY; + evtimer_add(&qry->next_qry_timer, &asap); + } else { + printReply (qry, 0, NULL); + } + return; -} +} + + static void tcp_timeout_callback (int __attribute((unused)) unused, const short __attribute((unused)) event, void *s) @@ -746,6 +767,7 @@ static void tcp_reporterr(struct tu_env *env, enum tu_err cause, const char *str) { struct query_state * qry; + struct timeval asap = { 0, 0 }; qry = ENV2QRY(env); // if (env != &state->tu_env) abort(); // Why do i need this? AA @@ -780,7 +802,14 @@ static void tcp_reporterr(struct tu_env *env, enum tu_err cause, crondlog(DIE9 "reporterr: bad cause %d", cause); break; } - printReply (qry, 0, NULL); + if (qry->retry < qry->opt_retry_max) { + qry->retry++; + free_qry_inst(qry); + qry->qst = STATUS_RETRANSMIT_QUERY; + evtimer_add(&qry->next_qry_timer, &asap); + } else { + printReply (qry, 0, NULL); + } } static void tcp_dnscount(struct tu_env *env, int count) @@ -1044,6 +1073,8 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) qry->str_Atlas = NULL; tdig_base->activeqry++; qry->qst = 0; + qry->retry = 0; + qry->opt_retry_max = DEFAULT_RETRY_MAX; qry->wire_size = 0; qry->triptime = 0; qry->opt_edns0 = 512; @@ -1157,6 +1188,10 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) qry->opt_abuf = 0; break; + case O_RETRY : + qry->opt_retry_max = strtoul(optarg, NULL, 10); + break; + case O_RESOLV_CONF : qry->opt_resolv_conf = Q_RESOLV_CONF ; qry->opt_v6_only = 1; @@ -1253,7 +1288,19 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) qry->qtype = T_RRSIG; qry->qclass = C_IN; qry->lookupname = strdup(optarg); - break;break; + break; + + case (100000 + T_SRV): + qry->qtype = T_SRV; + qry->qclass = C_IN; + qry->lookupname = strdup(optarg); + break; + + case (100000 + T_NAPTR): + qry->qtype = T_NAPTR; + qry->qclass = C_IN; + qry->lookupname = strdup(optarg); + break; default: fprintf(stderr, "ERROR unknown option %d ??\n", c); @@ -1289,12 +1336,19 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) else qry->server_name = strdup(argv[optind]); - if(qry->lookupname == NULL) { + if (qry->lookupname == NULL) { crondlog(LVL9 "ERROR no query in command line"); tdig_delete(qry); return NULL; } + if (qry->lookupname[strlen(qry->lookupname) - 1] != '.') { + crondlog(LVL9 "ERROR query %s does not end with a dot ", qry->lookupname); + tdig_delete(qry); + return NULL; + } + + if (qry->out_filename && !validate_filename(qry->out_filename, SAFE_PREFIX)) { @@ -1450,7 +1504,8 @@ void tdig_start (struct query_state *qry) switch(qry->qst) { case STATUS_NEXT_QUERY : - case STATUS_FREE : + case STATUS_FREE : + case STATUS_RETRANSMIT_QUERY: break; default: printErrorQuick(qry); @@ -1861,6 +1916,9 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result ) if(strlen(line)) JS(src_addr, line); } + if(qry->retry) { + JS1(retry, %d, qry->retry); + } JS_NC(proto, qry->opt_proto == 6 ? "TCP" : "UDP" ); if(qry->opt_qbuf && qry->qbuf.size) { @@ -1870,7 +1928,6 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result ) JS_NC(qbuf, qry->qbuf.buf ); } - if(result) { dnsR = (struct DNS_HEADER*) result; @@ -2013,6 +2070,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result ) fprintf(fh, "\n"); if (qry->out_filename) fclose(fh); + qry->retry = 0; free_qry_inst(qry); } diff --git a/eperd/ping.c b/eperd/ping.c index bf51019..8a6d2a2 100644 --- a/eperd/ping.c +++ b/eperd/ping.c @@ -14,12 +14,16 @@ #include #include +#include #include #include "eperd.h" #define SAFE_PREFIX ATLAS_DATA_NEW +/* Don't report psize yet. */ +#define DO_PSIZE 0 + #define DBQ(str) "\"" #str "\"" #define PING_OPT_STRING ("!46rc:s:A:O:") @@ -40,7 +44,9 @@ enum * default data size is calculated as to be like the original */ #define IPHDR 20 -#define MAX_DATA_SIZE (4096 - IPHDR - ICMP_MINLEN) +#define MAX_DATA_SIZE (4096 - IPHDR) + +#define ICMP6_HDRSIZE (offsetof(struct icmp6_hdr, icmp6_data16[2])) /* Error codes */ #define PING_ERR_NONE 0 @@ -109,6 +115,7 @@ struct pingstate char no_dst; unsigned char ttl; unsigned size; + unsigned psize; char *result; size_t reslen; @@ -246,6 +253,10 @@ static void report(struct pingstate *state) fprintf(fh, ", " DBQ(ttl) ":%d", state->ttl); fprintf(fh, ", " DBQ(size) ":%d", state->size); +#if DO_PSIZE + if (state->psize != -1) + fprintf(fh, ", " DBQ(psize) ":%d", state->psize); +#endif /* DO_PSIZE */ fprintf(fh, ", \"result\": [ %s ] }\n", state->result); free(state->result); @@ -257,7 +268,7 @@ static void report(struct pingstate *state) fclose(fh); } -static void ping_cb(int result, int bytes, +static void ping_cb(int result, int bytes, int psize, struct sockaddr *sa, socklen_t socklen, struct sockaddr *loc_sa, socklen_t loc_socklen, int seq, int ttl, @@ -265,7 +276,7 @@ static void ping_cb(int result, int bytes, { struct pingstate *pingstate; unsigned long usecs; - char namebuf[NI_MAXHOST]; + char namebuf1[NI_MAXHOST], namebuf2[NI_MAXHOST]; char line[256]; (void)socklen; /* Suppress GCC unused parameter warning */ @@ -287,6 +298,7 @@ static void ping_cb(int result, int bytes, if (pingstate->first) { pingstate->size= bytes; + pingstate->psize= psize; pingstate->ttl= ttl; } @@ -325,6 +337,15 @@ static void ping_cb(int result, int bytes, add_str(pingstate, line); pingstate->size= bytes; } + if (pingstate->psize != psize && psize != -1) + { +#if DO_PSIZE + snprintf(line, sizeof(line), + ", " DBQ(psize) ":%d", psize); + add_str(pingstate, line); +#endif /* DO_PSIZE */ + pingstate->psize= psize; + } if (pingstate->ttl != ttl) { snprintf(line, sizeof(line), @@ -332,14 +353,21 @@ static void ping_cb(int result, int bytes, add_str(pingstate, line); pingstate->ttl= ttl; } - if (memcmp(&pingstate->loc_sin6, loc_sa, loc_socklen) != 0) + namebuf1[0]= '\0'; + getnameinfo(&pingstate->loc_sin6, loc_socklen, namebuf1, + sizeof(namebuf1), NULL, 0, NI_NUMERICHOST); + namebuf2[0]= '\0'; + getnameinfo(loc_sa, loc_socklen, namebuf2, + sizeof(namebuf2), NULL, 0, NI_NUMERICHOST); + + if (strcmp(namebuf1, namebuf2) != 0) { - namebuf[0]= '\0'; - getnameinfo(loc_sa, loc_socklen, namebuf, - sizeof(namebuf), NULL, 0, NI_NUMERICHOST); + printf("loc_sin6: %s\n", namebuf1); + + printf("loc_sa: %s\n", namebuf2); snprintf(line, sizeof(line), - ", " DBQ(srcaddr) ":" DBQ(%s), namebuf); + ", " DBQ(srcaddr) ":" DBQ(%s), namebuf2); add_str(pingstate, line); } @@ -367,14 +395,14 @@ static void ping_cb(int result, int bytes, { if (pingstate->first && pingstate->loc_socklen != 0) { - namebuf[0]= '\0'; + namebuf1[0]= '\0'; getnameinfo((struct sockaddr *)&pingstate->loc_sin6, pingstate->loc_socklen, - namebuf, sizeof(namebuf), + namebuf1, sizeof(namebuf1), NULL, 0, NI_NUMERICHOST); snprintf(line, sizeof(line), - ", " DBQ(srcaddr) ":" DBQ(%s), namebuf); + ", " DBQ(srcaddr) ":" DBQ(%s), namebuf1); add_str(pingstate, line); } add_str(pingstate, " }"); @@ -383,6 +411,7 @@ static void ping_cb(int result, int bytes, if (result == PING_ERR_DNS) { pingstate->size= bytes; + pingstate->psize= psize; snprintf(line, sizeof(line), "%s{ " DBQ(error) ":" DBQ(dns resolution failed: %s) " }", pingstate->first ? "" : ", ", (char *)sa); @@ -450,11 +479,11 @@ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq, struct timeval now; - minlen= ICMP_MINLEN + sizeof(*data); + minlen= sizeof(*data); if (*sizep < minlen) *sizep= minlen; - if (*sizep > MAX_DATA_SIZE) - *sizep= MAX_DATA_SIZE; + if (*sizep > MAX_DATA_SIZE - ICMP_MINLEN) + *sizep= MAX_DATA_SIZE - ICMP_MINLEN; if (*sizep > minlen) memset(buffer+minlen, '\0', *sizep-minlen); @@ -472,7 +501,7 @@ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq, /* Last, compute ICMP checksum */ icmp->icmp_cksum = 0; - icmp->icmp_cksum = mkcksum((u_short *) icmp, *sizep); /* ones complement checksum of struct */ + icmp->icmp_cksum = mkcksum((u_short *) icmp, ICMP_MINLEN + *sizep); /* ones complement checksum of struct */ } @@ -496,15 +525,15 @@ static void fmticmp6(u_char *buffer, size_t *sizep, { size_t minlen; struct icmp6_hdr *icmp = (struct icmp6_hdr *) buffer; - struct evdata *data = (struct evdata *) (buffer + offsetof(struct icmp6_hdr, icmp6_data16[2])); + struct evdata *data = (struct evdata *) (buffer + ICMP6_HDRSIZE); struct timeval now; - minlen= offsetof(struct icmp6_hdr, icmp6_data16[2]) + sizeof(*data); + minlen= sizeof(*data); if (*sizep < minlen) *sizep= minlen; - if (*sizep > MAX_DATA_SIZE) - *sizep= MAX_DATA_SIZE; + if (*sizep > MAX_DATA_SIZE - ICMP6_HDRSIZE) + *sizep= MAX_DATA_SIZE - ICMP6_HDRSIZE; if (*sizep > minlen) memset(buffer+minlen, '\0', *sizep-minlen); @@ -532,10 +561,11 @@ static void ping_xmit(struct pingstate *host) int nsent, fd4, fd6, t_errno, r; host->send_error= 0; + host->got_reply= 0; if (host->sentpkts >= host->maxpkts) { /* Done. */ - ping_cb(PING_ERR_DONE, host->cursize, + ping_cb(PING_ERR_DONE, host->cursize, host->psize, (struct sockaddr *)&host->sin6, host->socklen, (struct sockaddr *)&host->loc_sin6, host->loc_socklen, 0, host->rcvd_ttl, NULL, @@ -572,7 +602,7 @@ static void ping_xmit(struct pingstate *host) } } - nsent = sendto(fd6, base->packet, host->cursize, + nsent = sendto(fd6, base->packet, host->cursize+ICMP6_HDRSIZE, MSG_DONTWAIT, (struct sockaddr *)&host->sin6, host->socklen); @@ -601,7 +631,7 @@ static void ping_xmit(struct pingstate *host) } - nsent = sendto(fd4, base->packet, host->cursize, + nsent = sendto(fd4, base->packet, host->cursize+ICMP_MINLEN, MSG_DONTWAIT, (struct sockaddr *)&host->sin6, host->socklen); @@ -622,7 +652,7 @@ static void ping_xmit(struct pingstate *host) host->send_error= 1; /* Report the failure and stop */ - ping_cb(PING_ERR_SENDTO, host->cursize, + ping_cb(PING_ERR_SENDTO, host->cursize, -1, (struct sockaddr *)&host->sin6, host->socklen, (struct sockaddr *)&host->loc_sin6, host->loc_socklen, errno, 0, NULL, @@ -642,7 +672,7 @@ static void noreply_callback(int __attribute((unused)) unused, const short __att if (!host->got_reply && !host->send_error) { - ping_cb(PING_ERR_TIMEOUT, host->cursize, + ping_cb(PING_ERR_TIMEOUT, host->cursize, -1, (struct sockaddr *)&host->sin6, host->socklen, NULL, 0, host->seq, -1, &host->base->tv_interval, @@ -765,7 +795,7 @@ printf("ready_callback4: too short\n"); */ isDup= (ntohs(icmp->un.echo.sequence) != host->seq); ping_cb(isDup ? PING_ERR_DUP : PING_ERR_NONE, - nrecv - IPHDR, + nrecv - IPHDR - ICMP_MINLEN, nrecv, (struct sockaddr *)&host->sin6, host->socklen, (struct sockaddr *)&loc_sin4, sizeof(loc_sin4), ntohs(icmp->un.echo.sequence), ip->ip_ttl, &elapsed, @@ -895,7 +925,7 @@ static void ready_callback6 (int __attribute((unused)) unused, */ isDup= (ntohs(icmp->icmp6_seq) != host->seq); ping_cb(isDup ? PING_ERR_DUP : PING_ERR_NONE, - nrecv - IPHDR,\ + nrecv - ICMP6_HDRSIZE, nrecv + sizeof(struct ip6_hdr), (struct sockaddr *)&host->sin6, host->socklen, (struct sockaddr *)&loc_sin6, sizeof(loc_sin6), ntohs(icmp->icmp6_seq), host->rcvd_ttl, &elapsed, @@ -1159,12 +1189,12 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) if (result != 0) { - ping_cb(PING_ERR_DNS, env->maxsize, + ping_cb(PING_ERR_DNS, env->maxsize, -1, (struct sockaddr *)evutil_gai_strerror(result), 0, (struct sockaddr *)NULL, 0, 0, 0, NULL, env); - ping_cb(PING_ERR_DONE, env->maxsize, + ping_cb(PING_ERR_DONE, env->maxsize, -1, (struct sockaddr *)NULL, 0, (struct sockaddr *)NULL, 0, 0, 0, NULL, @@ -1200,7 +1230,7 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) evutil_freeaddrinfo(env->dns_res); env->dns_res= NULL; env->dns_curr= NULL; - ping_cb(PING_ERR_DNS_NO_ADDR, env->cursize, + ping_cb(PING_ERR_DNS_NO_ADDR, env->cursize, -1, (struct sockaddr *)NULL, 0, (struct sockaddr *)NULL, 0, 0, 0, NULL, @@ -1242,8 +1272,6 @@ static void ping_start(void *state) memset(&hints, '\0', sizeof(hints)); hints.ai_socktype= SOCK_DGRAM; hints.ai_family= pingstate->af; - printf("hostname '%s', family %d\n", - pingstate->hostname, hints.ai_family); (void) evdns_getaddrinfo(DnsBase, pingstate->hostname, NULL, &hints, dns_cb, pingstate); } diff --git a/eperd/traceroute.c b/eperd/traceroute.c index f8fa7f7..07a0eb0 100644 --- a/eperd/traceroute.c +++ b/eperd/traceroute.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "eperd.h" @@ -27,7 +28,7 @@ #define uh_sum check #endif -#define TRACEROUTE_OPT_STRING ("!46IUFra:c:f:g:m:w:z:A:O:S:") +#define TRACEROUTE_OPT_STRING ("!46IUFrTa:c:f:g:m:p:w:z:A:O:S:") #define OPT_4 (1 << 0) #define OPT_6 (1 << 1) @@ -35,6 +36,11 @@ #define OPT_U (1 << 3) #define OPT_F (1 << 4) #define OPT_r (1 << 5) +#define OPT_T (1 << 6) + +#define IPHDR 20 +#define ICMP6_HDR (sizeof(struct icmp6_hdr)) +#define TCP_HDR (sizeof(*tcphdr)) #define BASE_PORT (0x8000 + 666) #define SRC_BASE_PORT (20480) @@ -61,12 +67,16 @@ struct trtbase 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; @@ -85,8 +95,11 @@ struct trtstate /* Parameters */ char *atlas; char *hostname; + char *destportstr; char *out_filename; - char do_icmp; + char do_Xicmp; + char do_tcp; + char do_udp; char do_v6; char dont_fragment; char delay_name_res; @@ -149,7 +162,7 @@ struct trtstate static struct trtbase *trt_base; -struct udp_ph +struct v4_ph { struct in_addr src; struct in_addr dst; @@ -199,7 +212,7 @@ static int in_cksum(unsigned short *buf, int sz) return ans; } -static int in_cksum_udp(struct udp_ph *udp_ph, struct udphdr *udp, +static int in_cksum_udp(struct v4_ph *v4_ph, struct udphdr *udp, unsigned short *buf, int sz) { int nleft = sz; @@ -207,18 +220,21 @@ static int in_cksum_udp(struct udp_ph *udp_ph, struct udphdr *udp, unsigned short *w = buf; unsigned short ans = 0; - nleft= sizeof(*udp_ph); - w= (unsigned short *)udp_ph; + nleft= sizeof(*v4_ph); + w= (unsigned short *)v4_ph; while (nleft > 1) { sum += *w++; nleft -= 2; } - nleft= sizeof(*udp); - w= (unsigned short *)udp; - while (nleft > 1) { - sum += *w++; - nleft -= 2; + if (udp) + { + nleft= sizeof(*udp); + w= (unsigned short *)udp; + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } } nleft= sz; @@ -291,6 +307,7 @@ static void add_str(struct trtstate *state, const char *str) static void report(struct trtstate *state) { FILE *fh; + const char *proto; char namebuf[NI_MAXHOST]; event_del(&state->timer); @@ -335,8 +352,14 @@ static void report(struct trtstate *state) fprintf(fh, ", " DBQ(src_addr) ":" DBQ(%s), namebuf); } + if (state->do_Xicmp) + proto= "ICMP"; + else if (state->do_tcp) + proto= "TCP"; + else + proto= "UDP"; fprintf(fh, ", " DBQ(proto) ":" DBQ(%s) ", " DBQ(af) ": %d", - state->do_icmp ? "ICMP" : "UDP", + proto, state->dnsip ? (state->do_v6 ? 6 : 4) : (state->sin6.sin6_family == AF_INET6 ? 6 : 4)); @@ -367,10 +390,12 @@ static void send_pkt(struct trtstate *state) struct icmp *icmp_hdr; struct icmp6_hdr *icmp6_hdr; struct v6info *v6info; - struct udp_ph udp_ph; + struct tcphdr *tcphdr; + struct v4_ph v4_ph; struct v6_ph v6_ph; struct udphdr udp; struct timeval interval; + struct sockaddr_in6 sin6copy; char line[80]; char id[]= "http://atlas.ripe.net Atlas says Hi!"; @@ -424,7 +449,113 @@ static void send_pkt(struct trtstate *state) { hop= state->hop; - if (state->do_icmp) + if (state->do_tcp) + { + sock= socket(AF_INET6, SOCK_RAW, IPPROTO_TCP); + if (sock == -1) + { + crondlog(DIE9 "socket failed"); + } + + on= 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, + sizeof(on)); + + /* Bind to source addr/port */ + r= bind(sock, + (struct sockaddr *)&state->loc_sin6, + state->loc_socklen); + if (r == -1) + { + serrno= errno; + + snprintf(line, sizeof(line), + "%s{ " DBQ(error) ":" DBQ(bind failed: %s) " } ] }", + state->sent ? " }, " : "", + strerror(serrno)); + add_str(state, line); + report(state); + close(sock); + return; + } + + tcphdr= (struct tcphdr *)base->packet; + memset(tcphdr, '\0', sizeof(*tcphdr)); + + len= sizeof(*tcphdr); + + tcphdr->seq= htonl((state->index) << 16 | state->seq); + tcphdr->doff= len / 4; + tcphdr->syn= 1; + + if (state->curpacksize > 0) + { + memset(&base->packet[len], '\0', + state->curpacksize); + strcpy((char *)&base->packet[len], id); + len += state->curpacksize; + } + + { + int offset = 2; + setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, + &offset, sizeof(offset)); + } + + memset(&v6_ph, '\0', sizeof(v6_ph)); + v6_ph.src= state->loc_sin6.sin6_addr; + v6_ph.dst= state->sin6.sin6_addr; + v6_ph.len= htonl(len); + v6_ph.nxt= IPPROTO_TCP; + tcphdr->source= state->loc_sin6.sin6_port; + tcphdr->dest= state->sin6.sin6_port; + tcphdr->uh_sum= 0; + + sum= in_cksum_icmp6(&v6_ph, + (unsigned short *)base->packet, len); + + tcphdr->check= sum; + + /* Set hop count */ + setsockopt(sock, SOL_IPV6, IPV6_UNICAST_HOPS, + &hop, sizeof(hop)); + + /* Set/clear don't fragment */ + on= (state->dont_fragment ? IPV6_PMTUDISC_DO : + IPV6_PMTUDISC_DONT); + setsockopt(sock, IPPROTO_IPV6, + IPV6_MTU_DISCOVER, &on, sizeof(on)); + + sin6copy= state->sin6; + sin6copy.sin6_port= 0; + r= sendto(sock, base->packet, len, 0, + (struct sockaddr *)&sin6copy, + state->socklen); + +#if 0 + { static int doit=1; if (doit && r != -1) + { errno= ENOSYS; r= -1; } doit= !doit; } +#endif + serrno= errno; + close(sock); + + if (r == -1) + { + if (serrno != EACCES && + serrno != ECONNREFUSED && + serrno != EMSGSIZE) + { + snprintf(line, sizeof(line), + "%s{ " DBQ(error) ":" DBQ(sendto failed: %s) " } ] }", + state->sent ? " }, " : "", + strerror(serrno)); + add_str(state, line); + report(state); + return; + } + } + } + else if (state->do_Xicmp) { /* Set hop count */ setsockopt(base->v6icmp_snd, SOL_IPV6, @@ -450,18 +581,21 @@ static void send_pkt(struct trtstate *state) v6info->seq= htonl(state->seq); v6info->tv= state->xmit_time; - len= sizeof(*icmp6_hdr)+sizeof(*v6info); + len= sizeof(*v6info); if (state->curpacksize < len) state->curpacksize= len; if (state->curpacksize > len) { - memset(&base->packet[len], '\0', + memset(&base->packet[ICMP6_HDR+len], '\0', state->curpacksize-len); - strcpy((char *)&base->packet[len], id); + strcpy((char *)&base->packet[ICMP6_HDR+len], + id); len= state->curpacksize; } + len += ICMP6_HDR; + if (state->parismod) { memset(&v6_ph, '\0', sizeof(v6_ph)); @@ -493,9 +627,12 @@ static void send_pkt(struct trtstate *state) #endif } + 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, - (struct sockaddr *)&state->sin6, - state->socklen); + (struct sockaddr *)&sin6copy, + sizeof(sin6copy)); #if 0 { static int doit=1; if (doit && r != -1) @@ -518,7 +655,7 @@ static void send_pkt(struct trtstate *state) } } } - else + else if (state->do_udp) { sock= socket(AF_INET6, SOCK_DGRAM, 0); if (sock == -1) @@ -633,7 +770,144 @@ static void send_pkt(struct trtstate *state) state->do_icmp, state->parismod, state->index, state); #endif - if (state->do_icmp) + if (state->do_tcp) + { + sock= socket(AF_INET, SOCK_RAW, IPPROTO_TCP); + if (sock == -1) + { + crondlog(DIE9 "socket failed"); + } + + on= 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, + sizeof(on)); + + /* Bind to source addr/port */ + r= bind(sock, + (struct sockaddr *)&state->loc_sin6, + state->loc_socklen); +#if 0 + { static int doit=1; if (doit && r != -1) + { errno= ENOSYS; r= -1; } doit= !doit; } +#endif + if (r == -1) + { + serrno= errno; + + snprintf(line, sizeof(line), + "%s{ " DBQ(error) ":" DBQ(bind failed: %s) " } ] }", + state->sent ? " }, " : "", + strerror(serrno)); + add_str(state, line); + report(state); + close(sock); + return; + } + + hop= state->hop; + + tcphdr= (struct tcphdr *)base->packet; + memset(tcphdr, '\0', sizeof(*tcphdr)); + + len= sizeof(*tcphdr); + + tcphdr->seq= htonl((state->index) << 16 | state->seq); + tcphdr->doff= len / 4; + tcphdr->syn= 1; + + if (state->curpacksize > 0) + { + memset(&base->packet[len], '\0', + state->curpacksize); + strcpy((char *)&base->packet[len], id); + len += state->curpacksize; + } + + v4_ph.src= ((struct sockaddr_in *)&state->loc_sin6)-> + sin_addr; + v4_ph.dst= ((struct sockaddr_in *)&state->sin6)-> + sin_addr; + v4_ph.zero= 0; + v4_ph.proto= IPPROTO_TCP; + v4_ph.len= htons(len); + tcphdr->source= + ((struct sockaddr_in *)&state->loc_sin6)-> + sin_port; + tcphdr->dest= ((struct sockaddr_in *)&state->sin6)-> + sin_port; + tcphdr->uh_sum= 0; + + sum= in_cksum_udp(&v4_ph, NULL, + (unsigned short *)base->packet, len); + + tcphdr->check= sum; + +#if 0 + if (state->parismod) + { + /* Make sure that the sequence number ends + * up in the checksum field. We can't store + * 0. So we add 1. + */ + if (state->seq == 0) + state->seq++; + val= state->seq; + } + else + { + /* Use id+1 */ + val= state->index+1; + } + + sum= ntohs(sum); + usum= sum + (0xffff - val); + sum= usum + (usum >> 16); + + base->packet[0]= sum >> 8; + base->packet[1]= sum; + + sum= in_cksum_udp(&udp_ph, &udp, + (unsigned short *)base->packet, len); +#endif + + /* Set hop count */ + setsockopt(sock, IPPROTO_IP, IP_TTL, + &hop, sizeof(hop)); + + /* Set/clear don't fragment */ + on= (state->dont_fragment ? IP_PMTUDISC_DO : + IP_PMTUDISC_DONT); + setsockopt(sock, IPPROTO_IP, + IP_MTU_DISCOVER, &on, sizeof(on)); + + r= sendto(sock, base->packet, len, 0, + (struct sockaddr *)&state->sin6, + state->socklen); + +#if 0 + { static int doit=0; if (doit && r != -1) + { errno= ENOSYS; r= -1; } doit= !doit; } +#endif + + serrno= errno; + close(sock); + if (r == -1) + { + if (serrno != EMSGSIZE) + { + serrno= errno; + + snprintf(line, sizeof(line), + "%s{ " DBQ(error) ":" DBQ(sendto failed: %s) " } ] }", + state->sent ? " }, " : "", + strerror(serrno)); + add_str(state, line); + report(state); + return; + } + } + } + else if (state->do_Xicmp) { hop= state->hop; @@ -648,14 +922,14 @@ static void send_pkt(struct trtstate *state) len= offsetof(struct icmp, icmp_data[2]); - if (state->curpacksize < len) - state->curpacksize= len; - if (state->curpacksize > len) + if (state->curpacksize+ICMP_MINLEN < len) + state->curpacksize= len-ICMP_MINLEN; + if (state->curpacksize+ICMP_MINLEN > len) { memset(&base->packet[len], '\0', - state->curpacksize-len); + state->curpacksize-ICMP_MINLEN-len); strcpy((char *)&base->packet[len], id); - len= state->curpacksize; + len= state->curpacksize+ICMP_MINLEN; } if (state->parismod) @@ -715,7 +989,7 @@ static void send_pkt(struct trtstate *state) } } } - else + else if (state->do_udp) { sock= socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) @@ -778,22 +1052,22 @@ static void send_pkt(struct trtstate *state) len= state->curpacksize; } - udp_ph.src= ((struct sockaddr_in *)&state->loc_sin6)-> + v4_ph.src= ((struct sockaddr_in *)&state->loc_sin6)-> sin_addr; - udp_ph.dst= ((struct sockaddr_in *)&state->sin6)-> + v4_ph.dst= ((struct sockaddr_in *)&state->sin6)-> sin_addr; - udp_ph.zero= 0; - udp_ph.proto= IPPROTO_UDP; - udp_ph.len= htons(sizeof(udp)+len); + v4_ph.zero= 0; + v4_ph.proto= IPPROTO_UDP; + v4_ph.len= htons(sizeof(udp)+len); udp.uh_sport= ((struct sockaddr_in *)&state->loc_sin6)-> sin_port; udp.uh_dport= ((struct sockaddr_in *)&state->sin6)-> sin_port; - udp.uh_ulen= udp_ph.len; + udp.uh_ulen= v4_ph.len; udp.uh_sum= 0; - sum= in_cksum_udp(&udp_ph, &udp, + sum= in_cksum_udp(&v4_ph, &udp, (unsigned short *)base->packet, len); if (state->parismod) @@ -819,7 +1093,7 @@ static void send_pkt(struct trtstate *state) base->packet[0]= sum >> 8; base->packet[1]= sum; - sum= in_cksum_udp(&udp_ph, &udp, + sum= in_cksum_udp(&v4_ph, &udp, (unsigned short *)base->packet, len); /* Set hop count */ @@ -967,11 +1241,12 @@ static void ready_callback4(int __attribute((unused)) unused, struct trtbase *base; struct trtstate *state; int hlen, ehlen, ind, nextmtu, late, isDup, icmp_prefixlen, offset; - unsigned seq; + unsigned seq, srcport; ssize_t nrecv; socklen_t slen; struct ip *ip, *eip; struct icmp *icmp, *eicmp; + struct tcphdr *etcp; struct udphdr *eudp; double ms; struct timeval now, interval; @@ -1017,8 +1292,219 @@ static void ready_callback4(int __attribute((unused)) unused, printf("ready_callback4: too short %d\n", (int)nrecv); return; } - - if (eip->ip_p == IPPROTO_UDP) + + if (eip->ip_p == IPPROTO_TCP) + { + /* Now check if there is also a TCP header in the + * packet + */ + if (nrecv < hlen + ICMP_MINLEN + ehlen + 8) + { + printf("ready_callback4: too short %d\n", + (int)nrecv); + return; + } + + /* ICMP only guarantees 8 bytes! */ + etcp= (struct tcphdr *)((char *)eip+ehlen); + + /* Quick check if the source port is in range */ + srcport= ntohs(etcp->source); + if (srcport < SRC_BASE_PORT || + srcport > SRC_BASE_PORT+256) + { + printf( + "ready_callback4: unknown TCP port in ICMP: %d\n", srcport); + return; /* Not for us */ + } + + /* We store the id in high order 16 bits of the + * sequence number + */ + ind= ntohl(etcp->seq) >> 16; + + state= NULL; + if (ind >= 0 && ind < base->tabsiz) + state= base->table[ind]; + if (state && state->sin6.sin6_family != AF_INET) + state= NULL; + if (state && !state->do_tcp) + state= NULL; + + if (!state) + { + /* Nothing here */ + printf( + "ready_callback4: no state for ind %d\n", + ind); + return; + } + +#if 0 + printf("ready_callback4: from %s", + inet_ntoa(remote.sin_addr)); + printf(" for %s hop %d\n", + inet_ntoa(((struct sockaddr_in *) + &state->sin6)->sin_addr), state->hop); +#endif + + if (!state->busy) + { +#if 0 + printf( + "ready_callback4: index (%d) is not busy\n", + ind); +#endif + return; + } + + late= 0; + isDup= 0; + + /* Sequence number is in seq field */ + seq= ntohl(etcp->seq) & 0xffff; + + if (seq != state->seq) + { + if (seq > state->seq) + { +#if 0 + printf( + "ready_callback4: mismatch for seq, got 0x%x, expected 0x%x (for %s)\n", + seq, state->seq, + state->hostname); +#endif + return; + } + late= 1; + + snprintf(line, sizeof(line), "\"late\":%d", + state->seq-seq); + add_str(state, line); + } + else if (state->gotresp) + { + isDup= 1; + add_str(state, " }, { \"dup\":true"); + } + + if (!late && !isDup) + state->last_response_hop= state->hop; + + ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + + (now.tv_usec-state->xmit_time.tv_usec)/1e3; + + snprintf(line, sizeof(line), "%s\"from\":\"%s\"", + (late || isDup) ? ", " : "", + inet_ntoa(remote.sin_addr)); + add_str(state, line); + snprintf(line, sizeof(line), + ", \"ttl\":%d, \"size\":%d", + ip->ip_ttl, (int)nrecv - IPHDR - ICMP_MINLEN); + add_str(state, line); + if (!late) + { + snprintf(line, sizeof(line), ", \"rtt\":%.3f", + ms); + add_str(state, line); + } + + if (eip->ip_ttl != 1) + { + snprintf(line, sizeof(line), ", \"ittl\":%d", + eip->ip_ttl); + add_str(state, line); + } + + if (memcmp(&eip->ip_src, + &((struct sockaddr_in *)&state->loc_sin6)-> + sin_addr, sizeof(eip->ip_src)) != 0) + { + printf("ready_callback4: changed source %s\n", + inet_ntoa(eip->ip_src)); + } + if (memcmp(&eip->ip_dst, + &((struct sockaddr_in *)&state->sin6)-> + sin_addr, sizeof(eip->ip_dst)) != 0) + { + snprintf(line, sizeof(line), + ", \"edst\":\"%s\"", + inet_ntoa(eip->ip_dst)); + add_str(state, line); + } + if (memcmp(&ip->ip_dst, + &((struct sockaddr_in *)&state->loc_sin6)-> + sin_addr, sizeof(eip->ip_src)) != 0) + { + printf("ready_callback4: weird destination %s\n", + inet_ntoa(ip->ip_dst)); + } + +#if 0 + printf("ready_callback4: from %s, ttl %d", + inet_ntoa(remote.sin_addr), ip->ip_ttl); + printf(" for %s hop %d\n", + inet_ntoa(((struct sockaddr_in *) + &state->sin6)->sin_addr), state->hop); +#endif + + if (icmp->icmp_type == ICMP_TIME_EXCEEDED) + { + if (!late) + state->not_done= 1; + } + else if (icmp->icmp_type == ICMP_DEST_UNREACH) + { + if (!late) + state->done= 1; + switch(icmp->icmp_code) + { + case ICMP_UNREACH_NET: + add_str(state, ", \"err\":\"N\""); + break; + case ICMP_UNREACH_HOST: + add_str(state, ", \"err\":\"H\""); + break; + case ICMP_UNREACH_PROTOCOL: + add_str(state, ", \"err\":\"P\""); + break; + case ICMP_UNREACH_PORT: + break; + case ICMP_UNREACH_NEEDFRAG: + nextmtu= ntohs(icmp->icmp_nextmtu); + snprintf(line, sizeof(line), + ", \"mtu\":%d", + nextmtu); + add_str(state, line); + if (!late && nextmtu >= sizeof(*ip)+ + sizeof(*etcp)) + { + nextmtu -= sizeof(*ip)+ + sizeof(*etcp); + if (nextmtu < + state->curpacksize) + { + state->curpacksize= + nextmtu; + } + } +printf("curpacksize: %d\n", state->curpacksize); + if (!late) + state->not_done= 1; + break; + case ICMP_UNREACH_FILTER_PROHIB: + add_str(state, ", \"err\":\"A\""); + break; + default: + snprintf(line, sizeof(line), + ", \"err\":%d", + icmp->icmp_code); + add_str(state, line); + break; + } + } + } + else if (eip->ip_p == IPPROTO_UDP) { /* Now check if there is also a UDP header in the * packet @@ -1041,7 +1527,7 @@ static void ready_callback4(int __attribute((unused)) unused, state= base->table[ind]; if (state && state->sin6.sin6_family != AF_INET) state= NULL; - if (state && state->do_icmp) + if (state && state->do_Xicmp) state= NULL; if (!state) @@ -1126,7 +1612,7 @@ static void ready_callback4(int __attribute((unused)) unused, add_str(state, line); snprintf(line, sizeof(line), ", \"ttl\":%d, \"size\":%d", - ip->ip_ttl, (int)nrecv); + ip->ip_ttl, (int)nrecv-IPHDR-ICMP_MINLEN); add_str(state, line); if (!late) { @@ -1280,7 +1766,7 @@ printf("curpacksize: %d\n", state->curpacksize); return; } - if (!state->do_icmp) + if (!state->do_Xicmp) { printf( "ready_callback4: index (%d) is not doing ICMP\n", @@ -1342,9 +1828,10 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family (late || isDup) ? ", " : "", inet_ntoa(remote.sin_addr)); add_str(state, line); +printf("nrecv=%d\n", nrecv); snprintf(line, sizeof(line), ", \"ttl\":%d, \"size\":%d", - ip->ip_ttl, (int)nrecv); + ip->ip_ttl, (int)nrecv-IPHDR-ICMP_MINLEN); add_str(state, line); if (!late) { @@ -1421,9 +1908,11 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family ", \"mtu\":%d", nextmtu); add_str(state, line); - if (!late && nextmtu >= sizeof(*ip)) + if (!late && nextmtu >= sizeof(*ip) + + ICMP_MINLEN) { - nextmtu -= sizeof(*ip); + nextmtu -= sizeof(*ip) + + ICMP_MINLEN; if (nextmtu < state->curpacksize) { @@ -1452,7 +1941,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } else { - printf("ready_callback4: not UDP or ICMP (%d\n", + printf("ready_callback4: not TCP, UDP or ICMP (%d\n", eip->ip_p); return; } @@ -1599,7 +2088,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family inet_ntoa(remote.sin_addr)); add_str(state, line); snprintf(line, sizeof(line), ", \"ttl\":%d, \"size\":%d", - ip->ip_ttl, (int)nrecv); + ip->ip_ttl, (int)nrecv - IPHDR - ICMP_MINLEN); add_str(state, line); if (!late) { @@ -1648,18 +2137,362 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } } +static void ready_tcp4(int __attribute((unused)) unused, + const short __attribute((unused)) event, void *s) +{ + uint16_t myport; + socklen_t slen; + int hlen, late, isDup; + unsigned ind, seq; + ssize_t nrecv; + struct trtbase *base; + struct trtstate *state; + struct ip *ip; + double ms; + struct tcphdr *tcphdr; + struct sockaddr_in remote; + struct timeval now; + struct timeval interval; + char line[80]; + + gettimeofday(&now, NULL); + + base= s; + + slen= sizeof(remote); + nrecv= recvfrom(base->v4tcp_rcv, base->packet, sizeof(base->packet), + MSG_DONTWAIT, (struct sockaddr *)&remote, &slen); + if (nrecv == -1) + { + /* Strange, read error */ + printf("ready_tcp4: read error '%s'\n", strerror(errno)); + return; + } + + ip= (struct ip *)base->packet; + hlen= ip->ip_hl*4; + + if (nrecv < hlen + sizeof(*tcphdr) || ip->ip_hl < 5) + { + /* Short packet */ + printf("ready_tcp4: too short %d\n", (int)nrecv); + return; + } + + tcphdr= (struct tcphdr *)(base->packet+hlen); + + /* Quick check if the port is in range */ + myport= ntohs(tcphdr->dest); + if (myport < SRC_BASE_PORT || myport > SRC_BASE_PORT+256) + { + return; /* Not for us */ + } + + /* 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 (state && state->sin6.sin6_family != AF_INET) + state= NULL; + if (state && !state->do_tcp) + state= NULL; + + if (!state) + { + /* Nothing here */ + printf("ready_tcp4: no state for index %d\n", ind); + return; + } + + if (!state->busy) + { +printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family); + printf( + "ready_callback4: index (%d) is not busy\n", + ind); + return; + } + + late= 0; + isDup= 0; + + /* Only check if the ack is without 64k of what we expect */ + seq= ntohl(tcphdr->ack_seq) & 0xffff; + if (seq-state->seq > 0x2000) + { +printf("got seq %d, expected %d\n", seq, state->seq); + if (seq > state->seq) + { +#if 0 + printf( +"ready_callback4: mismatch for seq, got 0x%x, expected 0x%x, for %s\n", + seq, state->seq, state->hostname); +#endif + return; + } + late= 1; + + snprintf(line, sizeof(line), "\"late\":%d", + state->seq-seq); + add_str(state, line); + } + else if (state->gotresp) + { + isDup= 1; + add_str(state, " }, { \"dup\":true"); + } + + ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + + (now.tv_usec-state->xmit_time.tv_usec)/1e3; + + snprintf(line, sizeof(line), "%s\"from\":\"%s\"", + (late || isDup) ? ", " : "", + inet_ntoa(remote.sin_addr)); + add_str(state, line); + snprintf(line, sizeof(line), ", \"ttl\":%d, \"size\":%d", + ip->ip_ttl, (int)nrecv - IPHDR - sizeof(*tcphdr)); + add_str(state, line); + snprintf(line, sizeof(line), ", \"flags\":\"%s%s%s%s%s%s\"", + (tcphdr->fin ? "F" : ""), + (tcphdr->syn ? "S" : ""), + (tcphdr->rst ? "R" : ""), + (tcphdr->psh ? "P" : ""), + (tcphdr->ack ? "A" : ""), + (tcphdr->urg ? "U" : "")); + add_str(state, line); + + if (!late) + { + snprintf(line, sizeof(line), ", \"rtt\":%.3f", ms); + add_str(state, line); + } + +#if 0 + printf("ready_callback4: from %s, ttl %d", + inet_ntoa(remote.sin_addr), ip->ip_ttl); + printf(" for %s hop %d\n", + inet_ntoa(((struct sockaddr_in *) + &state->sin6)->sin_addr), state->hop); +#endif + + /* Done */ + state->done= 1; + + if (late) + add_str(state, " }, { "); + + if (!late && !isDup) + { + if (state->duptimeout) + { + state->gotresp= 1; + interval.tv_sec= state->duptimeout/1000000; + interval.tv_usec= state->duptimeout % 1000000; + evtimer_add(&state->timer, &interval); + } + else + send_pkt(state); + } + + return; +} + +static void ready_tcp6(int __attribute((unused)) unused, + const short __attribute((unused)) event, void *s) +{ + uint16_t myport; + int late, isDup, rcvdttl; + unsigned ind, seq; + ssize_t nrecv; + struct trtbase *base; + struct trtstate *state; + double ms; + struct tcphdr *tcphdr; + struct cmsghdr *cmsgptr; + struct msghdr msg; + struct iovec iov[1]; + struct sockaddr_in6 remote; + struct in6_addr dstaddr; + struct timeval now; + struct timeval interval; + char buf[INET6_ADDRSTRLEN]; + char line[80]; + char cmsgbuf[256]; + + gettimeofday(&now, NULL); + + base= s; + + iov[0].iov_base= base->packet; + iov[0].iov_len= sizeof(base->packet); + msg.msg_name= &remote; + msg.msg_namelen= sizeof(remote); + msg.msg_iov= iov; + msg.msg_iovlen= 1; + msg.msg_control= cmsgbuf; + msg.msg_controllen= sizeof(cmsgbuf); + msg.msg_flags= 0; /* Not really needed */ + + nrecv= recvmsg(base->v6tcp_rcv, &msg, MSG_DONTWAIT); + if (nrecv == -1) + { + /* Strange, read error */ + printf("ready_tcp6: read error '%s'\n", strerror(errno)); + return; + } + + rcvdttl= -42; /* To spot problems */ + memset(&dstaddr, '\0', sizeof(dstaddr)); + for (cmsgptr= CMSG_FIRSTHDR(&msg); cmsgptr; + cmsgptr= CMSG_NXTHDR(&msg, cmsgptr)) + { + if (cmsgptr->cmsg_len == 0) + break; /* Can this happen? */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_HOPLIMIT) + { + rcvdttl= *(int *)CMSG_DATA(cmsgptr); + } + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_PKTINFO) + { + dstaddr= ((struct in6_pktinfo *) + CMSG_DATA(cmsgptr))->ipi6_addr; + } + } + + tcphdr= (struct tcphdr *)(base->packet); + + /* Quick check if the port is in range */ + myport= ntohs(tcphdr->dest); + if (myport < SRC_BASE_PORT || myport > SRC_BASE_PORT+256) + { + return; /* Not for us */ + } + + /* 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 (state && state->sin6.sin6_family != AF_INET6) + state= NULL; + if (state && !state->do_tcp) + state= NULL; + + if (!state) + { + /* Nothing here */ + printf("ready_tcp6: no state for index %d\n", ind); + return; + } + + if (!state->busy) + { +printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family); + printf("ready_tcp6: index (%d) is not busy\n", ind); + return; + } + + late= 0; + isDup= 0; + + /* Only check if the ack is within 64k of what we expect */ + seq= ntohl(tcphdr->ack_seq) & 0xffff; + if (seq-state->seq > 0x2000) + { +printf("got seq %d, expected %d\n", seq, state->seq); + if (seq > state->seq) + { +#if 0 + printf( +"ready_callback4: mismatch for seq, got 0x%x, expected 0x%x, for %s\n", + seq, state->seq, state->hostname); +#endif + return; + } + late= 1; + + snprintf(line, sizeof(line), "\"late\":%d", + state->seq-seq); + add_str(state, line); + } + else if (state->gotresp) + { + isDup= 1; + add_str(state, " }, { \"dup\":true"); + } + + ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + + (now.tv_usec-state->xmit_time.tv_usec)/1e3; + + snprintf(line, sizeof(line), "%s\"from\":\"%s\"", + (late || isDup) ? ", " : "", + inet_ntop(AF_INET6, &remote.sin6_addr, buf, sizeof(buf))); + add_str(state, line); + snprintf(line, sizeof(line), ", \"ttl\":%d, \"size\":%d", + rcvdttl, (int)nrecv - sizeof(*tcphdr)); + add_str(state, line); + snprintf(line, sizeof(line), ", \"flags\":\"%s%s%s%s%s%s\"", + (tcphdr->fin ? "F" : ""), + (tcphdr->syn ? "S" : ""), + (tcphdr->rst ? "R" : ""), + (tcphdr->psh ? "P" : ""), + (tcphdr->ack ? "A" : ""), + (tcphdr->urg ? "U" : "")); + add_str(state, line); + if (!late) + { + snprintf(line, sizeof(line), ", \"rtt\":%.3f", ms); + add_str(state, line); + } + +#if 0 + printf("ready_callback4: from %s, ttl %d", + inet_ntoa(remote.sin_addr), ip->ip_ttl); + printf(" for %s hop %d\n", + inet_ntoa(((struct sockaddr_in *) + &state->sin6)->sin_addr), state->hop); +#endif + + /* Done */ + state->done= 1; + + if (late) + add_str(state, " }, { "); + + if (!late && !isDup) + { + if (state->duptimeout) + { + state->gotresp= 1; + interval.tv_sec= state->duptimeout/1000000; + interval.tv_usec= state->duptimeout % 1000000; + evtimer_add(&state->timer, &interval); + } + else + send_pkt(state); + } + + return; +} + static void ready_callback6(int __attribute((unused)) unused, const short __attribute((unused)) event, void *s) { ssize_t nrecv; int ind, rcvdttl, late, isDup, nxt, icmp_prefixlen, offset; unsigned nextmtu, seq; - size_t ehdrsiz, siz; + size_t ehdrsiz, v6info_siz, siz; struct trtbase *base; struct trtstate *state; struct ip6_hdr *eip; struct ip6_frag *frag; struct icmp6_hdr *icmp, *eicmp; + struct tcphdr *etcp; struct udphdr *eudp; struct v6info *v6info; struct cmsghdr *cmsgptr; @@ -1744,8 +2577,9 @@ static void ready_callback6(int __attribute((unused)) unused, return; } - /* Make sure we have UDP or ICMP or a fragment header */ + /* Make sure we have TCP, UDP, ICMP or a fragment header */ if (eip->ip6_nxt == IPPROTO_FRAGMENT || + eip->ip6_nxt == IPPROTO_TCP || eip->ip6_nxt == IPPROTO_UDP || eip->ip6_nxt == IPPROTO_ICMPV6) { @@ -1779,7 +2613,13 @@ static void ready_callback6(int __attribute((unused)) unused, nxt= frag->ip6f_nxt; } - if (nxt == IPPROTO_UDP) + v6info_siz= sizeof(*v6info); + if (nxt == IPPROTO_TCP) + { + ehdrsiz += sizeof(*etcp); + v6info_siz= 0; + } + else if (nxt == IPPROTO_UDP) ehdrsiz += sizeof(*eudp); else ehdrsiz += sizeof(*eicmp); @@ -1788,7 +2628,7 @@ static void ready_callback6(int __attribute((unused)) unused, * packet. */ if (nrecv < sizeof(*icmp) + sizeof(*eip) - + ehdrsiz + sizeof(*v6info)) + + ehdrsiz + v6info_siz) { #if 0 printf( @@ -1799,10 +2639,16 @@ static void ready_callback6(int __attribute((unused)) unused, return; } + etcp= NULL; eudp= NULL; eicmp= NULL; + v6info= NULL; ptr= (frag ? (void *)&frag[1] : (void *)&eip[1]); - if (nxt == IPPROTO_UDP) + if (nxt == IPPROTO_TCP) + { + etcp= (struct tcphdr *)ptr; + } + else if (nxt == IPPROTO_UDP) { eudp= (struct udphdr *)ptr; v6info= (struct v6info *)&eudp[1]; @@ -1821,13 +2667,23 @@ static void ready_callback6(int __attribute((unused)) unused, ntohl(v6info->seq)); #endif - if (ntohl(v6info->pid) != base->my_pid) + if (etcp) { - /* From a different process */ - return; + /* We store the id in high order 16 bits of the + * sequence number + */ + ind= ntohl(etcp->seq) >> 16; } + else + { + if (ntohl(v6info->pid) != base->my_pid) + { + /* From a different process */ + return; + } - ind= ntohl(v6info->id); + ind= ntohl(v6info->id); + } state= NULL; if (ind >= 0 && ind < base->tabsiz) @@ -1838,8 +2694,9 @@ static void ready_callback6(int __attribute((unused)) unused, if (state) { - if ((eudp && state->do_icmp) || - (eicmp && !state->do_icmp)) + if ((etcp && !state->do_tcp) || + (eudp && !state->do_udp) || + (eicmp && !state->do_Xicmp)) { state= NULL; } @@ -1871,15 +2728,23 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family late= 0; isDup= 0; - seq= ntohl(v6info->seq); + if (etcp) + { + /* Sequence number is in seq field */ + seq= ntohl(etcp->seq) & 0xffff; + } + else + seq= ntohl(v6info->seq); if (seq != state->seq) { if (seq > state->seq) { +#if 0 printf( "ready_callback6: mismatch for seq, got 0x%x, expected 0x%x\n", ntohl(v6info->seq), state->seq); +#endif return; } late= 1; @@ -1939,7 +2804,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family (now.tv_usec-state->xmit_time.tv_usec)/ 1e3; } - else + else if (v6info) { ms= (now.tv_sec-v6info->tv.tv_sec)*1000 + (now.tv_usec-v6info->tv.tv_usec)/ @@ -1953,7 +2818,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family add_str(state, line); snprintf(line, sizeof(line), ", \"ttl\":%d, \"rtt\":%.3f, \"size\":%d", - rcvdttl, ms, (int)nrecv); + rcvdttl, ms, (int)nrecv-ICMP6_HDR); add_str(state, line); if (eip->ip6_hops != 1) { @@ -1985,6 +2850,10 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family siz= sizeof(*eip); if (eudp) siz += sizeof(*eudp); + else if (eicmp) + siz += sizeof(*eicmp); + else if (etcp) + siz += sizeof(*etcp); if (!late && nextmtu >= siz) { nextmtu -= siz; @@ -2118,7 +2987,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family if (state && state->sin6.sin6_family != AF_INET6) state= NULL; - if (state && !state->do_icmp) + if (state && !state->do_Xicmp) { state= NULL; } @@ -2206,7 +3075,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family add_str(state, line); snprintf(line, sizeof(line), ", \"ttl\":%d, \"rtt\":%.3f, \"size\":%d", - rcvdttl, ms, (int)nrecv); + rcvdttl, ms, (int)nrecv - ICMP6_HDR); add_str(state, line); #if 0 @@ -2268,6 +3137,8 @@ static struct trtbase *traceroute_base_new(struct event_base 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(); @@ -2279,13 +3150,22 @@ static struct trtbase *traceroute_base_new(struct event_base 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; } @@ -2311,14 +3191,17 @@ static void noreply_callback(int __attribute((unused)) unused, static void *traceroute_init(int __attribute((unused)) argc, char *argv[], void (*done)(void *state)) { + uint16_t destport; uint32_t opt; - int i, do_icmp, do_v6, dont_fragment, delay_name_res; + int i, do_icmp, do_v6, dont_fragment, delay_name_res, do_tcp, do_udp; unsigned count, duptimeout, firsthop, gaplimit, maxhops, maxpacksize, parismod, timeout; /* must be int-sized */ size_t newsiz; char *str_Atlas; const char *hostname; char *out_filename; + char *destportstr; + char *check; struct trtstate *state; sa_family_t af; len_and_sockaddr *lsa; @@ -2337,15 +3220,20 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], gaplimit= 5; maxhops= 32; maxpacksize= 40; + destportstr= "80"; duptimeout= 10; timeout= 1000; parismod= 16; str_Atlas= NULL; out_filename= NULL; opt_complementary = "=1:4--6:i--u:a+:c+:f+:g+:m+:w+:z+:S+"; + +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, &timeout, &duptimeout, - &str_Atlas, &out_filename, &maxpacksize); + &firsthop, &gaplimit, &maxhops, &destportstr, &timeout, + &duptimeout, &str_Atlas, &out_filename, &maxpacksize); hostname = argv[optind]; if (opt == 0xffffffff) @@ -2358,6 +3246,8 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], do_v6= !!(opt & OPT_6); dont_fragment= !!(opt & OPT_F); delay_name_res= !!(opt & OPT_r); + do_tcp= !!(opt & OPT_T); + do_udp= !(do_icmp || do_tcp); if (maxpacksize > sizeof(trt_base->packet)) maxpacksize= sizeof(trt_base->packet); @@ -2391,7 +3281,10 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], { /* Attempt to resolve 'name' */ af= do_v6 ? AF_INET6 : AF_INET; - lsa= host_and_af2sockaddr(hostname, 0, af); + destport= strtoul(destportstr, &check, 0); + if (check[0] != '\0' || destport == 0) + return NULL; + lsa= host_and_af2sockaddr(hostname, destport, af); if (!lsa) return NULL; @@ -2415,11 +3308,14 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], state->maxpacksize= maxpacksize; state->maxhops= maxhops; state->gaplimit= gaplimit; + state->destportstr= destportstr; state->duptimeout= duptimeout*1000; state->timeout= timeout*1000; state->atlas= str_Atlas ? strdup(str_Atlas) : NULL; state->hostname= strdup(hostname); - state->do_icmp= do_icmp; + state->do_Xicmp= do_icmp; + state->do_tcp= do_tcp; + state->do_udp= do_udp; state->do_v6= do_v6; state->dont_fragment= dont_fragment; state->delay_name_res= delay_name_res; @@ -2449,9 +3345,6 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], trt_base->table[i]= state; trt_base->done= done; - printf("traceroute_init: state %p, index %d\n", - state, state->index); - memset(&state->loc_sin6, '\0', sizeof(state->loc_sin6)); state->loc_socklen= 0; @@ -2521,7 +3414,7 @@ static void traceroute_start2(void *state) snprintf(line, sizeof(line), "{ \"hop\":%d", trtstate->hop); add_str(trtstate, line); - if (trtstate->do_icmp) + if (trtstate->do_Xicmp) { if (trtstate->do_v6) { @@ -2613,7 +3506,6 @@ static void traceroute_start2(void *state) { crondlog(DIE9 "socket failed"); } -printf("traceroute_start2: before bind\n"); r= bind(sock, (struct sockaddr *)&loc_sa6, sizeof(loc_sa6)); if (r == -1) @@ -2674,9 +3566,12 @@ printf("traceroute_start2: before bind\n"); loc_sa4.sin_port= htons(SRC_BASE_PORT + trtstate->index);; - /* Also set destination port */ - ((struct sockaddr_in *)&trtstate->sin6)-> - sin_port= htons(BASE_PORT); + if (!trtstate->do_tcp) + { + /* Also set destination port */ + ((struct sockaddr_in *)&trtstate->sin6)-> + sin_port= htons(BASE_PORT); + } sock= socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) @@ -2831,8 +3726,8 @@ static void traceroute_start(void *state) hints.ai_socktype= SOCK_DGRAM; hints.ai_family= trtstate->do_v6 ? AF_INET6 : AF_INET; trtstate->dnsip= 1; - (void) evdns_getaddrinfo(DnsBase, trtstate->hostname, NULL, - &hints, dns_cb, trtstate); + (void) evdns_getaddrinfo(DnsBase, trtstate->hostname, + trtstate->destportstr, &hints, dns_cb, trtstate); } static int traceroute_delete(void *state) diff --git a/include/usage.h b/include/usage.h index 5870924..e83abbd 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1061,9 +1061,28 @@ "todo" #define evtraceroute_trivial_usage \ - "todo" -#define evtraceroute_full_usage "\n\n" \ - "todo" + "-[46FIrTU] [-a ] [-c ] [-f ]" \ +"\n [-g ] [-m ] [-w ] [-z ] [-A ] [-O ]" \ +"\n [-S ]" + +#define evtraceroute_full_usage "\n" \ + "\n -4 Use IPv4 (default)" \ + "\n -6 Use IPv6" \ + "\n -F Don't fragment" \ + "\n -I Use ICMP" \ + "\n -r Name resolution during each run" \ + "\n -T Use TCP" \ + "\n -U Use UDP (default)" \ + "\n -a Enables Paris-traceroute" \ + "\n -c #packets per hop" \ + "\n -f Starting hop" \ + "\n -g Gap limit" \ + "\n -m Max hops" \ + "\n -w No reply timeout (ms)" \ + "\n -z Dup timeout (ms)" \ + "\n -A Atlas measurement ID" \ + "\n -O Name of output file" \ + "\n -S Size of packet" \ #define expand_trivial_usage \ "[-i] [-t NUM] [FILE|-]" diff --git a/libevent-2.0.20-stable/evdns.c b/libevent-2.0.20-stable/evdns.c index 8beee70..cf38418 100644 --- a/libevent-2.0.20-stable/evdns.c +++ b/libevent-2.0.20-stable/evdns.c @@ -4054,6 +4054,13 @@ evdns_base_parse_hosts_line(struct evdns_base *base, char *line) memcpy(he->hostname, hostname, namelen+1); he->addrlen = socklen; +#if 0 + fprintf(stderr, "evdns_base_parse_hosts_line: base %p, he %p\n", + base, he); + fprintf(stderr, + "evdns_base_parse_hosts_line: tqh_first %p, tqh_last %p\n", + base->hostsdb.tqh_first, base->hostsdb.tqh_last); +#endif TAILQ_INSERT_TAIL(&base->hostsdb, he, next); if (hash) @@ -4073,6 +4080,15 @@ evdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname) ASSERT_LOCKED(base); + { + struct hosts_entry *victim; + while ((victim = TAILQ_FIRST(&base->hostsdb))) { + TAILQ_REMOVE(&base->hostsdb, victim, next); + mm_free(victim); + } + } + + if (hosts_fname == NULL || (err = evutil_read_file(hosts_fname, &str, &len, 0)) < 0) { char tmp[64]; @@ -4167,7 +4183,7 @@ evdns_err_to_getaddrinfo_err(int e1) else if (e1 == DNS_ERR_NOTEXIST) return EVUTIL_EAI_NONAME; else - return EVUTIL_EAI_FAIL; + return EVUTIL_EAI_FAIL_1; } /* Return the more informative of two getaddrinfo errors. */ @@ -4529,7 +4545,7 @@ evdns_getaddrinfo(struct evdns_base *dns_base, log(EVDNS_LOG_WARN, "Call to getaddrinfo_async with no " "evdns_base configured."); - cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */ + cb(EVUTIL_EAI_FAIL_2, NULL, arg); /* ??? better error? */ return NULL; } } @@ -4630,7 +4646,7 @@ evdns_getaddrinfo(struct evdns_base *dns_base, return data; } else { mm_free(data); - cb(EVUTIL_EAI_FAIL, NULL, arg); + cb(EVUTIL_EAI_FAIL_3, NULL, arg); return NULL; } } diff --git a/libevent-2.0.20-stable/evutil.c b/libevent-2.0.20-stable/evutil.c index e17e5b8..b07319a 100644 --- a/libevent-2.0.20-stable/evutil.c +++ b/libevent-2.0.20-stable/evutil.c @@ -1443,6 +1443,12 @@ evutil_gai_strerror(int err) return "invalid value for ai_flags"; case EVUTIL_EAI_FAIL: return "non-recoverable failure in name resolution"; + case EVUTIL_EAI_FAIL_1: + return "non-recoverable failure in name resolution (1)"; + case EVUTIL_EAI_FAIL_2: + return "non-recoverable failure in name resolution (2)"; + case EVUTIL_EAI_FAIL_3: + return "non-recoverable failure in name resolution (3)"; case EVUTIL_EAI_FAMILY: return "ai_family not supported"; case EVUTIL_EAI_MEMORY: diff --git a/libevent-2.0.20-stable/include/event2/util.h b/libevent-2.0.20-stable/include/event2/util.h index 4b7e8b4..adc3ce5 100644 --- a/libevent-2.0.20-stable/include/event2/util.h +++ b/libevent-2.0.20-stable/include/event2/util.h @@ -548,6 +548,9 @@ struct evutil_addrinfo { #else #define EVUTIL_EAI_FAIL -904 #endif +#define EVUTIL_EAI_FAIL_1 -921 +#define EVUTIL_EAI_FAIL_2 -922 +#define EVUTIL_EAI_FAIL_3 -923 #ifdef EAI_FAMILY #define EVUTIL_EAI_FAMILY EAI_FAMILY #else diff --git a/networking/telnetd.c b/networking/telnetd.c index 1855f1b..03d6d27 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c @@ -1024,6 +1024,7 @@ static int equal_sessionid(char *passwd) return 0; } + fgets(line, sizeof(line), file); /* Skip first empty line */ if (fgets(line, sizeof(line), file) == NULL) { syslog(LOG_ERR, "unable to read from '%s': %m", -- cgit v1.2.3