From 8712f3f01a5acaa5426c03fc4510f18985b84b66 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Sat, 4 Mar 2017 21:05:37 +0100 Subject: ripe-atlas-fw: imported version 4750 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- eperd/eooqd.c | 82 +++++++++++++++--- eperd/eperd.c | 60 ++++++++++++-- eperd/evtdig.c | 53 ++++++++---- eperd/evtraceroute.c | 1 + eperd/ntp.c | 12 ++- eperd/readresolv.c | 116 +++++++------------------- eperd/readresolv.h | 4 +- eperd/traceroute.c | 17 +++- libevent-2.0.20-stable/evdns.c | 34 ++++++++ libevent-2.0.20-stable/include/event2/dns.h | 8 ++ miscutils/ooqd.c | 22 ++++- networking/rptaddrs.c | 5 +- networking/rptra6.c | 82 +++++++++++++++++- networking/rxtxrpt.c | 124 ++++++++++++++++++++++++++-- shell/hush.c | 87 +++++++++++++++++++ 15 files changed, 563 insertions(+), 144 deletions(-) diff --git a/eperd/eooqd.c b/eperd/eooqd.c index ed8ea64..8c11f62 100644 --- a/eperd/eooqd.c +++ b/eperd/eooqd.c @@ -28,6 +28,9 @@ #define BARRIER_CMD "barrier" #define POST_CMD "post" +#define RELOAD_RESOLV_CONF_CMD "reload_resolv_conf" + +#define RESOLV_CONF "/etc/resolv.conf" struct slot { @@ -68,6 +71,9 @@ static struct builtin static const char *atlas_id; static const char *queue_id; +static char *resolv_conf; +static char output_filename[80]; + static void report(const char *fmt, ...); static void report_err(const char *fmt, ...); @@ -88,18 +94,22 @@ int eooqd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int eooqd_main(int argc, char *argv[]) { int r; - char *pid_file_name, *instance_id_str; + size_t len; + char *pid_file_name, *interface_name, *instance_id_str; char *check; struct event *checkQueueEvent, *rePostEvent; struct timeval tv; struct rlimit limit; + struct stat sb; atlas_id= NULL; + interface_name= NULL; instance_id_str= NULL; pid_file_name= NULL; queue_id= ""; - (void)getopt32(argv, "A:i:P:q:", &atlas_id, &instance_id_str, + (void)getopt32(argv, "A:I:i:P:q:", &atlas_id, + &interface_name, &instance_id_str, &pid_file_name, &queue_id); if (argc != optind+1) @@ -120,6 +130,28 @@ int eooqd_main(int argc, char *argv[]) } } + if (interface_name) + { + len= strlen(RESOLV_CONF) + 1 + + strlen(interface_name) + 1; + resolv_conf= malloc(len); + snprintf(resolv_conf, len, "%s.%s", + RESOLV_CONF, interface_name); + + /* Check if this resolv.conf exists. If it doen't, switch + * to the standard one. + */ + if (stat(resolv_conf, &sb) == -1) + { + free(resolv_conf); + resolv_conf= strdup(RESOLV_CONF); + } + } + else + { + resolv_conf= strdup(RESOLV_CONF); + } + if(pid_file_name) { write_pidfile(pid_file_name); @@ -145,6 +177,9 @@ int eooqd_main(int argc, char *argv[]) sizeof(state->curr_qfile)); strlcat(state->curr_qfile, SUFFIX, sizeof(state->curr_qfile)); + snprintf(output_filename, sizeof(output_filename), + OOQD_OUT_PREFIX "%s/ooq.out", queue_id); + signal(SIGQUIT, SIG_DFL); limit.rlim_cur= RLIM_INFINITY; limit.rlim_max= RLIM_INFINITY; @@ -156,13 +191,32 @@ int eooqd_main(int argc, char *argv[]) { crondlog(DIE9 "event_base_new failed"); /* exits */ } - DnsBase= evdns_base_new(EventBase, 1 /*initialize*/); + DnsBase= evdns_base_new(EventBase, 0 /*initialize*/); if (!DnsBase) { event_base_free(EventBase); crondlog(DIE9 "evdns_base_new failed"); /* exits */ } + if (interface_name) + { + r= evdns_base_set_interface(DnsBase, interface_name); + if (r == -1) + { + event_base_free(EventBase); + crondlog(DIE9 "evdns_base_set_interface failed"); + /* exits */ + } + } + + r = evdns_base_resolv_conf_parse(DnsBase, DNS_OPTIONS_ALL, + resolv_conf); + if (r == -1) + { + event_base_free(EventBase); + crondlog(DIE9 "evdns_base_resolv_conf_parse failed"); /* exits */ + } + checkQueueEvent= event_new(EventBase, -1, EV_TIMEOUT|EV_PERSIST, checkQueue, NULL); if (!checkQueueEvent) @@ -190,7 +244,6 @@ static void checkQueue(evutil_socket_t fd UNUSED_PARAM, { int r; struct stat sb; - char filename[80]; if (!state->curr_file) { @@ -246,9 +299,7 @@ static void checkQueue(evutil_socket_t fd UNUSED_PARAM, break; /* Wait for barrier to complete */ } - snprintf(filename, sizeof(filename), - OOQD_OUT_PREFIX "%s/ooq.out", queue_id); - check_resolv_conf2(filename, atlas_id); + check_resolv_conf2(output_filename, atlas_id); } static int add_line(void) @@ -328,6 +379,14 @@ static int add_line(void) return 0; } + /* Check for the reload resolv.conf command */ + if (strcmp(cmdline, RELOAD_RESOLV_CONF_CMD) == 0) + { + /* Trigger a reload */ + check_resolv_conf2(output_filename, atlas_id); + return 0; /* Done */ + } + cmdstate= NULL; reason= NULL; for (bp= builtin_cmds; bp->cmd != NULL; bp++) @@ -555,7 +614,6 @@ static void cmddone(void *cmdstate) } } -#define RESOLV_CONF "/etc/resolv.conf" static void check_resolv_conf2(const char *out_file, const char *atlasid) { static time_t last_time= -1; @@ -564,7 +622,7 @@ static void check_resolv_conf2(const char *out_file, const char *atlasid) FILE *fn; struct stat sb; - r= stat(RESOLV_CONF, &sb); + r= stat(resolv_conf, &sb); if (r == -1) { crondlog(LVL8 "error accessing resolv.conf: %s", @@ -573,10 +631,14 @@ static void check_resolv_conf2(const char *out_file, const char *atlasid) } if (sb.st_mtime == last_time) + { + crondlog(LVL7 "check_resolv_conf2: no change (time %d)", + sb.st_mtime); return; /* resolv.conf did not change */ + } evdns_base_clear_nameservers_and_suspend(DnsBase); r= evdns_base_resolv_conf_parse(DnsBase, DNS_OPTIONS_ALL, - RESOLV_CONF); + resolv_conf); evdns_base_resume(DnsBase); if ((r != 0 || last_time != -1) && out_file != NULL) diff --git a/eperd/eperd.c b/eperd/eperd.c index 9c602c6..83aff15 100644 --- a/eperd/eperd.c +++ b/eperd/eperd.c @@ -57,6 +57,8 @@ #define URANDOM_DEV "/dev/urandom" #define ATLAS_FW_VERSION "/home/atlas/state/FIRMWARE_APPS_VERSION" +#define RESOLV_CONF "/etc/resolv.conf" + struct CronLine { struct CronLine *cl_Next; char *cl_Shell; /* shell command */ @@ -121,6 +123,7 @@ struct globals G; static int do_kick_watchdog; static char *out_filename= NULL; static char *atlas_id= NULL; +static char *resolv_conf; static void CheckUpdates(evutil_socket_t fd, short what, void *arg); static void CheckUpdatesHour(evutil_socket_t fd, short what, void *arg); @@ -257,11 +260,14 @@ int eperd_main(int argc UNUSED_PARAM, char **argv) unsigned opt; int r, fd; unsigned seed; + size_t len; struct event *updateEventMin, *updateEventHour; struct timeval tv; struct rlimit limit; + struct stat sb; const char *PidFileName = NULL; + char *interface_name= NULL; atexit(my_exit); @@ -270,8 +276,9 @@ int eperd_main(int argc UNUSED_PARAM, char **argv) /* "-b after -f is ignored", and so on for every pair a-b */ opt_complementary = "f-b:b-f:S-L:L-S" USE_FEATURE_PERD_D(":d-l") ":i+:l+:d+"; /* -i, -l and -d have numeric param */ - opt = getopt32(argv, "i:l:L:fc:A:DP:" USE_FEATURE_PERD_D("d:") "O:", - &instance_id, &LogLevel, &LogFile, &CDir, + opt = getopt32(argv, "I:i:l:L:fc:A:DP:" USE_FEATURE_PERD_D("d:") "O:", + &interface_name, &instance_id, &LogLevel, + &LogFile, &CDir, &atlas_id, &PidFileName USE_FEATURE_PERD_D(,&LogLevel), &out_filename); /* both -d N and -l N set the same variable: LogLevel */ @@ -294,6 +301,29 @@ int eperd_main(int argc UNUSED_PARAM, char **argv) logmode = LOGMODE_SYSLOG; } + if (interface_name) + { + len= strlen(RESOLV_CONF) + 1 + + strlen(interface_name) + 1; + resolv_conf= malloc(len); + snprintf(resolv_conf, len, "%s.%s", + RESOLV_CONF, interface_name); + + /* Check if this resolv.conf exists. If it doen't, switch + * to the standard one. + */ + if (stat(resolv_conf, &sb) == -1) + { + free(resolv_conf); + resolv_conf= strdup(RESOLV_CONF); + } + } + else + { + resolv_conf= strdup(RESOLV_CONF); + } + + do_kick_watchdog= !!(opt & OPT_D); xchdir(CDir); @@ -312,12 +342,31 @@ int eperd_main(int argc UNUSED_PARAM, char **argv) { crondlog(DIE9 "event_base_new failed"); /* exits */ } - DnsBase= evdns_base_new(EventBase, 1 /*initialize*/); + DnsBase= evdns_base_new(EventBase, 0 /*!initialize*/); if (!DnsBase) { crondlog(DIE9 "evdns_base_new failed"); /* exits */ } + if (interface_name) + { + r= evdns_base_set_interface(DnsBase, interface_name); + if (r == -1) + { + event_base_free(EventBase); + crondlog(DIE9 "evdns_base_set_interface failed"); + /* exits */ + } + } + + r = evdns_base_resolv_conf_parse(DnsBase, DNS_OPTIONS_ALL, + resolv_conf); + if (r == -1) + { + event_base_free(EventBase); + crondlog(DIE9 "evdns_base_resolv_conf_parse failed"); /* exits */ + } + fd= open(URANDOM_DEV, O_RDONLY); /* Best effort, just ignore errors */ @@ -591,7 +640,6 @@ static void SynchronizeFile(const char *fileName) DeleteFile(); } -#define RESOLV_CONF "/etc/resolv.conf" static void check_resolv_conf(void) { static time_t last_time= -1; @@ -600,7 +648,7 @@ static void check_resolv_conf(void) FILE *fn; struct stat sb; - r= stat(RESOLV_CONF, &sb); + r= stat(resolv_conf, &sb); if (r == -1) { crondlog(LVL8 "error accessing resolv.conf: %s", @@ -612,7 +660,7 @@ static void check_resolv_conf(void) return; /* resolv.conf did not change */ evdns_base_clear_nameservers_and_suspend(DnsBase); r= evdns_base_resolv_conf_parse(DnsBase, DNS_OPTIONS_ALL, - RESOLV_CONF); + resolv_conf); evdns_base_resume(DnsBase); if ((r != 0 || last_time != -1) && out_filename) diff --git a/eperd/evtdig.c b/eperd/evtdig.c index df223ff..c5879de 100644 --- a/eperd/evtdig.c +++ b/eperd/evtdig.c @@ -231,8 +231,6 @@ struct tdig_base { struct query_state *qry_head; struct event statsReportEvent; - int resolv_max; - char nslist[MAXNS][INET6_ADDRSTRLEN * 2]; counter_t sendfail; /* # of failed sendto() */ counter_t sentok; /* # of successful sendto() */ @@ -297,6 +295,10 @@ struct query_state { char * server_name; char *out_filename ; + /* Contents of resolv.conf during a measurement */ + int resolv_max; + char *nslist[MAXNS]; + /* For fuzzing */ char *response_out; char *response_in; @@ -1343,10 +1345,6 @@ static bool argProcess (int argc, char *argv[], struct query_state *qry ) { if( qry->opt_resolv_conf) { qry->resolv_i = 0; - get_local_resolvers(tdig_base->nslist, &tdig_base->resolv_max); - if(tdig_base->resolv_max ) { - qry->server_name = strdup(tdig_base->nslist[qry->resolv_i]); - } } else if (optind != argc-1) { crondlog(LVL9 "ERROR no server IP address in input"); @@ -1911,7 +1909,6 @@ struct tdig_base * tdig_base_new(struct event_base *event_base) tdig_base->recvbytes = 0; tdig_base->timeout = 0; tdig_base->activeqry = 0; - tdig_base->resolv_max = 0; memset(tdig_base, 0, sizeof(struct tdig_base)); tdig_base->event_base = event_base; @@ -1970,17 +1967,20 @@ void tdig_start (void *arg) /* Get time in case we don't send any packet */ qry->xmit_time= time(NULL); qry->resolv_i = 0; - crondlog(LVL5 "RESOLV QUERY FREE %s resolv_max %d", qry->server_name, tdig_base->resolv_max); + crondlog(LVL5 "RESOLV QUERY FREE %s resolv_max %d", qry->server_name, qry->resolv_max); if( qry->opt_resolv_conf) { - get_local_resolvers (tdig_base->nslist, &tdig_base->resolv_max); - crondlog(LVL5 "AAA RESOLV QUERY FREE %s resolv_max %d %d", qry->server_name, tdig_base->resolv_max, qry->resolv_i); - if(tdig_base->resolv_max ) { + get_local_resolvers (qry->nslist, + &qry->resolv_max, + qry->infname); + crondlog(LVL5 "AAA RESOLV QUERY FREE %s resolv_max %d %d", qry->server_name, qry->resolv_max, qry->resolv_i); + if(qry->resolv_max ) { free(qry->server_name); qry->server_name = NULL; - qry->server_name = strdup(tdig_base->nslist[qry->resolv_i]); + qry->server_name = qry->nslist[qry->resolv_i]; + qry->nslist[qry->resolv_i]= NULL; } else { - crondlog(LVL5 "AAA RESOLV QUERY FREE %s resolv_max is zero %d i %d", qry->server_name, tdig_base->resolv_max, qry->resolv_i); + crondlog(LVL5 "AAA RESOLV QUERY FREE %s resolv_max is zero %d i %d", qry->server_name, qry->resolv_max, qry->resolv_i); free(qry->server_name); qry->server_name = NULL; snprintf(line, DEFAULT_LINE_LENGTH, "\"nameserver\": \"no local resolvers found\""); @@ -2201,6 +2201,7 @@ static void ChangetoDnsNameFormat(u_char * dns, char* qry) static void free_qry_inst(struct query_state *qry) { + int i; struct timeval asap = { 1, 0 }; BLURT(LVL5 "freeing instance of %s ", qry->server_name); @@ -2248,18 +2249,27 @@ static void free_qry_inst(struct query_state *qry) if ( qry->opt_resolv_conf) { // this loop goes over servers in /etc/resolv.conf // select the next server and restart - if(qry->resolv_i < tdig_base->resolv_max) { + if(qry->resolv_i < qry->resolv_max) { if(qry->server_name) { free (qry->server_name); qry->server_name = NULL; } - qry->server_name = strdup(tdig_base->nslist[qry->resolv_i]); + qry->server_name = strdup(qry->nslist[qry->resolv_i]); qry->qst = STATUS_NEXT_QUERY; evtimer_add(&qry->next_qry_timer, &asap); return; } } + for (i= 0; inslist[i]) + { + free(qry->nslist[i]); + qry->nslist[i]= NULL; + } + } + switch(qry->qst){ case STATUS_RETRANSMIT_QUERY: break; @@ -2281,6 +2291,7 @@ static void free_qry_inst(struct query_state *qry) static int tdig_delete(void *state) { + int i; struct query_state *qry; qry = state; @@ -2343,6 +2354,14 @@ static int tdig_delete(void *state) free(qry->server_name); qry->server_name = NULL; } + for (i= 0; inslist[i]) + { + free(qry->nslist[i]); + qry->nslist[i]= NULL; + } + } if (qry->udp_fd != -1) { event_del(&qry->event); @@ -2451,7 +2470,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) if ( qry->opt_resolv_conf ) { JD (subid, (qry->resolv_i+1)); - JD (submax, qry->base->resolv_max); + JD (submax, qry->resolv_max); } if( qry->ressent && qry->server_name) @@ -2655,7 +2674,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) if(qry->opt_resolv_conf){ qry->resolv_i++; - if(qry->resolv_i >= tdig_base->resolv_max) { + if(qry->resolv_i >= qry->resolv_max) { write_out = TRUE; if(qry->opt_rset) { AS ("]"); /* reseultset : [{}] */ diff --git a/eperd/evtraceroute.c b/eperd/evtraceroute.c index d5e0d36..c596e3c 100644 --- a/eperd/evtraceroute.c +++ b/eperd/evtraceroute.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "eperd.h" diff --git a/eperd/ntp.c b/eperd/ntp.c index fb788c2..c1d509a 100644 --- a/eperd/ntp.c +++ b/eperd/ntp.c @@ -1830,12 +1830,11 @@ static void traceroute_start2(void *state) ntpstate= state; - if (ntpstate->busy) + if (!ntpstate->busy) { - printf("ntp_start: busy, can't start\n"); + printf("ntp_start: not busy, can't continue\n"); return; } - ntpstate->busy= 1; ntpstate->min= ULONG_MAX; ntpstate->max= 0; @@ -2070,6 +2069,13 @@ static void ntp_start(void *state) ntpstate= state; + if (ntpstate->busy) + { + printf("ntp_start: busy, can't start\n"); + return; + } + ntpstate->busy= 1; + if (ntpstate->response_out) { ntpstate->resp_file_out= fopen(ntpstate->response_out, "w"); diff --git a/eperd/readresolv.c b/eperd/readresolv.c index 9d04866..df464bc 100644 --- a/eperd/readresolv.c +++ b/eperd/readresolv.c @@ -7,18 +7,15 @@ #include "libbb.h" #include "resolv.h" #include "eperd.h" +#include "readresolv.h" #include -static void nameserver_ip_add (char *nsentry, char *ip_as_string) +static void nameserver_ip_add (char **nsentry, char *ip_as_string) { - - strncpy (nsentry, ip_as_string, LINEL); - // printf("AA added nameserver %s\n", ip_as_string); - // printf("AA added nameserver to ns %s\n", nsentry); - return; + *nsentry= strdup(ip_as_string); } -static int resolv_conf_parse_line (char *nsentry, char *line) +static int resolv_conf_parse_line (char **nsentry, char *line) { #define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state) @@ -32,7 +29,7 @@ static int resolv_conf_parse_line (char *nsentry, char *line) char *const nameserver = NEXT_TOKEN; if (nameserver) { if(nameserver[(strlen(nameserver) - 1)] == '\n') - nameserver[(strlen(nameserver) - 1)] = NULL; + nameserver[(strlen(nameserver) - 1)] = '\0'; nameserver_ip_add(nsentry, nameserver); //printf("AA added nameserver %s\n", nsentry); return 1; @@ -41,108 +38,51 @@ static int resolv_conf_parse_line (char *nsentry, char *line) return 0; } -void get_local_resolvers(char nslist[MAXNS][INET6_ADDRSTRLEN * 2], - int *resolv_max) +void get_local_resolvers(char *nslist[MAXNS], int *resolv_max, char *ifname) { #ifndef RESOLV_CONF #define RESOLV_CONF "/etc/resolv.conf" #endif char buf[LINEL]; + char filename[80]; char *buf_start; int i = 0; - time_t now; - int r; struct stat sb; + FILE *R; - static resolv_last_check = -1; - static time_t last_time= -1; - - now = time(NULL); - - if(*resolv_max){ - if ( pow (resolv_last_check - now, 2) > 3) { - crondlog(LVL5 "check the %s", RESOLV_CONF); - } - else { - return; - } - - } - - - r = stat(RESOLV_CONF, &sb); - if (r == -1) - { - crondlog(LVL8 "error accessing resolv.conf: %s", - strerror(errno)); - return; - } - - resolv_last_check = now; - - if (last_time == sb.st_mtime) + if (ifname) { - /* nothing changed */ - crondlog(LVL5 "re-read %s. not reading this time", RESOLV_CONF); - return; - } - else { - crondlog(LVL5 "re-read %s . it has changed", RESOLV_CONF); - } - - FILE *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); + snprintf(filename, sizeof(filename), "%s.%s", + RESOLV_CONF, ifname); + + /* Check if it exists */ + if (stat(filename, &sb) == -1) + { + crondlog(LVL8 "get_local_resolvers: stat of %s failed: %s", + filename, strerror(errno)); + /* Fall back to resolv.conf */ + strlcpy(filename, RESOLV_CONF, sizeof(filename)); } - fclose (R); } - - last_time = sb.st_mtime; - - *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) + else { - crondlog(LVL8 "error accessing resolv.conf: %s", - strerror(errno)); - return; + /* Just use resolv.conf */ + strlcpy(filename, RESOLV_CONF, sizeof(filename)); } - R = fopen (RESOLV_CONF, "r"); + crondlog(LVL8 "get_local_resolvers: using %s", filename); + + R = fopen (filename, "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); + if(resolv_conf_parse_line(&nslist[i], buf) ) { + crondlog(LVL5 "parsed file %s , line %s i=%d", filename, buf_start, i); i++; } else - crondlog(LVL5 "ERROR failed to parse from %s i=%d, line %s", RESOLV_CONF, i, buf_start); + crondlog(LVL5 "ERROR failed to parse from %s i=%d, line %s", filename, i, buf_start); } fclose (R); } diff --git a/eperd/readresolv.h b/eperd/readresolv.h index a71fd4a..2223a6d 100644 --- a/eperd/readresolv.h +++ b/eperd/readresolv.h @@ -2,6 +2,4 @@ * Copyright (c) 2013-2014 RIPE NCC * 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); +void get_local_resolvers(char *nslist[MAXNS], int *resolv_max, char *infname); diff --git a/eperd/traceroute.c b/eperd/traceroute.c index 441aebd..b335a9d 100644 --- a/eperd/traceroute.c +++ b/eperd/traceroute.c @@ -3977,7 +3977,7 @@ for (i= 0; argv[i] != NULL; i++) state->maxpacksize= maxpacksize; state->maxhops= maxhops; state->gaplimit= gaplimit; - state->interface= interface; + state->interface= interface ? strdup(interface) : NULL; state->destportstr= strdup(destportstr); state->duptimeout= duptimeout*1000; state->timeout= timeout*1000; @@ -4057,9 +4057,9 @@ static void traceroute_start2(void *state) trtstate= state; - if (trtstate->busy) + if (!trtstate->busy) { - printf("traceroute_start: busy, can't start\n"); + printf("traceroute_start: not busy, can't continue\n"); return; } trtstate->busy= 1; @@ -4180,6 +4180,8 @@ static int create_socket(struct trtstate *state, int do_tcp) if (bind_interface(state->socket_icmp, af, state->interface) == -1) { + crondlog(LVL7 "binding to interface '%s' failed with '%s'", state->interface, strerror(errno)); + snprintf(line, sizeof(line), ", " DBQ(error) ":" DBQ(bind_interface failed) " }"); add_str(state, line); @@ -4443,6 +4445,13 @@ static void traceroute_start(void *state) trtstate= state; + if (trtstate->busy) + { + printf("traceroute_start: busy, can't start\n"); + return; + } + trtstate->busy= 1; + if (trtstate->response_out) { trtstate->resp_file_out= fopen(trtstate->response_out, "w"); @@ -4493,6 +4502,8 @@ static int traceroute_delete(void *state) free(trtstate->atlas); trtstate->atlas= NULL; + free(trtstate->interface); + trtstate->interface= NULL; free(trtstate->bundle_id); trtstate->bundle_id= NULL; free(trtstate->hostname); diff --git a/libevent-2.0.20-stable/evdns.c b/libevent-2.0.20-stable/evdns.c index cf38418..b9110f0 100644 --- a/libevent-2.0.20-stable/evdns.c +++ b/libevent-2.0.20-stable/evdns.c @@ -313,6 +313,8 @@ struct evdns_base { struct event_base *event_base; + char *interface_name; + /* The number of good nameservers that we have */ int global_good_nameservers; @@ -2475,6 +2477,16 @@ _evdns_nameserver_add_impl(struct evdns_base *base, const struct sockaddr *addre ns->socket = socket(address->sa_family, SOCK_DGRAM, 0); if (ns->socket < 0) { err = 1; goto out1; } + if (ns->base->interface_name) + { + if (setsockopt(ns->socket, SOL_SOCKET, SO_BINDTODEVICE, + ns->base->interface_name, + strlen(ns->base->interface_name)+1) == -1) + { + err= 2; + goto out2; + } + } evutil_make_socket_closeonexec(ns->socket); evutil_make_socket_nonblocking(ns->socket); @@ -3967,6 +3979,12 @@ evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests) base->server_head = NULL; base->global_good_nameservers = 0; + if (base->interface_name) + { + free(base->interface_name); + base->interface_name= NULL; + } + if (base->global_search_state) { for (dom = base->global_search_state->head; dom; dom = dom_next) { dom_next = dom->next; @@ -3999,6 +4017,22 @@ evdns_base_free(struct evdns_base *base, int fail_requests) evdns_base_free_and_unlock(base, fail_requests); } +int evdns_base_set_interface(struct evdns_base *base, char *interface_name) +{ + if (base->interface_name) + { + free(base->interface_name); + base->interface_name= NULL; + } + if (!interface_name) + return 0; + + base->interface_name= strdup(interface_name); + if (!base->interface_name) + return -1; + return 0; +} + void evdns_shutdown(int fail_requests) { diff --git a/libevent-2.0.20-stable/include/event2/dns.h b/libevent-2.0.20-stable/include/event2/dns.h index ca0da3c..797d3f9 100644 --- a/libevent-2.0.20-stable/include/event2/dns.h +++ b/libevent-2.0.20-stable/include/event2/dns.h @@ -230,6 +230,14 @@ struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize */ void evdns_base_free(struct evdns_base *base, int fail_requests); +/** + Set the outging interface to be used for DNS queries + + @param base the evdns base to modify + @param interface_name the name of the interface to be used + */ +int evdns_base_set_interface(struct evdns_base *base, char *interface_name); + /** Convert a DNS error code to a string. diff --git a/miscutils/ooqd.c b/miscutils/ooqd.c index 85114c9..44721e9 100644 --- a/miscutils/ooqd.c +++ b/miscutils/ooqd.c @@ -116,9 +116,9 @@ static void skip_nonspace(char *cp, char **ncpp) *ncpp= cp; } -static void find_eos(char *cp, char **ncpp) +static void find_eos(char *cp, char **ncpp, char quote_char) { - while (cp[0] != '\0' && cp[0] != '"') + while (cp[0] != '\0' && cp[0] != quote_char) cp++; *ncpp= cp; } @@ -250,7 +250,7 @@ printf("got cp %p, line %p, '%s'\n", cp, line, cp); if (cp[0] == '"') { /* Special code for strings */ - find_eos(cp+1, &ncp); + find_eos(cp+1, &ncp, '"'); if (ncp[0] != '"') { report( @@ -263,6 +263,22 @@ printf("got cp %p, line %p, '%s'\n", cp, line, cp); cp[0]= '\0'; cp++; } + else if (cp[0] == '\'') + { + /* Also try single quotes */ + find_eos(cp+1, &ncp, '\''); + if (ncp[0] != '\'') + { + report( + "command line '%s', end of string not found", + line); + continue; /* Just skip it */ + } + argv[argc]= cp+1; + cp= ncp; + cp[0]= '\0'; + cp++; + } else { skip_nonspace(cp, &ncp); diff --git a/networking/rptaddrs.c b/networking/rptaddrs.c index 8506ac8..5ec0d9f 100644 --- a/networking/rptaddrs.c +++ b/networking/rptaddrs.c @@ -549,11 +549,11 @@ static int setup_ipv6_rpt(FILE *of) static int setup_dns(FILE *of) { int i, resolv_max; - char nslist[MAXNS][INET6_ADDRSTRLEN * 2]; + char *nslist[MAXNS]; resolv_max= 0; - get_local_resolvers_nocache(nslist, &resolv_max); + get_local_resolvers(nslist, &resolv_max, NULL); fprintf(of, ", " DBQ(dns) ": [ "); for (i= 0; i #include -#define OPT_STRING "lP:r:" +#define OPT_STRING "lsI:P:r:u:" enum { OPT_l = (1 << 0), + OPT_s = (1 << 1), }; #define DBQ(str) "\"" #str "\"" @@ -27,6 +28,10 @@ struct in6_addr in6addr_all_nodes = IN6ADDR_ALL_NODES_INIT; /* ff02::1 */ #define RA_PREF_HIGH 0x08 #define RA_PREF_LOW 0x18 +/* RFC-4861 */ +#define MAX_RTR_SOLICITATIONS 3 +#define RTR_SOLICITATION_INTERVAL 4 + struct opt_rdnss /* RDNSS option */ { uint8_t nd_opt_rdnss_type; @@ -35,6 +40,10 @@ struct opt_rdnss /* RDNSS option */ uint32_t nd_opt_rdnss_lifetime; }; +static int solicit_retries; +static int solicit_sock; +static char *update_cmd; + static void usage(void) { fprintf(stderr, "Usage: rptra6 \n"); @@ -132,6 +141,8 @@ static void do_resolv(char *str_resolv, char *str_resolv_new, } fclose(f); rename(str_resolv_new, str_resolv); + if (update_cmd) + system(update_cmd); } if (lifetime) *dnsexpires= time(NULL) + lifetime; @@ -390,29 +401,64 @@ static void log_ra(char *out_name, char *new_name, exit(1); } +static int send_sol(int sock) +{ + struct icmp6_hdr pkt; + struct sockaddr_in6 sin6; + + if (solicit_retries <= 0) + return 0; /* Done */ + solicit_retries--; + + pkt.icmp6_type= ND_ROUTER_SOLICIT; + pkt.icmp6_code= 0; + pkt.icmp6_data32[0]= 0; + + memset(&sin6, '\0', sizeof(sin6)); + inet_pton(AF_INET6, "FF02::2", &sin6.sin6_addr); + sin6.sin6_family= AF_INET6; + + sendto(sock, &pkt, sizeof(pkt), 0, &sin6, sizeof(sin6)); + + alarm(RTR_SOLICITATION_INTERVAL); + + return 0; +} + +static void solicit_alarm(int sig UNUSED_PARAM) +{ + send_sol(solicit_sock); +} + int rptra6_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; int rptra6_main(int argc, char *argv[]) { - int i, sock, on, nrecv, do_log; + int i, sock, hlim, on, nrecv, do_log, do_solicit; unsigned opts; size_t len; time_t dnsexpires; - char *new_name, *out_name, *str_resolv, *str_resolv_new; + char *new_name, *out_name, + *str_interface, *str_resolv, *str_resolv_new, *str_update; struct icmp6_hdr * icmp; FILE *of; char *str_pidfile; struct sockaddr_in6 remote; /* responding internet address */ struct msghdr msg; + struct sigaction sa; struct iovec iov[1]; char dnscurr[N_DNS][INET6_ADDRSTRLEN]; char cmsgbuf[256]; char packet[4096]; + str_interface= NULL; str_pidfile= NULL; str_resolv= NULL; - opts= getopt32(argv, OPT_STRING, &str_pidfile, &str_resolv); + str_update= NULL; + opts= getopt32(argv, OPT_STRING, &str_interface, &str_pidfile, + &str_resolv, &str_update); do_log= !!(opts & OPT_l); + do_solicit= !!(opts & OPT_s); if (do_log) { @@ -440,6 +486,8 @@ int rptra6_main(int argc, char *argv[]) } } + update_cmd= str_update; + str_resolv_new= NULL; if (str_resolv) { @@ -457,12 +505,35 @@ int rptra6_main(int argc, char *argv[]) return 1; } + if (str_interface) + { + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, + str_interface, strlen(str_interface)+1) == -1) + { + close(sock); + return 1; + } + } + on = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); on = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)); + if (do_solicit) + { + hlim= 255; + setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &hlim, sizeof(hlim)); + solicit_sock= sock; + solicit_retries= MAX_RTR_SOLICITATIONS; + sa.sa_handler= solicit_alarm; + sigemptyset(&sa.sa_mask); + sa.sa_flags= 0; + sigaction(SIGALRM, &sa, NULL); + send_sol(sock); + } icmp = (struct icmp6_hdr *) packet; @@ -489,6 +560,8 @@ int rptra6_main(int argc, char *argv[]) nrecv= recvmsg(sock, &msg, 0); if (nrecv < 0) { + if (errno == EINTR) + continue; printf("recvmsg failed: %s\n", strerror(errno)); break; } @@ -503,6 +576,7 @@ int rptra6_main(int argc, char *argv[]) case ICMP6_TIME_EXCEEDED: /* 3 */ case ICMP6_ECHO_REQUEST: /* 128 */ case ICMP6_ECHO_REPLY: /* 129 */ + case MLD_LISTENER_QUERY: /* 130 */ case ND_NEIGHBOR_SOLICIT: /* 135 */ case ND_NEIGHBOR_ADVERT: /* 136 */ case ND_REDIRECT: /* 137 */ diff --git a/networking/rxtxrpt.c b/networking/rxtxrpt.c index 609cedb..98e94f7 100644 --- a/networking/rxtxrpt.c +++ b/networking/rxtxrpt.c @@ -12,11 +12,15 @@ table if it has changed. #include "libbb.h" +#define NEW_FORMAT + #define DEV_FILE "/proc/net/dev" #define IF_INET6_FILE "/proc/net/if_inet6" #define IPV6_ROUTE_FILE "/proc/net/ipv6_route" #define SUFFIX ".new" +#define DBQ(str) "\"" #str "\"" + int do_atlas= 0; static int rpt_rxtx(void); @@ -28,12 +32,11 @@ static void report_err(const char *fmt, ...); int rxtxrpt_main(int argc, char *argv[]) { int r, need_report; - unsigned opt; char *opt_atlas, *cache_name; opt_atlas= NULL; opt_complementary= NULL; - opt= getopt32(argv, "A:", &opt_atlas); + getopt32(argv, "A:", &opt_atlas); do_atlas= (opt_atlas != NULL); @@ -46,13 +49,31 @@ int rxtxrpt_main(int argc, char *argv[]) if (do_atlas) { +#ifdef NEW_FORMAT + printf("RESULT { " DBQ(id) ": " DBQ(%s) ", ", opt_atlas); + printf(DBQ(fw) ": %d, ", get_atlas_fw_version()); + printf(DBQ(time) ": %lld, ", (long long)time(NULL)); + printf(DBQ(lts) ": %d, ", get_timesync()); + printf(DBQ(interfaces) ": ["); +#else /* !NEW_FORMWAT */ printf("%s %lu ", opt_atlas, time(NULL)); +#endif /* NEW_FORMWAT */ } r= rpt_rxtx(); if (r != 0) return r; + if (do_atlas) + { +#ifdef NEW_FORMAT + printf(" ] }\n"); +#else /* !NEW_FORMAT */ + printf("\n"); + +#endif /* NEW_FORMAT */ + } + if (cache_name) { r= setup_ipv6_rpt(cache_name, &need_report); @@ -66,12 +87,104 @@ int rxtxrpt_main(int argc, char *argv[]) } } - if (do_atlas) - printf("\n"); - return 0; } +#ifdef NEW_FORMAT +static int rpt_rxtx(void) +{ + int i; + unsigned long long bytes_recv, pkt_recv, errors_recv, dropped_recv, + fifo_recv, framing_recv, compressed_recv, multicast_recv, + bytes_sent, pkt_sent, errors_sent, dropped_sent, + fifo_sent, collisions_sent, carr_lost_sent, compressed_sent; + char *cp, *infname; + FILE *file; + char buf[256]; + + file= fopen(DEV_FILE, "r"); + if (!file) + { + report_err("unable to open '%s'", DEV_FILE); + return 1; + } + + /* Skip two lines */ + if (fgets(buf, sizeof(buf), file) == NULL || + fgets(buf, sizeof(buf), file) == NULL) + { + report_err("unable to read from '%s'", DEV_FILE); + fclose(file); + return 1; + } + + for (i= 0; i<4; i++) + { + if (fgets(buf, sizeof(buf), file) == NULL) + { + if (feof(file)) + break; + report_err("unable to read from '%s'", DEV_FILE); + fclose(file); + return 1; + } + + cp= buf; + + /* Skip leading white space */ + while (*cp == ' ') + cp++; + infname= cp; + cp= strchr(cp, ':'); + if (cp == NULL) + { + report_err("format error in '%s'", DEV_FILE); + fclose(file); + return 1; + } + + /* Get all the values */ + if (sscanf(cp+1, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", + &bytes_recv, &pkt_recv, &errors_recv, &dropped_recv, + &fifo_recv, &framing_recv, &compressed_recv, + &multicast_recv, + &bytes_sent, &pkt_sent, &errors_sent, &dropped_sent, + &fifo_sent, &collisions_sent, &carr_lost_sent, + &compressed_sent) != 16) + { + report_err("format error in '%s'", DEV_FILE); + fclose(file); + return 1; + } + + *cp= '\0'; + + printf("%s { " DBQ(name) ": " DBQ(%s) ", ", + i == 0 ? "" : ",", infname); + + printf(DBQ(bytes_recv) ": %llu, ", bytes_recv); + printf(DBQ(pkt_recv) ": %llu, ", pkt_recv); + printf(DBQ(errors_recv) ": %llu, ", errors_recv); + printf(DBQ(dropped_recv) ": %llu, ", dropped_recv); + printf(DBQ(fifo_recv) ": %llu, ", fifo_recv); + printf(DBQ(framing_recv) ": %llu, ", framing_recv); + printf(DBQ(compressed_recv) ": %llu, ", compressed_recv); + printf(DBQ(multicast_recv) ": %llu, ", multicast_recv); + printf(DBQ(bytes_sent) ": %llu, ", bytes_sent); + printf(DBQ(pkt_sent) ": %llu, ", pkt_sent); + printf(DBQ(errors_sent) ": %llu, ", errors_sent); + printf(DBQ(dropped_sent) ": %llu, ", dropped_sent); + printf(DBQ(fifo_sent) ": %llu, ", fifo_sent); + printf(DBQ(collisions_sent) ": %llu, ", collisions_sent); + printf(DBQ(carr_lost_sent) ": %llu, ", carr_lost_sent); + printf(DBQ(compressed_sent) ": %llu", compressed_sent); + printf(" }"); + } + fclose(file); + + return 0; +} +#else /* !NEW_FORMAT */ static int rpt_rxtx(void) { int i; @@ -120,6 +233,7 @@ static int rpt_rxtx(void) return 0; } +#endif /* NEW_FORMAT */ static int setup_ipv6_rpt(char *cache_name, int *need_report) { diff --git a/shell/hush.c b/shell/hush.c index 54d0c55..d696d73 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -102,6 +102,7 @@ /* In progress... */ #define ENABLE_HUSH_FUNCTIONS 0 +#define DBQ(str) "\"" #str "\"" /* If you comment out one of these below, it will be #defined later * to perform debug printfs to stderr: */ @@ -772,6 +773,7 @@ static int builtin_dfrm(char **argv); static int builtin_rxtxrpt(char **argv); static int builtin_rptaddrs(char **argv); static int builtin_rptuptime(char **argv); +static int builtin_onlyuptime(char **argv); static int builtin_true(char **argv); static int builtin_set(char **argv); static int builtin_shift(char **argv); @@ -833,6 +835,7 @@ static const struct built_in_command bltins[] = { BLTIN("rxtxrpt" , builtin_rxtxrpt, "report RX and TX"), BLTIN("rptaddrs" , builtin_rptaddrs, "report address(es), route(s), and dns"), BLTIN("rptuptime" , builtin_rptuptime, "report uptime"), + BLTIN("onlyuptime" , builtin_onlyuptime, "report uptime in seconds"), 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"), @@ -4536,6 +4539,79 @@ static int builtin_epoch (char **argv) return EXIT_SUCCESS; } +#define NEW_FORMAT + +#ifdef NEW_FORMAT +static int builtin_buddyinfo(char **argv) +{ + char *lowmemChar; + unsigned lowmem = 0; + FILE *fp = xfopen_for_read("/proc/buddyinfo"); + char aa[10]; + char *my_mac ; + int i = 0; + int j = 0; + int memBlock = 4; + int need_reboot = 0; // don't reboot + int freeMem = 0; + int jMax = 64; // enough + struct sysinfo info; + + lowmemChar = argv[1]; + + if(lowmemChar) + lowmem = xatou(lowmemChar); + fscanf(fp, "%s", aa); + fscanf(fp, "%s", aa); + fscanf(fp, "%s", aa); + fscanf(fp, "%s", aa); + + my_mac = getenv("ETHER_SCANNED"); + + if (lowmem >= 4 ) + { + /* We need to reboot unless we find a big enough chunk + * of memory. + */ + need_reboot = 1; + } + printf ("RESULT { " DBQ(id) ": " DBQ(9001) ", " DBQ(time) ": %lld", + (long long)time(0)); + if (my_mac != NULL) + printf(", " DBQ(macaddr) ": " DBQ(%s), my_mac); + + /* get uptime and print it */ + sysinfo(&info); + printf (", " DBQ(uptime) ": %ld", info.uptime ); + + printf(", " DBQ(buddyinfo) ": [ "); + for (j=0; j < jMax; j++) + { + if (fscanf(fp, "%d", &i) != 1) + break; + printf("%s%d", j == 0 ? "" : ", ", i); + freeMem += ( memBlock * i); + if (i > 0 && lowmem >= 4 && memBlock >= lowmem) + { + /* Found a big enough chunk */ + need_reboot = 0; + } + memBlock *= 2; + } + + /* now print it */ + printf (" ], " DBQ(freemem) ": %d }\n" , freeMem); + + fclose (fp); + + if(need_reboot) + { + fprintf(stderr, "buddy info returned 1 for block %d\n", lowmem); + return (EXIT_FAILURE); + } + return 0; +} +#else /* !NEW_FORMAT */ static int builtin_buddyinfo(char **argv) { char *lowmemChar; @@ -4625,6 +4701,7 @@ static int builtin_buddyinfo(char **argv) } return 0; } +#endif /* NEW_FORMAT */ static int builtin_findpid(char **argv) { @@ -4710,6 +4787,16 @@ static int builtin_rptuptime(char **argv __attribute((unused))) return 0; } +static int builtin_onlyuptime(char **argv __attribute((unused))) +{ + struct sysinfo info; + + sysinfo(&info); + printf("%ld\n", (long)info.uptime); + + return 0; +} + static int builtin_rchoose(char **argv) { int argc = 0; -- cgit v1.2.3