diff options
author | Bjørn Mork <bjorn@mork.no> | 2015-05-15 10:25:21 +0200 |
---|---|---|
committer | Bjørn Mork <bjorn@mork.no> | 2015-05-15 10:25:21 +0200 |
commit | b8c5c3b44362778c099531f7a905c56a0423bcef (patch) | |
tree | e9ccaff5d19f39e7bc58734e1b5babf4025a3a9c /eperd/traceroute.c | |
parent | b1b227fa5e00d08af047ab9a012211b66c6b0f13 (diff) |
ripe-atlas-fw: imported version 46504650
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Diffstat (limited to 'eperd/traceroute.c')
-rw-r--r-- | eperd/traceroute.c | 674 |
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; |