aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2015-05-15 10:25:25 +0200
committerBjørn Mork <bjorn@mork.no>2015-05-15 10:25:25 +0200
commit73e699faf130d0fc0f2f076d95db9dbd7f42a8b6 (patch)
tree6f0e62ed18a2791e66525b9efb6430e851ba76d8
parentb8c5c3b44362778c099531f7a905c56a0423bcef (diff)
ripe-atlas-fw: imported version 46604660
Signed-off-by: Bjørn Mork <bjorn@mork.no>
-rw-r--r--.config3
-rw-r--r--eperd/Config.in6
-rw-r--r--eperd/Kbuild2
-rw-r--r--eperd/eooqd.c8
-rw-r--r--eperd/eperd.c1
-rw-r--r--eperd/eperd.h1
-rw-r--r--eperd/evntp.c57
-rw-r--r--eperd/evtdig.c2
-rw-r--r--eperd/ntp.c1955
-rw-r--r--eperd/ping.c69
-rw-r--r--eperd/traceroute.c55
-rw-r--r--include/applets.h1
-rw-r--r--include/usage.h6
13 files changed, 2133 insertions, 33 deletions
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 <atlas@ripe.net>
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Standalone version of the event-based ntp.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+#include <event2/dns.h>
+#include <event2/event.h>
+#include <event2/event_struct.h>
+
+#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 <atlas@ripe.net>
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * traceroute.c
+ */
+
+#include "libbb.h"
+#include <event2/dns.h>
+#include <event2/event.h>
+#include <event2/event_struct.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#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; i<ntp_base->tabsiz; 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; i<newsiz; i++)
+ ntp_base->table[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" \