From b8c5c3b44362778c099531f7a905c56a0423bcef Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 15 May 2015 10:25:21 +0200 Subject: ripe-atlas-fw: imported version 4650 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- .config | 4 +- checksum | 4 +- eperd/eooqd.c | 5 +- eperd/evtdig.c | 17 +- eperd/httpget.c | 21 +- eperd/ping.c | 350 +++++++++++----------- eperd/readresolv.c | 39 +++ eperd/readresolv.h | 2 + eperd/sslgetcert.c | 11 +- eperd/tcputil.c | 44 ++- eperd/tcputil.h | 5 +- eperd/traceroute.c | 674 +++++++++++++++++++++--------------------- include/applets.h | 2 +- include/libbb.h | 2 + include/usage.h | 12 +- libbb/Kbuild | 2 + libbb/atlas_timesync.c | 19 ++ libbb/bind_interface.c | 42 +++ networking/Config.in | 6 +- networking/Kbuild | 2 +- networking/atlasinit.c | 740 ++++++++++++++++++++++++++++++++++++++++++++++ networking/rptaddrs.c | 775 +++++++++++++++++++++++++++++++++++++++++++++++++ networking/rptra6.c | 2 +- shell/hush.c | 10 +- 24 files changed, 2258 insertions(+), 532 deletions(-) create mode 100644 libbb/atlas_timesync.c create mode 100644 libbb/bind_interface.c create mode 100644 networking/atlasinit.c create mode 100644 networking/rptaddrs.c diff --git a/.config b/.config index fe8c41e..f6026bd 100644 --- a/.config +++ b/.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.13.3 -# Mon Mar 10 17:14:26 2014 +# Wed May 7 07:15:57 2014 # CONFIG_HAVE_DOT_CONFIG=y @@ -711,7 +711,7 @@ CONFIG_FEATURE_FANCY_PING=y CONFIG_PSCAN=y CONFIG_ROUTE=y CONFIG_RPTRA6=y -CONFIG_RPTADDR6=y +CONFIG_RPTADDRS=y CONFIG_RXTXRPT=y CONFIG_SLATTACH=y CONFIG_SSLGETCERT=y diff --git a/checksum b/checksum index bcff836..cd6d912 100644 --- a/checksum +++ b/checksum @@ -1,2 +1,2 @@ -9220584710f5cb827a35a20b139231c774d60bc1e66706cc42c6808a34a28b34 ripe-atlas-fw-4570.tar.gz -5fa4008d6321d66ed15235dd51bef6fbee1c455dccdf01c1b9a92db979a82fdc307dd2f11cc9f79de2adf467638954180c4d5b9ad9e30501f699af7691079bbc ripe-atlas-fw-4570.tar.gz +6b015256e73151f92c700c31c4551c24fef023e57c74316fa35d024f013b1737 ripe-atlas-fw-4610.tar.gz +8d22f3f0e332df7271c893ea599975939e29fda1e0a9f001dc7b50dd2ffc835c43c2859042ba835edce312222e830e38c6c6cc417b038e234d3f14942120dd39 ripe-atlas-fw-4610.tar.gz diff --git a/eperd/eooqd.c b/eperd/eooqd.c index 7e071c0..41efa1b 100644 --- a/eperd/eooqd.c +++ b/eperd/eooqd.c @@ -616,7 +616,10 @@ static const char *get_session_id(void) cp= strchr(session_id, '\n'); if (cp) *cp= '\0'; - return session_id; + cp= strrchr(session_id, ' '); + if (!cp) + return NULL; + return cp+1; } static void skip_space(char *cp, char **ncpp) diff --git a/eperd/evtdig.c b/eperd/evtdig.c index b3813de..e0a8ae5 100644 --- a/eperd/evtdig.c +++ b/eperd/evtdig.c @@ -712,7 +712,7 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet) dns->aa = 0; //Not Authoritative dns->tc = 0; //This message is not truncated dns->rd = 0; //Recursion not Desired - dns->ra = 1; //Recursion not available! hey we dont have it (lol) + dns->ra = 0; //Recursion not available! hey we dont have it (lol) dns->z = 0; dns->ad = 0; dns->cd = 0; @@ -1895,7 +1895,8 @@ void tdig_start (struct query_state *qry) interval.tv_sec = CONN_TO; interval.tv_usec= 0; tu_connect_to_name (&qry->tu_env, qry->server_name, port_as_char, - &interval, &hints, tcp_timeout_callback, tcp_reporterr, + &interval, &hints, NULL, + tcp_timeout_callback, tcp_reporterr, tcp_dnscount, tcp_beforeconnect, tcp_connected, tcp_readcb, tcp_writecb); @@ -2194,7 +2195,9 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) int flagAnswer = 0; int data_len; int write_out = FALSE; - u_int32_t fw; + + int fw = get_atlas_fw_version(); + int lts = get_timesync(); if(! qry->result.size){ buf_init(&qry->result, -1); @@ -2206,19 +2209,21 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) JS(id, qry->str_Atlas); } - fw = get_atlas_fw_version(); - JU(fw, fw); - + JD(fw, fw); if (qry->opt_rset){ JS1(time, %ld, qry->xmit_time.tv_sec); + JD(lts,lts); AS("\"resultset\" : [ {"); } + } else if(qry->opt_rset) { AS (",{"); } JS1(time, %ld, qry->xmit_time.tv_sec); + JD(lts,lts); + if ( qry->opt_resolv_conf ) { JD (subid, (qry->resolv_i+1)); JD (submax, qry->base->resolv_max); diff --git a/eperd/httpget.c b/eperd/httpget.c index d0d3e4c..4b22bca 100644 --- a/eperd/httpget.c +++ b/eperd/httpget.c @@ -91,6 +91,7 @@ struct hgstate int etim; size_t read_limit; unsigned timeout; + char *infname; /* State */ char busy; @@ -368,7 +369,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], char *url, *check; char *post_file, *output_file, *post_footer, *post_header, *A_arg, *store_headers, *store_body, *read_limit_str, - *timeout_str; + *timeout_str, *infname; const char *user_agent; char *host, *port, *hostport, *path; struct hgstate *state; @@ -390,6 +391,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], read_limit_str= NULL; timeout_str= NULL; A_arg= NULL; + infname= NULL; only_v4= 0; only_v6= 0; do_etim= 0; @@ -406,7 +408,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], /* Allow us to be called directly by another program in busybox */ optind= 0; - while (c= getopt_long(argc, argv, "01aA:cO:46", longopts, NULL), c != -1) + while (c= getopt_long(argc, argv, "01aA:cI:O:46", longopts, NULL), c != -1) { switch(c) { @@ -455,6 +457,9 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], case 'h': /* --post-header */ post_header= optarg; break; + case 'I': + infname= optarg; + break; case 'O': output_file= optarg; break; @@ -622,6 +627,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[], state->max_body= max_body; state->read_limit= read_limit; state->timeout= timeout; + state->infname= infname; state->only_v4= 2; @@ -701,8 +707,10 @@ static void report(struct hgstate *state) { fprintf(fh, DBQ(id) ":" DBQ(%s) ", " DBQ(fw) ":%d, " + DBQ(lts) ":%d, " DBQ(time) ":%ld, ", state->atlas, get_atlas_fw_version(), + get_timesync(), state->gstart); } fprintf(fh, DBQ(result) ":[ "); @@ -1822,6 +1830,13 @@ static void reporterr(struct tu_env *env, enum tu_err cause, err_reading(state); break; + case TU_SOCKET_ERR: + snprintf(line, sizeof(line), + "{ " DBQ(sockerr) ":" DBQ(%s) ", ", str); + add_str(state, line); + report(state); + break; + case TU_CONNECT_ERR: snprintf(line, sizeof(line), DBQ(err) ":" DBQ(connect: %s) ", ", str); @@ -1890,7 +1905,7 @@ static void httpget_start(void *state) interval.tv_sec= hgstate->timeout / 1000; interval.tv_usec= (hgstate->timeout % 1000) * 1000; tu_connect_to_name(&hgstate->tu_env, hgstate->host, hgstate->port, - &interval, &hints, timeout_callback, + &interval, &hints, hgstate->infname, timeout_callback, reporterr, dnscount, beforeconnect, connected, readcb, writecb); } diff --git a/eperd/ping.c b/eperd/ping.c index 16aa8fe..4d17317 100644 --- a/eperd/ping.c +++ b/eperd/ping.c @@ -26,7 +26,7 @@ #define DBQ(str) "\"" #str "\"" -#define PING_OPT_STRING ("!46rc:s:A:O:") +#define PING_OPT_STRING ("!46rc:s:A:O:i:I:") enum { @@ -71,25 +71,13 @@ struct pingbase { struct event_base *event_base; - evutil_socket_t rawfd4; /* Raw socket used to ping hosts (IPv4) - */ - evutil_socket_t rawfd6; /* Raw socket used to ping hosts (IPv6) - */ - pid_t pid; /* Identifier to send with each ICMP * Request */ - struct timeval tv_interval; /* Ping interval between two subsequent - * pings */ - /* A list of hosts to ping. */ struct pingstate **table; int tabsiz; - struct event event4; /* Used to detect read events on raw - * socket */ - struct event event6; /* Used to detect read events on raw - * socket */ void (*done)(void *state); /* Called when a ping is done */ u_char packet [MAX_DATA_SIZE]; @@ -100,9 +88,11 @@ struct pingstate /* Parameters */ char *atlas; char *hostname; + char *interface; int pingcount; char *out_filename; char delay_name_res; + unsigned interval; /* State */ struct sockaddr_in6 sin6; @@ -110,6 +100,7 @@ struct pingstate struct sockaddr_in6 loc_sin6; socklen_t loc_socklen; int busy; + int socket; char got_reply; char first; char no_dst; @@ -117,6 +108,9 @@ struct pingstate unsigned size; unsigned psize; + struct event event; /* Used to detect read events on raw + * socket */ + char *result; size_t reslen; size_t resmax; @@ -186,19 +180,6 @@ static void add_str(struct pingstate *state, const char *str) //printf("add_str: result = '%s'\n", state->result); } -static int get_timesync(void) -{ - FILE *fh; - int lastsync; - - fh= fopen(ATLAS_TIMESYNC_FILE, "r"); - if (!fh) - return -1; - fscanf(fh, "%d", &lastsync); - fclose(fh); - return time(NULL)-lastsync; -} - static void report(struct pingstate *state) { FILE *fh; @@ -259,13 +240,23 @@ static void report(struct pingstate *state) #endif /* DO_PSIZE */ 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 */ + event_del(&state->event); + if (state->socket != -1) + { + close(state->socket); + state->socket= -1; + } + + state->busy= 0; + } static void ping_cb(int result, int bytes, int psize, @@ -558,8 +549,9 @@ static void fmticmp6(u_char *buffer, size_t *sizep, static void ping_xmit(struct pingstate *host) { struct pingbase *base = host->base; + struct timeval tv_interval; - int nsent, fd4, fd6, t_errno, r; + int nsent; if (host->sentpkts >= host->maxpkts) { @@ -587,27 +579,14 @@ static void ping_xmit(struct pingstate *host) fmticmp6(base->packet, &host->cursize, host->seq, host->index, base->pid); - fd6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - if (fd6 != -1) - { - r= connect(fd6, (struct sockaddr *)&host->sin6, - host->socklen); - if (r == 0) - { - host->loc_socklen= - sizeof(host->loc_sin6); - getsockname(fd6, &host->loc_sin6, - &host->loc_socklen); - } - } + host->loc_socklen= sizeof(host->loc_sin6); + getsockname(host->socket, &host->loc_sin6, &host->loc_socklen); - nsent = sendto(fd6, base->packet, host->cursize+ICMP6_HDRSIZE, + nsent = sendto(host->socket, base->packet, + host->cursize+ICMP6_HDRSIZE, MSG_DONTWAIT, (struct sockaddr *)&host->sin6, host->socklen); - t_errno= errno; - close(fd6); - errno= t_errno; } else { @@ -615,28 +594,13 @@ static void ping_xmit(struct pingstate *host) fmticmp4(base->packet, &host->cursize, host->seq, host->index, base->pid); - fd4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - if (fd4 != -1) - { - r= connect(fd4, (struct sockaddr *)&host->sin6, - host->socklen); - if (r == 0) - { - host->loc_socklen= - sizeof(host->loc_sin6); - getsockname(fd4, &host->loc_sin6, - &host->loc_socklen); - } - } + host->loc_socklen= sizeof(host->loc_sin6); + getsockname(host->socket, &host->loc_sin6, &host->loc_socklen); - - nsent = sendto(fd4, base->packet, host->cursize+ICMP_MINLEN, + nsent = sendto(host->socket, base->packet, + host->cursize+ICMP_MINLEN, MSG_DONTWAIT, (struct sockaddr *)&host->sin6, host->socklen); - - t_errno= errno; - close(fd4); - errno= t_errno; } if (nsent > 0) @@ -660,7 +624,8 @@ static void ping_xmit(struct pingstate *host) /* Add the timer to handle no reply condition in the given timeout */ - evtimer_add(&host->ping_timer, &host->base->tv_interval); + msecstotv(host->interval, &tv_interval); + evtimer_add(&host->ping_timer, &tv_interval); } @@ -673,9 +638,7 @@ static void noreply_callback(int __attribute((unused)) unused, const short __att { ping_cb(PING_ERR_TIMEOUT, host->cursize, -1, (struct sockaddr *)&host->sin6, host->socklen, - NULL, 0, - host->seq, -1, &host->base->tv_interval, - host); + NULL, 0, host->seq, -1, NULL, host); /* Update the sequence number for the next run */ host->seq = (host->seq + 1) % 256; @@ -698,29 +661,32 @@ static void noreply_callback(int __attribute((unused)) unused, const short __att static void ready_callback4 (int __attribute((unused)) unused, const short __attribute((unused)) event, void * arg) { - struct pingbase *base = arg; - + struct pingstate *state; + struct pingbase *base; int nrecv, isDup; - struct sockaddr_in remote; /* responding internet address */ + struct sockaddr_in remote; /* responding internet address */ socklen_t slen = sizeof(struct sockaddr); struct sockaddr_in *sin4p; struct sockaddr_in loc_sin4; - - /* Pointer to relevant portions of the packet (IP, ICMP and user data) */ - struct ip * ip = (struct ip *) base->packet; + struct ip * ip; struct icmphdr * icmp; - struct evdata * data = (struct evdata *) (base->packet + IPHDR + ICMP_MINLEN); + struct evdata * data; int hlen = 0; - struct timeval now; - struct pingstate * host; + state= arg; + base = state->base; + + /* Pointer to relevant portions of the packet (IP, ICMP and user + * data) */ + ip = (struct ip *) base->packet; + data = (struct evdata *) (base->packet + IPHDR + ICMP_MINLEN); /* Time the packet has been received */ gettimeofday(&now, NULL); // printf("ready_callback4: before recvfrom\n"); /* Receive data from the network */ - nrecv = recvfrom(base->rawfd4, base->packet, sizeof(base->packet), MSG_DONTWAIT, (struct sockaddr *) &remote, &slen); + nrecv = recvfrom(state->socket, base->packet, sizeof(base->packet), MSG_DONTWAIT, (struct sockaddr *) &remote, &slen); if (nrecv < 0) { goto done; @@ -766,7 +732,8 @@ printf("ready_callback4: too short\n"); } /* Get the pointer to the host descriptor in our internal table */ - host= base->table[data->index]; + if (state != base->table[data->index]) + goto done; /* Not for us */ /* Check for Destination Host Unreachable */ if (icmp->type == ICMP_ECHO) @@ -786,31 +753,31 @@ printf("ready_callback4: too short\n"); memset(sin4p, '\0', sizeof(*sin4p)); sin4p->sin_family= AF_INET; sin4p->sin_addr= ip->ip_dst; - host->rcvd_ttl= ip->ip_ttl; + state->rcvd_ttl= ip->ip_ttl; /* Report everything with the wrong sequence number as a dup. * This is not quite right, it could be a late packet. Do we * care? */ - isDup= (ntohs(icmp->un.echo.sequence) != host->seq); + isDup= (ntohs(icmp->un.echo.sequence) != state->seq); ping_cb(isDup ? PING_ERR_DUP : PING_ERR_NONE, nrecv - IPHDR - ICMP_MINLEN, nrecv, - (struct sockaddr *)&host->sin6, host->socklen, + (struct sockaddr *)&state->sin6, state->socklen, (struct sockaddr *)&loc_sin4, sizeof(loc_sin4), ntohs(icmp->un.echo.sequence), ip->ip_ttl, &elapsed, - host); + state); /* Update the sequence number for the next run */ - host->seq = (host->seq + 1) % 256; + state->seq = (state->seq + 1) % 256; if (!isDup) - host->got_reply= 1; + state->got_reply= 1; } else { printf("ready_callback4: not an echo reply\n"); /* Handle this condition exactly as the request has expired */ - noreply_callback (-1, -1, host); + noreply_callback (-1, -1, state); } done: @@ -831,18 +798,16 @@ done: static void ready_callback6 (int __attribute((unused)) unused, const short __attribute((unused)) event, void * arg) { - struct pingbase *base = arg; + struct pingbase *base; + struct pingstate *state; int nrecv, isDup; struct sockaddr_in remote; /* responding internet address */ - /* Pointer to relevant portions of the packet (IP, ICMP and user data) */ - struct icmp6_hdr * icmp = (struct icmp6_hdr *) base->packet; - struct evdata * data = (struct evdata *) (base->packet + - offsetof(struct icmp6_hdr, icmp6_data16[2])); + struct icmp6_hdr *icmp; + struct evdata * data; struct timeval now; - struct pingstate * host; struct cmsghdr *cmsgptr; struct sockaddr_in6 *sin6p; struct msghdr msg; @@ -850,6 +815,15 @@ static void ready_callback6 (int __attribute((unused)) unused, struct iovec iov[1]; char cmsgbuf[256]; + state= arg; + base = state->base; + + /* Pointer to relevant portions of the packet (IP, ICMP and user + * data) */ + icmp = (struct icmp6_hdr *) base->packet; + data = (struct evdata *) (base->packet + + offsetof(struct icmp6_hdr, icmp6_data16[2])); + /* Time the packet has been received */ gettimeofday(&now, NULL); @@ -864,7 +838,7 @@ static void ready_callback6 (int __attribute((unused)) unused, msg.msg_flags= 0; /* Not really needed */ /* Receive data from the network */ - nrecv= recvmsg(base->rawfd6, &msg, MSG_DONTWAIT); + nrecv= recvmsg(state->socket, &msg, MSG_DONTWAIT); if (nrecv < 0) { goto done; @@ -885,7 +859,8 @@ static void ready_callback6 (int __attribute((unused)) unused, } /* Get the pointer to the host descriptor in our internal table */ - host= base->table[data->index]; + if (state != base->table[data->index]) + goto done; /* Not for us */ /* Check for Destination Host Unreachable */ if (icmp->icmp6_type == ICMP6_ECHO_REPLY) @@ -914,7 +889,7 @@ static void ready_callback6 (int __attribute((unused)) unused, if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) { - host->rcvd_ttl= *(int *)CMSG_DATA(cmsgptr); + state->rcvd_ttl= *(int *)CMSG_DATA(cmsgptr); } } @@ -922,23 +897,23 @@ static void ready_callback6 (int __attribute((unused)) unused, * This is not quite right, it could be a late packet. Do we * care? */ - isDup= (ntohs(icmp->icmp6_seq) != host->seq); + isDup= (ntohs(icmp->icmp6_seq) != state->seq); ping_cb(isDup ? PING_ERR_DUP : PING_ERR_NONE, nrecv - ICMP6_HDRSIZE, nrecv + sizeof(struct ip6_hdr), - (struct sockaddr *)&host->sin6, host->socklen, + (struct sockaddr *)&state->sin6, state->socklen, (struct sockaddr *)&loc_sin6, sizeof(loc_sin6), - ntohs(icmp->icmp6_seq), host->rcvd_ttl, &elapsed, - host); + ntohs(icmp->icmp6_seq), state->rcvd_ttl, &elapsed, + state); /* Update the sequence number for the next run */ - host->seq = (host->seq + 1) % 256; + state->seq = (state->seq + 1) % 256; if (!isDup) - host->got_reply= 1; + state->got_reply= 1; } else /* Handle this condition exactly as the request has expired */ - noreply_callback (-1, -1, host); + noreply_callback (-1, -1, state); done: ; @@ -953,53 +928,18 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], int i, newsiz, delay_name_res; uint32_t opt; unsigned pingcount; /* must be int-sized */ - unsigned size; + unsigned size, interval; sa_family_t af; const char *hostname; char *str_Atlas; char *out_filename; + char *interface; struct pingstate *state; len_and_sockaddr *lsa; FILE *fh; if (!ping_base) { - int p_proto, on; - struct protoent *protop; - evutil_socket_t fd4, fd6; - - /* Check if the ICMP protocol is available on this system */ - protop = getprotobyname("icmp"); - if (protop) - p_proto= protop->p_proto; - else - p_proto= IPPROTO_ICMP; - - /* Create an endpoint for communication using raw socket for ICMP calls */ - if ((fd4 = socket(AF_INET, SOCK_RAW, p_proto)) == -1) { - return NULL; - } - - /* Check if the ICMP6 protocol is available on this system */ - protop = getprotobyname("icmp6"); - if (protop) - p_proto= protop->p_proto; - else - p_proto= IPPROTO_ICMPV6; - - if ((fd6 = socket(AF_INET6, SOCK_RAW, p_proto)) == -1) { - close(fd4); - return NULL; - } - - on = 1; - setsockopt(fd6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, - sizeof(on)); - - on = 1; - setsockopt(fd6, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, - sizeof(on)); - ping_base = malloc(sizeof(*ping_base)); if (ping_base == NULL) return (NULL); @@ -1011,27 +951,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], ping_base->table= xzalloc(ping_base->tabsiz * sizeof(*ping_base->table)); - ping_base->rawfd4 = fd4; - ping_base->rawfd6 = fd6; - evutil_make_socket_nonblocking(ping_base->rawfd4); - evutil_make_socket_nonblocking(ping_base->rawfd6); - /* Set default values */ ping_base->pid = getpid(); - msecstotv(DEFAULT_PING_INTERVAL, &ping_base->tv_interval); - - /* Define the callback to handle ICMP Echo Reply and add the - * raw file descriptor to those monitored for read events */ - event_assign(&ping_base->event4, ping_base->event_base, - ping_base->rawfd4, EV_READ | EV_PERSIST, - ready_callback4, ping_base); - event_assign(&ping_base->event6, ping_base->event_base, - ping_base->rawfd6, EV_READ | EV_PERSIST, - ready_callback6, ping_base); - event_add(&ping_base->event4, NULL); - event_add(&ping_base->event6, NULL); - ping_base->done= 0; } @@ -1040,10 +962,12 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], size= 0; str_Atlas= NULL; out_filename= NULL; + interval= DEFAULT_PING_INTERVAL; + interface= NULL; /* exactly one argument needed; -c NUM */ - opt_complementary = "=1:c+:s+"; + opt_complementary = "=1:c+:s+:i+"; opt = getopt32(argv, PING_OPT_STRING, &pingcount, &size, - &str_Atlas, &out_filename); + &str_Atlas, &out_filename, &interval, &interface); hostname = argv[optind]; if (opt == 0xffffffff) @@ -1052,6 +976,12 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], return NULL; } + if (interval < 1 || interval > 60000) + { + crondlog(LVL8 "bad interval"); + return NULL; + } + if (out_filename) { if (!validate_filename(out_filename, SAFE_PREFIX)) @@ -1078,10 +1008,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], } } - af= AF_UNSPEC; if (opt & opt_4) af= AF_INET; - if (opt & opt_6) + else af= AF_INET6; delay_name_res= !!(opt & opt_r); @@ -1113,6 +1042,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], state->base = ping_base; state->af= af; state->delay_name_res= delay_name_res; + state->interval= interval; + state->interface= interface; + state->socket= -1; state->seq = 1; @@ -1157,7 +1089,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], static void ping_start2(void *state) { + int p_proto, on, fd; struct pingstate *pingstate; + char line[80]; pingstate= state; @@ -1167,6 +1101,98 @@ static void ping_start2(void *state) pingstate->send_error= 0; pingstate->got_reply= 0; + if (pingstate->af == AF_INET) + { + /* Check if the ICMP protocol is available on this system */ + p_proto= IPPROTO_ICMP; + + /* Create an endpoint for communication using raw socket for + * ICMP calls */ + if ((fd = socket(AF_INET, SOCK_RAW, p_proto)) == -1) { + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(socket failed: %s) + " }", strerror(errno)); + add_str(pingstate, line); + report(pingstate); + if (pingstate->base->done) + pingstate->base->done(pingstate); + return; + } + pingstate->socket= fd; + + /* Define the callback to handle ICMP Echo Reply and add the + * raw file descriptor to those monitored for read events */ + event_assign(&pingstate->event, pingstate->base->event_base, + pingstate->socket, EV_READ | EV_PERSIST, + ready_callback4, state); + } + else + { + /* Check if the ICMP6 protocol is available on this system */ + p_proto= IPPROTO_ICMPV6; + + if ((fd = socket(AF_INET6, SOCK_RAW, p_proto)) == -1) { + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(socket failed: %s) + " }", strerror(errno)); + add_str(pingstate, line); + report(pingstate); + if (pingstate->base->done) + pingstate->base->done(pingstate); + return; + } + + on = 1; + setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + sizeof(on)); + + on = 1; + setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + sizeof(on)); + + pingstate->socket= fd; + + /* Define the callback to handle ICMP Echo Reply and add the + * raw file descriptor to those monitored for read events */ + event_assign(&pingstate->event, pingstate->base->event_base, + pingstate->socket, EV_READ | EV_PERSIST, + ready_callback6, state); + } + + evutil_make_socket_nonblocking(pingstate->socket); + + if (pingstate->interface) + { + if (bind_interface(pingstate->socket, pingstate->af, + pingstate->interface) == -1) + { + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" + DBQ(bind to interface failed) + " }"); + add_str(pingstate, line); + report(pingstate); + if (pingstate->base->done) + pingstate->base->done(pingstate); + return; + } + } + + if (connect(pingstate->socket, &pingstate->sin6, + pingstate->socklen) == -1) + { + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(connect failed: %s) + " }", strerror(errno)); + add_str(pingstate, line); + report(pingstate); + if (pingstate->base->done) + pingstate->base->done(pingstate); + return; + } + + event_add(&pingstate->event, NULL); + ping_xmit(pingstate); } diff --git a/eperd/readresolv.c b/eperd/readresolv.c index cd43bd3..0f68a37 100644 --- a/eperd/readresolv.c +++ b/eperd/readresolv.c @@ -110,3 +110,42 @@ void get_local_resolvers(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], *resolv_max = i; return; } + +void get_local_resolvers_nocache(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], + int *resolv_max) +{ + +#ifndef RESOLV_CONF +#define RESOLV_CONF "/etc/resolv.conf" +#endif + FILE *R; + char buf[LINEL]; + char *buf_start; + int i = 0; + int r; + struct stat sb; + + r = stat(RESOLV_CONF, &sb); + if (r == -1) + { + crondlog(LVL8 "error accessing resolv.conf: %s", + strerror(errno)); + return; + } + + R = fopen (RESOLV_CONF, "r"); + if (R != NULL) { + while ( (fgets (buf, LINEL, R)) && (i < MAXNS)) { + buf_start = buf; + if(resolv_conf_parse_line(nslist[i], buf) ) { + crondlog(LVL5 "parsed file %s , line %s i=%d", RESOLV_CONF, buf_start, i); + i++; + } + else + crondlog(LVL5 "ERROR failed to parse from %s i=%d, line %s", RESOLV_CONF, i, buf_start); + } + fclose (R); + } + + *resolv_max = i; +} diff --git a/eperd/readresolv.h b/eperd/readresolv.h index 4c1fa83..b418d71 100644 --- a/eperd/readresolv.h +++ b/eperd/readresolv.h @@ -3,3 +3,5 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ void get_local_resolvers(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], int *resolv_max); +void get_local_resolvers_nocache(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], + int *resolv_max); diff --git a/eperd/sslgetcert.c b/eperd/sslgetcert.c index 2b71cc4..0a0f885 100644 --- a/eperd/sslgetcert.c +++ b/eperd/sslgetcert.c @@ -748,8 +748,9 @@ static void report(struct state *state) { fprintf(fh, DBQ(id) ":" DBQ(%s) ", " DBQ(fw) ":%d, " + DBQ(lts) ":%d, " DBQ(time) ":%ld, ", - state->atlas, get_atlas_fw_version(), + state->atlas, get_atlas_fw_version(), get_timesync(), state->gstart); } @@ -977,8 +978,10 @@ static int eat_certificate(struct state *state) if (state->atlas) { fprintf(fh, DBQ(id) ":" DBQ(%s) - ", " DBQ(fw) ":%d", - state->atlas, get_atlas_fw_version()); + ", " DBQ(fw) ":%d" + ", " DBQ(lts) ":%d", + state->atlas, get_atlas_fw_version(), + get_timesync()); } fprintf(fh, "%s" DBQ(time) ":%ld", @@ -1260,7 +1263,7 @@ static void sslgetcert_start(void *vstate) tu_connect_to_name(&state->tu_env, state->hostname, state->portname, - &interval, &hints, timeout_callback, + &interval, &hints, NULL, timeout_callback, reporterr, dnscount, beforeconnect, connected, readcb, writecb); } diff --git a/eperd/tcputil.c b/eperd/tcputil.c index d3d6134..355f42a 100644 --- a/eperd/tcputil.c +++ b/eperd/tcputil.c @@ -13,12 +13,13 @@ #include "tcputil.h" static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx); -static void create_bev(struct tu_env *env); +static int create_bev(struct tu_env *env); static void eventcb(struct bufferevent *bev, short events, void *ptr); void tu_connect_to_name(struct tu_env *env, char *host, char *port, struct timeval *interval, struct evutil_addrinfo *hints, + char *infname, void (*timeout_callback)(int unused, const short event, void *s), void (*reporterr)(struct tu_env *env, enum tu_err cause, const char *err), @@ -30,6 +31,7 @@ void tu_connect_to_name(struct tu_env *env, char *host, char *port, void (*writecb)(struct bufferevent *bev, void *ptr)) { env->interval= *interval; + env->infname= infname; env->reporterr= reporterr; env->reportcount= reportcount; env->beforeconnect= beforeconnect; @@ -49,6 +51,7 @@ void tu_connect_to_name(struct tu_env *env, char *host, char *port, void tu_restart_connect(struct tu_env *env) { + int r; struct bufferevent *bev; /* Delete old bev */ @@ -59,7 +62,11 @@ void tu_restart_connect(struct tu_env *env) } /* And create a new one */ - create_bev(env); + r= create_bev(env); + if (r == -1) + { + return; + } bev= env->bev; /* Connect failed, try next address */ @@ -118,7 +125,7 @@ void tu_cleanup(struct tu_env *env) static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) { - int count; + int r, count; struct tu_env *env; struct bufferevent *bev; struct evutil_addrinfo *cur; @@ -151,7 +158,11 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) env->reportcount(env, count); - create_bev(env); + r= create_bev(env); + if (r == -1) + { + return; + } while (env->dns_curr) { @@ -192,21 +203,44 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) env->reporterr(env, TU_OUT_OF_ADDRS, ""); } -static void create_bev(struct tu_env *env) +static int create_bev(struct tu_env *env) { + int af, fd; struct bufferevent *bev; + af= env->dns_curr->ai_addr->sa_family; + bev= bufferevent_socket_new(EventBase, -1, BEV_OPT_CLOSE_ON_FREE); if (!bev) { crondlog(DIE9 "bufferevent_socket_new failed"); } + if (env->infname) + { + fd= socket(af, SOCK_STREAM, 0); + if (fd == -1) + { + env->reporterr(env, TU_SOCKET_ERR, + "socket call failed"); + return -1; + } + + if (bind_interface(fd, af, env->infname) == -1) + { + env->reporterr(env, TU_SOCKET_ERR, + "bind_interface failed"); + close(fd); + return -1; + } + bufferevent_setfd(bev, fd); + } bufferevent_setcb(bev, env->readcb, env->writecb, eventcb, env); bufferevent_enable(bev, EV_WRITE); env->bev= bev; env->connecting= 1; + return 0; } static void eventcb(struct bufferevent *bev, short events, void *ptr) diff --git a/eperd/tcputil.h b/eperd/tcputil.h index d2b11ec..da26641 100644 --- a/eperd/tcputil.h +++ b/eperd/tcputil.h @@ -6,7 +6,8 @@ #include -enum tu_err { TU_DNS_ERR, TU_READ_ERR, TU_CONNECT_ERR, TU_OUT_OF_ADDRS }; +enum tu_err { TU_DNS_ERR, TU_READ_ERR, TU_SOCKET_ERR, TU_CONNECT_ERR, + TU_OUT_OF_ADDRS }; struct tu_env { char dnsip; @@ -15,6 +16,7 @@ struct tu_env struct evutil_addrinfo *dns_curr; struct bufferevent *bev; struct timeval interval; + char *infname; struct event timer; void (*reporterr)(struct tu_env *env, enum tu_err cause, const char *str); @@ -29,6 +31,7 @@ struct tu_env void tu_connect_to_name(struct tu_env *env, char *host, char *port, struct timeval *timeout, struct evutil_addrinfo *hints, + char *infname, void (*timeout_callback)(int unused, const short event, void *env), void (*reporterr)(struct tu_env *env, enum tu_err cause, const char *err), 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; diff --git a/include/applets.h b/include/applets.h index 128d8d9..829ba14 100644 --- a/include/applets.h +++ b/include/applets.h @@ -320,7 +320,7 @@ USE_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, USE_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_RPTRA6(APPLET(rptra6, _BB_DIR_BIN, _BB_SUID_NEVER)) -USE_RPTADDR6(APPLET(rptaddr6, _BB_DIR_BIN, _BB_SUID_NEVER)) +USE_RPTADDRS(APPLET(rptaddrs, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_RTCWAKE(APPLET(rtcwake, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, _BB_DIR_BIN, _BB_SUID_NEVER, run_parts)) diff --git a/include/libbb.h b/include/libbb.h index d5c3178..598e74e 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -314,6 +314,8 @@ extern char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC; extern int validate_filename(const char *path, const char *prefix); extern int validate_atlas_id(const char *atlas_id); extern int get_probe_id(void); +extern int get_timesync(void); +extern int bind_interface(int socket, int af, char *name); int ndelay_on(int fd) FAST_FUNC; int ndelay_off(int fd) FAST_FUNC; diff --git a/include/usage.h b/include/usage.h index ea3b78b..c4953bc 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1062,8 +1062,8 @@ #define evtraceroute_trivial_usage \ "-[46FIrTU] [-a ] [-c ] [-f ]" \ -"\n [-g ] [-m ] [-p ] [-w ] [-z ] [-A ] [-O ]" \ -"\n [-S ]" +"\n [-g ] [-m ] [-p ] [-w ] [-z ] [-A ]" \ +"\n [-O ] [-S ] [-H ] [-D ]" #define evtraceroute_full_usage "\n" \ "\n -4 Use IPv4 (default)" \ @@ -1082,6 +1082,8 @@ "\n -w No reply timeout (ms)" \ "\n -z Dup timeout (ms)" \ "\n -A Atlas measurement ID" \ + "\n -D Add IPv6 Destination Option this size" \ + "\n -H Add IPv6 Hop-by-hop Option this size" \ "\n -O Name of output file" \ "\n -S Size of packet" \ @@ -3569,11 +3571,11 @@ #define rpm2cpio_full_usage "\n\n" \ "Output a cpio archive of the rpm file" -#define rptra6_trivial_usage \ +#define rptaddrs_trivial_usage \ -#define rptaddr6_full_usage "\n\n" \ +#define rptaddrs_full_usage "\n\n" \ -#define rptaddr6_trivial_usage \ +#define rptra6_trivial_usage \ #define rptra6_full_usage "\n\n" \ diff --git a/libbb/Kbuild b/libbb/Kbuild index 178347d..0b77f72 100644 --- a/libbb/Kbuild +++ b/libbb/Kbuild @@ -10,6 +10,7 @@ lib-y += appletlib.o lib-y += ask_confirmation.o lib-y += atlas_bb64.o lib-y += atlas_probe.o +lib-y += atlas_timesync.o lib-y += bb_askpass.o lib-y += bb_basename.o lib-y += bb_do_delay.o @@ -17,6 +18,7 @@ lib-y += bb_pwd.o lib-y += bb_qsort.o lib-y += bb_strtod.o lib-y += bb_strtonum.o +lib-y += bind_interface.o lib-y += change_identity.o lib-y += chomp.o lib-y += compare_string_array.o diff --git a/libbb/atlas_timesync.c b/libbb/atlas_timesync.c new file mode 100644 index 0000000..3434493 --- /dev/null +++ b/libbb/atlas_timesync.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2013 RIPE NCC + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +int get_timesync(void) +{ + FILE *fh; + int lastsync; + + fh= fopen(ATLAS_TIMESYNC_FILE, "r"); + if (!fh) + return -1; + fscanf(fh, "%d", &lastsync); + fclose(fh); + return time(NULL)-lastsync; +} + diff --git a/libbb/bind_interface.c b/libbb/bind_interface.c new file mode 100644 index 0000000..1eb4414 --- /dev/null +++ b/libbb/bind_interface.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 RIPE NCC + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" + +int bind_interface(int socket, int af, char *name) +{ + struct sockaddr_storage sa; + + memset(&sa, '\0', sizeof(sa)); + + if (af == AF_INET) + { + sa.ss_family= AF_INET; + if (inet_pton(af, name, + &((struct sockaddr_in *)&sa)->sin_addr) == 1) + { + return bind(socket, (struct sockaddr *)&sa, + sizeof(sa)); + } + } + else + { + sa.ss_family= AF_INET6; + if (inet_pton(af, name, + &((struct sockaddr_in6 *)&sa)->sin6_addr) == 1) + { + return bind(socket, (struct sockaddr *)&sa, + sizeof(sa)); + } + } + if (setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, name, + strlen(name)+1) == -1) + { + return -1; + } + + return 0; +} + diff --git a/networking/Config.in b/networking/Config.in index cdf067a..84c89ad 100644 --- a/networking/Config.in +++ b/networking/Config.in @@ -705,11 +705,11 @@ config RPTRA6 help Report received IPv6 router advertisements -config RPTADDR6 - bool "rptaddr6" +config RPTADDRS + bool "rptaddrs" default n help - Report IPv6 addresses and routes + Report addresses, routes, dns both static and dynamic config RXTXRPT bool "rxtxrpt" diff --git a/networking/Kbuild b/networking/Kbuild index ddb143a..d550ed4 100644 --- a/networking/Kbuild +++ b/networking/Kbuild @@ -32,7 +32,7 @@ lib-$(CONFIG_PING6) += ping.o lib-$(CONFIG_PSCAN) += pscan.o lib-$(CONFIG_ROUTE) += route.o lib-$(CONFIG_RPTRA6) += rptra6.o -lib-$(CONFIG_RPTADDR6) += rptaddr6.o +lib-$(CONFIG_RPTADDRS) += rptaddrs.o lib-$(CONFIG_RXTXRPT) += rxtxrpt.o lib-$(CONFIG_SLATTACH) += slattach.o lib-$(CONFIG_SSLGETCERT) += sslgetcert.o diff --git a/networking/atlasinit.c b/networking/atlasinit.c new file mode 100644 index 0000000..121b508 --- /dev/null +++ b/networking/atlasinit.c @@ -0,0 +1,740 @@ +/* RIPEAtlas + * All the configurable variables - and some non configurables too + * Usage1: ./init_resp_parse < init_messagefile + * Usage2: ./init_resp_parse init_messagefile + * $Id: $ + */ + + +#include +#include +#include +#include +#include "atlasinit.h" + +//#ifndef NOTBUSYBOX +/* compiled to busybox. tested on 1.13 */ +#include "libbb.h" +//#endif + +#define ERROR 1 +#define INFO 2 +#define ATLAS_DEFAULT_WAIT 100 +#define OPT_STRING "rcdsi:I:" +#define ATLAS_WAIT 0 + +enum +{ + OPT_REG_INIT = (1 << 0), /* r */ + OPT_CNT_INIT = (1 << 1), /* c */ + OPT_CNT_HELLO = (1 << 2), /* d */ + OPT_SINCELAST = (1 << 3), /* s */ + OPT_P_TO_R_INIT = (1 << 4), /* i */ +}; + +#define DBQ(str) "\"" #str "\"" + +/********************************************************************* + * Set these constants to your liking + */ +static int read_wait (FILE *read_from, const char *type, int waittime); +static int reg_init_main( int argc, char *argv[] ); +static int con_hello_main( int argc, char *argv[] ); +static int con_init_main( int argc, char *argv[] ); +static void since_last_main (int argc, char *argv[]); +static void print_token_ver (FILE * write_to, int flag_rereg); + +const char atlas_log_file[]="./probe.log"; +const int atlas_log_level=INFO; + +const char atlas_contr_known_hosts[]="./known_hosts_controllers"; +const char atlas_rereg_timestamp[]="./rereg_time.sh"; +const char atlas_con_hello[]="./con_hello.txt"; +const char atlas_con_session_id[]="./con_session_id.txt"; +const char atlas_force_reg[] = "./force_reg.sh"; +const char atlas_netconfig_v4[] = "./netconfig_v4.vol"; +const char atlas_netconfig_v6[] = "./netconfig_v6.vol"; +const char atlas_resolv_conf[] = "./resolv.conf.vol"; +const char atlas_network_v4_info[] = "/home/atlas/status/network_v4_info.txt"; +const char atlas_network_v4_static_info[] = "/home/atlas/status/network_v4_static_info.txt"; +const char atlas_network_v4_static_info_json[] = "/home/atlas/status/network_v4_static_info.json"; +const char atlas_network_v6_static_info[] = "/home/atlas/status/network_v6_static_info.txt"; +const char atlas_network_v6_static_info_json[] = "/home/atlas/status/network_v6_static_info.json"; +const char atlas_network_dns_static_info[] = "/home/atlas/status/network_dns_static_info.txt"; +const char atlas_network_dns_static_info_json[] = "/home/atlas/status/network_dns_static_info.json"; + +const int max_lines = 16; /* maximum lines we'll process */ +const int min_rereg_time = 100; +const int max_rereg_time = 28*24*3600; /* 28d */ +const int default_rereg_time = 7*24*3600; /* 7d */ +char *str_reason; +const char *str_device; + +/**********************************************************************/ + +static char line[ATLAS_BUF_SIZE]; + +#ifdef NOTBUSYBOX +int main( int argc, char *argv[] ) +#else +int atlasinit_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int atlasinit_main( int argc, char *argv[] ) +#endif +{ + int opt = 0; + + if(argc > 1) + { + str_device= NULL; + opt = getopt32(argv, OPT_STRING, &str_reason, &str_device); + argv += optind; + argc -= optind; + argc++; // AA Hack + } + else + { // AA improve + // we are called without an option decide which is default + reg_init_main( argc, argv); + } + + if(opt & OPT_REG_INIT) + { + reg_init_main( argc, argv); + } + else if(opt & OPT_CNT_HELLO) + { + con_hello_main(argc, argv); + } + else if ( opt & OPT_CNT_INIT) + { + con_init_main(argc, argv); + + } + else if (opt & OPT_SINCELAST) + { + since_last_main(argc, argv); + } + else if(opt & OPT_P_TO_R_INIT) + { + print_token_ver(stdout, 1); + } + + return 0; +} + +static void print_token_ver (FILE * write_to, int flag_rereg) +{ +float root_fs_ver = 0; +FILE *fp = xfopen_for_read("/proc/version"); +FILE *fpv = fopen("/home/atlas/state/FIRMWARE_APPS_VERSION", "r"); + char *my_mac ; + +bzero( line, ATLAS_BUF_SIZE ); +fscanf (fp, "%s", line); +fscanf (fp, "%s", line); +fscanf (fp, "%s", line); +if(fpv) + fscanf (fpv, "%f", &root_fs_ver); + else + root_fs_ver=3100; + if(flag_rereg > 0) + fprintf(write_to, "P_TO_R_INIT\n"); + my_mac = getenv("ETHER_SCANNED"); + fprintf(write_to, "TOKEN_SPECS probev1 %s", line); + if (my_mac != NULL) + fprintf(write_to, "-%s ", my_mac ); + fprintf(write_to, " %d\n", (int)root_fs_ver); + if(flag_rereg > 0) + fprintf(write_to, "REASON_FOR_REGISTRATION %s\n", str_reason); + fclose(fp); +} + +static void since_last_main (int argc, char *argv[]) +{ + FILE *thenfile; + int then; + time_t mytime; + + mytime = time(0); + + if ( argc == 1) { + printf("%d\n", (int)mytime); + } + else { + if ((thenfile = fopen(argv[0], "r")) == NULL) { + printf("%d\n", (int)mytime); + } + else { + fscanf(thenfile, "%d", &then); + printf("%d\n", (int)(mytime - then)); + } + } +} + +static int con_hello_main( int argc, char *argv[] ) +{ + /* read response from P_TO_C_HELLO */ + FILE *read_from = stdin; + int ret = 0; + long tmp_long; + + time_t mytime = time(0); + time_t con_time; + if( argc > 1 ) { + read_from = fopen( argv[0], "rt" ); + if( read_from==NULL ) { + atlas_log( ERROR, "Cannot read from file %s\n", argv[1] ); + return 1; + } + } + /* read OK */ + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + + if( strncmp(line,"OK\n",3) == 0 ) { + int l=1; + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + while( !feof(read_from) && l<=max_lines ) { + if( strncmp(line,"CONTROLLER_TIMESTAMP ", 21)==0 ) { + int timediff2 ; + + sscanf( line+21, "%ld", &tmp_long); + con_time= tmp_long; + timediff2 = ( mytime - con_time ) * ( mytime - con_time ); + printf ("Mytime %d controller time %d\n",(int)mytime , (int)con_time); + if( timediff2 > 4 ) { + struct timeval tval; + + atlas_log( INFO, "Time difference is %d seconds, set time ?\n", timediff2); + printf ("Set mytime \n"); + tval.tv_sec = con_time; + tval.tv_usec = 0; + settimeofday( &tval, NULL); + } + + } + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + l++; + } + } + else { + fprintf (stderr, "P_TO_C_HELLO response is unexptedte %s\n", line); + } + + if (argc > 1 ) + fclose (read_from); + return ret; +} +static int con_init_main( int argc, char *argv[] ) +{ + FILE *read_from = stdin; + int ret = 0; + + int remote_port; + if( argc > 1 ) { + read_from = fopen( argv[0], "rt" ); + if( read_from==NULL ) { + atlas_log( ERROR, "Cannot read from file %s\n", argv[1] ); + return 1; + } + } + /* read OK */ + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + + if( strncmp(line,"OK\n",3) == 0 ) { + int l=1; + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + while( !feof(read_from) && l<=max_lines ) { + if( strncmp(line,"REMOTE_PORT", 11)==0 ) { + sscanf( line+11, "%d", &remote_port); + printf ("REMOTE_PORT=%d\n", remote_port); + } + else if ( strncmp(line,"SESSION_ID", 10)==0 ) + { + FILE *f = fopen( atlas_con_hello, "wt" ); + FILE *f1 = fopen( atlas_con_session_id, "wt" ); + + fprintf (f, "P_TO_C_HELLO\nSESSION_ID %s", line+11); + fprintf (f1, "\nSESSION_ID %s\n", line+11); + print_token_ver (f, 0 ); + fclose (f); + fclose (f1); + + } + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + l++; + } + } + else if (strncmp(line,"WAIT\n",5) == 0 ) + { + read_wait(read_from, "CON_WAIT_TIMER", ATLAS_WAIT); + } + else if (strncmp(line,"REFUSED\n",8) == 0 ) + { + FILE *f = fopen( atlas_force_reg, "wt" ); + + unlink(atlas_con_hello); + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + fprintf (f,"REASON=%s\n", line+8); + fclose(f); + + } + else { + char *p = strchr(line,'\n'); + if( p!=NULL ) *p = '\0'; + atlas_log( ERROR, "OK expected, got \"%s\" instead\n", line ); + read_wait(read_from, "CON_WAIT_TIMER", ATLAS_DEFAULT_WAIT); /* we got error the only action from probe is wait. so force it*/ + ret = 1; + } + + if (argc > 1 ) + fclose (read_from); + return ret; + +} +static int read_wait (FILE *read_from, const char *type, int waittime) +{ + unsigned delay; + time_t mytime = time(0); + if(waittime < 1) + { + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + if( strncmp(line,"TIMEOUT", 7)==0 ) { + sscanf( line+7, "%d", &delay); + } + else + { + delay = ATLAS_DEFAULT_WAIT; + } + } + else + { + delay = waittime; + } + mytime = time(0); + if(delay > max_rereg_time ) { + atlas_log( ERROR, "Reregister time %d is too high\n", delay ); + delay = max_rereg_time; + } + if(delay < min_rereg_time ) { + atlas_log( ERROR, "Reregister time %d is too high\n", delay ); + delay = min_rereg_time; + } + printf ("%s=%u\n", type, (uint)(mytime + delay)); + return (delay); +} + +static int reg_init_main( int argc, char *argv[] ) +{ + + time_t mytime; + FILE *read_from = stdin; + + char *token; + const char *search = " "; + const char *search_nl = " \n"; + int ret = 0; + int first; + + int reregister_time = default_rereg_time; + mytime = time(NULL); + + if (!str_device) + str_device= "eth0"; + + if( argc >1 ) { + read_from = fopen( argv[0], "rt" ); + if( read_from==NULL ) { + atlas_log( ERROR, "Cannot read from file %s\n", argv[1] ); + return 1; + } + } + + /* read OK */ + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + + if( strncmp(line,"OK\n",3) == 0 ) { + int l=1; + int n_controller = 0; + char *host_name; + char *type; + char *key; + int do_rm_v4_static_info; + int do_rm_v6_static_info; + int do_rm_dns_static_info; + + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + + do_rm_v4_static_info= 1; + do_rm_v6_static_info= 1; + do_rm_dns_static_info= 1; + while( !feof(read_from) && l<=max_lines ) { + if( strncmp(line,"CONTROLLER ", 11)==0 ) { + FILE *f; + char *ptr; + + n_controller++; + /* TODO: one can check whether it's about the right length and syntax */ + + ptr = strchr( line+11, ' ' ); + if( ptr==NULL ) { + atlas_log( ERROR, "CONTROLLER line is suspicious (line %d)\n", l ); + return 1; + } + f = fopen( atlas_contr_known_hosts, "wt" ); + if( f==NULL ) { + atlas_log( ERROR, "Unable to append to file %s\n", atlas_contr_known_hosts ); + return 1; + } + //fprintf( f, "%s\n", line+11 ); + token = strtok(line+11, search); + /* host name */ + printf ("CONTROLLER_%d_HOST=%s\n", n_controller, token); + fprintf( f, "%s ", token); + host_name = token; + + token = strtok(NULL, search); + printf ("CONTROLLER_%d_PORT=%s\n", n_controller, token); + token = strtok(NULL, search); + fprintf( f, "%s ", token); + type = token; + token = strtok(NULL, search); + fprintf( f, "%s\n", token); + key = token; + fprintf (f, "ipv4.%s %s %s\n", host_name, type, key); + fprintf (f, "ipv6.%s %s %s\n", host_name, type, key); + fclose(f); + + } + else if( strncmp(line,"REREGISTER ", 11)==0 ) + { + sscanf( line+11, "%d", &reregister_time ); + read_wait(read_from, "REREG_TIMER", reregister_time); + + } + else if( strncmp(line,"REGSERVER_TIMESTAMP ", 20)==0 ) { + int regserver_time; + int timediff2 ; + + sscanf( line+20, "%d", ®server_time ); + timediff2 = ( mytime - regserver_time ) * ( mytime - regserver_time ); + if( timediff2 > 4 ) { + struct timeval tval; + + atlas_log( INFO, "Time difference is %d seconds, what to do now?\n", (int)(mytime-regserver_time) ); + + tval.tv_sec = regserver_time; + tval.tv_usec = 0; + settimeofday( &tval, NULL); + } + } + else if( strncmp(line,"FIRMWARE_KERNEL ", 16)==0 ) + { + unsigned root_fs_ver = 0; + token = strtok (line+16, search); // version + sscanf (token, "%u", &root_fs_ver); + printf("FIRMWARE_KERNEL_VERSION=%u\n", + root_fs_ver); + token = strtok(NULL, search); // alg + printf("FIRMWARE_KERNEL_CS_ALG=%s\n", token); + + token = strtok(NULL, search); // comp hash + printf("FIRMWARE_KERNEL_CS_COMP=%s\n", token); + + token = strtok(NULL, search); // uncomp hash + + printf("FIRMWARE_KERNEL_CS_UNCOMP=%s\n", token); + token = strtok(NULL, search); // url hash + printf( "FIRMWARE_KERNEL=%s\n", token) ; + + } + else if( strncmp(line,"FIRMWARE_APPS ", 14)==0 ) + { + unsigned root_fs_ver = 0; + token = strtok (line+14, search); // version + sscanf (token, "%u", &root_fs_ver); + printf("FIRMWARE_APPS_VERSION=%u\n", + root_fs_ver); + token = strtok(NULL, search); // alg + printf("FIRMWARE_APPS_CS_ALG=%s\n", token); + + token = strtok(NULL, search); // comp hash + printf("FIRMWARE_APPS_CS_COMP=%s\n", token); + + token = strtok(NULL, search); // uncomp hash + + printf("FIRMWARE_APPS_CS_UNCOMP=%s\n", token); + token = strtok(NULL, search); // url hash + printf( "FIRMWARE_APPS=%s\n", token) ; + + } + + else if( strncmp(line,"DHCPV4 False ", 13)==0 ) + { + FILE *f = fopen(atlas_netconfig_v4, "wt"); + char *ipv4_address; + char *netmask; + char *broadcast; + char *ipv4_gw; + + if( f==NULL ) { + atlas_log( ERROR, "Unable to create %s\n", atlas_netconfig_v4 ); + return 1; + } + + // Statically configured probe. +//DHCPV4 False IPV4ADDRESS 10.0.0.151 IPV4NETMASK 255.255.255.0 IPV4NETWORK 10.0.0.0 IPV4BROADCAST 10.0.0.255 IPV4GATEWAY 10.0.0.137 + // fprintf (f, "%s\n", line); + token = strtok(line+13, search); //IPV4ADDRESS + token = strtok(NULL, search); //
+ fprintf (f, "/sbin/ifconfig %s 0.0.0.0\n", + str_device); + fprintf (f, "/sbin/ifconfig %s:1 %s ", + str_device, token); + ipv4_address = token; + token = strtok(NULL, search); // IPV4NETMASK + token = strtok(NULL, search); // + fprintf (f, "netmask %s ", token); + netmask = token; + token = strtok(NULL, search); // IPV4NETWORK + token = strtok(NULL, search); // + token = strtok(NULL, search); // IPV4BROADCAST + token = strtok(NULL, search); // + fprintf (f, "broadcast %s \n", token); + broadcast = token; + token = strtok(NULL, search); // IPV4GATEWAY + token = strtok(NULL, search); // + fprintf (f, "/sbin/route add default gw %s\n", token); + ipv4_gw = token; + ipv4_gw[(strlen(ipv4_gw) - 1)] = '\0'; + + // put parts in the shell script to make network info file + + fprintf (f, "echo \"P_TO_C_NETWORK_UPDATE\" > %s \n", atlas_network_v4_info ); + fprintf (f, "echo \"IPV4_LOCAL_ADDR %s\" >> %s \n", ipv4_address, atlas_network_v4_info ); + fprintf (f, "echo \"IPV4_NETMASK %s\" >> %s \n", netmask, atlas_network_v4_info ); + fprintf (f, "echo \"IPV4_BROADCAST %s\" >> %s \n", broadcast, atlas_network_v4_info ); + fprintf (f, "echo \"IPV4_GW %s\" >> %s \n",ipv4_gw , atlas_network_v4_info ); + fprintf (f, "echo \"DHCP False \" >> %s \n", atlas_network_v4_info ); + + + // second file for static + fprintf (f, "echo \"STATIC_IPV4_LOCAL_ADDR %s\" > %s \n", ipv4_address, atlas_network_v4_static_info ); + fprintf (f, "echo \"STATIC_IPV4_NETMASK %s\" >> %s \n", netmask, atlas_network_v4_static_info ); + fprintf (f, "echo \"STATIC_IPV4_BROADCAST %s\" >> %s \n", broadcast, atlas_network_v4_static_info ); + fprintf (f, "echo \"STATIC_IPV4_GW %s\" >> %s \n",ipv4_gw , atlas_network_v4_static_info ); + fprintf(f, "echo '" + DBQ(static-inet-addresses) " : [ { " + DBQ(inet-addr) ": " DBQ(%s) ", " + DBQ(netmask) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) + " } ], " + DBQ(static-inet-routes) " : [ { " + DBQ(destination) ": " DBQ(0.0.0.0) ", " + DBQ(netmask) ": " DBQ(0.0.0.0) ", " + DBQ(next-hop) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) + " } ]' > %s\n", + ipv4_address, + netmask, + str_device, + ipv4_gw, + str_device, + atlas_network_v4_static_info_json); + // ping the gateway + fprintf (f, "ping -c 2 -q %s \n", ipv4_gw); + fprintf (f, "IPV4_GW=%s; export IPV4_GW\n", ipv4_gw); + + fclose(f); + + do_rm_v4_static_info= 0; + } + //DHCPV6 False IPV6ADDRESS
IPV6PREFIXLEN IPV6GATEWAY ]| [DHCPV6 True ] + else if( strncmp(line,"DHCPV6 False ", 13)==0 ) + { + FILE *f = fopen(atlas_netconfig_v6, "wt"); + char *ipv6_address; + char *prefixlen; + char *ipv6_gw; + + if( f==NULL ) { + atlas_log( ERROR, "Unable to create %s\n", atlas_netconfig_v6 ); + return 1; + } + + // Statically configured probe. + + //fprintf (f, "%s\n", line); + token = strtok(line+13, search); //IPV6ADDRESS + token = strtok(NULL, search); //
+ ipv6_address = token; + token = strtok(NULL, search); // IPV6PREFIXLEN + token = strtok(NULL, search); // + prefixlen = token; + fprintf (f, "/sbin/ifconfig %s 0.0.0.0\n", + str_device); + fprintf (f, "/sbin/ifconfig %s %s/%s\n", + str_device, ipv6_address, prefixlen); + + token = strtok(NULL, search); // IPV6GATEWAY + token = strtok(NULL, search); // + ipv6_gw = token; + ipv6_gw[(strlen(ipv6_gw) - 1)] = '\0'; + ///sbin/route -A inet6 add default gw fe80::13:0:0:1 dev eth0 + fprintf (f, + "/sbin/route -A inet6 add default gw %s dev %s\n", + ipv6_gw, str_device); + // second file for static network info + fprintf (f, "echo \"STATIC_IPV6_LOCAL_ADDR %s/%s\" > %s \n", ipv6_address, prefixlen, atlas_network_v6_static_info ); + fprintf (f, "echo \"STATIC_IPV6_GW %s\" >> %s \n",ipv6_gw , atlas_network_v6_static_info ); + + fprintf(f, "echo '" + DBQ(static-inet6-addresses) ": [ { " + DBQ(inet6-addr) ": " DBQ(%s) ", " + DBQ(prefix-length) ": %s, " + DBQ(interface) ": " DBQ(%s) " } ], " + DBQ(static-inet6-routes) ": [ { " + DBQ(destination) ": " DBQ(::) ", " + DBQ(prefix-length) " : 0, " + DBQ(next-hop) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) " } ]" + "' > %s\n", + ipv6_address, prefixlen, str_device, + ipv6_gw, str_device, + atlas_network_v6_static_info_json); + + + fclose(f); + do_rm_v6_static_info= 0; + } + else if( strncmp(line,"DNS_SERVERS ", 11)==0 ) + { + FILE *f, *f1, *f2; + + f = fopen(atlas_resolv_conf, "wt"); + if( f==NULL ) { + atlas_log(ERROR, + "Unable to create %s\n", + atlas_resolv_conf ); + return 1; + } + + f1 = fopen(atlas_network_dns_static_info, "wt"); + if( f1==NULL ) { + atlas_log(ERROR, + "Unable to create %s\n", + atlas_network_dns_static_info); + fclose(f); + return 1; + } + f2 = fopen(atlas_network_dns_static_info_json, + "wt"); + if( f2==NULL ) { + atlas_log(ERROR, + "Unable to create %s\n", + atlas_network_dns_static_info_json); + fclose(f); + fclose(f1); + return 1; + } + + + // Statically configured probe. + //DNS_SERVERS 8.8.8.8 194.109.6.66 + // fprintf (f, "%s\n", line); + token = strtok(line+11, search_nl); // + fprintf (f1, "STATIC_DNS"); + fprintf(f2, DBQ(static-dns) ": [ "); + + first= 1; + while (token != NULL) + { + fprintf (f, "nameserver %s\n", token); + fprintf (f1, " %s", token); + fprintf(f2, "%s{ " DBQ(nameserver) ": " + DBQ(%s) " }", + first ? "" : ", ", token); + token = strtok(NULL, search_nl); + first= 0; + } + fprintf (f1, "\n"); + fprintf(f2, " ]\n"); + + fclose(f); + fclose(f1); + fclose(f2); + + do_rm_dns_static_info= 0; + } + else if( strncmp(line,"FIRMWARE_KERNEL ", 16)==0 ) + { + } + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + l++; + } + if(do_rm_v4_static_info) + { + // delete the static configuration + unlink(atlas_netconfig_v4); + unlink(atlas_network_v4_static_info); + unlink(atlas_network_v4_static_info_json); + } + if(do_rm_v6_static_info) + { + // delete the static configuration + unlink(atlas_netconfig_v6); + unlink(atlas_network_v6_static_info); + unlink(atlas_network_v6_static_info_json); + } + if (do_rm_dns_static_info) + { + unlink(atlas_network_dns_static_info); + unlink(atlas_network_dns_static_info_json); + } + } + else if (strncmp(line,"WAIT\n",5) == 0 ) + { + read_wait(read_from, "REG_WAIT_UNTIL", ATLAS_WAIT ); + + } + else { + char *p = strchr(line,'\n'); + if( p!=NULL ) *p = '\0'; + atlas_log( ERROR, "OK expected, got \"%s\" instead\n", line ); + read_wait(read_from, "REG_WAIT_UNTIL", ATLAS_DEFAULT_WAIT); /* we got error the only action from probe is wait. so force it*/ + ret = 1; + } + return ret; +} + + +void atlas_log( int level UNUSED_PARAM, const char *msg UNUSED_PARAM, ... ) +{ +/* + if( atlas_log_level<=level ) + { + va_list arg; + va_start ( arg, msg ); + + FILE *lf = fopen( atlas_log_file, "at" ); + if( lf==NULL ) + return; // not much we can do + + fprintf( lf, "%d\t%d\t", (int)time(NULL), level ); + vfprintf( lf, msg, arg ); + fclose(lf); + + va_end( arg ); + } +*/ +} diff --git a/networking/rptaddrs.c b/networking/rptaddrs.c new file mode 100644 index 0000000..1115559 --- /dev/null +++ b/networking/rptaddrs.c @@ -0,0 +1,775 @@ +/* + * rptaddrs.c + * Copyright (c) 2013 RIPE NCC + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../eperd/eperd.h" +#include "../eperd/readresolv.h" + +#include "libbb.h" + +#define IPV4_ROUTE_FILE "/proc/net/route" +#define IF_INET6_FILE "/proc/net/if_inet6" +#define IPV6_ROUTE_FILE "/proc/net/ipv6_route" +#define SUFFIX ".new" + +#define IPV4_STATIC ATLAS_STATUS "/network_v4_static_info.json" +#define IPV6_STATIC ATLAS_STATUS "/network_v6_static_info.json" +#define DNS_STATIC ATLAS_STATUS "/network_dns_static_info.json" +#define NETWORK_INFO ATLAS_STATUS "/network_info.txt" + +#define SAFE_PREFIX_N ATLAS_DATA_NEW + +#define OPT_STRING "A:O:c:" + +#define DBQ(str) "\"" #str "\"" +#define JS(key, val) fprintf(fh, "\"" #key"\" : \"%s\" , ", val); +#define JS1(key, fmt, val) fprintf(fh, "\"" #key"\" : "#fmt" , ", val); + +#ifndef IPV6_MASK +#define IPV6_MASK (RTF_GATEWAY|RTF_HOST|RTF_DEFAULT|RTF_ADDRCONF|RTF_CACHE) +#endif + +#define IPV6_ADDR_LOOPBACK 0x0010U +#define IPV6_ADDR_LINKLOCAL 0x0020U +#define IPV6_ADDR_SITELOCAL 0x0040U + +#define IPV6_ADDR_COMPATv4 0x0080U + +#define IPV6_ADDR_SCOPE_MASK 0x00f0U + +enum { + OPT_a = (1 << 0), +}; + +static FILE *setup_cache(char *cache_name); +static int setup_ipv4_rpt(FILE *of); +static int setup_dhcpv4(FILE *of); +static int setup_ipv6_rpt(FILE *of); +static int setup_dns(FILE *of); +static int setup_static_rpt(FILE *of); +static int report_line(FILE *of, const char *fn); +static int check_cache(char *cache_name); +static int rpt_ipv6(char *cache_name, char *out_name, char *opt_atlas, int opt_append); +static void report(const char *fmt, ...); +static void report_err(const char *fmt, ...); + +int rptaddrs_main(int argc, char *argv[]) +{ + int r, need_report; + unsigned opt; + char *opt_atlas; + char *cache_name; /* temp file in an intermediate format */ + char *out_name; /* output file in json: timestamp opt_atlas */ + int opt_append; + FILE *cf; + + opt_atlas= NULL; + out_name = NULL; + cache_name = NULL; + opt_atlas = NULL; + opt_complementary= NULL; + opt_append = FALSE; + + opt= getopt32(argv, OPT_STRING, &opt_atlas, &out_name, &cache_name); + + if (out_name && !validate_filename(out_name, SAFE_PREFIX_N)) + { + crondlog(LVL8 "insecure file '%s' : allowed '%s'", out_name, + SAFE_PREFIX_N); + return 1; + } + if (cache_name && !validate_filename(cache_name, SAFE_PREFIX_N)) + { + crondlog(LVL8 "insecure file '%s' allowed %s", cache_name, + SAFE_PREFIX_N); + return 1; + } + + if (!cache_name) { + crondlog(LVL8 "missing requried option, -c "); + return 1; + } + + if (opt & OPT_a) + opt_append = TRUE; + + cf= setup_cache(cache_name); + if (cf == NULL) + return 1; + + r= setup_ipv4_rpt(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + + r= setup_dhcpv4(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + + r= setup_ipv6_rpt(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + + r= setup_dns(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + + r= setup_static_rpt(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + fclose(cf); + + need_report= check_cache(cache_name); + if (need_report) + { + r = rpt_ipv6(cache_name, out_name, opt_atlas, opt_append); + if (r != 0) + return r; + } + + return 0; +} + +static FILE *setup_cache(char *cache_name) +{ + FILE *out_file; + char filename[80]; + + if (strlen(cache_name) + strlen(SUFFIX) + 1 > sizeof(filename)) + { + report("cache name '%s' too long", cache_name); + return NULL; + } + + strlcpy(filename, cache_name, sizeof(filename)); + strlcat(filename, SUFFIX, sizeof(filename)); + + out_file= fopen(filename, "w"); + if (out_file == NULL) + { + report_err("unable to create '%s'", filename); + return NULL; + } + + return out_file; +} + +#define MAX_INF 10 + +static int setup_ipv4_rpt(FILE *of) +{ + int i, r, s, first; + unsigned dest, gateway, flags, refcnt, use, metric, mask; + FILE *in_file; + struct in_addr in_addr; + struct ifconf ifconf; + struct ifreq ifreq1; + struct ifreq ifreq[MAX_INF]; + char infname[20]; + char line[256]; + + s= socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (s == -1) + { + report_err("socket failed"); + return -1; + } + ifconf.ifc_len= sizeof(ifreq); + ifconf.ifc_req= ifreq; + r= ioctl(s, SIOCGIFCONF, &ifconf); + if (r == -1) + { + report_err("SIOCGIFCONF failed"); + close(s); + return -1; + } + + fprintf(of, DBQ(inet-addresses) ": [ "); + for (i= 0; isin_addr)); + fprintf(of, DBQ(netmask) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) " }", + inet_ntoa(((struct sockaddr_in *)(&ifreq1.ifr_addr))-> + sin_addr), + ifreq[i].ifr_name); + } + + close(s); + + fprintf(of, " ]"); + + in_file= fopen(IPV4_ROUTE_FILE, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", IPV4_ROUTE_FILE); + return -1; + } + + /* Skip first line */ + fgets(line, sizeof(line), in_file); + + fprintf(of, ", " DBQ(inet-routes) ": [ "); + first= 1; + + while (fgets(line, sizeof(line), in_file) != NULL) + { + sscanf(line, "%16s %x %x %x %d %d %d %x", + infname, &dest, &gateway, &flags, &refcnt, &use, + &metric, &mask); + in_addr.s_addr= dest; + fprintf(of, "%s{ " DBQ(destination) ": " DBQ(%s) ", ", + first ? "" : ", ", inet_ntoa(in_addr)); + in_addr.s_addr= mask; + fprintf(of, DBQ(netmask) ": " DBQ(%s) ", ", + inet_ntoa(in_addr)); + in_addr.s_addr= gateway; + fprintf(of, DBQ(next-hop) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) " }", + inet_ntoa(in_addr), infname); + first= 0; + } + + fprintf(of, " ]"); + + fclose(in_file); + + return 0; +} + +static int setup_dhcpv4(FILE *of) +{ + int found; + FILE *in_file; + char *value; + char line[128]; + + in_file= fopen(NETWORK_INFO, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", NETWORK_INFO); + return -1; + } + found= 0; + while (fgets(line, sizeof(line), in_file) != NULL) + { + if (strncmp(line, "DHCP ", 5) == 0) + { + value= NULL; + if (strncmp(line+5, "True", 4) == 0) + value= "true"; + else if (strncmp(line+5, "False", 5) == 0) + value= "false"; + if (value) + { + fprintf(of, ", " DBQ(inet-dhcp) ": %s", + value); + found= 1; + break; + } + } + } + + fclose(in_file); + if (found) + return 0; + report("setup_dhcpv4: DHCP field not found"); + return -1; +} + +static int setup_ipv6_rpt(FILE *of) +{ + int r, n; + char filename[80]; + char dst6in[INET6_ADDRSTRLEN]; + char nh6in[INET6_ADDRSTRLEN]; /* next hop */ + char *dst6out = NULL; + char *nh6out = NULL; + char dst6p[8][5]; + char nh6p[8][5]; + char iface[16], flags[16]; + char Scope[32]; + int scope, dad_status, if_idx; + int iflags, metric, refcnt, use, prefix_len, slen; + struct sockaddr_in6 sdst6, snh6; + char buf2[1024]; + + FILE *in_file; + + /* Copy IF_INET6_FILE */ + in_file= fopen(IF_INET6_FILE, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", IF_INET6_FILE); + return -1; + } + n = 0; + while ((r = fscanf(in_file, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n", + dst6p[0], dst6p[1], dst6p[2] + , dst6p[3], dst6p[4], dst6p[5] + , dst6p[6], dst6p[7], &if_idx, &prefix_len + , &scope, &dad_status, iface)) != EOF) { + + snprintf(dst6in, sizeof(dst6in), "%s:%s:%s:%s:%s:%s:%s:%s", + dst6p[0], dst6p[1], dst6p[2], dst6p[3], + dst6p[4], dst6p[5], dst6p[6], dst6p[7]); + + inet_pton(AF_INET6, dst6in, (struct sockaddr *) &sdst6.sin6_addr); + sdst6.sin6_family = AF_INET6; + dst6out = INET6_rresolve((struct sockaddr_in6 *) &sdst6, 0x0fff); + + switch (scope & IPV6_ADDR_SCOPE_MASK) { + case 0: + snprintf(Scope, sizeof(Scope), "Global"); + break; + case IPV6_ADDR_LINKLOCAL: + snprintf(Scope, sizeof(Scope), "Link"); + break; + case IPV6_ADDR_SITELOCAL: + snprintf(Scope, sizeof(Scope), "Site"); + break; + case IPV6_ADDR_COMPATv4: + snprintf(Scope, sizeof(Scope), "Compat"); + break; + case IPV6_ADDR_LOOPBACK: + snprintf(Scope, sizeof(Scope), "Host"); + break; + default: + snprintf(Scope, sizeof(Scope), "Unknown %d", scope); + } + r = snprintf(buf2, sizeof(buf2), "%s %s{" DBQ(inet6-addr) " : " + DBQ(%s) ", " DBQ(prefix-length) " : %d," + DBQ(scope) " : " DBQ(%s) ", " DBQ(interface) + " : " DBQ(%s) "}", + n ? "" : ", \"inet6-addresses\" : [", n ? ", " : "" + , dst6out, prefix_len, Scope, iface); + + /* printf("%s\n", buf2); */ + + if(dst6out) { + free(dst6out); + dst6out=NULL; + } + n++; + if (fwrite(buf2, 1, r, of) != r) + { + report_err("error writing to '%s'", filename); + fclose(in_file); + return -1; + } + + if (ferror(in_file)) + { + report_err("error reading from '%s'", IF_INET6_FILE); + fclose(in_file); + return -1; + } + } + if ( n > 0 ) { + r = snprintf(buf2, 2, "]"); + } + if (fwrite(buf2, 1, r, of) != r) + { + report_err("error writing to '%s'", filename); + fclose(in_file); + return -1; + } + + fclose(in_file); + + /* Copy IPV6_ROUTE_FILE */ + in_file= fopen(IPV6_ROUTE_FILE, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", IPV6_ROUTE_FILE); + return -1; + } + + n = 0; + while ((r = fscanf (in_file, "%4s%4s%4s%4s%4s%4s%4s%4s%x%*s%x%4s%4s%4s%4s%4s%4s%4s%4s%x%x%x%x%s\n", + dst6p[0], dst6p[1], dst6p[2], dst6p[3], dst6p[4], + dst6p[5], dst6p[6], dst6p[7], &prefix_len, &slen, + nh6p[0], nh6p[1], nh6p[2], nh6p[3], nh6p[4], + nh6p[5], nh6p[6], nh6p[7], &metric, &use, &refcnt, &iflags, iface)) != EOF) { + + if (r != 23) { + if ((r < 0) && feof(in_file)) { /* EOF with no (nonspace) chars read. */ + break; + } + report_err("reading '%s'", IF_INET6_FILE); + fclose(in_file); + return -1; + } + + /* skip some the stuff we don't want to report */ + if (!(iflags & RTF_UP)) { /* Skip interfaces that are down. */ + continue; + } + if ((iflags & RTF_ADDRCONF) && (iflags & RTF_CACHE)) { /* Skip interfaces that are down. */ + continue; + } + + if ( strncmp (dst6p[0], "ff02", strlen("ff02")) == 0 ) { + continue; + } + if ( strncmp (dst6p[0], "ff00", strlen("ff00")) == 0 ) { + continue; + } + + snprintf(dst6in, sizeof(dst6in), "%s:%s:%s:%s:%s:%s:%s:%s", + dst6p[0], dst6p[1], dst6p[2], dst6p[3], + dst6p[4], dst6p[5], dst6p[6], dst6p[7]); + + snprintf(nh6in, sizeof(nh6in), "%s:%s:%s:%s:%s:%s:%s:%s", + nh6p[0], nh6p[1], nh6p[2], nh6p[3], + nh6p[4], nh6p[5], nh6p[6], nh6p[7]); + + + set_flags(flags, (iflags & IPV6_MASK)); + inet_pton(AF_INET6, dst6in, (struct sockaddr *) &sdst6.sin6_addr); + sdst6.sin6_family = AF_INET6; + dst6out = INET6_rresolve((struct sockaddr_in6 *) &sdst6, 0x0fff); + + inet_pton(AF_INET6, nh6in, (struct sockaddr *) &snh6.sin6_addr); + snh6.sin6_family = AF_INET6; + nh6out = INET6_rresolve((struct sockaddr_in6 *) &snh6, 0x0fff); + + + r = snprintf(buf2, sizeof(buf2), "%s %s{" DBQ(destination) " : " + DBQ(%s) ", " DBQ(prefix-length) " : %d," + DBQ(next-hop) " : " DBQ(%s) ", " DBQ(flags) + " : " DBQ(%s) ", " DBQ(metric) " : %d , " + DBQ(interface) " : " DBQ(%s) "}", + n ? "" : ", \"inet6-routes\" : [", n ? ", " : "" + , dst6out, prefix_len, nh6out, flags, metric + , iface); + + /* + r = snprintf(buf2, sizeof(buf2), "%s %s{" DBQ(destination) " : " + DBQ(%s) ", " DBQ(prefix-length) " : %d," + DBQ(next-hop) " : " DBQ(%s) ", " DBQ(flags) + " : " DBQ(%s) ", " DBQ(metric) " : %d , " + DBQ(interface) " : " DBQ(%s) "}", + n ? " " : '"inet6-routes" [' + , n ? ", " : "" + , dst6out, prefix_len, nh6out, flags, metric + , iface); + */ + + /* printf("%s\n", buf2); */ + + if(dst6out) { + free(dst6out); + dst6out=NULL; + } + if(nh6out) { + free(nh6out); + nh6out=NULL; + } + + if (fwrite(buf2, 1, r, of) != r) + { + report_err("error writing to '%s'", filename); + fclose(in_file); + return -1; + } + n++; + } + if ( n > 0 ) { + r = snprintf(buf2, 2, "]"); + } + if (fwrite(buf2, 1, r, of) != r) + { + report_err("error writing to '%s'", filename); + fclose(in_file); + return -1; + } + + + if (ferror(in_file)) + { + report_err("error reading from '%s'", IPV6_ROUTE_FILE); + fclose(in_file); + return -1; + } + fclose(in_file); + + return 0; +} + +static int setup_dns(FILE *of) +{ + int i, resolv_max; + char nslist[MAXNS][INET6_ADDRSTRLEN * 2]; + + resolv_max= 0; + + get_local_resolvers_nocache(nslist, &resolv_max); + + fprintf(of, ", " DBQ(dns) ": [ "); + for (i= 0; i 0) + { + if (fread(buf2, 1, sizeof(buf2), in_file) != r) + { + /* Ignore errors, just report */ + need_report= 1; + break; + } + + if (memcmp(buf1, buf2, r) != 0) + { + /* Something changed, report */ + need_report= 1; + break; + } + } + + /* Maybe something got added */ + if (!need_report) + { + if (fread(buf2, 1, sizeof(buf2), in_file) != 0) + { + need_report= 1; + } + } + fclose(cache_file); + fclose(in_file); + } + + if (need_report) + { + if (rename(filename, cache_name) == -1) + { + report_err("renaming '%s' to '%s' failed", + filename, cache_name); + return 0; + } + } + else + { + if (unlink(filename) == -1) + { + report_err("unlinking '%s' failed", + filename); + } + } + + return need_report; +} + +static int rpt_ipv6(char *cache_name, char *out_name, char *opt_atlas, int opt_append) +{ + FILE *file; + FILE *fh; + char buf[256]; + struct timeval now; + + file= fopen(cache_name, "r"); + if (!file) + { + report_err("unable to open cache file '%s'", cache_name); + return 1; + } + + if (out_name) { + if(opt_append) + fh= fopen(out_name, "a"); + else + fh= fopen(out_name, "w"); + + if (!fh) + { + report_err("unable to append to '%s'", out_name); + return 1; + } + } + else + fh = stdout; + + fprintf(fh, "RESULT { "); + if(opt_atlas) + { + JS(id, opt_atlas); + } + gettimeofday(&now, NULL); + JS1(time, %ld, now.tv_sec); + + /* Copy all lines */ + while (fgets(buf, sizeof(buf), file) != NULL) + { + fputs(buf, fh); + } + fprintf(fh, "}\n"); + fclose(file); + fclose(fh); + + return 0; +} + +static void report(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + fprintf(stderr, "rptaddrs: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + + va_end(ap); +} + +static void report_err(const char *fmt, ...) +{ + int t_errno; + va_list ap; + + t_errno= errno; + + va_start(ap, fmt); + + fprintf(stderr, "rptaddrs: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": %s\n", strerror(t_errno)); + + va_end(ap); +} diff --git a/networking/rptra6.c b/networking/rptra6.c index 8b45e72..b481252 100644 --- a/networking/rptra6.c +++ b/networking/rptra6.c @@ -35,7 +35,7 @@ static void usage(void) exit(1); } -int rptaddr6_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; +int rptra6_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; int rptra6_main(int argc, char *argv[]) { int i, r, first, sock, on, nrecv, rcvd_ttl, olen; diff --git a/shell/hush.c b/shell/hush.c index 13aceb3..10cab48 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -770,7 +770,7 @@ static int builtin_epoch(char **argv); static int builtin_condmv(char **argv); static int builtin_dfrm(char **argv); static int builtin_rxtxrpt(char **argv); -static int builtin_rptaddr6(char **argv); +static int builtin_rptaddrs(char **argv); static int builtin_true(char **argv); static int builtin_set(char **argv); static int builtin_shift(char **argv); @@ -830,7 +830,7 @@ static const struct built_in_command bltins[] = { BLTIN("condmv" , builtin_condmv, "conditional move"), BLTIN("dfrm" , builtin_dfrm, "cleanup if free space gets too low"), BLTIN("rxtxrpt" , builtin_rxtxrpt, "report RX and TX"), - BLTIN("rptaddr6" , builtin_rptaddr6, "report ipv6 address(es) and route(s)"), + BLTIN("rptaddrs" , builtin_rptaddrs, "report address(es), route(s), and dns"), BLTIN("echo" , builtin_echo, "Write to stdout"), BLTIN("eval" , builtin_eval, "Construct and run shell command"), BLTIN("exec" , builtin_exec, "Execute command, don't return to shell"), @@ -4682,15 +4682,15 @@ static int builtin_rxtxrpt(char **argv) return rxtxrpt_main(argc, argv); } -int builitin_rptaddr6(int argc, char *argv[]); +int builitin_rptaddrs(int argc, char *argv[]); -static int builtin_rptaddr6(char **argv) +static int builtin_rptaddrs(char **argv) { int argc; for (argc= 0; argv[argc] != 0; argc++) ; - return rptaddr6_main(argc, argv); + return rptaddrs_main(argc, argv); } -- cgit v1.2.3