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