From 73e699faf130d0fc0f2f076d95db9dbd7f42a8b6 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 15 May 2015 10:25:25 +0200 Subject: ripe-atlas-fw: imported version 4660 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- .config | 3 +- eperd/Config.in | 6 + eperd/Kbuild | 2 +- eperd/eooqd.c | 8 + eperd/eperd.c | 1 + eperd/eperd.h | 1 + eperd/evntp.c | 57 ++ eperd/evtdig.c | 2 + eperd/ntp.c | 1955 ++++++++++++++++++++++++++++++++++++++++++++++++++++ eperd/ping.c | 69 +- eperd/traceroute.c | 55 +- include/applets.h | 1 + include/usage.h | 6 + 13 files changed, 2133 insertions(+), 33 deletions(-) create mode 100644 eperd/evntp.c create mode 100644 eperd/ntp.c diff --git a/.config b/.config index f6026bd..d76fe13 100644 --- a/.config +++ b/.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.13.3 -# Wed May 7 07:15:57 2014 +# Sat Jun 21 16:01:25 2014 # CONFIG_HAVE_DOT_CONFIG=y @@ -338,6 +338,7 @@ CONFIG_FEATURE_ALLOW_EXEC=y CONFIG_EOOQD=y CONFIG_EPERD=y CONFIG_EVHTTPGET=y +CONFIG_EVNTP=y CONFIG_EVPING=y CONFIG_EVSSLGETCERT=y CONFIG_EVTDIG=y diff --git a/eperd/Config.in b/eperd/Config.in index ed1f7df..51ec49b 100644 --- a/eperd/Config.in +++ b/eperd/Config.in @@ -27,6 +27,12 @@ config EVHTTPGET help standalone version of event-driven httpget +config EVNTP + bool "evntp" + default n + help + standalone version of event-driven ntp + config EVPING bool "evping" default n diff --git a/eperd/Kbuild b/eperd/Kbuild index ae83fed..abafbe4 100644 --- a/eperd/Kbuild +++ b/eperd/Kbuild @@ -5,4 +5,4 @@ # Licensed under the GPL v2, see the file LICENSE in this tarball. lib-y:= -lib-$(CONFIG_EPERD) += eooqd.o eperd.o condmv.o httpget.o ping.o sslgetcert.o traceroute.o evhttpget.o evping.o evsslgetcert.o evtdig.o evtraceroute.o tcputil.o readresolv.o +lib-$(CONFIG_EPERD) += eooqd.o eperd.o condmv.o httpget.o ping.o sslgetcert.o traceroute.o evhttpget.o evping.o evsslgetcert.o evtdig.o evtraceroute.o tcputil.o readresolv.o evntp.o ntp.o diff --git a/eperd/eooqd.c b/eperd/eooqd.c index 41efa1b..4f572b7 100644 --- a/eperd/eooqd.c +++ b/eperd/eooqd.c @@ -51,6 +51,7 @@ static struct builtin } builtin_cmds[]= { { "evhttpget", &httpget_ops }, + { "evntp", &ntp_ops }, { "evping", &ping_ops }, { "evtdig", &tdig_ops }, { "evsslgetcert", &sslgetcert_ops }, @@ -84,6 +85,7 @@ int eooqd_main(int argc, char *argv[]) char *pid_file_name; struct event *checkQueueEvent, *rePostEvent; struct timeval tv; + struct rlimit limit; atlas_id= NULL; pid_file_name= NULL; @@ -122,6 +124,12 @@ int eooqd_main(int argc, char *argv[]) sizeof(state->curr_qfile)); strlcat(state->curr_qfile, SUFFIX, sizeof(state->curr_qfile)); + signal(SIGQUIT, SIG_DFL); + chdir("/home/atlas/data"); + limit.rlim_cur= RLIM_INFINITY; + limit.rlim_max= RLIM_INFINITY; + setrlimit(RLIMIT_CORE, &limit); + /* Create libevent event base */ EventBase= event_base_new(); if (!EventBase) diff --git a/eperd/eperd.c b/eperd/eperd.c index 131f5d5..20b68b5 100644 --- a/eperd/eperd.c +++ b/eperd/eperd.c @@ -843,6 +843,7 @@ static struct builtin } builtin_cmds[]= { { "evhttpget", &httpget_ops }, + { "evntp", &ntp_ops }, { "evping", &ping_ops }, { "evsslgetcert", &sslgetcert_ops }, { "evtdig", &tdig_ops }, diff --git a/eperd/eperd.h b/eperd/eperd.h index 8156022..25994fa 100644 --- a/eperd/eperd.h +++ b/eperd/eperd.h @@ -43,6 +43,7 @@ struct testops extern struct testops condmv_ops; extern struct testops httpget_ops; +extern struct testops ntp_ops; extern struct testops ping_ops; extern struct testops sslgetcert_ops; extern struct testops tdig_ops; diff --git a/eperd/evntp.c b/eperd/evntp.c new file mode 100644 index 0000000..0047d1b --- /dev/null +++ b/eperd/evntp.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 RIPE NCC + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Standalone version of the event-based ntp. + */ + +#include "libbb.h" +#include +#include +#include +#include + +#include "eperd.h" + +static void done(void *state UNUSED_PARAM) +{ + fprintf(stderr, "And we are done\n"); + exit(0); +} + +int evntp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int evntp_main(int argc UNUSED_PARAM, char **argv) +{ + int r; + void *state; + + /* Create libevent event base */ + EventBase= event_base_new(); + if (!EventBase) + { + fprintf(stderr, "evntp: event_base_new failed\n"); + exit(1); + } + DnsBase= evdns_base_new(EventBase, 1 /*initialize*/); + if (!DnsBase) + { + fprintf(stderr, "evdns_base_new failed\n"); + exit(1); + } + + state= ntp_ops.init(argc, argv, done); + if (!state) + { + fprintf(stderr, "evntp: ntp_ops.init failed\n"); + exit(1); + } + ntp_ops.start(state); + + r= event_base_loop(EventBase, 0); + if (r != 0) + { + fprintf(stderr, "evntp: event_base_loop failed\n"); + exit(1); + } + return 0; /* not reached */ +} + diff --git a/eperd/evtdig.c b/eperd/evtdig.c index e0a8ae5..a836745 100644 --- a/eperd/evtdig.c +++ b/eperd/evtdig.c @@ -1822,6 +1822,8 @@ void tdig_start (struct query_state *qry) get_local_resolvers (tdig_base->nslist, &tdig_base->resolv_max); crondlog(LVL5 "AAA RESOLV QUERY FREE %s resolv_max %d %d", qry->server_name, tdig_base->resolv_max, qry->resolv_i); if(tdig_base->resolv_max ) { + free(qry->server_name); + qry->server_name = NULL; qry->server_name = strdup(tdig_base->nslist[qry->resolv_i]); } else { diff --git a/eperd/ntp.c b/eperd/ntp.c new file mode 100644 index 0000000..251510d --- /dev/null +++ b/eperd/ntp.c @@ -0,0 +1,1955 @@ +/* + * Copyright (c) 2013 RIPE NCC + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * traceroute.c + */ + +#include "libbb.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "eperd.h" + +#define SAFE_PREFIX ATLAS_DATA_NEW + +#define DBQ(str) "\"" #str "\"" + +#ifndef STANDALONE_BUSYBOX +#define uh_sport source +#define uh_dport dest +#define uh_ulen len +#define uh_sum check +#endif + +#define NTP_PORT 123 + +#define NTP_OPT_STRING ("!46c:i:w:A:O:") + +#define OPT_4 (1 << 0) +#define OPT_6 (1 << 1) +#define OPT_I (1 << 2) +#define OPT_U (1 << 3) +#define OPT_F (1 << 4) +#define OPT_r (1 << 5) +#define OPT_T (1 << 6) + +#define IPHDR 20 + +#define SRC_BASE_PORT (20480) +#define MAX_DATA_SIZE (4096) + +#define DBQ(str) "\"" #str "\"" + +struct ntp_ts +{ + uint32_t ntp_seconds; + uint32_t ntp_fraction; +}; + +struct ntpbase +{ + struct event_base *event_base; + + int my_pid; + + struct ntpstate **table; + int tabsiz; + + /* For standalone traceroute. Called when a traceroute instance is + * done. Just one pointer for all instances. It is up to the caller + * to keep it consistent. + */ + void (*done)(void *state); + + u_char packet[MAX_DATA_SIZE]; +}; + +struct ntpstate +{ + /* Parameters */ + char *atlas; + char *hostname; + char *destportstr; + char *out_filename; + char *interface; + char do_v6; + char count; + unsigned timeout; + + /* Base and index in table */ + struct ntpbase *base; + int index; + + struct sockaddr_in6 sin6; + socklen_t socklen; + struct sockaddr_in6 loc_sin6; + socklen_t loc_socklen; + + int sent; + uint16_t seq; + int socket; /* Socket for sending and receiving */ + struct event event_socket; /* Event for this socket */ + unsigned first:1; /* Waiting for first response */ + unsigned done:1; /* We got something from the target + * host or a destination unreachable. + */ + unsigned not_done:1; /* Not got something else */ + unsigned busy:1; /* Busy, do not start another one */ + unsigned gotresp:1; /* Got a response to the last packet + * we sent. For dup detection. + */ + unsigned dnsip:1; /* Busy with dns name resolution */ + struct evutil_addrinfo *dns_res; + struct evutil_addrinfo *dns_curr; + + time_t starttime; + struct timeval xmit_time; + + uint8_t ntp_flags; + uint8_t ntp_stratum; + int8_t ntp_poll; + int8_t ntp_precision; + uint32_t ntp_root_delay; + uint32_t ntp_root_dispersion; + uint32_t ntp_reference_id; + struct ntp_ts ntp_reference_ts; + + struct event timer; + + unsigned long min; + unsigned long max; + unsigned long sum; + int sentpkts; + int rcvdpkts; + int duppkts; + + char *result; + size_t reslen; + size_t resmax; + char open_result; +}; + +static struct ntpbase *ntp_base; + +struct ntphdr +{ + uint8_t ntp_flags; + uint8_t ntp_stratum; + int8_t ntp_poll; + int8_t ntp_precision; + uint32_t ntp_root_delay; + uint32_t ntp_root_dispersion; + uint32_t ntp_reference_id; + struct ntp_ts ntp_reference_ts; + struct ntp_ts ntp_origin_ts; + struct ntp_ts ntp_receive_ts; + struct ntp_ts ntp_transmit_ts; +}; + +#define NTP_LI_MASK 0xC0 +#define NTP_LI_SHIFT 6 +#define LI_NO_WARNING 0 +#define LI_61 1 +#define LI_59 2 +#define LI_UNKNOWN 3 +#define NTP_VERSION 4 +#define NTP_VERSION_MASK 0x38 +#define NTP_VERSION_SHIFT 3 +#define NTP_MODE_CLIENT 3 +#define NTP_MODE_MASK 0x7 +#define MODE_RESERVED 0 +#define MODE_SYM_ACT 1 +#define MODE_SYM_PASS 2 +#define MODE_CLIENT 3 +#define MODE_SERVER 4 +#define MODE_BROADCAST 5 +#define MODE_CONTROL 6 +#define MODE_PRIVATE 7 + +#define STRATUM_INVALID 0 +#define STRATUM_UNSYNCHRONIZED 16 + +#define NTP_1970 2208988800UL /* 1970 - 1900 in seconds */ + +#define NTP_4G 4294967296.0 + + +static int create_socket(struct ntpstate *state); + +static void add_str(struct ntpstate *state, const char *str) +{ + size_t len; + + len= strlen(str); + if (state->reslen + len+1 > state->resmax) + { + state->resmax= state->reslen + len+1 + 80; + state->result= xrealloc(state->result, state->resmax); + } + memcpy(state->result+state->reslen, str, len+1); + state->reslen += len; + //printf("add_str: result = '%s'\n", state->result); +} + +static void format_li(char *line, size_t size, uint8_t flags) +{ + const char *str; + + switch((flags & NTP_LI_MASK) >> NTP_LI_SHIFT) + { + case LI_NO_WARNING: str= "no"; break; + case LI_61: str= "61"; break; + case LI_59: str= "59"; break; + case LI_UNKNOWN: str= "unknown"; break; + } + snprintf(line, size, DBQ(li) ": " DBQ(%s), str); +} + +static void format_mode(char *line, size_t size, uint8_t flags) +{ + const char *str; + + switch(flags & NTP_MODE_MASK) + { + case MODE_RESERVED: str= "reserved"; break; + case MODE_SYM_ACT: str= "sym. active"; break; + case MODE_SYM_PASS: str= "sym. passive"; break; + case MODE_CLIENT: str= "client"; break; + case MODE_SERVER: str= "server"; break; + case MODE_BROADCAST: str= "broadcast"; break; + case MODE_CONTROL: str= "control"; break; + case MODE_PRIVATE: str= "private"; break; + } + snprintf(line, size, DBQ(mode) ": " DBQ(%s), str); +} + +static void format_stratum(char *line, size_t size, uint8_t stratum) +{ + const char *str; + + str= NULL; + switch(stratum) + { + case STRATUM_INVALID: str= "invalid"; break; + case STRATUM_UNSYNCHRONIZED: str= "unsynchronized"; break; + } + if (str) + { + snprintf(line, size, DBQ(stratum) ": " DBQ(%s), + str); + } + else if (stratum < STRATUM_UNSYNCHRONIZED) + { + snprintf(line, size, DBQ(stratum) ": %d", + stratum); + } + else + { + snprintf(line, size, DBQ(stratum) ": " DBQ(reserved (%d)), + stratum); + } +} + +static void format_8bit(char *line, size_t size, const char *label, + int8_t value) +{ + if (value >= 0) + { + snprintf(line, size, DBQ(%s) ": %d", label, 1 << value); + } + else + { + snprintf(line, size, DBQ(%s) ": %g", label, + 1.0 / (1 << -value)); + } +} + +static void format_short_ts(char *line, size_t size, const char *label, + uint32_t value) +{ + snprintf(line, size, DBQ(%s) ": %g", label, value/65536.0); +} + +static void format_ref_id(char *line, size_t size, uint32_t value, + uint8_t stratum) +{ + if (stratum == 0 || stratum == 1) + { + snprintf(line, size, DBQ(ref-id) ": " DBQ(%.4s), + (char *)&value); + } + else + { + snprintf(line, size, DBQ(ref-id) ": " DBQ(%08x), + ntohl(value)); + } +} + +static void format_ts(char *line, size_t size, const char *label, + struct ntp_ts *ts) +{ + double d; + + d= ntohl(ts->ntp_seconds) + ntohl(ts->ntp_fraction)/NTP_4G; + snprintf(line, size, DBQ(%s) ": %.9f", label, d); +} + +static void report(struct ntpstate *state) +{ + FILE *fh; + const char *proto; + char namebuf[NI_MAXHOST]; + char line[80]; + + event_del(&state->timer); + + if (state->out_filename) + { + fh= fopen(state->out_filename, "a"); + if (!fh) + crondlog(DIE9 "unable to append to '%s'", + state->out_filename); + } + else + fh= stdout; + + fprintf(fh, "RESULT { "); + if (state->atlas) + { + fprintf(fh, DBQ(id) ":" DBQ(%s) + ", " DBQ(fw) ":%d" + ", " DBQ(lts) ":%d" + ", " DBQ(time) ":%ld, ", + state->atlas, get_atlas_fw_version(), + get_timesync(), + state->starttime); + } + + fprintf(fh, DBQ(dst_name) ":" DBQ(%s), + state->hostname); + + if (!state->dnsip) + { + getnameinfo((struct sockaddr *)&state->sin6, state->socklen, + namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); + + fprintf(fh, ", " DBQ(dst_addr) ":" DBQ(%s), namebuf); + + namebuf[0]= '\0'; + getnameinfo((struct sockaddr *)&state->loc_sin6, + state->loc_socklen, + namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); + + fprintf(fh, ", " DBQ(src_addr) ":" DBQ(%s), namebuf); + } + + proto= "UDP"; + fprintf(fh, ", " DBQ(proto) ":" DBQ(%s) ", " DBQ(af) ": %d", + proto, + state->dnsip ? (state->do_v6 ? 6 : 4) : + (state->sin6.sin6_family == AF_INET6 ? 6 : 4)); + + if (!state->first) + { + format_li(line, sizeof(line), state->ntp_flags); + fprintf(fh, ", %s", line); + fprintf(fh, ", " DBQ(version) ": %d", + ((state->ntp_flags & NTP_VERSION_MASK) >> + NTP_VERSION_SHIFT)); + + format_mode(line, sizeof(line), state->ntp_flags); + fprintf(fh, ", %s", line); + + format_stratum(line, sizeof(line), state->ntp_stratum); + fprintf(fh, ", %s", line); + + format_8bit(line, sizeof(line), "poll", state->ntp_poll); + fprintf(fh, ", %s", line); + + format_8bit(line, sizeof(line), "precision", + state->ntp_precision); + fprintf(fh, ", %s", line); + + format_short_ts(line, sizeof(line), "root-delay", + ntohl(state->ntp_root_delay)); + fprintf(fh, ", %s", line); + + format_short_ts(line, sizeof(line), "root-dispersion", + ntohl(state->ntp_root_dispersion)); + fprintf(fh, ", %s", line); + + format_ref_id(line, sizeof(line), state->ntp_reference_id, + state->ntp_stratum); + fprintf(fh, ", %s", line); + + format_ts(line, sizeof(line), "ref-ts", + &state->ntp_reference_ts); + fprintf(fh, ", %s", line); + } + + fprintf(fh, ", " DBQ(result) ": [ %s ] }\n", state->result); + + free(state->result); + state->result= NULL; + + if (state->out_filename) + fclose(fh); + + /* Kill the event and close socket */ + if (state->socket != -1) + { + event_del(&state->event_socket); + close(state->socket); + state->socket= -1; + } + + state->busy= 0; + + if (state->base->done) + state->base->done(state); +} + +static void send_pkt(struct ntpstate *state) +{ + int r, len, serrno; + struct ntpbase *base; + struct ntphdr *ntphdr; + double d; + struct timeval interval; + char line[80]; + + state->gotresp= 0; + + base= state->base; + + if (state->sent >= state->count) + { + add_str(state, " }"); + + /* We are done */ + report(state); + return; + } + state->seq++; + + ntphdr= (struct ntphdr *)base->packet; + len= sizeof(*ntphdr); + + memset(ntphdr, '\0', len); + ntphdr->ntp_flags= (NTP_VERSION << NTP_VERSION_SHIFT) | NTP_MODE_CLIENT; + + gettimeofday(&state->xmit_time, NULL); + + ntphdr->ntp_transmit_ts.ntp_seconds= + htonl(state->xmit_time.tv_sec + NTP_1970); + d= state->xmit_time.tv_usec / 1e6; + d *= NTP_4G; + ntphdr->ntp_transmit_ts.ntp_fraction= htonl((uint32_t)d); + + if (state->sin6.sin6_family == AF_INET6) + { + /* Set port */ + state->sin6.sin6_port= htons(NTP_PORT); + + r= sendto(state->socket, base->packet, len, 0, + (struct sockaddr *)&state->sin6, + state->socklen); + +#if 0 + { static int doit=1; if (doit && r != -1) + { errno= ENOSYS; r= -1; } doit= !doit; } +#endif + serrno= errno; + + 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 0 + printf( +"send_pkt: sending IPv4 packet, do_icmp %d, parismod %d, index %d, state %p\n", + state->do_icmp, state->parismod, state->index, state); +#endif + + /* Set port */ + ((struct sockaddr_in *)&state->sin6)->sin_port= + htons(NTP_PORT); + + r= sendto(state->socket, 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; + 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; + } + } + } + + if (state->open_result) + add_str(state, " }, "); + add_str(state, "{ "); + state->open_result= 0; + + /* Increment packets sent */ + state->sent++; + + /* Set timer */ + interval.tv_sec= state->timeout/1000000; + interval.tv_usec= state->timeout % 1000000; + evtimer_add(&state->timer, &interval); + +} + +static void ready_callback(int __attribute((unused)) unused, + const short __attribute((unused)) event, void *s) +{ + struct ntpbase *base; + struct ntpstate *state; + int head; + ssize_t nrecv; + socklen_t slen; + double d; + struct ntphdr *ntphdr; + struct timeval now; + struct ntp_ts final_ts; + struct sockaddr_in remote; + char line[80]; + + gettimeofday(&now, NULL); + + state= s; + base= state->base; + + slen= sizeof(remote); + nrecv= recvfrom(state->socket, base->packet, sizeof(base->packet), + MSG_DONTWAIT, (struct sockaddr *)&remote, &slen); + if (nrecv == -1) + { + /* Strange, read error */ + printf("ready_callback: read error '%s'\n", strerror(errno)); + return; + } + // printf("ready_callback: got packet\n"); + + if (nrecv < sizeof(*ntphdr)) + { + /* Short packet */ + printf("ready_callback: too short %d\n", (int)nrecv); + return; + } + + if (!state->busy) + { +printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family); + return; + } + + if (state->open_result) + add_str(state, " }, { "); + + head= 1; + + ntphdr= (struct ntphdr *)base->packet; + + if (state->first) + { + /* Copy mostly static fields */ + state->ntp_flags= ntphdr->ntp_flags; + state->ntp_stratum= ntphdr->ntp_stratum; + state->ntp_poll= ntphdr->ntp_poll; + state->ntp_precision= ntphdr->ntp_precision; + state->ntp_root_delay= ntphdr->ntp_root_delay; + state->ntp_root_dispersion= ntphdr->ntp_root_dispersion; + state->ntp_reference_id= ntphdr->ntp_reference_id; + state->ntp_reference_ts= ntphdr->ntp_reference_ts; + + state->first= 0; + } + else + { + if ((ntphdr->ntp_flags & NTP_LI_MASK) != + (state->ntp_flags & NTP_LI_MASK)) + { + format_li(line, sizeof(line), ntphdr->ntp_flags); + add_str(state, line); + head= 0; + } + + if ((ntphdr->ntp_flags & NTP_VERSION_MASK) != + (state->ntp_flags & NTP_VERSION_MASK)) + { + snprintf(line, sizeof(line), ", " DBQ(version) ": %d", + ((ntphdr->ntp_flags & NTP_VERSION_MASK) >> + NTP_VERSION_SHIFT)); + add_str(state, line); + head= 0; + } + + if ((ntphdr->ntp_flags & NTP_MODE_MASK) != + (state->ntp_flags & NTP_MODE_MASK)) + { + if (!head) + add_str(state, ", "); + format_mode(line, sizeof(line), ntphdr->ntp_flags); + add_str(state, line); + head= 0; + } + + if (ntphdr->ntp_stratum != state->ntp_stratum) + { + if (!head) + add_str(state, ", "); + format_stratum(line, sizeof(line), ntphdr->ntp_stratum); + add_str(state, line); + head= 0; + } + + if (ntphdr->ntp_poll != state->ntp_poll) + { + if (!head) + add_str(state, ", "); + format_8bit(line, sizeof(line), "poll", + ntphdr->ntp_poll); + add_str(state, line); + head= 0; + } + + if (ntphdr->ntp_precision != state->ntp_precision) + { + if (!head) + add_str(state, ", "); + format_8bit(line, sizeof(line), "precision", + ntphdr->ntp_precision); + add_str(state, line); + head= 0; + } + + if (ntphdr->ntp_root_delay != state->ntp_root_delay) + { + if (!head) + add_str(state, ", "); + format_short_ts(line, sizeof(line), "root-delay", + ntohl(ntphdr->ntp_root_delay)); + add_str(state, line); + head= 0; + } + + if (ntphdr->ntp_root_dispersion != state->ntp_root_dispersion) + { + if (!head) + add_str(state, ", "); + format_short_ts(line, sizeof(line), "root-dispersion", + ntohl(ntphdr->ntp_root_dispersion)); + add_str(state, line); + head= 0; + } + + if (ntphdr->ntp_reference_id != state->ntp_reference_id) + { + if (!head) + add_str(state, ", "); + format_ref_id(line, sizeof(line), + ntphdr->ntp_reference_id, ntphdr->ntp_stratum); + add_str(state, line); + head= 0; + } + + if (memcmp(&ntphdr->ntp_reference_ts, &state->ntp_reference_ts, + sizeof(ntphdr->ntp_reference_ts)) != 0) + { + if (!head) + add_str(state, ", "); + format_ts(line, sizeof(line), "ref-ts", + &ntphdr->ntp_reference_ts); + add_str(state, line); + head= 0; + } + } + + d= ntohl(ntphdr->ntp_origin_ts.ntp_seconds) + + ntohl(ntphdr->ntp_origin_ts.ntp_fraction)/NTP_4G; + snprintf(line, sizeof(line), "%s" DBQ(origin-ts) ": %.9f", + head ? "" : ", ", d); + head= 0; + add_str(state, line); + + d= ntohl(ntphdr->ntp_receive_ts.ntp_seconds) + + ntohl(ntphdr->ntp_receive_ts.ntp_fraction)/NTP_4G; + snprintf(line, sizeof(line), ", " DBQ(receive-ts) ": %.9f", d); + add_str(state, line); + + d= ntohl(ntphdr->ntp_transmit_ts.ntp_seconds) + + ntohl(ntphdr->ntp_transmit_ts.ntp_fraction)/NTP_4G; + snprintf(line, sizeof(line), ", " DBQ(transmit-ts) ": %.9f", d); + add_str(state, line); + + final_ts.ntp_seconds= now.tv_sec + NTP_1970; + d= now.tv_usec / 1e6; + d *= 4294967296.0; + final_ts.ntp_fraction= d; + + d= final_ts.ntp_seconds + final_ts.ntp_fraction/NTP_4G; + snprintf(line, sizeof(line), ", " DBQ(final-ts) ": %.9f", d); + add_str(state, line); + + /* Compute rtt */ + d= final_ts.ntp_seconds - ntohl(ntphdr->ntp_origin_ts.ntp_seconds) - + (ntohl(ntphdr->ntp_transmit_ts.ntp_seconds) - + ntohl(ntphdr->ntp_receive_ts.ntp_seconds)) + + final_ts.ntp_fraction/NTP_4G - + ntohl(ntphdr->ntp_origin_ts.ntp_fraction)/NTP_4G - + (ntohl(ntphdr->ntp_transmit_ts.ntp_fraction)/NTP_4G - + ntohl(ntphdr->ntp_receive_ts.ntp_fraction)/NTP_4G); + snprintf(line, sizeof(line), ", " DBQ(rtt) ": %f", d); + add_str(state, line); + + d= (ntohl(ntphdr->ntp_origin_ts.ntp_seconds) + + final_ts.ntp_seconds)/2.0 - + (ntohl(ntphdr->ntp_receive_ts.ntp_seconds) + + ntohl(ntphdr->ntp_transmit_ts.ntp_seconds))/2.0 + + (ntohl(ntphdr->ntp_origin_ts.ntp_fraction)/NTP_4G + + final_ts.ntp_fraction/NTP_4G)/2.0 - + (ntohl(ntphdr->ntp_receive_ts.ntp_fraction)/NTP_4G + + ntohl(ntphdr->ntp_transmit_ts.ntp_fraction)/NTP_4G)/2.0; + snprintf(line, sizeof(line), ", " DBQ(offset) ": %f", d); + add_str(state, line); + + state->open_result= 1; + + send_pkt(state); +#if 0 + 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)); + } + + 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 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; + + state->open_result= 1; + + 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; + } + else if (icmp->icmp_type == ICMP_ECHO || + icmp->icmp_type == ICMP_ROUTERADVERT) + { + /* No need to do anything */ + } + else + { + printf("ready_callback4: got type %d\n", icmp->icmp_type); + return; + } +#endif +} + +#if 0 +static void ready_callback6(int __attribute((unused)) unused, + const short __attribute((unused)) event, void *s) +{ + crondlog(DIE9 "ready_callback6"); abort(); +#if 0 + ssize_t nrecv; + int ind, rcvdttl, nxt, icmp_prefixlen, offset; + unsigned nextmtu, seq, optlen, hbhoptsize, dstoptsize; + size_t ehdrsiz, v6info_siz, siz; + struct trtbase *base; + struct trtstate *state; + struct ip6_hdr *eip; + struct ip6_frag *frag; + struct ip6_ext *opthdr; + struct icmp6_hdr *icmp, *eicmp; + struct tcphdr *etcp; + struct udphdr *eudp; + struct v6info *v6info; + struct cmsghdr *cmsgptr; + void *ptr; + double ms; + struct timeval now; + struct sockaddr_in6 remote; + struct in6_addr dstaddr; + struct msghdr msg; + struct iovec iov[1]; + struct timeval interval; + char buf[INET6_ADDRSTRLEN]; + char line[80]; + char cmsgbuf[256]; + + gettimeofday(&now, NULL); + + state= s; + base= state->base; + + 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(state->socket_icmp, &msg, MSG_DONTWAIT); + if (nrecv == -1) + { + /* Strange, read error */ + printf("ready_callback6: 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; + } + } + + if (nrecv < sizeof(*icmp)) + { + /* Short packet */ +#if 0 + printf("ready_callback6: too short %d (icmp)\n", (int)nrecv); +#endif + return; + } + + icmp= (struct icmp6_hdr *)&base->packet; + + hbhoptsize= 0; + dstoptsize= 0; + if (icmp->icmp6_type == ICMP6_DST_UNREACH || + icmp->icmp6_type == ICMP6_PACKET_TOO_BIG || + icmp->icmp6_type == ICMP6_TIME_EXCEEDED) + { + eip= (struct ip6_hdr *)&icmp[1]; + + /* Make sure the packet we have is big enough */ + if (nrecv < sizeof(*icmp) + sizeof(*eip)) + { +#if 0 + printf("ready_callback6: too short %d (icmp_ip)\n", + (int)nrecv); +#endif + return; + } + + /* Make sure we have TCP, UDP, ICMP or a fragment header */ + if (eip->ip6_nxt == IPPROTO_FRAGMENT || + eip->ip6_nxt == IPPROTO_HOPOPTS || + eip->ip6_nxt == IPPROTO_DSTOPTS || + eip->ip6_nxt == IPPROTO_TCP || + eip->ip6_nxt == IPPROTO_UDP || + eip->ip6_nxt == IPPROTO_ICMPV6) + { + ehdrsiz= 0; + frag= NULL; + nxt= eip->ip6_nxt; + ptr= &eip[1]; + if (nxt == IPPROTO_HOPOPTS) + { + /* Make sure the options header is completely + * there. + */ + if (nrecv < sizeof(*icmp) + sizeof(*eip) + + sizeof(*opthdr)) + { +#if 0 + printf( + "ready_callback6: too short %d (icmp+ip+opt)\n", + (int)nrecv); +#endif + return; + } + opthdr= (struct ip6_ext *)ptr; + hbhoptsize= 8*opthdr->ip6e_len; + optlen= hbhoptsize+8; + if (nrecv < sizeof(*icmp) + sizeof(*eip) + + optlen) + { + /* Does not contain the full header */ + return; + } + ehdrsiz += optlen; + nxt= opthdr->ip6e_nxt; + ptr= ((char *)opthdr)+optlen; + } + if (nxt == IPPROTO_FRAGMENT) + { + /* Make sure the fragment header is completely + * there. + */ + if (nrecv < sizeof(*icmp) + sizeof(*eip) + + sizeof(*frag)) + { +#if 0 + printf( + "ready_callback6: too short %d (icmp+ip+frag)\n", + (int)nrecv); +#endif + return; + } + frag= (struct ip6_frag *)ptr; + if ((ntohs(frag->ip6f_offlg) & ~3) != 0) + { + /* Not first fragment, just ignore + * it. + */ + return; + } + ehdrsiz += sizeof(*frag); + nxt= frag->ip6f_nxt; + ptr= &frag[1]; + } + if (nxt == IPPROTO_DSTOPTS) + { + /* Make sure the options header is completely + * there. + */ + if (nrecv < sizeof(*icmp) + sizeof(*eip) + + sizeof(*opthdr)) + { +#if 0 + printf( + "ready_callback6: too short %d (icmp+ip+opt)\n", + (int)nrecv); +#endif + return; + } + opthdr= (struct ip6_ext *)ptr; + dstoptsize= 8*opthdr->ip6e_len; + optlen= dstoptsize+8; + if (nrecv < sizeof(*icmp) + sizeof(*eip) + + optlen) + { + /* Does not contain the full header */ + return; + } + ehdrsiz += optlen; + nxt= opthdr->ip6e_nxt; + ptr= ((char *)opthdr)+optlen; + } + + 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); + + /* Now check if there is also a header in the + * packet. + */ + if (nrecv < sizeof(*icmp) + sizeof(*eip) + + ehdrsiz + v6info_siz) + { +#if 0 + printf( + "ready_callback6: too short %d (all) from %s\n", + (int)nrecv, inet_ntop(AF_INET6, + &remote.sin6_addr, buf, sizeof(buf))); +#endif + return; + } + + etcp= NULL; + eudp= NULL; + eicmp= NULL; + v6info= NULL; + if (nxt == IPPROTO_TCP) + { + etcp= (struct tcphdr *)ptr; + } + else if (nxt == IPPROTO_UDP) + { + eudp= (struct udphdr *)ptr; + v6info= (struct v6info *)&eudp[1]; + } + else + { + eicmp= (struct icmp6_hdr *)ptr; + v6info= (struct v6info *)&eicmp[1]; + } + +#if 0 + if (v6info) + { + printf( +"ready_callback6: pid = htonl(%d), id = htonl(%d), seq = htonl(%d)\n", + ntohl(v6info->pid), + ntohl(v6info->id), + ntohl(v6info->seq)); + } +#endif + + if (etcp) + { + /* 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); + } + + if (ind != state->index) + state= NULL; + + if (state && state->sin6.sin6_family != AF_INET6) + state= NULL; + + if (state) + { + if ((etcp && !state->do_tcp) || + (eudp && !state->do_udp) || + (eicmp && !state->do_icmp)) + { + state= NULL; + } + } + + if (!state) + { + /* Nothing here */ + return; + } + +#if 0 + printf("ready_callback6: from %s", + inet_ntop(AF_INET6, &remote.sin6_addr, + buf, sizeof(buf))); + printf(" for %s hop %d\n", + inet_ntop(AF_INET6, &state->sin6.sin6_addr, + buf, sizeof(buf)), state->hop); +#endif + + if (!state->busy) + { +printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family); + printf( + "ready_callback6: index (%d) is not busy\n", + ind); + return; + } + + late= 0; + isDup= 0; + if (etcp) + { + /* Sequence number is in seq field */ + seq= ntohl(etcp->seq) & 0xffff; + } + else + seq= ntohl(v6info->seq); + + if (state->open_result) + add_str(state, " }, { "); + + 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; + + snprintf(line, sizeof(line), DBQ(late) ":%d", + state->seq-seq); + add_str(state, line); + } else if (state->gotresp) + { + isDup= 1; + add_str(state, DBQ(dup) ":true"); + } + + if (!late && !isDup) + state->last_response_hop= state->hop; + + if (memcmp(&eip->ip6_src, + &state->loc_sin6.sin6_addr, + sizeof(eip->ip6_src)) != 0) + { + printf("ready_callback6: changed source %s\n", + inet_ntop(AF_INET6, &eip->ip6_src, + buf, sizeof(buf))); + } + if (memcmp(&eip->ip6_dst, + &state->sin6.sin6_addr, + sizeof(eip->ip6_dst)) != 0) + { + printf( + "ready_callback6: changed destination %s for %s\n", + inet_ntop(AF_INET6, &eip->ip6_dst, + buf, sizeof(buf)), + state->hostname); + } + if (memcmp(&dstaddr, + &state->loc_sin6.sin6_addr, + sizeof(dstaddr)) != 0) + { + printf("ready_callback6: weird destination %s\n", + inet_ntop(AF_INET6, &dstaddr, + buf, sizeof(buf))); + } + + if (eicmp && state->parismod && + ntohs(eicmp->icmp6_cksum) != + state->paris % state->parismod + 1) + { + printf( + "ready_callback6: got checksum 0x%x, expected 0x%x\n", + ntohs(eicmp->icmp6_cksum), + state->paris % state->parismod + 1); + } + + if (!late) + { + ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + + (now.tv_usec-state->xmit_time.tv_usec)/ + 1e3; + } + else if (v6info) + { + ms= (now.tv_sec-v6info->tv.tv_sec)*1000 + + (now.tv_usec-v6info->tv.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, \"rtt\":%.3f, \"size\":%d", + rcvdttl, ms, (int)(nrecv-ICMP6_HDR)); + add_str(state, line); + if (eip->ip6_hops != 1) + { + snprintf(line, sizeof(line), ", \"ittl\":%d", + eip->ip6_hops); + add_str(state, line); + } + if (hbhoptsize) + { + snprintf(line, sizeof(line), + ", \"hbhoptsize\":%d", hbhoptsize); + add_str(state, line); + } + if (dstoptsize) + { + snprintf(line, sizeof(line), + ", \"dstoptsize\":%d", dstoptsize); + add_str(state, line); + } + +#if 0 + printf("ready_callback6: from %s, ttl %d", + inet_ntop(AF_INET6, &remote.sin6_addr, buf, + sizeof(buf)), rcvdttl); + printf(" for %s hop %d\n", + inet_ntop(AF_INET6, &state->sin6.sin6_addr, buf, + sizeof(buf)), state->hop); +#endif + + if (icmp->icmp6_type == ICMP6_TIME_EXCEEDED) + { + if (!late && !isDup) + state->not_done= 1; + } + else if (icmp->icmp6_type == ICMP6_PACKET_TOO_BIG) + { + nextmtu= ntohl(icmp->icmp6_mtu); + snprintf(line, sizeof(line), ", \"mtu\":%d", + nextmtu); + add_str(state, line); + siz= sizeof(*eip); + if (eudp) + siz += sizeof(*eudp); + else if (eicmp) + siz += sizeof(*eicmp); + else if (etcp) + siz += sizeof(*etcp); + if (nextmtu < 1200) + { + /* This is IPv6, no need to go + * below 1280. Use 1200 to deal with + * off by one error or weird tunnels. + */ + nextmtu= 1200; + } + if (!late && nextmtu >= siz) + { + nextmtu -= siz; + if (nextmtu < state->curpacksize) + state->curpacksize= nextmtu; + } + if (!late) + state->not_done= 1; + } + else if (icmp->icmp6_type == ICMP6_DST_UNREACH) + { + if (!late) + state->done= 1; + switch(icmp->icmp6_code) + { + case ICMP6_DST_UNREACH_NOROUTE: /* 0 */ + add_str(state, ", \"err\":\"N\""); + break; + case ICMP6_DST_UNREACH_ADMIN: /* 1 */ + add_str(state, ", \"err\":\"A\""); + break; + case ICMP6_DST_UNREACH_BEYONDSCOPE: /* 2 */ + add_str(state, ", \"err\":\"h\""); + break; + case ICMP6_DST_UNREACH_ADDR: /* 3 */ + add_str(state, ", \"err\":\"H\""); + break; + case ICMP6_DST_UNREACH_NOPORT: /* 4 */ + break; + default: + snprintf(line, sizeof(line), + ", \"err\":%d", + icmp->icmp6_code); + add_str(state, line); + break; + } + } + } + else + { + printf( + "ready_callback6: not UDP or ICMP (ip6_nxt = %d)\n", + eip->ip6_nxt); + return; + } + + /* RFC-4884, Multi-Part ICMP messages */ + icmp_prefixlen= icmp->icmp6_data8[0] * 8; + if (icmp_prefixlen != 0) + { + + printf("icmp6_data8[0]: 0x%x for %s\n", icmp->icmp6_data8[0], state->hostname); + printf("icmp_prefixlen: 0x%x for %s\n", icmp_prefixlen, inet_ntop(AF_INET6, &state->sin6.sin6_addr, buf, sizeof(buf))); + offset= sizeof(*icmp) + icmp_prefixlen; + if (nrecv > offset) + { + do_icmp_multi(state, base->packet+offset, + nrecv-offset, 0 /*!pre_rfc4884*/); + } + else + { +#if 0 + printf( + "ready_callback6: too short %d (Multi-Part ICMP)\n", + (int)nrecv); +#endif + } + } + else if (nrecv > 128) + { + /* Try old style extensions */ + icmp_prefixlen= 128; + offset= sizeof(*icmp) + icmp_prefixlen; + if (nrecv > offset) + { + do_icmp_multi(state, base->packet+offset, + nrecv-offset, 1 /*pre_rfc4884*/); + } + else + { + printf( + "ready_callback6: too short %d (Multi-Part ICMP)\n", + (int)nrecv); + } + } + + state->open_result= 1; + + 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); + } + } + else if (icmp->icmp6_type == ICMP6_ECHO_REPLY) + { + eip= NULL; + + /* Now check if there is also a header in the packet */ + if (nrecv < sizeof(*icmp) + sizeof(*v6info)) + { +#if 0 + printf("ready_callback6: too short %d (echo reply)\n", + (int)nrecv); +#endif + return; + } + + eudp= NULL; + eicmp= NULL; + + v6info= (struct v6info *)&icmp[1]; + + if (ntohl(v6info->pid) != base->my_pid) + { + /* From a different process */ + return; + } + + ind= ntohl(v6info->id); + + if (ind != state->index) + state= NULL; + if (state && state->sin6.sin6_family != AF_INET6) + state= NULL; + + if (state && !state->do_icmp) + { + state= NULL; + } + + if (!state) + { + /* Nothing here */ + return; + } + +#if 0 + printf("ready_callback6: from %s", + inet_ntop(AF_INET6, &remote.sin6_addr, + buf, sizeof(buf))); + printf(" for %s hop %d\n", + inet_ntop(AF_INET6, &state->sin6.sin6_addr, + buf, sizeof(buf)), state->hop); +#endif + + if (!state->busy) + { +printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family); + printf( + "ready_callback6: index (%d) is not busy\n", + ind); + return; + } + + if (state->open_result) + add_str(state, " }, { "); + + late= 0; + isDup= 0; + seq= ntohl(v6info->seq); + if (seq != state->seq) + { + if (seq > state->seq) + { + printf( +"ready_callback6: mismatch for seq, got 0x%x, expected 0x%x\n", + ntohl(v6info->seq), + state->seq); + return; + } + late= 1; + + snprintf(line, sizeof(line), DBQ(late) ":%d", + state->seq-seq); + add_str(state, line); + } + else if (state->gotresp) + { + isDup= 1; + add_str(state, DBQ(dup) ":true"); + } + + state->done= 1; + + if (memcmp(&dstaddr, &state->loc_sin6.sin6_addr, + sizeof(dstaddr)) != 0) + { + printf("ready_callback6: weird destination %s\n", + inet_ntop(AF_INET6, &dstaddr, + buf, sizeof(buf))); + } + + if (!late) + { + ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + + (now.tv_usec-state->xmit_time.tv_usec)/ + 1e3; + } + else + { + ms= (now.tv_sec-v6info->tv.tv_sec)*1000 + + (now.tv_usec-v6info->tv.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, \"rtt\":%.3f, \"size\":%d", + rcvdttl, ms, (int)(nrecv - ICMP6_HDR)); + add_str(state, line); + +#if 0 + printf("ready_callback6: from %s, ttl %d", + inet_ntop(AF_INET6, &remote.sin6_addr, buf, + sizeof(buf)), rcvdttl); + printf(" for %s hop %d\n", + inet_ntop(AF_INET6, &state->sin6.sin6_addr, buf, + sizeof(buf)), state->hop); +#endif + + state->open_result= 1; + + send_pkt(state); + } + else if (icmp->icmp6_type == ICMP6_ECHO_REQUEST /* 128 */ || + icmp->icmp6_type == MLD_LISTENER_QUERY /* 130 */ || + icmp->icmp6_type == MLD_LISTENER_REPORT /* 131 */ || + icmp->icmp6_type == ND_ROUTER_ADVERT /* 134 */ || + icmp->icmp6_type == ND_NEIGHBOR_SOLICIT /* 135 */ || + icmp->icmp6_type == ND_NEIGHBOR_ADVERT /* 136 */ || + icmp->icmp6_type == ND_REDIRECT /* 137 */) + { + /* No need to do anything */ + } + else + { + printf("ready_callback6: got type %d\n", icmp->icmp6_type); + return; + } +#endif +} +#endif + +static struct ntpbase *ntp_base_new(struct event_base + *event_base) +{ + struct ntpbase *base; + + base= xzalloc(sizeof(*base)); + + base->event_base= event_base; + + base->tabsiz= 10; + base->table= xzalloc(base->tabsiz * sizeof(*base->table)); + + base->my_pid= getpid(); + + return base; +} + +static void noreply_callback(int __attribute((unused)) unused, + const short __attribute((unused)) event, void *s) +{ + struct ntpstate *state; + + state= s; + +#if 0 + printf("noreply_callback: gotresp = %d\n", + state->gotresp); +#endif + + if (!state->gotresp) + { + if (state->open_result) + add_str(state, " }, { "); + add_str(state, DBQ(x) ":" DBQ(*)); + state->open_result= 1; + } + + send_pkt(state); +} + +static void *ntp_init(int __attribute((unused)) argc, char *argv[], + void (*done)(void *state)) +{ + uint32_t opt; + int i, do_v6; + unsigned count, timeout; + /* must be int-sized */ + size_t newsiz; + char *str_Atlas; + const char *hostname; + char *out_filename; + const char *destportstr; + char *interface; + struct ntpstate *state; + FILE *fh; + + if (!ntp_base) + { + ntp_base= ntp_base_new(EventBase); + if (!ntp_base) + crondlog(DIE9 "ntp_base_new failed"); + } + + /* Parse arguments */ + count= 3; + interface= NULL; + timeout= 1000; + str_Atlas= NULL; + out_filename= NULL; + opt_complementary = "=1:4--6:i--u:c+:w+:"; + + opt = getopt32(argv, NTP_OPT_STRING, &count, + &interface, &timeout, &str_Atlas, &out_filename); + hostname = argv[optind]; + + if (opt == 0xffffffff) + { + crondlog(LVL8 "bad options"); + return NULL; + } + + do_v6= !!(opt & OPT_6); + + if (out_filename) + { + if (!validate_filename(out_filename, SAFE_PREFIX)) + { + crondlog(LVL8 "insecure file '%s'", out_filename); + return NULL; + } + fh= fopen(out_filename, "a"); + if (!fh) + { + crondlog(LVL8 "unable to append to '%s'", + out_filename); + return NULL; + } + fclose(fh); + } + + if (str_Atlas) + { + if (!validate_atlas_id(str_Atlas)) + { + crondlog(LVL8 "bad atlas ID '%s'", str_Atlas); + return NULL; + } + } + + destportstr= "123"; + + state= xzalloc(sizeof(*state)); + state->count= count; + state->interface= interface; + state->destportstr= strdup(destportstr); + state->timeout= timeout*1000; + state->atlas= str_Atlas ? strdup(str_Atlas) : NULL; + state->hostname= strdup(hostname); + state->do_v6= do_v6; + state->out_filename= out_filename ? strdup(out_filename) : NULL; + state->base= ntp_base; + state->busy= 0; + state->result= NULL; + state->reslen= 0; + state->resmax= 0; + + for (i= 0; itabsiz; i++) + { + if (ntp_base->table[i] == NULL) + break; + } + if (i >= ntp_base->tabsiz) + { + newsiz= 2*ntp_base->tabsiz; + ntp_base->table= xrealloc(ntp_base->table, + newsiz*sizeof(*ntp_base->table)); + for (i= ntp_base->tabsiz; itable[i]= NULL; + i= ntp_base->tabsiz; + ntp_base->tabsiz= newsiz; + } + state->index= i; + ntp_base->table[i]= state; + ntp_base->done= done; + + memset(&state->loc_sin6, '\0', sizeof(state->loc_sin6)); + state->loc_socklen= 0; + + evtimer_assign(&state->timer, state->base->event_base, + noreply_callback, state); + + return state; +} + +static void traceroute_start2(void *state) +{ + struct ntpstate *ntpstate; + + ntpstate= state; + + if (ntpstate->busy) + { + printf("ntp_start: busy, can't start\n"); + return; + } + ntpstate->busy= 1; + + ntpstate->min= ULONG_MAX; + ntpstate->max= 0; + ntpstate->sum= 0; + ntpstate->sentpkts= 0; + ntpstate->rcvdpkts= 0; + ntpstate->duppkts= 0; + + ntpstate->sent= 0; + ntpstate->seq= 0; + ntpstate->first= 1; + ntpstate->done= 0; + ntpstate->not_done= 0; + + if (ntpstate->result) free(ntpstate->result); + ntpstate->resmax= 80; + ntpstate->result= xmalloc(ntpstate->resmax); + ntpstate->reslen= 0; + ntpstate->open_result= 0; + ntpstate->starttime= time(NULL); + + ntpstate->socket= -1; + + if (create_socket(ntpstate) == -1) + return; + if (ntpstate->do_v6) + { + ntpstate->loc_sin6.sin6_port= htons(SRC_BASE_PORT + + ntpstate->index); + } + else + { + ((struct sockaddr_in *)(&ntpstate->loc_sin6))-> + sin_port= htons(SRC_BASE_PORT + + ntpstate->index); + } + + send_pkt(ntpstate); +} + +static int create_socket(struct ntpstate *state) +{ + int af, type, protocol; + int r, serrno; + char line[80]; + + af= (state->do_v6 ? AF_INET6 : AF_INET); + type= SOCK_DGRAM; + protocol= 0; + + state->socket= xsocket(af, type, protocol); + if (state->socket == -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, + 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, + (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(state, line); + report(state); + return -1; + } + state->loc_socklen= sizeof(state->loc_sin6); + if (getsockname(state->socket, + &state->loc_sin6, + &state->loc_socklen) == -1) + { + crondlog(DIE9 "getsockname failed"); + } +#if 0 + printf("Got localname: %s\n", + inet_ntop(AF_INET6, + &state->loc_sin6.sin6_addr, + buf, sizeof(buf))); +#endif + + + event_assign(&state->event_socket, state->base->event_base, + state->socket, + EV_READ | EV_PERSIST, + (af == AF_INET6 ? ready_callback : ready_callback), + state); + event_add(&state->event_socket, NULL); + + return 0; +} + +static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) +{ + int count; + struct ntpstate *env; + struct evutil_addrinfo *cur; + char line[160]; + + env= ctx; + + if (!env->dnsip) + { + crondlog(LVL7 + "dns_cb: in dns_cb but not doing dns at this time"); + if (res) + evutil_freeaddrinfo(res); + return; + } + + if (result != 0) + { + /* Hmm, great. Where do we put this init code */ + if (env->result) free(env->result); + env->resmax= 80; + env->result= xmalloc(env->resmax); + env->reslen= 0; + + env->starttime= time(NULL); + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(name resolution failed: %s) " }", + evutil_gai_strerror(result)); + add_str(env, line); + report(env); + return; + } + + env->dnsip= 0; + + env->dns_res= res; + env->dns_curr= res; + + count= 0; + for (cur= res; cur; cur= cur->ai_next) + count++; + + // env->reportcount(env, count); + + while (env->dns_curr) + { + env->socklen= env->dns_curr->ai_addrlen; + if (env->socklen > sizeof(env->sin6)) + continue; /* Weird */ + memcpy(&env->sin6, env->dns_curr->ai_addr, + env->socklen); + + traceroute_start2(env); + + evutil_freeaddrinfo(env->dns_res); + env->dns_res= NULL; + env->dns_curr= NULL; + return; + } + + /* Something went wrong */ + evutil_freeaddrinfo(env->dns_res); + env->dns_res= NULL; + env->dns_curr= NULL; + snprintf(line, sizeof(line), +"%s{ " DBQ(error) ":" DBQ(name resolution failed: out of addresses) " } ] }", + env->sent ? " }, " : ""); + add_str(env, line); + report(env); +} + +static void ntp_start(void *state) +{ + struct ntpstate *ntpstate; + struct evutil_addrinfo hints; + + ntpstate= state; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_socktype= SOCK_DGRAM; + hints.ai_family= ntpstate->do_v6 ? AF_INET6 : AF_INET; + ntpstate->dnsip= 1; + (void) evdns_getaddrinfo(DnsBase, ntpstate->hostname, + ntpstate->destportstr, &hints, dns_cb, ntpstate); +} + +static int ntp_delete(void *state) +{ + int ind; + struct ntpstate *ntpstate; + struct ntpbase *base; + + ntpstate= state; + + printf("ntp_delete: state %p, index %d, busy %d\n", + state, ntpstate->index, ntpstate->busy); + + if (ntpstate->busy) + return 0; + + base= ntpstate->base; + ind= ntpstate->index; + + if (base->table[ind] != ntpstate) + crondlog(DIE9 "strange, state not in table"); + base->table[ind]= NULL; + + event_del(&ntpstate->timer); + + free(ntpstate->atlas); + ntpstate->atlas= NULL; + free(ntpstate->hostname); + ntpstate->hostname= NULL; + free(ntpstate->destportstr); + ntpstate->destportstr= NULL; + free(ntpstate->out_filename); + ntpstate->out_filename= NULL; + + free(ntpstate); + + return 1; +} + +struct testops ntp_ops = { ntp_init, ntp_start, ntp_delete }; + diff --git a/eperd/ping.c b/eperd/ping.c index 4d17317..834b9dc 100644 --- a/eperd/ping.c +++ b/eperd/ping.c @@ -66,6 +66,12 @@ enum /* Definition for various types of counters */ typedef uint64_t counter_t; +/* For matching up requests and replies. Assume that 64 bits is enough */ +struct cookie +{ + uint8_t data[8]; +}; + /* How to keep track of a PING session */ struct pingbase { @@ -116,6 +122,7 @@ struct pingstate size_t resmax; struct pingbase *base; + struct cookie cookie; sa_family_t af; /* Desired address family */ struct evutil_addrinfo *dns_res; @@ -153,6 +160,7 @@ struct pingstate struct evdata { struct timeval ts; uint32_t index; + struct cookie cookie; }; @@ -209,13 +217,15 @@ static void report(struct pingstate *state) fprintf(fh, DBQ(dst_name) ":" DBQ(%s), state->hostname); + fprintf(fh, ", " DBQ(af) ":%d", + state->af == AF_INET ? 4 : 6); + if (!state->no_dst) { getnameinfo((struct sockaddr *)&state->sin6, state->socklen, namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); - fprintf(fh, ", " DBQ(dst_addr) ":" DBQ(%s) ", " DBQ(af) ":%d", - namebuf, state->sin6.sin6_family == AF_INET6 ? 6 : 4); + fprintf(fh, ", " DBQ(dst_addr) ":" DBQ(%s), namebuf); } if (state->got_reply) @@ -302,7 +312,6 @@ static void ping_cb(int result, int bytes, int psize, "%s{ ", pingstate->first ? "" : ", "); add_str(pingstate, line); pingstate->first= 0; - pingstate->no_dst= 0; if (result == PING_ERR_DUP) { add_str(pingstate, DBQ(dup) ":1, "); @@ -373,7 +382,6 @@ static void ping_cb(int result, int bytes, int psize, "%s{ " DBQ(x) ":" DBQ(*), pingstate->first ? "" : ", "); add_str(pingstate, line); - pingstate->no_dst= 0; } if (result == PING_ERR_SENDTO) { @@ -381,7 +389,6 @@ static void ping_cb(int result, int bytes, int psize, "%s{ " DBQ(error) ":" DBQ(sendto failed: %s), pingstate->first ? "" : ", ", strerror(seq)); add_str(pingstate, line); - pingstate->no_dst= 0; } if (result == PING_ERR_TIMEOUT || result == PING_ERR_SENDTO) { @@ -463,7 +470,7 @@ static int mkcksum(u_short *p, int n) * ho hosts being monitored */ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq, - uint32_t idx, pid_t pid) + uint32_t idx, pid_t pid, struct cookie *cookiep) { size_t minlen; struct icmp *icmp = (struct icmp *) buffer; @@ -477,8 +484,7 @@ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq, if (*sizep > MAX_DATA_SIZE - ICMP_MINLEN) *sizep= MAX_DATA_SIZE - ICMP_MINLEN; - if (*sizep > minlen) - memset(buffer+minlen, '\0', *sizep-minlen); + memset(buffer, '\0', *sizep + ICMP_MINLEN); /* The ICMP header (no checksum here until user data has been filled in) */ icmp->icmp_type = ICMP_ECHO; /* type of message */ @@ -490,6 +496,7 @@ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq, gettimeofday(&now, NULL); data->ts = now; /* current time */ data->index = idx; /* index into an array */ + data->cookie= *cookiep; /* Last, compute ICMP checksum */ icmp->icmp_cksum = 0; @@ -513,7 +520,7 @@ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq, * ho hosts being monitored */ static void fmticmp6(u_char *buffer, size_t *sizep, - u_int8_t seq, uint32_t idx, pid_t pid) + u_int8_t seq, uint32_t idx, pid_t pid, struct cookie *cookiep) { size_t minlen; struct icmp6_hdr *icmp = (struct icmp6_hdr *) buffer; @@ -527,8 +534,7 @@ static void fmticmp6(u_char *buffer, size_t *sizep, if (*sizep > MAX_DATA_SIZE - ICMP6_HDRSIZE) *sizep= MAX_DATA_SIZE - ICMP6_HDRSIZE; - if (*sizep > minlen) - memset(buffer+minlen, '\0', *sizep-minlen); + memset(buffer, '\0', *sizep+ICMP6_HDRSIZE); /* The ICMP header (no checksum here until user data has been filled in) */ icmp->icmp6_type = ICMP6_ECHO_REQUEST; /* type of message */ @@ -540,6 +546,7 @@ static void fmticmp6(u_char *buffer, size_t *sizep, gettimeofday(&now, NULL); data->ts = now; /* current time */ data->index = idx; /* index into an array */ + data->cookie= *cookiep; icmp->icmp6_cksum = 0; } @@ -577,7 +584,7 @@ static void ping_xmit(struct pingstate *host) { /* Format the ICMP Echo Reply packet to send */ fmticmp6(base->packet, &host->cursize, host->seq, host->index, - base->pid); + base->pid, &host->cookie); host->loc_socklen= sizeof(host->loc_sin6); getsockname(host->socket, &host->loc_sin6, &host->loc_socklen); @@ -592,7 +599,7 @@ static void ping_xmit(struct pingstate *host) { /* Format the ICMP Echo Reply packet to send */ fmticmp4(base->packet, &host->cursize, host->seq, host->index, - base->pid); + base->pid, &host->cookie); host->loc_socklen= sizeof(host->loc_sin6); getsockname(host->socket, &host->loc_sin6, &host->loc_socklen); @@ -735,6 +742,13 @@ printf("ready_callback4: too short\n"); if (state != base->table[data->index]) goto done; /* Not for us */ + /* Make sure we got the right cookie */ + if (memcmp(&state->cookie, &data->cookie, sizeof(state->cookie)) != 0) + { + crondlog(LVL8 "ICMP with wrong cookie"); + goto done; + } + /* Check for Destination Host Unreachable */ if (icmp->type == ICMP_ECHO) { @@ -802,7 +816,7 @@ static void ready_callback6 (int __attribute((unused)) unused, struct pingstate *state; int nrecv, isDup; - struct sockaddr_in remote; /* responding internet address */ + struct sockaddr_in6 remote; /* responding internet address */ struct icmp6_hdr *icmp; struct evdata * data; @@ -862,6 +876,13 @@ static void ready_callback6 (int __attribute((unused)) unused, if (state != base->table[data->index]) goto done; /* Not for us */ + /* Make sure we got the right cookie */ + if (memcmp(&state->cookie, &data->cookie, sizeof(state->cookie)) != 0) + { + crondlog(LVL8 "ICMP with wrong cookie"); + goto done; + } + /* Check for Destination Host Unreachable */ if (icmp->icmp6_type == ICMP6_ECHO_REPLY) { @@ -925,7 +946,7 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], { static struct pingbase *ping_base; - int i, newsiz, delay_name_res; + int i, r, fd, newsiz, delay_name_res; uint32_t opt; unsigned pingcount; /* must be int-sized */ unsigned size, interval; @@ -937,6 +958,7 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], struct pingstate *state; len_and_sockaddr *lsa; FILE *fh; + struct cookie cookie; if (!ping_base) { @@ -957,6 +979,21 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], ping_base->done= 0; } + /* Get cookie */ + fd= open("/dev/urandom", O_RDONLY); + if (fd == -1) + { + crondlog(LVL8 "unable to open /dev/urandom"); + return NULL; + } + r= read(fd, &cookie, sizeof(cookie)); + close(fd); + if (r != sizeof(cookie)) + { + crondlog(LVL8 "unable to read from /dev/urandom"); + return NULL; + } + /* Parse arguments */ pingcount= 3; size= 0; @@ -1080,6 +1117,7 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], state->result= NULL; state->reslen= 0; state->resmax= 0; + state->cookie= cookie; state->maxsize = size; state->base->done= done; @@ -1100,6 +1138,7 @@ static void ping_start2(void *state) pingstate->send_error= 0; pingstate->got_reply= 0; + pingstate->no_dst= 0; if (pingstate->af == AF_INET) { diff --git a/eperd/traceroute.c b/eperd/traceroute.c index a3d0f24..ee0489b 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:i:m:p:w:z:A:O:S:H:D:") +#define TRACEROUTE_OPT_STRING ("!46IUFrTa:b:c:f:g:i:m:p:w:z:A:O:S:H:D:") #define OPT_4 (1 << 0) #define OPT_6 (1 << 1) @@ -99,6 +99,7 @@ struct trtstate unsigned char maxhops; unsigned char gaplimit; unsigned char parismod; + unsigned char parisbase; unsigned duptimeout; unsigned timeout; @@ -426,8 +427,7 @@ static void report(struct trtstate *state) fprintf(fh, ", \"size\":%d", state->maxpacksize); if (state->parismod) { - fprintf(fh, ", \"paris_id\":%d", - state->paris % state->parismod); + fprintf(fh, ", \"paris_id\":%d", state->paris); } fprintf(fh, ", \"result\": [ %s ] }\n", state->result); @@ -703,7 +703,7 @@ static void send_pkt(struct trtstate *state) (unsigned short *)base->packet, len); /* Avoid 0 */ - val= state->paris % state->parismod + 1; + val= state->paris + 1; sum= ntohs(sum); usum= sum + (0xffff - val); @@ -795,7 +795,7 @@ static void send_pkt(struct trtstate *state) if (state->parismod) { state->sin6.sin6_port= htons(BASE_PORT + - (state->paris % state->parismod)); + state->paris); } else { @@ -1135,8 +1135,7 @@ static void send_pkt(struct trtstate *state) if (state->parismod) { ((struct sockaddr_in *)&state->sin6)->sin_port= - htons(BASE_PORT + - (state->paris % state->parismod)); + htons(BASE_PORT + state->paris); } else { @@ -1299,9 +1298,13 @@ static void do_icmp_multi(struct trtstate *state, cksum= in_cksum((unsigned short *)packet, size); if (cksum != 0) { - /* There is also anoption for a zero checksum. */ + /* There is also an option for a zero checksum. */ if (!pre_rfc4884) + { +#if 0 printf("do_icmp_multi: bad checksum\n"); +#endif + } return; } @@ -1329,7 +1332,9 @@ static void do_icmp_multi(struct trtstate *state, if (len < 4 || o+len > size) { add_str(state, " }"); +#if 0 printf("do_icmp_multi: bad len %d\n", len); +#endif break; } if (class == ICMPEXT_MPLS && ctype == ICMPEXT_MPLS_IN) @@ -1421,8 +1426,10 @@ static void ready_callback4(int __attribute((unused)) unused, if (srcport < SRC_BASE_PORT || srcport > SRC_BASE_PORT+256) { +#if 0 printf( "ready_callback4: unknown TCP port in ICMP: %d\n", srcport); +#endif return; /* Not for us */ } @@ -1865,9 +1872,11 @@ printf("curpacksize: %d\n", state->curpacksize); if (ind != state->index) { /* Nothing here */ +#if 0 printf( "ready_callback4: nothing at index (%d)\n", ind); +#endif return; } @@ -1898,8 +1907,8 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family { printf( "ready_callback4: mismatch for paris, got 0x%x, expected 0x%x (%s)\n", - ntohs(eicmp->icmp_cksum), state->paris, - state->hostname); + ntohs(eicmp->icmp_cksum), + state->paris, state->hostname); } if (state->open_result) @@ -2064,8 +2073,10 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family if (icmp_prefixlen != 0) { +#if 0 printf("icmp_pmvoid: 0x%x for %s\n", icmp->icmp_pmvoid, state->hostname); printf("icmp_prefixlen: 0x%x for %s\n", icmp_prefixlen, inet_ntoa(remote.sin_addr)); +#endif offset= hlen + ICMP_MINLEN + icmp_prefixlen; if (nrecv > offset) { @@ -2074,9 +2085,11 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } else { +#if 0 printf( "ready_callback4: too short %d (Multi-Part ICMP)\n", (int)nrecv); +#endif } } else if (nrecv > hlen + ICMP_MINLEN + 128) @@ -2136,9 +2149,11 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family if (ind != state->index) { /* Nothing here */ +#if 0 printf( "ready_callback4: nothing at index (%d)\n", ind); +#endif return; } @@ -2976,12 +2991,12 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family if (eicmp && state->parismod && ntohs(eicmp->icmp6_cksum) != - state->paris % state->parismod + 1) + state->paris + 1) { printf( "ready_callback6: got checksum 0x%x, expected 0x%x\n", ntohs(eicmp->icmp6_cksum), - state->paris % state->parismod + 1); + state->paris + 1); } if (!late) @@ -3375,7 +3390,7 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], uint32_t opt; int i, do_icmp, do_v6, dont_fragment, delay_name_res, do_tcp, do_udp; unsigned count, duptimeout, firsthop, gaplimit, maxhops, maxpacksize, - hbhoptsize, destoptsize, parismod, timeout; + hbhoptsize, destoptsize, parismod, parisbase, timeout; /* must be int-sized */ size_t newsiz; char *str_Atlas; @@ -3407,16 +3422,18 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[], duptimeout= 10; timeout= 1000; parismod= 16; + parisbase= 0; 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+"; + opt_complementary = "=1:4--6:i--u:a+:b+:c+:f+:g+:m+:w+:z+:S+:H+:D+"; for (i= 0; argv[i] != NULL; i++) printf("argv[%d] = '%s'\n", i, argv[i]); - opt = getopt32(argv, TRACEROUTE_OPT_STRING, &parismod, &count, + opt = getopt32(argv, TRACEROUTE_OPT_STRING, &parismod, &parisbase, + &count, &firsthop, &gaplimit, &interface, &maxhops, &destportstr, &timeout, &duptimeout, &str_Atlas, &out_filename, &maxpacksize, @@ -3490,6 +3507,7 @@ for (i= 0; argv[i] != NULL; i++) state= xzalloc(sizeof(*state)); state->parismod= parismod; + state->parisbase= parisbase; state->trtcount= count; state->firsthop= firsthop; state->maxpacksize= maxpacksize; @@ -3511,6 +3529,7 @@ for (i= 0; argv[i] != NULL; i++) state->destoptsize= destoptsize; state->out_filename= out_filename ? strdup(out_filename) : NULL; state->base= trt_base; + state->paris= 0; state->busy= 0; state->result= NULL; state->reslen= 0; @@ -3583,7 +3602,11 @@ static void traceroute_start2(void *state) trtstate->hop= trtstate->firsthop; trtstate->sent= 0; trtstate->seq= 0; - trtstate->paris++; + if (trtstate->parismod) + { + trtstate->paris= (trtstate->paris-trtstate->parisbase+1) % + trtstate->parismod + trtstate->parisbase; + } trtstate->last_response_hop= 0; /* Should be starting hop */ trtstate->done= 0; trtstate->not_done= 0; diff --git a/include/applets.h b/include/applets.h index 829ba14..4e6a702 100644 --- a/include/applets.h +++ b/include/applets.h @@ -148,6 +148,7 @@ USE_EOOQD(APPLET(eooqd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_EPERD(APPLET(eperd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ether_wake)) USE_EVHTTPGET(APPLET(evhttpget, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) +USE_EVNTP(APPLET(evntp, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_EVPING(APPLET(evping, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_EVSSLGETCERT(APPLET(evsslgetcert, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_EVTDIG(APPLET(evtdig, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) diff --git a/include/usage.h b/include/usage.h index c4953bc..1a386b9 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1043,6 +1043,12 @@ "\n -4 Only IPv4 addresses" \ "\n -6 Only IPv6 addresses" \ +#define evntp_trivial_usage \ + "todo" + +#define evntp_full_usage \ + "todo" + #define evping_trivial_usage \ "todo" #define evping_full_usage "\n\n" \ -- cgit v1.2.3