aboutsummaryrefslogtreecommitdiff
path: root/eperd/traceroute.c
diff options
context:
space:
mode:
Diffstat (limited to 'eperd/traceroute.c')
-rw-r--r--eperd/traceroute.c674
1 files changed, 344 insertions, 330 deletions
diff --git a/eperd/traceroute.c b/eperd/traceroute.c
index d655e44..a3d0f24 100644
--- a/eperd/traceroute.c
+++ b/eperd/traceroute.c
@@ -28,7 +28,7 @@
#define uh_sum check
#endif
-#define TRACEROUTE_OPT_STRING ("!46IUFrTa:c:f:g:m:p:w:z:A:O:S:H:D:")
+#define TRACEROUTE_OPT_STRING ("!46IUFrTa:c:f:g:i:m:p:w:z:A:O:S:H:D:")
#define OPT_4 (1 << 0)
#define OPT_6 (1 << 1)
@@ -63,21 +63,8 @@ struct trtbase
{
struct event_base *event_base;
- int v4icmp_rcv;
- int v6icmp_rcv;
- int v4icmp_snd;
- int v6icmp_snd;
- int v4tcp_rcv;
- int v6tcp_rcv;
- int v4udp_snd;
-
int my_pid;
- struct event event4;
- struct event tcp_event4;
- struct event event6;
- struct event tcp_event6;
-
struct trtstate **table;
int tabsiz;
@@ -95,9 +82,10 @@ struct trtstate
/* Parameters */
char *atlas;
char *hostname;
- const char *destportstr;
+ char *destportstr;
char *out_filename;
- char do_Xicmp;
+ char *interface;
+ char do_icmp;
char do_tcp;
char do_udp;
char do_v6;
@@ -128,6 +116,13 @@ struct trtstate
uint16_t paris;
uint16_t seq;
unsigned short curpacksize;
+
+ int socket_icmp; /* Socket for sending and receiving
+ * ICMPs */
+ struct event event_icmp; /* Event for this socket */
+ int socket_tcp; /* Socket for sending and receiving
+ * raw TCP */
+ struct event event_tcp; /* Event for this socket */
uint8_t last_response_hop; /* Hop at which we last got something
* back.
@@ -160,6 +155,7 @@ struct trtstate
char *result;
size_t reslen;
size_t resmax;
+ char open_result;
};
static struct trtbase *trt_base;
@@ -191,6 +187,8 @@ struct v6info
struct timeval tv;
};
+static int create_socket(struct trtstate *state, int do_tcp);
+
#define OPT_PAD1 0
#define OPT_PADN 1
static void do_hbh_dest_opt(struct trtbase *base, int sock, int hbh_dest,
@@ -387,9 +385,11 @@ static void report(struct trtstate *state)
{
fprintf(fh, DBQ(id) ":" DBQ(%s)
", " DBQ(fw) ":%d"
+ ", " DBQ(lts) ":%d"
", " DBQ(time) ":%ld"
", " DBQ(endtime) ":%ld, ",
state->atlas, get_atlas_fw_version(),
+ get_timesync(),
state->starttime,
(long)time(NULL));
}
@@ -412,7 +412,7 @@ static void report(struct trtstate *state)
fprintf(fh, ", " DBQ(src_addr) ":" DBQ(%s), namebuf);
}
- if (state->do_Xicmp)
+ if (state->do_icmp)
proto= "ICMP";
else if (state->do_tcp)
proto= "TCP";
@@ -430,13 +430,29 @@ static void report(struct trtstate *state)
state->paris % state->parismod);
}
fprintf(fh, ", \"result\": [ %s ] }\n", state->result);
+
free(state->result);
state->result= NULL;
- state->busy= 0;
if (state->out_filename)
fclose(fh);
+ /* Kill the event and close socket */
+ if (state->socket_icmp != -1)
+ {
+ event_del(&state->event_icmp);
+ close(state->socket_icmp);
+ state->socket_icmp= -1;
+ }
+ if (state->socket_tcp != -1)
+ {
+ event_del(&state->event_tcp);
+ close(state->socket_tcp);
+ state->socket_tcp= -1;
+ }
+
+ state->busy= 0;
+
if (state->base->done)
state->base->done(state);
}
@@ -498,8 +514,9 @@ static void send_pkt(struct trtstate *state)
}
snprintf(line, sizeof(line),
- ", { \"hop\":%d, \"result\": [ ", state->hop);
+ ", { " DBQ(hop) ":%d, " DBQ(result) ": [ ", state->hop);
add_str(state, line);
+ state->open_result= 0;
}
state->seq++;
@@ -628,21 +645,21 @@ static void send_pkt(struct trtstate *state)
}
}
}
- else if (state->do_Xicmp)
+ else if (state->do_icmp)
{
/* Set hop count */
- setsockopt(base->v6icmp_snd, SOL_IPV6,
+ setsockopt(state->socket_icmp, SOL_IPV6,
IPV6_UNICAST_HOPS, &hop, sizeof(hop));
/* Set/clear don't fragment */
on= (state->dont_fragment ? IPV6_PMTUDISC_DO :
IPV6_PMTUDISC_DONT);
- setsockopt(base->v6icmp_snd, IPPROTO_IPV6,
+ setsockopt(state->socket_icmp, IPPROTO_IPV6,
IPV6_MTU_DISCOVER, &on, sizeof(on));
- do_hbh_dest_opt(base, base->v6icmp_snd, 0 /* hbh */,
+ do_hbh_dest_opt(base, state->socket_icmp, 0 /* hbh */,
state->hbhoptsize);
- do_hbh_dest_opt(base, base->v6icmp_snd, 1 /* dest */,
+ do_hbh_dest_opt(base, state->socket_icmp, 1 /* dest */,
state->destoptsize);
icmp6_hdr= (struct icmp6_hdr *)base->packet;
@@ -708,7 +725,7 @@ static void send_pkt(struct trtstate *state)
memset(&sin6copy, '\0', sizeof(sin6copy));
sin6copy.sin6_family= AF_INET6;
sin6copy.sin6_addr= state->sin6.sin6_addr;
- r= sendto(base->v6icmp_snd, base->packet, len, 0,
+ r= sendto(state->socket_icmp, base->packet, len, 0,
(struct sockaddr *)&sin6copy,
sizeof(sin6copy));
@@ -996,7 +1013,7 @@ static void send_pkt(struct trtstate *state)
}
}
}
- else if (state->do_Xicmp)
+ else if (state->do_icmp)
{
hop= state->hop;
@@ -1044,16 +1061,16 @@ static void send_pkt(struct trtstate *state)
#endif
/* Set hop count */
- setsockopt(base->v4icmp_snd, IPPROTO_IP, IP_TTL,
+ setsockopt(state->socket_icmp, IPPROTO_IP, IP_TTL,
&hop, sizeof(hop));
/* Set/clear don't fragment */
on= (state->dont_fragment ? IP_PMTUDISC_DO :
IP_PMTUDISC_DONT);
- setsockopt(base->v4icmp_snd, IPPROTO_IP,
+ setsockopt(state->socket_icmp, IPPROTO_IP,
IP_MTU_DISCOVER, &on, sizeof(on));
- r= sendto(base->v4icmp_snd, base->packet, len, 0,
+ r= sendto(state->socket_icmp, base->packet, len, 0,
(struct sockaddr *)&state->sin6,
state->socklen);
@@ -1224,9 +1241,10 @@ static void send_pkt(struct trtstate *state)
}
}
- if (state->sent)
+ if (state->open_result)
add_str(state, " }, ");
add_str(state, "{ ");
+ state->open_result= 0;
/* Increment packets sent */
state->sent++;
@@ -1344,10 +1362,11 @@ static void ready_callback4(int __attribute((unused)) unused,
gettimeofday(&now, NULL);
- base= s;
+ state= s;
+ base= state->base;
slen= sizeof(remote);
- nrecv= recvfrom(base->v4icmp_rcv, base->packet, sizeof(base->packet),
+ nrecv= recvfrom(state->socket_icmp, base->packet, sizeof(base->packet),
MSG_DONTWAIT, (struct sockaddr *)&remote, &slen);
if (nrecv == -1)
{
@@ -1412,9 +1431,8 @@ static void ready_callback4(int __attribute((unused)) unused,
*/
ind= ntohl(etcp->seq) >> 16;
- state= NULL;
- if (ind >= 0 && ind < base->tabsiz)
- state= base->table[ind];
+ if (ind != state->index)
+ state= NULL;
if (state && state->sin6.sin6_family != AF_INET)
state= NULL;
if (state && !state->do_tcp)
@@ -1453,6 +1471,9 @@ static void ready_callback4(int __attribute((unused)) unused,
/* Sequence number is in seq field */
seq= ntohl(etcp->seq) & 0xffff;
+ if (state->open_result)
+ add_str(state, " }, { ");
+
if (seq != state->seq)
{
if (seq > state->seq)
@@ -1467,14 +1488,14 @@ static void ready_callback4(int __attribute((unused)) unused,
}
late= 1;
- snprintf(line, sizeof(line), "\"late\":%d",
+ snprintf(line, sizeof(line), DBQ(late) ":%d",
state->seq-seq);
add_str(state, line);
}
else if (state->gotresp)
{
isDup= 1;
- add_str(state, " }, { \"dup\":true");
+ add_str(state, " " DBQ(dup) ":true");
}
if (!late && !isDup)
@@ -1611,12 +1632,11 @@ printf("curpacksize: %d\n", state->curpacksize);
*/
ind= ntohs(eudp->uh_sport) - SRC_BASE_PORT;
- state= NULL;
- if (ind >= 0 && ind < base->tabsiz)
- state= base->table[ind];
+ if (ind != state->index)
+ state= NULL;
if (state && state->sin6.sin6_family != AF_INET)
state= NULL;
- if (state && state->do_Xicmp)
+ if (state && state->do_icmp)
state= NULL;
if (!state)
@@ -1665,6 +1685,9 @@ printf("curpacksize: %d\n", state->curpacksize);
seq= ntohs(eudp->uh_dport)-BASE_PORT;
}
+ if (state->open_result)
+ add_str(state, " }, { ");
+
if (seq != state->seq)
{
if (seq > state->seq)
@@ -1679,14 +1702,14 @@ printf("curpacksize: %d\n", state->curpacksize);
}
late= 1;
- snprintf(line, sizeof(line), "\"late\":%d",
+ snprintf(line, sizeof(line), DBQ(late) ":%d",
state->seq-seq);
add_str(state, line);
}
else if (state->gotresp)
{
isDup= 1;
- add_str(state, " }, { \"dup\":true");
+ add_str(state, " " DBQ(dup) ":true");
}
if (!late && !isDup)
@@ -1839,8 +1862,7 @@ printf("curpacksize: %d\n", state->curpacksize);
return;
}
- state= base->table[ind];
- if (!state)
+ if (ind != state->index)
{
/* Nothing here */
printf(
@@ -1855,7 +1877,7 @@ printf("curpacksize: %d\n", state->curpacksize);
return;
}
- if (!state->do_Xicmp)
+ if (!state->do_icmp)
{
printf(
"ready_callback4: index (%d) is not doing ICMP\n",
@@ -1880,6 +1902,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
state->hostname);
}
+ if (state->open_result)
+ add_str(state, " }, { ");
+
late= 0;
isDup= 0;
seq= ntohs(eicmp->icmp_seq);
@@ -1897,14 +1922,14 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
}
late= 1;
- snprintf(line, sizeof(line), "\"late\":%d",
+ snprintf(line, sizeof(line), DBQ(late) ":%d",
state->seq-seq);
add_str(state, line);
}
else if (state->gotresp)
{
isDup= 1;
- add_str(state, " }, { \"dup\":true");
+ add_str(state, DBQ(dup) ":true");
}
if (!late && !isDup)
@@ -2072,8 +2097,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
}
}
- if (late)
- add_str(state, " }, { ");
+ state->open_result= 1;
if (!late && !isDup)
{
@@ -2109,8 +2133,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
return;
}
- state= base->table[ind];
- if (!state)
+ if (ind != state->index)
{
/* Nothing here */
printf(
@@ -2134,6 +2157,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
return;
}
+ if (state->open_result)
+ add_str(state, " }, { ");
+
late= 0;
isDup= 0;
seq= ntohs(icmp->icmp_seq);
@@ -2150,14 +2176,14 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
}
late= 1;
- snprintf(line, sizeof(line), "\"late\":%d",
+ snprintf(line, sizeof(line), DBQ(late) ":%d",
state->seq-seq);
add_str(state, line);
}
else if (state->gotresp)
{
isDup= 1;
- add_str(state, " }, { \"dup\":true");
+ add_str(state, DBQ(dup) ":true");
}
if (memcmp(&ip->ip_dst,
@@ -2195,8 +2221,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
/* Done */
state->done= 1;
- if (late)
- add_str(state, " }, { ");
+ state->open_result= 1;
if (!late && !isDup)
{
@@ -2245,10 +2270,11 @@ static void ready_tcp4(int __attribute((unused)) unused,
gettimeofday(&now, NULL);
- base= s;
+ state= s;
+ base= state->base;
slen= sizeof(remote);
- nrecv= recvfrom(base->v4tcp_rcv, base->packet, sizeof(base->packet),
+ nrecv= recvfrom(state->socket_tcp, base->packet, sizeof(base->packet),
MSG_DONTWAIT, (struct sockaddr *)&remote, &slen);
if (nrecv == -1)
{
@@ -2279,9 +2305,8 @@ static void ready_tcp4(int __attribute((unused)) unused,
/* We store the id in high order 16 bits of the sequence number */
ind= ntohl(tcphdr->ack_seq) >> 16;
- state= NULL;
- if (ind >= 0 && ind < base->tabsiz)
- state= base->table[ind];
+ if (ind != state->index)
+ state= NULL;
if (state && state->sin6.sin6_family != AF_INET)
state= NULL;
if (state && !state->do_tcp)
@@ -2306,6 +2331,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
late= 0;
isDup= 0;
+ if (state->open_result)
+ add_str(state, " }, { ");
+
/* Only check if the ack is without 64k of what we expect */
seq= ntohl(tcphdr->ack_seq) & 0xffff;
if (seq-state->seq > 0x2000)
@@ -2322,14 +2350,14 @@ printf("got seq %d, expected %d\n", seq, state->seq);
}
late= 1;
- snprintf(line, sizeof(line), "\"late\":%d",
+ snprintf(line, sizeof(line), DBQ(late) ":%d",
state->seq-seq);
add_str(state, line);
}
else if (state->gotresp)
{
isDup= 1;
- add_str(state, " }, { \"dup\":true");
+ add_str(state, DBQ(dup) ":true");
}
ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 +
@@ -2368,8 +2396,7 @@ printf("got seq %d, expected %d\n", seq, state->seq);
/* Done */
state->done= 1;
- if (late)
- add_str(state, " }, { ");
+ state->open_result= 1;
if (!late && !isDup)
{
@@ -2411,7 +2438,8 @@ static void ready_tcp6(int __attribute((unused)) unused,
gettimeofday(&now, NULL);
- base= s;
+ state= s;
+ base= state->base;
iov[0].iov_base= base->packet;
iov[0].iov_len= sizeof(base->packet);
@@ -2423,7 +2451,7 @@ static void ready_tcp6(int __attribute((unused)) unused,
msg.msg_controllen= sizeof(cmsgbuf);
msg.msg_flags= 0; /* Not really needed */
- nrecv= recvmsg(base->v6tcp_rcv, &msg, MSG_DONTWAIT);
+ nrecv= recvmsg(state->socket_tcp, &msg, MSG_DONTWAIT);
if (nrecv == -1)
{
/* Strange, read error */
@@ -2463,9 +2491,8 @@ static void ready_tcp6(int __attribute((unused)) unused,
/* We store the id in high order 16 bits of the sequence number */
ind= ntohl(tcphdr->ack_seq) >> 16;
- state= NULL;
- if (ind >= 0 && ind < base->tabsiz)
- state= base->table[ind];
+ if (ind != state->index)
+ state= NULL;
if (state && state->sin6.sin6_family != AF_INET6)
state= NULL;
if (state && !state->do_tcp)
@@ -2488,6 +2515,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
late= 0;
isDup= 0;
+ if (state->open_result)
+ add_str(state, " }, { ");
+
/* Only check if the ack is within 64k of what we expect */
seq= ntohl(tcphdr->ack_seq) & 0xffff;
if (seq-state->seq > 0x2000)
@@ -2504,14 +2534,14 @@ printf("got seq %d, expected %d\n", seq, state->seq);
}
late= 1;
- snprintf(line, sizeof(line), "\"late\":%d",
+ snprintf(line, sizeof(line), DBQ(late) ":%d",
state->seq-seq);
add_str(state, line);
}
else if (state->gotresp)
{
isDup= 1;
- add_str(state, " }, { \"dup\":true");
+ add_str(state, DBQ(dup) ":true");
}
ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 +
@@ -2549,8 +2579,7 @@ printf("got seq %d, expected %d\n", seq, state->seq);
/* Done */
state->done= 1;
- if (late)
- add_str(state, " }, { ");
+ state->open_result= 1;
if (!late && !isDup)
{
@@ -2599,7 +2628,8 @@ static void ready_callback6(int __attribute((unused)) unused,
gettimeofday(&now, NULL);
- base= s;
+ state= s;
+ base= state->base;
iov[0].iov_base= base->packet;
iov[0].iov_len= sizeof(base->packet);
@@ -2611,7 +2641,7 @@ static void ready_callback6(int __attribute((unused)) unused,
msg.msg_controllen= sizeof(cmsgbuf);
msg.msg_flags= 0; /* Not really needed */
- nrecv= recvmsg(base->v6icmp_rcv, &msg, MSG_DONTWAIT);
+ nrecv= recvmsg(state->socket_icmp, &msg, MSG_DONTWAIT);
if (nrecv == -1)
{
/* Strange, read error */
@@ -2695,7 +2725,7 @@ static void ready_callback6(int __attribute((unused)) unused,
#endif
return;
}
- opthdr= (struct ip6_ext *)&eip[1];
+ opthdr= (struct ip6_ext *)ptr;
hbhoptsize= 8*opthdr->ip6e_len;
optlen= hbhoptsize+8;
if (nrecv < sizeof(*icmp) + sizeof(*eip) +
@@ -2704,7 +2734,7 @@ static void ready_callback6(int __attribute((unused)) unused,
/* Does not contain the full header */
return;
}
- ehdrsiz= optlen;
+ ehdrsiz += optlen;
nxt= opthdr->ip6e_nxt;
ptr= ((char *)opthdr)+optlen;
}
@@ -2723,7 +2753,7 @@ static void ready_callback6(int __attribute((unused)) unused,
#endif
return;
}
- frag= (struct ip6_frag *)&eip[1];
+ frag= (struct ip6_frag *)ptr;
if ((ntohs(frag->ip6f_offlg) & ~3) != 0)
{
/* Not first fragment, just ignore
@@ -2731,7 +2761,7 @@ static void ready_callback6(int __attribute((unused)) unused,
*/
return;
}
- ehdrsiz= sizeof(*frag);
+ ehdrsiz += sizeof(*frag);
nxt= frag->ip6f_nxt;
ptr= &frag[1];
}
@@ -2750,7 +2780,7 @@ static void ready_callback6(int __attribute((unused)) unused,
#endif
return;
}
- opthdr= (struct ip6_ext *)&eip[1];
+ opthdr= (struct ip6_ext *)ptr;
dstoptsize= 8*opthdr->ip6e_len;
optlen= dstoptsize+8;
if (nrecv < sizeof(*icmp) + sizeof(*eip) +
@@ -2759,7 +2789,7 @@ static void ready_callback6(int __attribute((unused)) unused,
/* Does not contain the full header */
return;
}
- ehdrsiz= optlen;
+ ehdrsiz += optlen;
nxt= opthdr->ip6e_nxt;
ptr= ((char *)opthdr)+optlen;
}
@@ -2838,9 +2868,8 @@ static void ready_callback6(int __attribute((unused)) unused,
ind= ntohl(v6info->id);
}
- state= NULL;
- if (ind >= 0 && ind < base->tabsiz)
- state= base->table[ind];
+ if (ind != state->index)
+ state= NULL;
if (state && state->sin6.sin6_family != AF_INET6)
state= NULL;
@@ -2849,7 +2878,7 @@ static void ready_callback6(int __attribute((unused)) unused,
{
if ((etcp && !state->do_tcp) ||
(eudp && !state->do_udp) ||
- (eicmp && !state->do_Xicmp))
+ (eicmp && !state->do_icmp))
{
state= NULL;
}
@@ -2888,6 +2917,10 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
}
else
seq= ntohl(v6info->seq);
+
+ if (state->open_result)
+ add_str(state, " }, { ");
+
if (seq != state->seq)
{
if (seq > state->seq)
@@ -2902,13 +2935,13 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
}
late= 1;
- snprintf(line, sizeof(line), "\"late\":%d",
+ snprintf(line, sizeof(line), DBQ(late) ":%d",
state->seq-seq);
add_str(state, line);
} else if (state->gotresp)
{
isDup= 1;
- add_str(state, " }, { \"dup\":true");
+ add_str(state, DBQ(dup) ":true");
}
if (!late && !isDup)
@@ -3042,16 +3075,19 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
state->done= 1;
switch(icmp->icmp6_code)
{
- case ICMP6_DST_UNREACH_NOROUTE:
+ case ICMP6_DST_UNREACH_NOROUTE: /* 0 */
add_str(state, ", \"err\":\"N\"");
break;
- case ICMP6_DST_UNREACH_ADDR:
- add_str(state, ", \"err\":\"H\"");
+ case ICMP6_DST_UNREACH_ADMIN: /* 1 */
+ add_str(state, ", \"err\":\"A\"");
break;
- case ICMP6_DST_UNREACH_NOPORT:
+ case ICMP6_DST_UNREACH_BEYONDSCOPE: /* 2 */
+ add_str(state, ", \"err\":\"h\"");
break;
- case ICMP6_DST_UNREACH_ADMIN:
- add_str(state, ", \"err\":\"A\"");
+ case ICMP6_DST_UNREACH_ADDR: /* 3 */
+ add_str(state, ", \"err\":\"H\"");
+ break;
+ case ICMP6_DST_UNREACH_NOPORT: /* 4 */
break;
default:
snprintf(line, sizeof(line),
@@ -3110,8 +3146,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
}
}
- if (late)
- add_str(state, " }, { ");
+ state->open_result= 1;
if (!late && !isDup)
{
@@ -3153,14 +3188,12 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
ind= ntohl(v6info->id);
- state= NULL;
- if (ind >= 0 && ind < base->tabsiz)
- state= base->table[ind];
-
+ if (ind != state->index)
+ state= NULL;
if (state && state->sin6.sin6_family != AF_INET6)
state= NULL;
- if (state && !state->do_Xicmp)
+ if (state && !state->do_icmp)
{
state= NULL;
}
@@ -3189,6 +3222,9 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
return;
}
+ if (state->open_result)
+ add_str(state, " }, { ");
+
late= 0;
isDup= 0;
seq= ntohl(v6info->seq);
@@ -3204,14 +3240,14 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
}
late= 1;
- snprintf(line, sizeof(line), "\"late\":%d",
+ snprintf(line, sizeof(line), DBQ(late) ":%d",
state->seq-seq);
add_str(state, line);
}
else if (state->gotresp)
{
isDup= 1;
- add_str(state, " }, { \"dup\":true");
+ add_str(state, DBQ(dup) ":true");
}
if (!late && !isDup)
@@ -3260,8 +3296,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
sizeof(buf)), state->hop);
#endif
- if (late)
- add_str(state, " }, { ");
+ state->open_result= 1;
if (!late && !isDup)
{
@@ -3296,7 +3331,6 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
static struct trtbase *traceroute_base_new(struct event_base
*event_base)
{
- int on;
struct trtbase *base;
base= xzalloc(sizeof(*base));
@@ -3306,40 +3340,8 @@ static struct trtbase *traceroute_base_new(struct event_base
base->tabsiz= 10;
base->table= xzalloc(base->tabsiz * sizeof(*base->table));
- base->v4icmp_rcv= xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- base->v6icmp_rcv= xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
- base->v4icmp_snd= xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- base->v6icmp_snd= xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
- base->v4tcp_rcv= xsocket(AF_INET, SOCK_RAW, IPPROTO_TCP);
- base->v6tcp_rcv= xsocket(AF_INET6, SOCK_RAW, IPPROTO_TCP);
- base->v4udp_snd= xsocket(AF_INET, SOCK_DGRAM, 0);
-
base->my_pid= getpid();
- on = 1;
- setsockopt(base->v6icmp_rcv, IPPROTO_IPV6, IPV6_RECVPKTINFO,
- &on, sizeof(on));
-
- on = 1;
- setsockopt(base->v6icmp_rcv, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
- &on, sizeof(on));
- on = 1;
- setsockopt(base->v6tcp_rcv, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
- &on, sizeof(on));
-
- event_assign(&base->event4, base->event_base, base->v4icmp_rcv,
- EV_READ | EV_PERSIST, ready_callback4, base);
- event_assign(&base->tcp_event4, base->event_base, base->v4tcp_rcv,
- EV_READ | EV_PERSIST, ready_tcp4, base);
- event_assign(&base->event6, base->event_base, base->v6icmp_rcv,
- EV_READ | EV_PERSIST, ready_callback6, base);
- event_assign(&base->tcp_event6, base->event_base, base->v6tcp_rcv,
- EV_READ | EV_PERSIST, ready_tcp6, base);
- event_add(&base->event4, NULL);
- event_add(&base->tcp_event4, NULL);
- event_add(&base->event6, NULL);
- event_add(&base->tcp_event6, NULL);
-
return base;
}
@@ -3356,7 +3358,12 @@ static void noreply_callback(int __attribute((unused)) unused,
#endif
if (!state->gotresp)
- add_str(state, "\"x\":\"*\"");
+ {
+ if (state->open_result)
+ add_str(state, " }, { ");
+ add_str(state, DBQ(x) ":" DBQ(*));
+ state->open_result= 1;
+ }
send_pkt(state);
}
@@ -3375,6 +3382,7 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[],
const char *hostname;
char *out_filename;
const char *destportstr;
+ char *interface;
char *check;
struct trtstate *state;
sa_family_t af;
@@ -3392,12 +3400,15 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[],
count= 3;
firsthop= 1;
gaplimit= 5;
+ interface= NULL;
maxhops= 32;
maxpacksize= 40;
destportstr= "80";
duptimeout= 10;
timeout= 1000;
parismod= 16;
+ hbhoptsize= 0;
+ destoptsize= 0;
str_Atlas= NULL;
out_filename= NULL;
opt_complementary = "=1:4--6:i--u:a+:c+:f+:g+:m+:w+:z+:S+:H+:D+";
@@ -3406,7 +3417,8 @@ for (i= 0; argv[i] != NULL; i++)
printf("argv[%d] = '%s'\n", i, argv[i]);
opt = getopt32(argv, TRACEROUTE_OPT_STRING, &parismod, &count,
- &firsthop, &gaplimit, &maxhops, &destportstr, &timeout,
+ &firsthop, &gaplimit, &interface, &maxhops, &destportstr,
+ &timeout,
&duptimeout, &str_Atlas, &out_filename, &maxpacksize,
&hbhoptsize, &destoptsize);
hostname = argv[optind];
@@ -3483,12 +3495,13 @@ for (i= 0; argv[i] != NULL; i++)
state->maxpacksize= maxpacksize;
state->maxhops= maxhops;
state->gaplimit= gaplimit;
- state->destportstr= destportstr;
+ state->interface= interface;
+ state->destportstr= strdup(destportstr);
state->duptimeout= duptimeout*1000;
state->timeout= timeout*1000;
state->atlas= str_Atlas ? strdup(str_Atlas) : NULL;
state->hostname= strdup(hostname);
- state->do_Xicmp= do_icmp;
+ state->do_icmp= do_icmp;
state->do_tcp= do_tcp;
state->do_udp= do_udp;
state->do_v6= do_v6;
@@ -3548,15 +3561,10 @@ for (i= 0; argv[i] != NULL; i++)
static void traceroute_start2(void *state)
{
- int r, serrno;
struct trtstate *trtstate;
- struct trtbase *trtbase;
- struct sockaddr_in loc_sa4;
- struct sockaddr_in6 loc_sa6;
char line[80];
trtstate= state;
- trtbase= trtstate->base;
if (trtstate->busy)
{
@@ -3586,231 +3594,235 @@ static void traceroute_start2(void *state)
trtstate->resmax= 80;
trtstate->result= xmalloc(trtstate->resmax);
trtstate->reslen= 0;
+ trtstate->open_result= 0;
trtstate->starttime= time(NULL);
+ trtstate->socket_icmp= -1;
+ trtstate->socket_tcp= -1;
+
snprintf(line, sizeof(line), "{ \"hop\":%d", trtstate->hop);
add_str(trtstate, line);
- if (trtstate->do_Xicmp)
+ if (trtstate->do_icmp)
{
+ if (create_socket(trtstate, 0 /*do_tcp*/) == -1)
+ return;
+ }
+ else if (trtstate->do_udp)
+ {
+ if (create_socket(trtstate, 0 /*do_tcp*/) == -1)
+ return;
if (trtstate->do_v6)
{
- memset(&loc_sa6, '\0', sizeof(loc_sa6));
- loc_sa6.sin6_family= AF_INET;
-
- r= connect(trtbase->v6icmp_snd,
- (struct sockaddr *)&trtstate->sin6,
- trtstate->socklen);
-#if 0
- { errno= ENOSYS; r= -1; }
-#endif
- if (r == -1)
- {
- serrno= errno;
-
- snprintf(line, sizeof(line),
- ", " DBQ(error) ":" DBQ(connect failed: %s) " }",
- strerror(serrno));
- add_str(trtstate, line);
- report(trtstate);
- return;
- }
- trtstate->loc_socklen= sizeof(trtstate->loc_sin6);
- if (getsockname(trtbase->v6icmp_snd,
- &trtstate->loc_sin6,
- &trtstate->loc_socklen) == -1)
- {
- crondlog(DIE9 "getsockname failed");
- }
-#if 0
- printf("Got localname: %s\n",
- inet_ntop(AF_INET6,
- &trtstate->loc_sin6.sin6_addr,
- buf, sizeof(buf)));
-#endif
+ trtstate->loc_sin6.sin6_port= htons(SRC_BASE_PORT +
+ trtstate->index);
}
else
{
- memset(&loc_sa4, '\0', sizeof(loc_sa4));
- loc_sa4.sin_family= AF_INET;
- ((struct sockaddr_in *)&trtstate->sin6)->sin_port=
- htons(0x8000);
-
- r= connect(trtbase->v4icmp_snd,
- (struct sockaddr *)&trtstate->sin6,
- trtstate->socklen);
-#if 0
- { errno= ENOSYS; r= -1; }
-#endif
- if (r == -1)
- {
- serrno= errno;
-
- snprintf(line, sizeof(line),
- ", " DBQ(error) ":" DBQ(connect failed: %s) " }",
- strerror(serrno));
- add_str(trtstate, line);
- report(trtstate);
- return;
- }
- trtstate->loc_socklen= sizeof(trtstate->loc_sin6);
- if (getsockname(trtbase->v4icmp_snd,
- &trtstate->loc_sin6,
- &trtstate->loc_socklen) == -1)
- {
- crondlog(DIE9 "getsockname failed");
- }
-#if 0
- printf("Got localname: %s\n",
- inet_ntoa(((struct sockaddr_in *)
- &trtstate->loc_sin6)->sin_addr));
-#endif
+ ((struct sockaddr_in *)(&trtstate->loc_sin6))->
+ sin_port= htons(SRC_BASE_PORT +
+ trtstate->index);
}
}
- else
+ else if (trtstate->do_tcp)
{
+ if (create_socket(trtstate, 1 /*do_tcp*/) == -1)
+ return;
+
if (trtstate->do_v6)
{
- int sock;
+ trtstate->loc_sin6.sin6_port= htons(SRC_BASE_PORT +
+ trtstate->index);
+ }
+ else
+ {
+ ((struct sockaddr_in *)(&trtstate->loc_sin6))->
+ sin_port= htons(SRC_BASE_PORT +
+ trtstate->index);
+ }
+ }
- memset(&loc_sa6, '\0', sizeof(loc_sa6));
- loc_sa6.sin6_family= AF_INET6;
- loc_sa6.sin6_port= htons(SRC_BASE_PORT +
- trtstate->index);;
+ add_str(trtstate, ", \"result\": [ ");
- sock= socket(AF_INET6, SOCK_DGRAM, 0);
- if (sock == -1)
- {
- crondlog(DIE9 "socket failed");
- }
- r= bind(sock, (struct sockaddr *)&loc_sa6,
- sizeof(loc_sa6));
- if (r == -1)
- {
- serrno= errno;
+ send_pkt(trtstate);
+}
- snprintf(line, sizeof(line),
- ", " DBQ(error) ":" DBQ(bind failed: %s) " }",
- strerror(serrno));
- add_str(trtstate, line);
- report(trtstate);
- close(sock);
- return;
- }
+static int create_socket(struct trtstate *state, int do_tcp)
+{
+ int af, type, protocol;
+ int r, on, serrno;
+ char line[80];
+
+ af= (state->do_v6 ? AF_INET6 : AF_INET);
+ type= SOCK_RAW;
+ protocol= (af == AF_INET6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP);
- r= connect(sock, (struct sockaddr *)&trtstate->sin6,
- trtstate->socklen);
+ state->socket_icmp= xsocket(af, type, protocol);
+ if (state->socket_icmp == -1)
+ {
+ serrno= errno;
+
+ snprintf(line, sizeof(line),
+ ", " DBQ(error) ":" DBQ(socket failed: %s) " }",
+ strerror(serrno));
+ add_str(state, line);
+ report(state);
+ return -1;
+ }
+
+ if (state->interface)
+ {
+ if (bind_interface(state->socket_icmp,
+ af, state->interface) == -1)
+ {
+ snprintf(line, sizeof(line),
+ ", " DBQ(error) ":" DBQ(bind_interface failed) " }");
+ add_str(state, line);
+ report(state);
+ return -1;
+ }
+ }
+
+ r= connect(state->socket_icmp,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
#if 0
{ errno= ENOSYS; r= -1; }
#endif
- if (r == -1)
- {
- serrno= errno;
-
- snprintf(line, sizeof(line),
- ", " DBQ(error) ":" DBQ(connect failed: %s) " }",
- strerror(serrno));
- add_str(trtstate, line);
- report(trtstate);
- return;
- }
-
- trtstate->loc_socklen= sizeof(trtstate->loc_sin6);
- if (getsockname(sock,
- &trtstate->loc_sin6,
- &trtstate->loc_socklen) == -1)
- {
- crondlog(DIE9 "getsockname failed");
- }
+ if (r == -1)
+ {
+ serrno= errno;
- close(sock);
+ snprintf(line, sizeof(line),
+ ", " DBQ(error) ":" DBQ(connect failed: %s) " }",
+ strerror(serrno));
+ add_str(state, line);
+ report(state);
+ return -1;
+ }
+ state->loc_socklen= sizeof(state->loc_sin6);
+ if (getsockname(state->socket_icmp,
+ &state->loc_sin6,
+ &state->loc_socklen) == -1)
+ {
+ crondlog(DIE9 "getsockname failed");
+ }
#if 0
- printf("Got localname: %s:%d\n",
- inet_ntop(AF_INET6,
- &trtstate->loc_sin6.sin6_addr,
- buf, sizeof(buf)),
- ntohs(((struct sockaddr_in *)&trtstate->
- loc_sin6)->sin_port));
+ printf("Got localname: %s\n",
+ inet_ntop(AF_INET6,
+ &state->loc_sin6.sin6_addr,
+ buf, sizeof(buf)));
#endif
- }
- else
+
+ close(state->socket_icmp);
+ state->socket_icmp= xsocket(af, type,
+ protocol);
+ if (state->socket_icmp == -1)
+ {
+ serrno= errno;
+
+ snprintf(line, sizeof(line),
+ ", " DBQ(error) ":" DBQ(socket failed: %s) " }",
+ strerror(serrno));
+ add_str(state, line);
+ report(state);
+ return -1;
+ }
+
+ if (af == AF_INET6)
+ {
+ on = 1;
+ setsockopt(state->socket_icmp, IPPROTO_IPV6,
+ IPV6_RECVPKTINFO, &on, sizeof(on));
+
+ on = 1;
+ setsockopt(state->socket_icmp, IPPROTO_IPV6,
+ IPV6_RECVHOPLIMIT, &on, sizeof(on));
+ }
+
+ if (state->interface)
+ {
+ if (bind_interface(state->socket_icmp,
+ af, state->interface) == -1)
{
- int sock;
+ snprintf(line, sizeof(line),
+ ", " DBQ(error) ":" DBQ(bind_interface failed) " }");
+ add_str(state, line);
+ report(state);
+ return -1;
+ }
+ }
- memset(&loc_sa4, '\0', sizeof(loc_sa4));
- loc_sa4.sin_family= AF_INET;
+ event_assign(&state->event_icmp, state->base->event_base,
+ state->socket_icmp,
+ EV_READ | EV_PERSIST,
+ (af == AF_INET6 ? ready_callback6 : ready_callback4),
+ state);
+ event_add(&state->event_icmp, NULL);
- loc_sa4.sin_port= htons(SRC_BASE_PORT +
- trtstate->index);;
+ if (do_tcp)
+ {
+ state->socket_tcp= xsocket(af, SOCK_RAW,
+ IPPROTO_TCP);
+ if (state->socket_tcp == -1)
+ {
+ serrno= errno;
- if (!trtstate->do_tcp)
- {
- /* Also set destination port */
- ((struct sockaddr_in *)&trtstate->sin6)->
- sin_port= htons(BASE_PORT);
- }
+ snprintf(line, sizeof(line),
+ ", " DBQ(error) ":" DBQ(socket failed: %s) " }",
+ strerror(serrno));
+ add_str(state, line);
+ report(state);
+ return -1;
+ }
- sock= socket(AF_INET, SOCK_DGRAM, 0);
- if (sock == -1)
- {
- crondlog(DIE9 "socket failed");
- }
- r= bind(sock, (struct sockaddr *)&loc_sa4,
- sizeof(loc_sa4));
-#if 0
- { errno= ENOSYS; r= -1; }
-#endif
- if (r == -1)
- {
- serrno= errno;
+ if (af == AF_INET6)
+ {
+ on = 1;
+ setsockopt(state->socket_tcp, IPPROTO_IPV6,
+ IPV6_RECVHOPLIMIT, &on, sizeof(on));
+ }
+ if (state->interface)
+ {
+ if (bind_interface(state->socket_tcp,
+ af, state->interface) == -1)
+ {
snprintf(line, sizeof(line),
- ", " DBQ(error) ":" DBQ(bind failed: %s) " }",
- strerror(serrno));
- add_str(trtstate, line);
- report(trtstate);
- close(sock);
- return;
+ ", " DBQ(error) ":" DBQ(bind_interface failed) " }");
+ add_str(state, line);
+ report(state);
+ return -1;
}
+ }
- r= connect(sock, (struct sockaddr *) &trtstate->sin6,
- trtstate->socklen);
+ r= connect(state->socket_tcp,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
#if 0
{ errno= ENOSYS; r= -1; }
#endif
- if (r == -1)
- {
- serrno= errno;
+ if (r == -1)
+ {
+ serrno= errno;
- snprintf(line, sizeof(line),
- ", " DBQ(error) ":" DBQ(connect failed: %s) " }",
- strerror(serrno));
- add_str(trtstate, line);
- report(trtstate);
- close(sock);
- return;
- }
- trtstate->loc_socklen= sizeof(trtstate->loc_sin6);
- if (getsockname(sock,
- &trtstate->loc_sin6,
- &trtstate->loc_socklen) == -1)
- {
- crondlog(DIE9 "getsockname failed");
- }
- close(sock);
-#if 0
- printf("Got localname: %s:%d\n",
- inet_ntoa(((struct sockaddr_in *)
- &trtstate->loc_sin6)->sin_addr),
- ntohs(((struct sockaddr_in *)&trtstate->
- loc_sin6)->sin_port));
-#endif
+ snprintf(line, sizeof(line),
+ ", " DBQ(error) ":" DBQ(connect failed: %s) " }",
+ strerror(serrno));
+ add_str(state, line);
+ report(state);
+ return -1;
}
- }
- add_str(trtstate, ", \"result\": [ ");
+ event_assign(&state->event_tcp, state->base->event_base,
+ state->socket_tcp,
+ EV_READ | EV_PERSIST,
+ (af == AF_INET6 ? ready_tcp6 : ready_tcp4),
+ state);
+ event_add(&state->event_tcp, NULL);
+ }
- send_pkt(trtstate);
+ return 0;
}
static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx)
@@ -3934,6 +3946,8 @@ static int traceroute_delete(void *state)
trtstate->atlas= NULL;
free(trtstate->hostname);
trtstate->hostname= NULL;
+ free(trtstate->destportstr);
+ trtstate->destportstr= NULL;
free(trtstate->out_filename);
trtstate->out_filename= NULL;