From 7f8d8aa7a9e542524e9edfcca1fe1220abbf8e40 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Wed, 20 Jan 2016 18:46:57 +0100 Subject: ripe-atlas-fw: imported version 4720 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- eperd/eooqd.c | 32 +- eperd/eperd.c | 56 +++ eperd/eperd.h | 4 + eperd/evtdig.c | 142 ++++--- eperd/httpget.c | 55 +-- eperd/ntp.c | 62 +++- eperd/ping.c | 90 +++-- eperd/sslgetcert.c | 334 +++++++++++------ eperd/tcputil.c | 16 + eperd/tcputil.h | 2 +- eperd/traceroute.c | 153 ++++++-- include/libbb.h | 1 + libbb/Kbuild | 1 + libbb/atlas_check_addr.c | 102 ++++++ miscutils/crond.c | 935 ----------------------------------------------- miscutils/ooqd.c | 31 +- networking/atlasinit.c | 740 ------------------------------------- networking/atlasinit.h | 33 -- networking/rptaddr6.c | 493 ------------------------- networking/rptaddrs.c | 8 + 20 files changed, 847 insertions(+), 2443 deletions(-) create mode 100644 libbb/atlas_check_addr.c delete mode 100644 miscutils/crond.c delete mode 100644 networking/atlasinit.c delete mode 100644 networking/atlasinit.h delete mode 100644 networking/rptaddr6.c diff --git a/eperd/eooqd.c b/eperd/eooqd.c index 04bfcd6..ed8ea64 100644 --- a/eperd/eooqd.c +++ b/eperd/eooqd.c @@ -189,20 +189,44 @@ static void checkQueue(evutil_socket_t fd UNUSED_PARAM, short what UNUSED_PARAM, void *arg UNUSED_PARAM) { int r; + struct stat sb; char filename[80]; if (!state->curr_file) { + if (stat(state->queue_file, &sb) == -1) + { + if (errno == ENOENT) + { + return; + } + report_err("stat failed"); + return; + } + + /* Remove curr_qfile. Renaming queue_file to curr_qfile + * will silently fail to delete queue_file if queue_file and + * curr_qfile are hard links. + */ + if (unlink(state->curr_qfile) == -1) + { + /* Expect ENOENT */ + if (errno != ENOENT) + { + report_err("unlink failed"); + return; + } + } + /* Try to move queue_file to curr_qfile. This provides at most * once behavior and allows producers to create a new * queue_file while we process the old one. */ if (rename(state->queue_file, state->curr_qfile) == -1) { - if (errno == ENOENT) - { - return; - } + /* We verified queue_file is there so any failure is + * fatal. + */ report_err("rename failed"); return; } diff --git a/eperd/eperd.c b/eperd/eperd.c index 30a485d..464cd6c 100644 --- a/eperd/eperd.c +++ b/eperd/eperd.c @@ -84,6 +84,10 @@ struct CronLine { /* For debugging */ time_t lasttime; + time_t nexttime; + time_t waittime; + time_t debug_cycle; + time_t debug_generated; }; @@ -712,6 +716,11 @@ static void set_timeout(CronLine *line, int init_next_cycle) line->start_time, line->distr_offset.tv_sec + line->distr_offset.tv_usec/1e6, now.tv_sec, tv.tv_sec); + line->debug_cycle= line->nextcycle; + line->debug_generated= now.tv_sec; + line->nexttime= line->nextcycle*line->interval + line->start_time + + line->distr_offset.tv_sec; + line->waittime= tv.tv_sec; event_add(&line->event, &tv); } @@ -1182,8 +1191,11 @@ static void EndJob(const char *user, CronLine *line) static void RunJob(evutil_socket_t __attribute__ ((unused)) fd, short __attribute__ ((unused)) what, void *arg) { + char c; + char *p; CronLine *line; struct timeval now; + FILE *fn; line= arg; @@ -1199,6 +1211,50 @@ static void RunJob(evutil_socket_t __attribute__ ((unused)) fd, crondlog(LVL7 "RubJob, now %d, end_time %d\n", now.tv_sec, line->end_time); + if (now.tv_sec < line->nexttime-10 || now.tv_sec > line->nexttime+10) + { + if (out_filename) + { + fn= fopen(out_filename, "a"); + if (!fn) + { + crondlog(DIE9 "unable to append to '%s'", + out_filename); + } + fprintf(fn, "RESULT { "); + if (atlas_id) + fprintf(fn, DBQ(id) ":" DBQ(%s) ", ", atlas_id); + fprintf(fn, DBQ(fw) ":" DBQ(%d) ", " DBQ(time) ":%ld, ", + get_atlas_fw_version(), (long)time(NULL)); + fprintf(fn, DBQ(reason) ": " + DBQ(inconsistent time; now %d; nexttime %d; waittime %d; cycle %d; generated %d) ", ", + (int)now.tv_sec, (int)line->nexttime, + (int)line->waittime, (int)line->debug_cycle, + (int)line->debug_generated); + + fprintf(fn, DBQ(cmd) ": \""); + for (p= line->cl_Shell; *p; p++) + { + c= *p; + if (c == '"' || c == '\\') + fprintf(fn, "\\%c", c); + else if (isprint((unsigned char)c)) + fputc(c, fn); + else + fprintf(fn, "\\u%04x", (unsigned char)c); + } + fprintf(fn, "\""); + fprintf(fn, " }\n"); + fclose(fn); + } + crondlog( + LVL7 "RunJob: weird, now %d, nexttime %d, waittime %d\n", + now.tv_sec, line->nexttime, line->waittime); + + /* Recompute nextcycle */ + set_timeout(line, 1 /*init_next_cycle*/); + return; + } if (now.tv_sec > line->end_time) { diff --git a/eperd/eperd.h b/eperd/eperd.h index e19c1a0..73b5cc6 100644 --- a/eperd/eperd.h +++ b/eperd/eperd.h @@ -56,3 +56,7 @@ extern struct testops traceroute_ops; void crondlog(const char *ctl, ...); int get_atlas_fw_version(void); + +#ifndef CLOCK_MONOTONIC_RAW +#define CLOCK_MONOTONIC_RAW 4 +#endif diff --git a/eperd/evtdig.c b/eperd/evtdig.c index 0de3541..299a79e 100644 --- a/eperd/evtdig.c +++ b/eperd/evtdig.c @@ -316,7 +316,8 @@ struct query_state { struct event next_qry_timer; /* Timer event to start next query */ struct event done_qry_timer; /* Timer event to call done */ - struct timeval xmit_time; + time_t xmit_time; + struct timespec xmit_time_ts; double triptime; //tdig_callback_type user_callback; @@ -462,8 +463,8 @@ static struct option longopts[]= { "tsig", required_argument, NULL, (100000 + T_TSIG) }, { "txt", required_argument, NULL, (100000 + T_TXT) }, - { "type", required_argument, NULL, 'O_TYPE' }, - { "class", required_argument, NULL, 'O_CLASS' }, + { "type", required_argument, NULL, O_TYPE }, + { "class", required_argument, NULL, O_CLASS }, { "query", required_argument, NULL, O_QUERY}, // clas CHAOS @@ -476,7 +477,7 @@ static struct option longopts[]= { "edns0", required_argument, NULL, 'e' }, { "nsid", no_argument, NULL, 'n' }, { "do", no_argument, NULL, 'd' }, - { "cd", no_argument, NULL, 'O_CD'}, + { "cd", no_argument, NULL, O_CD}, { "retry", required_argument, NULL, O_RETRY }, { "resolv", no_argument, NULL, O_RESOLV_CONF }, @@ -501,7 +502,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result); void printErrorQuick (struct query_state *qry); static void local_exit(void *state); static void *tdig_init(int argc, char *argv[], void (*done)(void *state)); -static void process_reply(void * arg, int nrecv, struct timeval now); +static void process_reply(void * arg, int nrecv, struct timespec now); static void mk_dns_buff(struct query_state *qry, u_char *packet); int ip_addr_cmp (u_int16_t af_a, void *a, u_int16_t af_b, void *b); static void udp_dns_cb(int err, struct evutil_addrinfo *ev_res, void *arg); @@ -556,26 +557,39 @@ int evtdig_main(int argc, char **argv) void print_txt_json(unsigned char *rdata, int txt_len,struct query_state *qry) { - int i; + int i, len; - AS("\"RDATA\" : \""); + AS("\"RDATA\" : [ \""); + len= -1; for(i = 0; i < txt_len; i++) { + if (len == 0) + { + AS("\", \""); + len= -1; + } + if (len == -1) + { + len= *rdata; + rdata++; + continue; + } if( (*rdata == 34 ) || (*rdata == 92 )) { - snprintf(line, DEFAULT_LINE_LENGTH, "\\%c", *(char *)rdata ); + snprintf(line, DEFAULT_LINE_LENGTH, "\\\\%03d", *(char *)rdata ); buf_add(&qry->result, line, strlen (line)); } - // Space - DEL - else if ((*rdata > 31 ) && (*rdata < 128)) { + // Space - ~ + else if ((*rdata >= ' ' ) && (*rdata <= '~')) { snprintf(line, DEFAULT_LINE_LENGTH, "%c", *(char *)rdata ); buf_add(&qry->result, line, strlen (line)); } else { - snprintf(line, DEFAULT_LINE_LENGTH, "\\u00%02X", *rdata ); + snprintf(line, DEFAULT_LINE_LENGTH, "\\\\%03d", *rdata ); buf_add(&qry->result, line, strlen (line)); } + len--; rdata++; } - AS("\""); + AS("\" ] "); } static void local_exit(void *state UNUSED_PARAM) @@ -709,7 +723,10 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet) lookup_prepend = xzalloc(DEFAULT_LINE_LENGTH + sizeof(qry->lookupname)); - snprintf(lookup_prepend, (sizeof(qry->lookupname) + DEFAULT_LINE_LENGTH - 1), "%d.%lu.%s", probe_id, qry->xmit_time.tv_sec, qry->lookupname); + snprintf(lookup_prepend, (sizeof(qry->lookupname) + + DEFAULT_LINE_LENGTH - 1), + "%d.%lu.%s", probe_id, qry->xmit_time, + qry->lookupname); ChangetoDnsNameFormat(qname, lookup_prepend); // fill the query portion. @@ -783,12 +800,12 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet) /* Attempt to transmit a UDP DNS Request to a serveri. TCP is else where */ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event UNUSED_PARAM, void *h) { - int fd; + int r, fd; sa_family_t af; struct query_state *qry = h; struct tdig_base *base = qry->base; uint32_t nsent = 0; - u_char *outbuff; + u_char *outbuff= NULL; int err = 0; /* Clean the no reply timer (if any was previously set) */ @@ -798,7 +815,8 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event outbuff = xzalloc(MAX_DNS_OUT_BUF_SIZE); bzero(outbuff, MAX_DNS_OUT_BUF_SIZE); //AA delete qry->outbuff = outbuff; - gettimeofday(&qry->xmit_time, NULL); + qry->xmit_time= time(NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &qry->xmit_time_ts); mk_dns_buff(qry, outbuff); do { if (qry->udp_fd != -1) @@ -815,6 +833,8 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event snprintf(line, DEFAULT_LINE_LENGTH, "%s \"socket\" : \"socket failed %s\"", qry->err.size ? ", " : "", strerror(errno)); buf_add(&qry->err, line, strlen(line)); printReply (qry, 0, NULL); + free (outbuff); + outbuff = NULL; return; } @@ -835,10 +855,28 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event qry->err.size ? ", " : ""); buf_add(&qry->err, line, strlen(line)); printReply (qry, 0, NULL); + free (outbuff); + outbuff = NULL; return; } } + if (!qry->opt_resolv_conf) + { + r= atlas_check_addr(qry->res->ai_addr, + qry->res->ai_addrlen); + if (r == -1) + { + free (outbuff); + outbuff = NULL; + snprintf(line, DEFAULT_LINE_LENGTH, + "%s \"reason\" : \"address not allowed\"", + qry->err.size ? ", " : ""); + buf_add(&qry->err, line, strlen(line)); + printReply (qry, 0, NULL); + return; + } + } qry->loc_socklen = sizeof(qry->loc_sin6); if (connect(qry->udp_fd, qry->res->ai_addr, qry->res->ai_addrlen) == -1) { @@ -848,6 +886,8 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event strerror(errno)); buf_add(&qry->err, line, strlen(line)); printReply (qry, 0, NULL); + free (outbuff); + outbuff = NULL; return; } @@ -973,6 +1013,11 @@ static void tcp_reporterr(struct tu_env *env, enum tu_err cause, buf_add(&qry->err, line, strlen(line)); break; + case TU_BAD_ADDR: + snprintf(line, DEFAULT_LINE_LENGTH, "%s \"TU_BAD_ADDR\" : true", qry->err.size ? ", " : ""); + buf_add(&qry->err, line, strlen(line)); + break; + default: snprintf(line, DEFAULT_LINE_LENGTH, "%s \"TU_UNKNOWN\" : \"%d %s\"", qry->err.size ? ", " : "", cause, str ); crondlog(DIE9 "reporterr: bad cause %d", cause); @@ -1001,9 +1046,10 @@ static void tcp_beforeconnect(struct tu_env *env, { struct query_state * qry; qry = ENV2QRY(env); - gettimeofday(&qry->xmit_time, NULL); + qry->xmit_time= time(NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &qry->xmit_time_ts); qry->dst_ai_family = addr->sa_family; - BLURT(LVL5 "time : %d", qry->xmit_time.tv_sec); + BLURT(LVL5 "time : %d", qry->xmit_time); getnameinfo(addr, addrlen, qry->dst_addr_str, INET6_ADDRSTRLEN , NULL, 0, NI_NUMERICHOST); } @@ -1045,7 +1091,7 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) struct query_state *qry = ptr; int n; u_char b2[2]; - struct timeval rectime; + struct timespec rectime; struct evbuffer *input ; struct DNS_HEADER *dnsR = NULL; @@ -1062,7 +1108,7 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) return; } - gettimeofday(&rectime, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &rectime); bzero(qry->base->packet, MAX_DNS_BUF_SIZE); input = bufferevent_get_input(bev); @@ -1086,7 +1132,10 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) crondlog(LVL5 "DBG: base pointer address readcb %p", qry->base ); dnsR = (struct DNS_HEADER*) qry->packet.buf; if ( ntohs(dnsR->id) == qry->qryid ) { - qry->triptime = (rectime.tv_sec - qry->xmit_time.tv_sec)*1000 + (rectime.tv_usec-qry->xmit_time.tv_usec)/1e3; + qry->triptime = (rectime.tv_sec - + qry->xmit_time_ts.tv_sec)*1000 + + (rectime.tv_nsec - + qry->xmit_time_ts.tv_nsec)/1e6; printReply (qry, qry->packet.size, (unsigned char *)qry->packet.buf); } else { @@ -1121,7 +1170,7 @@ static void tcp_writecb(struct bufferevent *bev UNUSED_PARAM, void *ptr UNUSED_P * o the one we are looking for (matching the same identifier of all the packets the program is able to send) */ -static void process_reply(void * arg, int nrecv, struct timeval now) +static void process_reply(void * arg, int nrecv, struct timespec now) { struct DNS_HEADER *dnsR = NULL; struct tdig_base * base; @@ -1149,8 +1198,9 @@ static void process_reply(void * arg, int nrecv, struct timeval now) } qry->base->recvbytes += nrecv; - gettimeofday(&now, NULL); // lave this till fix now from ready_callback6 corruption; ghoost - qry->triptime = (now.tv_sec-qry->xmit_time.tv_sec)*1000 + (now.tv_usec-qry->xmit_time.tv_usec)/1e3; + clock_gettime(CLOCK_MONOTONIC_RAW, &now); // lave this till fix now from ready_callback6 corruption; ghoost + qry->triptime = (now.tv_sec-qry->xmit_time_ts.tv_sec)*1000 + + (now.tv_nsec-qry->xmit_time_ts.tv_nsec)/1e6; /* Clean the noreply timer */ evtimer_del(&qry->noreply_timer); @@ -1162,7 +1212,7 @@ static void ready_callback (int unused UNUSED_PARAM, const short event UNUSED_PA { struct query_state * qry; int nrecv; - struct timeval rectime; + struct timespec rectime; // printf("in ready_callback\n"); @@ -1171,7 +1221,7 @@ static void ready_callback (int unused UNUSED_PARAM, const short event UNUSED_PA bzero(qry->base->packet, MAX_DNS_BUF_SIZE); /* Time the packet has been received */ - gettimeofday(&rectime, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &rectime); /* Receive data from the network */ nrecv = recv(qry->udp_fd, qry->base->packet, sizeof(qry->base->packet), MSG_DONTWAIT); @@ -1189,7 +1239,7 @@ static void ready_callback6 (int unused UNUSED_PARAM, const short event UNUSED_P { struct query_state * qry; int nrecv; - struct timeval rectime; + struct timespec rectime; struct msghdr msg; struct iovec iov[1]; //char buf[INET6_ADDRSTRLEN]; @@ -1429,7 +1479,7 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) qry->opt_abuf = 0; break; - case 'O_TYPE': + case O_TYPE: qry->qtype = strtoul(optarg, &check, 10); if ((qry->qtype >= 0 ) && (qry->qclass < 65536)) { @@ -1448,11 +1498,11 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state)) } break; - case 'O_CD': + case O_CD: qry->opt_cd = 1; break; - case 'O_CLASS': + case O_CLASS: qry->qclass = strtoul(optarg, &check, 10); if ((qry->qclass >= 0 ) && (qry->qclass < 65536)) { @@ -1803,6 +1853,8 @@ void tdig_start (void *arg) switch(qry->qst) { case STATUS_FREE : + /* 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); if( qry->opt_resolv_conf) { @@ -1820,6 +1872,7 @@ void tdig_start (void *arg) snprintf(line, DEFAULT_LINE_LENGTH, "\"nameserver\": \"no local resolvers found\""); buf_add(&qry->err, line, strlen(line)); printReply (qry, 0, NULL); + return; } } break; @@ -1838,7 +1891,8 @@ void tdig_start (void *arg) hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = 0; - gettimeofday(&qry->xmit_time, NULL); + qry->xmit_time= time(NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &qry->xmit_time_ts); qry->qst = STATUS_DNS_RESOLV; if(qry->opt_v6_only == 1) @@ -1915,6 +1969,7 @@ int tdig_base_count_queries(struct tdig_base *base) static void tdig_stats(int unusg_statsed UNUSED_PARAM, const short event UNUSED_PARAM, void *h) { struct timeval now; + struct timeval interval; FILE *fh; struct tdig_base *base; struct query_state *qry_h; @@ -1932,9 +1987,9 @@ static void tdig_stats(int unusg_statsed UNUSED_PARAM, const short event UNUSED_ if(qry_h->base->done) { - now.tv_sec = DEFAULT_STATS_REPORT_INTERVEL; - now.tv_usec = 0; - event_add(&tdig_base->statsReportEvent, &now); + interval.tv_sec = DEFAULT_STATS_REPORT_INTERVEL; + interval.tv_usec = 0; + event_add(&tdig_base->statsReportEvent, &interval); return; } @@ -1954,7 +2009,7 @@ static void tdig_stats(int unusg_statsed UNUSED_PARAM, const short event UNUSED_ JS(id, "9201" ); fw = get_atlas_fw_version(); JU(fw, fw); - gettimeofday(&now, NULL); + gettimeofday(&now, NULL); JS1(time, %ld, now.tv_sec); JU(sok , base->sentok); JU(rok , base->recvok); @@ -1975,10 +2030,9 @@ static void tdig_stats(int unusg_statsed UNUSED_PARAM, const short event UNUSED_ buf_cleanup(&qry->result); free(qry); - // reuse timeval now - now.tv_sec = DEFAULT_STATS_REPORT_INTERVEL; - now.tv_usec = 0; - event_add(&tdig_base->statsReportEvent, &now); + interval.tv_sec = DEFAULT_STATS_REPORT_INTERVEL; + interval.tv_usec = 0; + event_add(&tdig_base->statsReportEvent, &interval); } @@ -2171,7 +2225,7 @@ void printErrorQuick (struct query_state *qry) { fprintf(fh, ",{"); fprintf(fh, "\"id\" : \"%s\"", qry->str_Atlas); - fprintf(fh, ",\"start time\" : %ld", qry->xmit_time.tv_sec); + fprintf(fh, ",\"start time\" : %ld", qry->xmit_time); if(qry->retry) { fprintf(fh, ",\"retry\": %d", qry->retry); @@ -2218,7 +2272,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) JD(fw, fw); if (qry->opt_rset){ - JS1(time, %ld, qry->xmit_time.tv_sec); + JS1(time, %ld, qry->xmit_time); JD(lts,lts); AS("\"resultset\" : [ {"); } @@ -2228,7 +2282,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) AS (",{"); } - JS1(time, %ld, qry->xmit_time.tv_sec); + JS1(time, %ld, qry->xmit_time); JD(lts,lts); if ( qry->opt_resolv_conf ) { @@ -2339,7 +2393,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) if(ntohs(answers[i].resource->type)==T_TXT) //txt { - data_len = ntohs(answers[i].resource->data_len) - 1; + data_len = ntohs(answers[i].resource->data_len); if(flagAnswer == 0) { AS(",\"answers\" : [ {"); flagAnswer++; @@ -2350,7 +2404,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result) flagAnswer++; JS (TYPE, "TXT"); JS (NAME, answers[i].name); - print_txt_json(&result[reader-result+1], data_len, qry); + print_txt_json(&result[reader-result], data_len, qry); reader = reader + ntohs(answers[i].resource->data_len); AS("}"); diff --git a/eperd/httpget.c b/eperd/httpget.c index f68ec81..92ce453 100644 --- a/eperd/httpget.c +++ b/eperd/httpget.c @@ -117,7 +117,7 @@ struct hgstate int subid; int submax; time_t gstart; - struct timeval start; + struct timespec start; double resptime; double ttr; /* Time to resolve */ double ttc; /* Time to connect */ @@ -353,9 +353,11 @@ static void timeout_callback(int __attribute((unused)) unused, #if 1 snprintf(errline, sizeof(errline), DBQ(err) ":" - DBQ(timeout reading chunk: state %d linelen %d lineoffset %d) + DBQ(timeout reading chunk: state %ld linelen %ld lineoffset %ld) ", ", - state->readstate, state->linelen, state->lineoffset); + (long)state->readstate, + (long)state->linelen, + (long)state->lineoffset); add_str(state, errline); #else add_str(state, DBQ(err) ":" DBQ(timeout reading chunk) ", "); @@ -866,7 +868,7 @@ static int get_input(struct hgstate *state) { int n; double t; - struct timeval endtime; + struct timespec endtime; char line[80]; /* Assume that we always end up with a full buffer anyway */ @@ -900,9 +902,9 @@ static int get_input(struct hgstate *state) if (state->etim >= 2 && state->report_roffset) { - gettimeofday(&endtime, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &endtime); t= (endtime.tv_sec-state->start.tv_sec)*1e3 + - (endtime.tv_usec-state->start.tv_usec)/1e3; + (endtime.tv_nsec-state->start.tv_nsec)/1e6; if (state->roffset != 0) add_str2(state, ","); snprintf(line, sizeof(line), @@ -1025,7 +1027,7 @@ static void readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) char *cp, *ncp, *check, *line; const char *prefix, *kw; struct hgstate *state; - struct timeval endtime; + struct timespec endtime; state= ENV2STATE(ptr); @@ -1053,10 +1055,10 @@ static void readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) switch(state->readstate) { case READ_FIRST: - gettimeofday(&endtime, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &endtime); state->ttfb= (endtime.tv_sec- state->start.tv_sec)*1e3 + - (endtime.tv_usec-state->start.tv_usec)/1e3; + (endtime.tv_nsec-state->start.tv_nsec)/1e6; state->readstate= READ_STATUS; state->roffset= 0; if (state->etim >= 2) @@ -1557,12 +1559,12 @@ static void readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) if (state->bev) { state->bev= NULL; - gettimeofday(&endtime, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &endtime); state->resptime= (endtime.tv_sec- state->start.tv_sec)*1e3 + - (endtime.tv_usec- - state->start.tv_usec)/1e3; + (endtime.tv_nsec- + state->start.tv_nsec)/1e6; report(state); } return; @@ -1619,7 +1621,7 @@ static void writecb(struct bufferevent *bev, void *ptr) struct evbuffer *output; off_t cLength; struct stat sb; - struct timeval endtime; + struct timespec endtime; state= ENV2STATE(ptr); @@ -1628,10 +1630,10 @@ static void writecb(struct bufferevent *bev, void *ptr) switch(state->writestate) { case WRITE_FIRST: - gettimeofday(&endtime, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &endtime); state->ttc= (endtime.tv_sec- state->start.tv_sec)*1e3 + - (endtime.tv_usec-state->start.tv_usec)/1e3; + (endtime.tv_nsec-state->start.tv_nsec)/1e6; state->writestate= WRITE_HEADER; continue; case WRITE_HEADER: @@ -1733,7 +1735,7 @@ static void writecb(struct bufferevent *bev, void *ptr) static void err_reading(struct hgstate *state) { - struct timeval endtime; + struct timespec endtime; switch(state->readstate) { @@ -1762,9 +1764,9 @@ static void err_reading(struct hgstate *state) add_str(state, DBQ(err) ":" DBQ(error reading body) ", "); } - gettimeofday(&endtime, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &endtime); state->resptime= (endtime.tv_sec-state->start.tv_sec)*1e3 + - (endtime.tv_usec-state->start.tv_usec)/1e3; + (endtime.tv_nsec-state->start.tv_nsec)/1e6; report(state); break; default: @@ -1785,7 +1787,7 @@ static void beforeconnect(struct tu_env *env, struct sockaddr *addr, socklen_t addrlen) { struct hgstate *state; - struct timeval endtime; + struct timespec endtime; state= ENV2STATE(env); @@ -1811,12 +1813,12 @@ static void beforeconnect(struct tu_env *env, if (state->first_connect) { - gettimeofday(&endtime, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &endtime); state->ttr= (endtime.tv_sec-state->start.tv_sec)*1e3 + - (endtime.tv_usec-state->start.tv_usec)/1e3; + (endtime.tv_nsec-state->start.tv_nsec)/1e6; state->first_connect= 0; } - gettimeofday(&state->start, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &state->start); } @@ -1866,6 +1868,13 @@ static void reporterr(struct tu_env *env, enum tu_err cause, report(state); break; + case TU_BAD_ADDR: + add_str(state, "{ " DBQ(error) ": " + DBQ(address not allowed) " }"); + state->dnserr= 1; + report(state); + break; + default: crondlog(DIE9 "reporterr: bad cause %d", cause); } @@ -1907,7 +1916,7 @@ static void httpget_start(void *state) hgstate->readstate= READ_STATUS; hgstate->writestate= WRITE_HEADER; hgstate->gstart= time(NULL); - gettimeofday(&hgstate->start, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &hgstate->start); hgstate->first_connect= 1; memset(&hints, '\0', sizeof(hints)); diff --git a/eperd/ntp.c b/eperd/ntp.c index 457f34a..7dc1109 100644 --- a/eperd/ntp.c +++ b/eperd/ntp.c @@ -5,6 +5,7 @@ */ #include "libbb.h" +#include #include #include #include @@ -260,14 +261,13 @@ static void format_stratum(char *line, size_t size, uint8_t stratum) static void format_8bit(char *line, size_t size, const char *label, int8_t value) { - if (value >= 0) + if (value >= 0 && value < 32) { - snprintf(line, size, DBQ(%s) ": %d", label, 1 << value); + snprintf(line, size, DBQ(%s) ": %u", label, 1U << value); } else { - snprintf(line, size, DBQ(%s) ": %g", label, - 1.0 / (1 << -value)); + snprintf(line, size, DBQ(%s) ": %g", label, pow(2, value)); } } @@ -280,10 +280,33 @@ static void format_short_ts(char *line, size_t size, const char *label, static void format_ref_id(char *line, size_t size, uint32_t value, uint8_t stratum) { + int i; + size_t offset; + unsigned char *p; + char line2[40]; + if (stratum == 0 || stratum == 1) { - snprintf(line, size, DBQ(ref-id) ": " DBQ(%.4s), - (char *)&value); + line2[0]= '\0'; + for (i= 0, p= (unsigned char *)&value; + i= 127) + { + snprintf(line2+offset, sizeof(line2)-offset, + "\\\\x%02x", *p); + } + else + { + snprintf(line2+offset, sizeof(line2)-offset, + "%c", *p); + } + + } + snprintf(line, size, DBQ(ref-id) ": " DBQ(%s), + line2); } else { @@ -360,7 +383,7 @@ static void report(struct ntpstate *state) state->dnsip ? (state->do_v6 ? 6 : 4) : (state->sin6.sin6_family == AF_INET6 ? 6 : 4)); - if (!state->first) + if (!state->first && !state->dnsip) { format_li(line, sizeof(line), state->ntp_flags); fprintf(fh, ", %s", line); @@ -1763,6 +1786,9 @@ static int create_socket(struct ntpstate *state) protocol= 0; state->socket= xsocket(af, type, protocol); +#if 0 + { errno= ENOSYS; state->socket= -1; } +#endif if (state->socket == -1) { serrno= errno; @@ -1799,7 +1825,7 @@ static int create_socket(struct ntpstate *state) serrno= errno; snprintf(line, sizeof(line), - ", " DBQ(error) ":" DBQ(connect failed: %s) " }", + "{ " DBQ(error) ":" DBQ(connect failed: %s) " }", strerror(serrno)); add_str(state, line); report(state); @@ -1832,7 +1858,7 @@ static int create_socket(struct ntpstate *state) static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) { - int count; + int r, count; struct ntpstate *env; struct evutil_addrinfo *cur; char line[160]; @@ -1884,6 +1910,24 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) memcpy(&env->sin6, env->dns_curr->ai_addr, env->socklen); + r= atlas_check_addr((struct sockaddr *)&env->sin6, + env->socklen); + if (r == -1) + { + if (env->result) free(env->result); + env->resmax= 80; + env->result= xmalloc(env->resmax); + env->reslen= 0; + + env->starttime= time(NULL); + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(address not allowed) " }"); + add_str(env, line); + env->dnsip= 1; + report(env); + return; + } + traceroute_start2(env); evutil_freeaddrinfo(env->dns_res); diff --git a/eperd/ping.c b/eperd/ping.c index 53cbbe5..0b8d1b2 100644 --- a/eperd/ping.c +++ b/eperd/ping.c @@ -58,6 +58,7 @@ enum #define PING_ERR_SENDTO 4 /* Sendto system call failed */ #define PING_ERR_DNS 5 /* DNS error */ #define PING_ERR_DNS_NO_ADDR 6 /* DNS no suitable addresses */ +#define PING_ERR_BAD_ADDR 7 /* Addresses is not allowed */ #define PING_ERR_SHUTDOWN 10 /* The request was canceled because the PING subsystem was shut down */ #define PING_ERR_CANCEL 12 /* The request was canceled via a call to evping_cancel_request */ #define PING_ERR_UNKNOWN 16 /* An unknown error occurred */ @@ -158,7 +159,7 @@ struct pingstate * and it is used to relate each response with the corresponding request */ struct evdata { - struct timeval ts; + struct timespec ts; uint32_t index; struct cookie cookie; }; @@ -271,10 +272,10 @@ static void ping_cb(int result, int bytes, int psize, struct sockaddr *sa, socklen_t socklen, struct sockaddr *loc_sa, socklen_t loc_socklen, int seq, int ttl, - struct timeval * elapsed, void * arg) + struct timespec * elapsed, void * arg) { struct pingstate *pingstate; - unsigned long usecs; + double nsecs; char namebuf1[NI_MAXHOST], namebuf2[NI_MAXHOST]; char line[256]; @@ -304,7 +305,7 @@ static void ping_cb(int result, int bytes, int psize, if (result == PING_ERR_NONE || result == PING_ERR_DUP) { /* Got a ping reply */ - usecs= (elapsed->tv_sec * 1000000 + elapsed->tv_usec); + nsecs= (elapsed->tv_sec * 1e9 + elapsed->tv_nsec); snprintf(line, sizeof(line), "%s{ ", pingstate->first ? "" : ", "); @@ -317,7 +318,7 @@ static void ping_cb(int result, int bytes, int psize, snprintf(line, sizeof(line), DBQ(rtt) ":%f", - usecs/1000.); + nsecs/1e6); add_str(pingstate, line); if (!pingstate->got_reply && result != PING_ERR_DUP) @@ -403,6 +404,16 @@ static void ping_cb(int result, int bytes, int psize, add_str(pingstate, line); report(pingstate); } + if (result == PING_ERR_BAD_ADDR) + { + pingstate->size= bytes; + pingstate->psize= psize; + snprintf(line, sizeof(line), + "%s{ " DBQ(error) ":" DBQ(address not allowed) " }", + pingstate->first ? "" : ", "); + add_str(pingstate, line); + report(pingstate); + } if (result == PING_ERR_DONE) { report(pingstate); @@ -462,7 +473,7 @@ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq, struct icmp *icmp = (struct icmp *) buffer; struct evdata *data = (struct evdata *) (buffer + ICMP_MINLEN); - struct timeval now; + struct timespec now; minlen= sizeof(*data); if (*sizep < minlen) @@ -481,8 +492,8 @@ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq, icmp->icmp_seq = htons(seq); /* message identifier */ /* User data */ - gettimeofday(&now, NULL); - data->ts = now; /* current time */ + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + data->ts = now; /* current uptime time */ data->index = idx; /* index into an array */ data->cookie= *cookiep; @@ -514,7 +525,7 @@ static void fmticmp6(u_char *buffer, size_t *sizep, struct icmp6_hdr *icmp = (struct icmp6_hdr *) buffer; struct evdata *data = (struct evdata *) (buffer + ICMP6_HDRSIZE); - struct timeval now; + struct timespec now; minlen= sizeof(*data); if (*sizep < minlen) @@ -531,8 +542,8 @@ static void fmticmp6(u_char *buffer, size_t *sizep, icmp->icmp6_seq = htons(seq); /* message identifier */ /* User data */ - gettimeofday(&now, NULL); - data->ts = now; /* current time */ + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + data->ts = now; /* current uptime time */ data->index = idx; /* index into an array */ data->cookie= *cookiep; @@ -666,7 +677,7 @@ static void ready_callback4 (int __attribute((unused)) unused, struct icmphdr * icmp; struct evdata * data; int hlen = 0; - struct timeval now; + struct timespec now; state= arg; base = state->base; @@ -676,7 +687,7 @@ static void ready_callback4 (int __attribute((unused)) unused, data = (struct evdata *) (base->packet + IPHDR + ICMP_MINLEN); /* Time the packet has been received */ - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &now); /* Receive data from the network */ nrecv = recvfrom(state->socket, base->packet, sizeof(base->packet), MSG_DONTWAIT, (struct sockaddr *) &remote, &slen); @@ -743,10 +754,16 @@ printf("ready_callback4: too short\n"); else if (icmp->type == ICMP_ECHOREPLY) { /* Use the User Data to relate Echo Request/Reply and evaluate the Round Trip Time */ - struct timeval elapsed; /* response time */ + struct timespec elapsed; /* response time */ /* Compute time difference to calculate the round trip */ - evutil_timersub (&now, &data->ts, &elapsed); + elapsed.tv_sec= now.tv_sec - data->ts.tv_sec; + if (now.tv_nsec < data->ts.tv_sec) + { + elapsed.tv_sec--; + now.tv_nsec += 1000000000; + } + elapsed.tv_nsec= now.tv_nsec - data->ts.tv_nsec; /* Set destination address of packet as local address */ sin4p= &loc_sin4; @@ -809,7 +826,7 @@ static void ready_callback6 (int __attribute((unused)) unused, struct icmp6_hdr *icmp; struct evdata * data; - struct timeval now; + struct timespec now; struct cmsghdr *cmsgptr; struct sockaddr_in6 *sin6p; struct msghdr msg; @@ -827,7 +844,7 @@ static void ready_callback6 (int __attribute((unused)) unused, offsetof(struct icmp6_hdr, icmp6_data16[2])); /* Time the packet has been received */ - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &now); iov[0].iov_base= base->packet; iov[0].iov_len= sizeof(base->packet); @@ -879,10 +896,16 @@ static void ready_callback6 (int __attribute((unused)) unused, else if (icmp->icmp6_type == ICMP6_ECHO_REPLY) { /* Use the User Data to relate Echo Request/Reply and evaluate the Round Trip Time */ - struct timeval elapsed; /* response time */ + struct timespec elapsed; /* response time */ /* Compute time difference to calculate the round trip */ - evutil_timersub (&now, &data->ts, &elapsed); + elapsed.tv_sec= now.tv_sec - data->ts.tv_sec; + if (now.tv_nsec < data->ts.tv_sec) + { + elapsed.tv_sec--; + now.tv_nsec += 1000000000; + } + elapsed.tv_nsec= now.tv_nsec - data->ts.tv_nsec; /* Set destination address of packet as local address */ memset(&loc_sin6, '\0', sizeof(loc_sin6)); @@ -1055,6 +1078,12 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[], free(lsa); return NULL; } + + if (atlas_check_addr(&lsa->u.sa, lsa->len) == -1) + { + free(lsa); + return NULL; + } } state= xzalloc(sizeof(*state)); @@ -1233,7 +1262,7 @@ static void ping_start2(void *state) static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) { - int count; + int r, count; struct pingstate *env; struct evutil_addrinfo *cur; @@ -1274,8 +1303,6 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) for (cur= res; cur; cur= cur->ai_next) count++; - // env->reportcount(env, count); - while (env->dns_curr) { env->socklen= env->dns_curr->ai_addrlen; @@ -1284,6 +1311,25 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) memcpy(&env->sin6, env->dns_curr->ai_addr, env->socklen); + r= atlas_check_addr((struct sockaddr *)&env->sin6, + env->socklen); + if (r == -1) + { + ping_cb(PING_ERR_BAD_ADDR, env->maxsize, -1, + NULL, 0, + (struct sockaddr *)NULL, 0, + 0, 0, NULL, + env); + ping_cb(PING_ERR_DONE, env->maxsize, -1, + (struct sockaddr *)NULL, 0, + (struct sockaddr *)NULL, 0, + 0, 0, NULL, + env); + if (env->base->done) + env->base->done(env); + return; + } + ping_start2(env); return; diff --git a/eperd/sslgetcert.c b/eperd/sslgetcert.c index fa3c254..91dea01 100644 --- a/eperd/sslgetcert.c +++ b/eperd/sslgetcert.c @@ -101,8 +101,8 @@ struct state int subid; int submax; time_t gstart; - struct timeval start; - struct timeval t_connect; + struct timespec start; + struct timespec t_connect; double resptime; FILE *post_fh; char *post_buf; @@ -133,6 +133,7 @@ struct state #define BUF_CHUNK 4096 +#define MSG_ALERT 21 #define MSG_HANDSHAKE 22 #define HS_CLIENT_HELLO 1 #define HS_SERVER_HELLO 2 @@ -355,7 +356,7 @@ static void msgbuf_add(struct msgbuf *msgbuf, void *buf, size_t size) buf_add(&msgbuf->buffer, buf, size); } -static int msgbuf_read(struct msgbuf *msgbuf, int type, +static int msgbuf_read(struct msgbuf *msgbuf, int *typep, char *majorp, char *minorp) { int r; @@ -377,12 +378,7 @@ static int msgbuf_read(struct msgbuf *msgbuf, int type, continue; } p= (uint8_t *)msgbuf->inbuf->buf+msgbuf->inbuf->offset; - type= p[0]; - if (p[0] != type) - { - fprintf(stderr, "msgbuf_read: got type %d\n", p[0]); - return -1; - } + *typep= p[0]; *majorp= p[1]; *minorp= p[2]; len= (p[3] << 8) + p[4]; @@ -522,10 +518,17 @@ static void add_ciphers(struct hsbuf *hsbuf) { uint8_t c; size_t len; - uint8_t ciphers[]= { 0x0,0xff, 0x0,0x88, 0x0,0x87, 0x0,0x39, 0x0,0x38, - 0x0,0x84, 0x0,0x35, 0x0,0x45, 0x0,0x44, 0x0,0x33, 0x0,0x32, - 0x0,0x96, 0x0,0x41, 0x0,0x4, 0x0,0x5, 0x0,0x2f, 0x0,0x16, - 0x0,0x13, 0xfe,0xff, 0x0,0xa }; + uint8_t ciphers[]= { + 0xc0,0x0a, /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */ + 0xc0,0x09, /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */ + 0xc0,0x13, /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA */ + 0xc0,0x14, /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA */ + 0x00,0x33, /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA */ + 0x00,0x39, /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA */ + 0x00,0x2f, /* TLS_RSA_WITH_AES_128_CBC_SHA */ + 0x00,0x35, /* TLS_RSA_WITH_AES_256_CBC_SHA */ + 0x00,0x0a, /* TLS_RSA_WITH_3DES_EDE_CBC_SHA */ + }; len= sizeof(ciphers); @@ -872,6 +875,11 @@ static void readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) r= eat_server_hello(state); if (r == -1) return; + if (r == 1) + { + state->readstate= READ_DONE; + continue; + } state->readstate= READ_CERTS; continue; @@ -898,9 +906,164 @@ static void readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr) } } +static FILE *report_head(struct state *state) +{ + int major, minor; + const char *method; + FILE *fh; + double resptime; + struct timespec endtime; + char hostbuf[NI_MAXHOST]; + + clock_gettime(CLOCK_MONOTONIC_RAW, &endtime); + + fh= NULL; + if (state->output_file) + { + fh= fopen(state->output_file, "a"); + if (!fh) + { + crondlog(DIE9 "unable to append to '%s'", + state->output_file); + return NULL; + } + } + else + fh= stdout; + + fprintf(fh, "RESULT { "); + if (state->atlas) + { + fprintf(fh, DBQ(id) ":" DBQ(%s) + ", " DBQ(fw) ":%d" + ", " DBQ(lts) ":%d", + state->atlas, get_atlas_fw_version(), + get_timesync()); + } + + fprintf(fh, "%s" DBQ(time) ":%ld", + state->atlas ? ", " : "", time(NULL)); + fprintf(fh, ", " DBQ(dst_name) ":" DBQ(%s) ", " + DBQ(dst_port) ":" DBQ(%s), + state->hostname, state->portname); + + if (state->recv_major == 3 && state->recv_minor == 3) + { + method= "TLS"; + major= 1; + minor= 2; + } + else if (state->recv_major == 3 && state->recv_minor == 2) + { + method= "TLS"; + major= 1; + minor= 1; + } + else if (state->recv_major == 3 && state->recv_minor == 1) + { + method= "TLS"; + major= 1; + minor= 0; + } + else if (state->recv_major == 3 && state->recv_minor == 0) + { + method= "SSL"; + major= 3; + minor= 0; + } + else + { + method= "(unknown)"; + major= state->recv_major; + minor= state->recv_minor; + } + + fprintf(fh, ", " DBQ(method) ":" DBQ(%s) ", " + DBQ(ver) ":" DBQ(%d.%d), method, major, minor); + getnameinfo((struct sockaddr *)&state->sin6, state->socklen, + hostbuf, sizeof(hostbuf), NULL, 0, + NI_NUMERICHOST); + fprintf(fh, ", " DBQ(dst_addr) ":" DBQ(%s), hostbuf); + fprintf(fh, ", " DBQ(af) ": %d", + state->sin6.sin6_family == AF_INET6 ? 6 : 4); + + getnameinfo((struct sockaddr *)&state->loc_sin6, + state->loc_socklen, hostbuf, sizeof(hostbuf), NULL, 0, + NI_NUMERICHOST); + fprintf(fh, ", " DBQ(src_addr) ":" DBQ(%s), hostbuf); + + resptime= (state->t_connect.tv_sec- state->start.tv_sec)*1e3 + + (state->t_connect.tv_nsec-state->start.tv_nsec)/1e6; + fprintf(fh, ", " DBQ(ttc) ": %f", resptime); + + resptime= (endtime.tv_sec- state->start.tv_sec)*1e3 + + (endtime.tv_nsec-state->start.tv_nsec)/1e6; + fprintf(fh, ", " DBQ(rt) ": %f", resptime); + + return fh; +} + +static int eat_alert(struct state *state) +{ + int r, type, level, descr; + uint8_t *p; + struct msgbuf *msgbuf; + FILE *fh; + + msgbuf= &state->msginbuf; + + for (;;) + { + if (msgbuf->buffer.size - msgbuf->buffer.offset < 2) + { + r= msgbuf_read(msgbuf, &type, + &state->recv_major, &state->recv_minor); + if (r < 0) + { + if (errno != EAGAIN) + { + fprintf(stderr, + "eat_alert: msgbuf_read failed: %s\n", + strerror(errno)); + } + return -1; + } + if (type != MSG_ALERT) + { + fprintf(stderr, + "eat_alert: got bad type %d from msgbuf_read\n", + type); + return -1; + } + continue; + } + p= (uint8_t *)msgbuf->buffer.buf+msgbuf->buffer.offset; + level= p[0]; + descr= p[1]; + + fh= report_head(state); + if (!fh) + return -1; + + fprintf(fh, ", " DBQ(alert) ": { " DBQ(level) ": %d, " + DBQ(decription) ": %d }", + level, descr); + + msgbuf->buffer.offset += 2; + break; + } + + fprintf(fh, " }\n"); + + if (state->output_file) + fclose(fh); + + return 1; +} + static int eat_server_hello(struct state *state) { - int r; + int r, type; size_t len; uint8_t *p; struct msgbuf *msgbuf; @@ -911,7 +1074,7 @@ static int eat_server_hello(struct state *state) { if (msgbuf->buffer.size - msgbuf->buffer.offset < 4) { - r= msgbuf_read(msgbuf, MSG_HANDSHAKE, + r= msgbuf_read(msgbuf, &type, &state->recv_major, &state->recv_minor); if (r < 0) { @@ -920,6 +1083,20 @@ static int eat_server_hello(struct state *state) return -1; } + if (type == MSG_ALERT) + { + r= eat_alert(state); + if (r == 0) + continue; + return r; /* No need to continue */ + } + if (type != MSG_HANDSHAKE) + { + fprintf(stderr, + "eat_server_hello: got bad type %d from msgbuf_read\n", + type); + return -1; + } continue; } p= (uint8_t *)msgbuf->buffer.buf+msgbuf->buffer.offset; @@ -932,7 +1109,7 @@ static int eat_server_hello(struct state *state) len= (p[1] << 16) + (p[2] << 8) + p[3]; if (msgbuf->buffer.size - msgbuf->buffer.offset < 4+len) { - r= msgbuf_read(msgbuf, MSG_HANDSHAKE, + r= msgbuf_read(msgbuf, &type, &state->recv_major, &state->recv_minor); if (r < 0) { @@ -940,6 +1117,13 @@ static int eat_server_hello(struct state *state) "eat_server_hello: msgbuf_read failed\n"); return -1; } + if (type != MSG_HANDSHAKE) + { + fprintf(stderr, + "eat_server_hello: got bad type %d from msgbuf_read\n", + type); + return -1; + } continue; } msgbuf->buffer.offset += 4+len; @@ -950,16 +1134,12 @@ static int eat_server_hello(struct state *state) static int eat_certificate(struct state *state) { - int i, n, r, first, slen, need_nl, major, minor; + int i, n, r, first, slen, need_nl, type; size_t o, len; - const char *method; uint8_t *p; struct msgbuf *msgbuf; FILE *fh; - double resptime; - struct timeval endtime; struct buf tmpbuf; - char hostbuf[NI_MAXHOST]; msgbuf= &state->msginbuf; @@ -967,7 +1147,7 @@ static int eat_certificate(struct state *state) { if (msgbuf->buffer.size - msgbuf->buffer.offset < 4) { - r= msgbuf_read(msgbuf, MSG_HANDSHAKE, + r= msgbuf_read(msgbuf, &type, &state->recv_major, &state->recv_minor); if (r < 0) { @@ -979,6 +1159,13 @@ static int eat_certificate(struct state *state) } return -1; } + if (type != MSG_HANDSHAKE) + { + fprintf(stderr, + "eat_certificate: got bad type %d from msgbuf_read\n", + type); + return -1; + } continue; } p= (uint8_t *)msgbuf->buffer.buf+msgbuf->buffer.offset; @@ -990,7 +1177,7 @@ static int eat_certificate(struct state *state) len= (p[1] << 16) + (p[2] << 8) + p[3]; if (msgbuf->buffer.size - msgbuf->buffer.offset < 4+len) { - r= msgbuf_read(msgbuf, MSG_HANDSHAKE, + r= msgbuf_read(msgbuf, &type, &state->recv_major, &state->recv_minor); if (r < 0) { @@ -998,93 +1185,22 @@ static int eat_certificate(struct state *state) "eat_certificate: msgbuf_read failed\n"); return -1; } + if (type != MSG_HANDSHAKE) + { + fprintf(stderr, + "eat_certificate: got bad type %d from msgbuf_read\n", + type); + return -1; + } continue; } p += 4; n= (p[0] << 16) + (p[1] << 8) + p[2]; o= 3; - gettimeofday(&endtime, NULL); - - fh= NULL; - if (state->output_file) - { - fh= fopen(state->output_file, "a"); - if (!fh) - crondlog(DIE9 "unable to append to '%s'", - state->output_file); - } - else - fh= stdout; - - fprintf(fh, "RESULT { "); - if (state->atlas) - { - fprintf(fh, DBQ(id) ":" DBQ(%s) - ", " DBQ(fw) ":%d" - ", " DBQ(lts) ":%d", - state->atlas, get_atlas_fw_version(), - get_timesync()); - } - - fprintf(fh, "%s" DBQ(time) ":%ld", - state->atlas ? ", " : "", time(NULL)); - fprintf(fh, ", " DBQ(dst_name) ":" DBQ(%s) ", " - DBQ(dst_port) ":" DBQ(%s), - state->hostname, state->portname); - - if (state->recv_major == 3 && state->recv_minor == 3) - { - method= "TLS"; - major= 1; - minor= 2; - } - else if (state->recv_major == 3 && state->recv_minor == 2) - { - method= "TLS"; - major= 1; - minor= 1; - } - else if (state->recv_major == 3 && state->recv_minor == 1) - { - method= "TLS"; - major= 1; - minor= 0; - } - else if (state->recv_major == 3 && state->recv_minor == 0) - { - method= "SSL"; - major= 3; - minor= 0; - } - else - { - method= "(unknown)"; - major= state->recv_major; - minor= state->recv_minor; - } - - fprintf(fh, ", " DBQ(method) ":" DBQ(%s) ", " - DBQ(ver) ":" DBQ(%d.%d), method, major, minor); - getnameinfo((struct sockaddr *)&state->sin6, state->socklen, - hostbuf, sizeof(hostbuf), NULL, 0, - NI_NUMERICHOST); - fprintf(fh, ", " DBQ(dst_addr) ":" DBQ(%s), hostbuf); - fprintf(fh, ", " DBQ(af) ": %d", - state->sin6.sin6_family == AF_INET6 ? 6 : 4); - - getnameinfo((struct sockaddr *)&state->loc_sin6, - state->loc_socklen, hostbuf, sizeof(hostbuf), NULL, 0, - NI_NUMERICHOST); - fprintf(fh, ", " DBQ(src_addr) ":" DBQ(%s), hostbuf); - - resptime= (state->t_connect.tv_sec- state->start.tv_sec)*1e3 + - (state->t_connect.tv_usec-state->start.tv_usec)/1e3; - fprintf(fh, ", " DBQ(ttc) ": %f", resptime); - - resptime= (endtime.tv_sec- state->start.tv_sec)*1e3 + - (endtime.tv_usec-state->start.tv_usec)/1e3; - fprintf(fh, ", " DBQ(rt) ": %f", resptime); + fh= report_head(state); + if (fh == NULL) + return -1; first= 1; fprintf(fh, ", " DBQ(cert) ":[ "); @@ -1158,7 +1274,7 @@ static void writecb(struct bufferevent *bev, void *ptr) switch(state->writestate) { case WRITE_HELLO: - gettimeofday(&state->t_connect, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &state->t_connect); buf_init(&outbuf, bev); msgbuf_init(&msgoutbuf, NULL, &outbuf); @@ -1242,7 +1358,7 @@ static void beforeconnect(struct tu_env *env, //if (!state->do_all || !state->do_combine) state->reslen= 0; - gettimeofday(&state->start, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &state->start); } @@ -1292,6 +1408,12 @@ static void reporterr(struct tu_env *env, enum tu_err cause, report(state); break; + case TU_BAD_ADDR: + add_str(state, DBQ(error) ": " DBQ(address not allowed)); + state->dnserr= 1; + report(state); + break; + default: crondlog(DIE9 "reporterr: bad cause %d", cause); } diff --git a/eperd/tcputil.c b/eperd/tcputil.c index e1d4505..22885b0 100644 --- a/eperd/tcputil.c +++ b/eperd/tcputil.c @@ -63,6 +63,14 @@ void tu_restart_connect(struct tu_env *env) { evtimer_add(&env->timer, &env->interval); + r= atlas_check_addr(env->dns_curr->ai_addr, + env->dns_curr->ai_addrlen); + if (r == -1) + { + env->reporterr(env, TU_BAD_ADDR, ""); + return; + } + env->beforeconnect(env, env->dns_curr->ai_addr, env->dns_curr->ai_addrlen); @@ -166,6 +174,14 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) { evtimer_add(&env->timer, &env->interval); + r= atlas_check_addr(env->dns_curr->ai_addr, + env->dns_curr->ai_addrlen); + if (r == -1) + { + env->reporterr(env, TU_BAD_ADDR, ""); + return; + } + env->beforeconnect(env, env->dns_curr->ai_addr, env->dns_curr->ai_addrlen); diff --git a/eperd/tcputil.h b/eperd/tcputil.h index 1264299..89cfbcd 100644 --- a/eperd/tcputil.h +++ b/eperd/tcputil.h @@ -7,7 +7,7 @@ #include enum tu_err { TU_DNS_ERR, TU_READ_ERR, TU_SOCKET_ERR, TU_CONNECT_ERR, - TU_OUT_OF_ADDRS }; + TU_OUT_OF_ADDRS, TU_BAD_ADDR }; struct tu_env { char dnsip; diff --git a/eperd/traceroute.c b/eperd/traceroute.c index 26194c0..4875721 100644 --- a/eperd/traceroute.c +++ b/eperd/traceroute.c @@ -142,7 +142,7 @@ struct trtstate struct evutil_addrinfo *dns_curr; time_t starttime; - struct timeval xmit_time; + struct timespec xmit_time; struct event timer; @@ -185,7 +185,7 @@ struct v6info uint32_t pid; uint32_t id; uint32_t seq; - struct timeval tv; + struct timespec tv; }; static int create_socket(struct trtstate *state, int do_tcp); @@ -520,7 +520,7 @@ static void send_pkt(struct trtstate *state) } state->seq++; - gettimeofday(&state->xmit_time, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &state->xmit_time); if (state->sin6.sin6_family == AF_INET6) { @@ -1362,11 +1362,12 @@ static void ready_callback4(int __attribute((unused)) unused, struct tcphdr *etcp; struct udphdr *eudp; double ms; - struct timeval now, interval; + struct timespec now; + struct timeval interval; struct sockaddr_in remote; char line[80]; - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &now); state= s; base= state->base; @@ -1510,7 +1511,7 @@ static void ready_callback4(int __attribute((unused)) unused, state->last_response_hop= state->hop; ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + - (now.tv_usec-state->xmit_time.tv_usec)/1e3; + (now.tv_nsec-state->xmit_time.tv_nsec)/1e6; snprintf(line, sizeof(line), "%s\"from\":\"%s\"", (late || isDup) ? ", " : "", @@ -1724,7 +1725,7 @@ printf("curpacksize: %d\n", state->curpacksize); state->last_response_hop= state->hop; ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + - (now.tv_usec-state->xmit_time.tv_usec)/1e3; + (now.tv_nsec-state->xmit_time.tv_nsec)/1e6; snprintf(line, sizeof(line), "%s\"from\":\"%s\"", (late || isDup) ? ", " : "", @@ -1952,7 +1953,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family state->last_response_hop= state->hop; ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + - (now.tv_usec-state->xmit_time.tv_usec)/1e3; + (now.tv_nsec-state->xmit_time.tv_nsec)/1e6; snprintf(line, sizeof(line), "%s\"from\":\"%s\"", (late || isDup) ? ", " : "", @@ -2223,7 +2224,7 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + - (now.tv_usec-state->xmit_time.tv_usec)/1e3; + (now.tv_nsec-state->xmit_time.tv_nsec)/1e6; snprintf(line, sizeof(line), "%s\"from\":\"%s\"", (late || isDup) ? ", " : "", @@ -2278,12 +2279,52 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family } } +static void report_hdropts(struct trtstate *state, unsigned char *s, + unsigned char *e) +{ + int o, len, mss; + unsigned char *orig_s; + char line[80]; + + add_str(state, ", " DBQ(hdropts) ": [ "); + orig_s= s; + while (s e) + { + printf("report_hdropts: bad option\n"); + break; + } + mss= (s[2] << 8) | s[3]; + snprintf(line, sizeof(line), + "%s{ " DBQ(mss) ":%d }", + s != orig_s ? ", " : "", mss); + add_str(state, line); + s += len; + continue; + default: + snprintf(line, sizeof(line), + "%s{ " DBQ(unknown-opt) ":%d }", + s != orig_s ? ", " : "", o); + add_str(state, line); + break; + } + break; + } + add_str(state, " ]"); +} + static void ready_tcp4(int __attribute((unused)) unused, const short __attribute((unused)) event, void *s) { uint16_t myport; socklen_t slen; - int hlen, late, isDup; + int hlen, late, isDup, tcp_hlen; unsigned ind, seq; ssize_t nrecv; struct trtbase *base; @@ -2291,12 +2332,13 @@ static void ready_tcp4(int __attribute((unused)) unused, struct ip *ip; double ms; struct tcphdr *tcphdr; + unsigned char *e, *p; struct sockaddr_in remote; - struct timeval now; + struct timespec now; struct timeval interval; char line[80]; - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &now); state= s; base= state->base; @@ -2323,6 +2365,14 @@ static void ready_tcp4(int __attribute((unused)) unused, tcphdr= (struct tcphdr *)(base->packet+hlen); + tcp_hlen= tcphdr->doff * 4; + if (nrecv < hlen + tcp_hlen || tcphdr->doff < 5) + { + /* Short packet */ + printf("ready_tcp4: too short %d\n", (int)nrecv); + return; + } + /* Quick check if the port is in range */ myport= ntohs(tcphdr->dest); if (myport < SRC_BASE_PORT || myport > SRC_BASE_PORT+256) @@ -2389,7 +2439,7 @@ printf("got seq %d, expected %d\n", seq, state->seq); } ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + - (now.tv_usec-state->xmit_time.tv_usec)/1e3; + (now.tv_nsec-state->xmit_time.tv_nsec)/1e6; snprintf(line, sizeof(line), "%s\"from\":\"%s\"", (late || isDup) ? ", " : "", @@ -2407,6 +2457,13 @@ printf("got seq %d, expected %d\n", seq, state->seq); (tcphdr->urg ? "U" : "")); add_str(state, line); + if (tcp_hlen > sizeof(*tcphdr)) + { + p= (unsigned char *)&tcphdr[1]; + e= ((unsigned char *)tcphdr) + tcp_hlen; + report_hdropts(state, p, e); + } + if (!late) { snprintf(line, sizeof(line), ", \"rtt\":%.3f", ms); @@ -2446,25 +2503,26 @@ static void ready_tcp6(int __attribute((unused)) unused, const short __attribute((unused)) event, void *s) { uint16_t myport; - int late, isDup, rcvdttl; + int late, isDup, rcvdttl, tcp_hlen; unsigned ind, seq; ssize_t nrecv; struct trtbase *base; struct trtstate *state; double ms; + unsigned char *e, *p; struct tcphdr *tcphdr; struct cmsghdr *cmsgptr; struct msghdr msg; struct iovec iov[1]; struct sockaddr_in6 remote; struct in6_addr dstaddr; - struct timeval now; + struct timespec now; struct timeval interval; char buf[INET6_ADDRSTRLEN]; char line[80]; char cmsgbuf[256]; - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &now); state= s; base= state->base; @@ -2509,6 +2567,14 @@ static void ready_tcp6(int __attribute((unused)) unused, tcphdr= (struct tcphdr *)(base->packet); + tcp_hlen= tcphdr->doff * 4; + if (nrecv < tcp_hlen || tcphdr->doff < 5) + { + /* Short packet */ + printf("ready_tcp6: too short %d\n", (int)nrecv); + return; + } + /* Quick check if the port is in range */ myport= ntohs(tcphdr->dest); if (myport < SRC_BASE_PORT || myport > SRC_BASE_PORT+256) @@ -2573,7 +2639,7 @@ printf("got seq %d, expected %d\n", seq, state->seq); } ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + - (now.tv_usec-state->xmit_time.tv_usec)/1e3; + (now.tv_nsec-state->xmit_time.tv_nsec)/1e6; snprintf(line, sizeof(line), "%s\"from\":\"%s\"", (late || isDup) ? ", " : "", @@ -2590,6 +2656,14 @@ printf("got seq %d, expected %d\n", seq, state->seq); (tcphdr->ack ? "A" : ""), (tcphdr->urg ? "U" : "")); add_str(state, line); + + if (tcp_hlen > sizeof(*tcphdr)) + { + p= (unsigned char *)&tcphdr[1]; + e= ((unsigned char *)tcphdr) + tcp_hlen; + report_hdropts(state, p, e); + } + if (!late) { snprintf(line, sizeof(line), ", \"rtt\":%.3f", ms); @@ -2644,7 +2718,7 @@ static void ready_callback6(int __attribute((unused)) unused, struct cmsghdr *cmsgptr; void *ptr; double ms; - struct timeval now; + struct timespec now; struct sockaddr_in6 remote; struct in6_addr dstaddr; struct msghdr msg; @@ -2654,7 +2728,7 @@ static void ready_callback6(int __attribute((unused)) unused, char line[80]; char cmsgbuf[256]; - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC_RAW, &now); state= s; base= state->base; @@ -3015,14 +3089,13 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family if (!late) { ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + - (now.tv_usec-state->xmit_time.tv_usec)/ - 1e3; + (now.tv_nsec-state->xmit_time.tv_nsec)/ + 1e6; } else if (v6info) { ms= (now.tv_sec-v6info->tv.tv_sec)*1000 + - (now.tv_usec-v6info->tv.tv_usec)/ - 1e3; + (now.tv_nsec-v6info->tv.tv_nsec)/1e6; } snprintf(line, sizeof(line), "%s\"from\":\"%s\"", @@ -3295,14 +3368,12 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family if (!late) { ms= (now.tv_sec-state->xmit_time.tv_sec)*1000 + - (now.tv_usec-state->xmit_time.tv_usec)/ - 1e3; + (now.tv_nsec-state->xmit_time.tv_nsec)/1e6; } else { ms= (now.tv_sec-v6info->tv.tv_sec)*1000 + - (now.tv_usec-v6info->tv.tv_usec)/ - 1e3; + (now.tv_nsec-v6info->tv.tv_nsec)/1e6; } snprintf(line, sizeof(line), "%s\"from\":\"%s\"", @@ -3510,6 +3581,12 @@ for (i= 0; argv[i] != NULL; i++) free(lsa); return NULL; } + + if (atlas_check_addr(&lsa->u.sa, lsa->len) == -1) + { + free(lsa); + return NULL; + } } else { @@ -3547,6 +3624,8 @@ for (i= 0; argv[i] != NULL; i++) state->result= NULL; state->reslen= 0; state->resmax= 0; + state->socket_icmp= -1; + state->socket_tcp= -1; for (i= 0; itabsiz; i++) { @@ -3863,7 +3942,7 @@ static int create_socket(struct trtstate *state, int do_tcp) static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) { - int count; + int r, count; struct trtstate *env; struct evutil_addrinfo *cur; char line[160]; @@ -3915,6 +3994,24 @@ static void dns_cb(int result, struct evutil_addrinfo *res, void *ctx) memcpy(&env->sin6, env->dns_curr->ai_addr, env->socklen); + r= atlas_check_addr((struct sockaddr *)&env->sin6, + env->socklen); + if (r == -1) + { + if (env->result) free(env->result); + env->resmax= 80; + env->result= xmalloc(env->resmax); + env->reslen= 0; + + env->starttime= time(NULL); + snprintf(line, sizeof(line), + "{ " DBQ(error) ":" DBQ(address not allowed) " }"); + add_str(env, line); + env->dnsip= 1; + report(env); + return; + } + traceroute_start2(env); evutil_freeaddrinfo(env->dns_res); diff --git a/include/libbb.h b/include/libbb.h index 98775ae..3c8ad56 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -316,6 +316,7 @@ 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); +extern int atlas_check_addr(const struct sockaddr *sa, socklen_t len); int ndelay_on(int fd) FAST_FUNC; int ndelay_off(int fd) FAST_FUNC; diff --git a/libbb/Kbuild b/libbb/Kbuild index 0b77f72..9a17725 100644 --- a/libbb/Kbuild +++ b/libbb/Kbuild @@ -11,6 +11,7 @@ lib-y += ask_confirmation.o lib-y += atlas_bb64.o lib-y += atlas_probe.o lib-y += atlas_timesync.o +lib-y += atlas_check_addr.o lib-y += bb_askpass.o lib-y += bb_basename.o lib-y += bb_do_delay.o diff --git a/libbb/atlas_check_addr.c b/libbb/atlas_check_addr.c new file mode 100644 index 0000000..ea6724d --- /dev/null +++ b/libbb/atlas_check_addr.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 RIPE NCC + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" + +struct ipv4_prefix +{ + uint32_t addr; + unsigned len; +} +static bad_ipv4[] = +{ + { 0x7F000000, 8 }, /* 127.0.0.0/8 localhost */ + { 0x0A000000, 8 }, /* 10.0.0.0/8 (RFC-1918) */ + { 0xAC100000, 12 }, /* 172.16.0.0/12 (RFC-1918) */ + { 0xC0A80000, 16 }, /* 192.168.0.0/16 (RFC-1918) */ + { 0xA9FE0000, 16 }, /* 169.254.0.0/16 (RFC-3927) */ + { 0xE0000000, 3 }, /* 224.0.0.0/3 multicast and reserved */ +}; + +struct ipv6_prefix +{ + uint16_t addr[8]; + unsigned len; +} +static bad_ipv6[] = +{ + { { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001 }, + 128 }, /* ::1 loopback */ + { { 0xE000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + 3 }, /* e000::/3 ULA, link local, multicast */ +}; + +int atlas_check_addr(const struct sockaddr *sa, socklen_t len) +{ + uint16_t addr2, mask2; + int i, j, prefix_len; + uint32_t addr4, mask4; + uint16_t *addr2p; + const struct sockaddr_in *sin4p; + const struct sockaddr_in6 *sin6p; + + switch(sa->sa_family) + { + case AF_INET: + if (len < sizeof(*sin4p)) + return -1; + sin4p= (const struct sockaddr_in *)sa; + addr4= sin4p->sin_addr.s_addr; + addr4= ntohl(addr4); + for (i= 0; isin6_addr; + for (i= 0; i -f -b - * - * run as root, but NOT setuid root - * - * Copyright 1994 Matthew Dillon (dillon@apollo.west.oic.com) - * (version 2.3.2) - * Vladimir Oleynik (C) 2002 - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - */ - -#include "libbb.h" -#include - -/* glibc frees previous setenv'ed value when we do next setenv() - * of the same variable. uclibc does not do this! */ -#if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */ -#define SETENV_LEAKS 0 -#else -#define SETENV_LEAKS 1 -#endif - - -#ifndef CRONTABS -#define CRONTABS "/var/spool/cron/crontabs" -#endif -#ifndef TMPDIR -#define TMPDIR "/var/spool/cron" -#endif -#ifndef SENDMAIL -#define SENDMAIL "sendmail" -#endif -#ifndef SENDMAIL_ARGS -#define SENDMAIL_ARGS "-ti", "oem" -#endif -#ifndef CRONUPDATE -#define CRONUPDATE "cron.update" -#endif -#ifndef MAXLINES -#define MAXLINES 256 /* max lines in non-root crontabs */ -#endif - - -typedef struct CronFile { - struct CronFile *cf_Next; - struct CronLine *cf_LineBase; - char *cf_User; /* username */ - smallint cf_Ready; /* bool: one or more jobs ready */ - smallint cf_Running; /* bool: one or more jobs running */ - smallint cf_Deleted; /* marked for deletion, ignore */ -} CronFile; - -typedef struct CronLine { - struct CronLine *cl_Next; - char *cl_Shell; /* shell command */ - pid_t cl_Pid; /* running pid, 0, or armed (-1) */ -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL - int cl_MailPos; /* 'empty file' size */ - smallint cl_MailFlag; /* running pid is for mail */ - char *cl_MailTo; /* whom to mail results */ -#endif - /* ordered by size, not in natural order. makes code smaller: */ - char cl_Dow[7]; /* 0-6, beginning sunday */ - char cl_Mons[12]; /* 0-11 */ - char cl_Hrs[24]; /* 0-23 */ - char cl_Days[32]; /* 1-31 */ - char cl_Mins[60]; /* 0-59 */ -} CronLine; - - -#define DaemonUid 0 - - -enum { - OPT_l = (1 << 0), - OPT_L = (1 << 1), - OPT_f = (1 << 2), - OPT_b = (1 << 3), - OPT_S = (1 << 4), - OPT_c = (1 << 5), - OPT_d = (1 << 6) * ENABLE_FEATURE_CROND_D, -}; -#if ENABLE_FEATURE_CROND_D -#define DebugOpt (option_mask32 & OPT_d) -#else -#define DebugOpt 0 -#endif - - -struct globals { - unsigned LogLevel; /* = 8; */ - const char *LogFile; - const char *CDir; /* = CRONTABS; */ - CronFile *FileBase; -#if SETENV_LEAKS - char *env_var_user; - char *env_var_home; -#endif -}; -#define G (*(struct globals*)&bb_common_bufsiz1) -#define LogLevel (G.LogLevel ) -#define LogFile (G.LogFile ) -#define CDir (G.CDir ) -#define FileBase (G.FileBase ) -#define env_var_user (G.env_var_user ) -#define env_var_home (G.env_var_home ) -#define INIT_G() do { \ - LogLevel = 8; \ - CDir = CRONTABS; \ -} while (0) - - -static void CheckUpdates(void); -static void SynchronizeDir(void); -static int TestJobs(time_t t1, time_t t2); -static void RunJobs(void); -static int CheckJobs(void); -static void RunJob(const char *user, CronLine *line); -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL -static void EndJob(const char *user, CronLine *line); -#else -#define EndJob(user, line) ((line)->cl_Pid = 0) -#endif -static void DeleteFile(const char *userName); - - -#define LVL5 "\x05" -#define LVL7 "\x07" -#define LVL8 "\x08" -#define LVL9 "\x09" -#define WARN9 "\x49" -#define DIE9 "\xc9" -/* level >= 20 is "error" */ -#define ERR20 "\x14" - -static void crondlog(const char *ctl, ...) -{ - va_list va; - int level = (ctl[0] & 0x1f); - - va_start(va, ctl); - if (level >= (int)LogLevel) { - /* Debug mode: all to (non-redirected) stderr, */ - /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ - if (!DebugOpt && LogFile) { - /* Otherwise (log to file): we reopen log file at every write: */ - int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600); - if (logfd >= 0) - xmove_fd(logfd, STDERR_FILENO); - } -// TODO: ERR -> error, WARN -> warning, LVL -> info - bb_verror_msg(ctl + 1, va, /* strerr: */ NULL); - } - va_end(va); - if (ctl[0] & 0x80) - exit(20); -} - -int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int crond_main(int argc UNUSED_PARAM, char **argv) -{ - unsigned opt; - - INIT_G(); - - /* "-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_CROND_D(":d-l") - ":l+:d+"; /* -l and -d have numeric param */ - opt = getopt32(argv, "l:L:fbSc:" USE_FEATURE_CROND_D("d:"), - &LogLevel, &LogFile, &CDir - USE_FEATURE_CROND_D(,&LogLevel)); - /* both -d N and -l N set the same variable: LogLevel */ - - if (!(opt & OPT_f)) { - /* close stdin, stdout, stderr. - * close unused descriptors - don't need them. */ - bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); - } - - if (!DebugOpt && LogFile == NULL) { - /* logging to syslog */ - openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); - logmode = LOGMODE_SYSLOG; - } - - xchdir(CDir); - //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ - xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ - crondlog(LVL9 "crond (busybox "BB_VER") started, log level %d", LogLevel); - SynchronizeDir(); - - /* main loop - synchronize to 1 second after the minute, minimum sleep - * of 1 second. */ - { - time_t t1 = time(NULL); - time_t t2; - long dt; - int rescan = 60; - int sleep_time = 60; - - write_pidfile("/var/run/crond.pid"); - for (;;) { - sleep((sleep_time + 1) - (time(NULL) % sleep_time)); - - t2 = time(NULL); - dt = (long)t2 - (long)t1; - - /* - * The file 'cron.update' is checked to determine new cron - * jobs. The directory is rescanned once an hour to deal - * with any screwups. - * - * check for disparity. Disparities over an hour either way - * result in resynchronization. A reverse-indexed disparity - * less then an hour causes us to effectively sleep until we - * match the original time (i.e. no re-execution of jobs that - * have just been run). A forward-indexed disparity less then - * an hour causes intermediate jobs to be run, but only once - * in the worst case. - * - * when running jobs, the inequality used is greater but not - * equal to t1, and less then or equal to t2. - */ - if (--rescan == 0) { - rescan = 60; - SynchronizeDir(); - } - CheckUpdates(); - if (DebugOpt) - crondlog(LVL5 "wakeup dt=%ld", dt); - if (dt < -60 * 60 || dt > 60 * 60) { - crondlog(WARN9 "time disparity of %d minutes detected", dt / 60); - } else if (dt > 0) { - TestJobs(t1, t2); - RunJobs(); - sleep(5); - if (CheckJobs() > 0) { - sleep_time = 10; - } else { - sleep_time = 60; - } - } - t1 = t2; - } - } - return 0; /* not reached */ -} - -#if SETENV_LEAKS -/* We set environment *before* vfork (because we want to use vfork), - * so we cannot use setenv() - repeated calls to setenv() may leak memory! - * Using putenv(), and freeing memory after unsetenv() won't leak */ -static void safe_setenv4(char **pvar_val, const char *var, const char *val /*, int len*/) -{ - const int len = 4; /* both var names are 4 char long */ - char *var_val = *pvar_val; - - if (var_val) { - var_val[len] = '\0'; /* nuke '=' */ - unsetenv(var_val); - free(var_val); - } - *pvar_val = xasprintf("%s=%s", var, val); - putenv(*pvar_val); -} -#endif - -static void SetEnv(struct passwd *pas) -{ -#if SETENV_LEAKS - safe_setenv4(&env_var_user, "USER", pas->pw_name); - safe_setenv4(&env_var_home, "HOME", pas->pw_dir); - /* if we want to set user's shell instead: */ - /*safe_setenv(env_var_user, "SHELL", pas->pw_shell, 5);*/ -#else - xsetenv("USER", pas->pw_name); - xsetenv("HOME", pas->pw_dir); -#endif - /* currently, we use constant one: */ - /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ -} - -static void ChangeUser(struct passwd *pas) -{ - /* careful: we're after vfork! */ - change_identity(pas); /* - initgroups, setgid, setuid */ - if (chdir(pas->pw_dir) < 0) { - crondlog(LVL9 "can't chdir(%s)", pas->pw_dir); - if (chdir(TMPDIR) < 0) { - crondlog(DIE9 "can't chdir(%s)", TMPDIR); /* exits */ - } - } -} - -static const char DowAry[] ALIGN1 = - "sun""mon""tue""wed""thu""fri""sat" - /* "Sun""Mon""Tue""Wed""Thu""Fri""Sat" */ -; - -static const char MonAry[] ALIGN1 = - "jan""feb""mar""apr""may""jun""jul""aug""sep""oct""nov""dec" - /* "Jan""Feb""Mar""Apr""May""Jun""Jul""Aug""Sep""Oct""Nov""Dec" */ -; - -static void ParseField(char *user, char *ary, int modvalue, int off, - const char *names, char *ptr) -/* 'names' is a pointer to a set of 3-char abbreviations */ -{ - char *base = ptr; - int n1 = -1; - int n2 = -1; - - // this can't happen due to config_read() - /*if (base == NULL) - return;*/ - - while (1) { - int skip = 0; - - /* Handle numeric digit or symbol or '*' */ - if (*ptr == '*') { - n1 = 0; /* everything will be filled */ - n2 = modvalue - 1; - skip = 1; - ++ptr; - } else if (isdigit(*ptr)) { - if (n1 < 0) { - n1 = strtol(ptr, &ptr, 10) + off; - } else { - n2 = strtol(ptr, &ptr, 10) + off; - } - skip = 1; - } else if (names) { - int i; - - for (i = 0; names[i]; i += 3) { - /* was using strncmp before... */ - if (strncasecmp(ptr, &names[i], 3) == 0) { - ptr += 3; - if (n1 < 0) { - n1 = i / 3; - } else { - n2 = i / 3; - } - skip = 1; - break; - } - } - } - - /* handle optional range '-' */ - if (skip == 0) { - goto err; - } - if (*ptr == '-' && n2 < 0) { - ++ptr; - continue; - } - - /* - * collapse single-value ranges, handle skipmark, and fill - * in the character array appropriately. - */ - if (n2 < 0) { - n2 = n1; - } - if (*ptr == '/') { - skip = strtol(ptr + 1, &ptr, 10); - } - - /* - * fill array, using a failsafe is the easiest way to prevent - * an endless loop - */ - { - int s0 = 1; - int failsafe = 1024; - - --n1; - do { - n1 = (n1 + 1) % modvalue; - - if (--s0 == 0) { - ary[n1 % modvalue] = 1; - s0 = skip; - } - if (--failsafe == 0) { - goto err; - } - } while (n1 != n2); - - } - if (*ptr != ',') { - break; - } - ++ptr; - n1 = -1; - n2 = -1; - } - - if (*ptr) { - err: - crondlog(WARN9 "user %s: parse error at %s", user, base); - return; - } - - if (DebugOpt && (LogLevel <= 5)) { /* like LVL5 */ - /* can't use crondlog, it inserts '\n' */ - int i; - for (i = 0; i < modvalue; ++i) - fprintf(stderr, "%d", (unsigned char)ary[i]); - fputc('\n', stderr); - } -} - -static void FixDayDow(CronLine *line) -{ - unsigned i; - int weekUsed = 0; - int daysUsed = 0; - - for (i = 0; i < ARRAY_SIZE(line->cl_Dow); ++i) { - if (line->cl_Dow[i] == 0) { - weekUsed = 1; - break; - } - } - for (i = 0; i < ARRAY_SIZE(line->cl_Days); ++i) { - if (line->cl_Days[i] == 0) { - daysUsed = 1; - break; - } - } - if (weekUsed != daysUsed) { - if (weekUsed) - memset(line->cl_Days, 0, sizeof(line->cl_Days)); - else /* daysUsed */ - memset(line->cl_Dow, 0, sizeof(line->cl_Dow)); - } -} - -static void SynchronizeFile(const char *fileName) -{ - struct parser_t *parser; - struct stat sbuf; - int maxLines; - char *tokens[6]; -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL - char *mailTo = NULL; -#endif - - if (!fileName) - return; - - DeleteFile(fileName); - parser = config_open(fileName); - if (!parser) - return; - - maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES; - - if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DaemonUid) { - CronFile *file = xzalloc(sizeof(CronFile)); - CronLine **pline; - int n; - - file->cf_User = xstrdup(fileName); - pline = &file->cf_LineBase; - - while (1) { - CronLine *line; - - if (!--maxLines) - break; - n = config_read(parser, tokens, 6, 1, "# \t", PARSE_NORMAL | PARSE_KEEP_COPY); - if (!n) - break; - - if (DebugOpt) - crondlog(LVL5 "user:%s entry:%s", fileName, parser->data); - - /* check if line is setting MAILTO= */ - if (0 == strncmp(tokens[0], "MAILTO=", 7)) { -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL - free(mailTo); - mailTo = (tokens[0][7]) ? xstrdup(&tokens[0][7]) : NULL; -#endif /* otherwise just ignore such lines */ - continue; - } - /* check if a minimum of tokens is specified */ - if (n < 6) - continue; - *pline = line = xzalloc(sizeof(*line)); - /* parse date ranges */ - ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, tokens[0]); - ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, tokens[1]); - ParseField(file->cf_User, line->cl_Days, 32, 0, NULL, tokens[2]); - ParseField(file->cf_User, line->cl_Mons, 12, -1, MonAry, tokens[3]); - ParseField(file->cf_User, line->cl_Dow, 7, 0, DowAry, tokens[4]); - /* - * fix days and dow - if one is not "*" and the other - * is "*", the other is set to 0, and vise-versa - */ - FixDayDow(line); -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL - /* copy mailto (can be NULL) */ - line->cl_MailTo = xstrdup(mailTo); -#endif - /* copy command */ - line->cl_Shell = xstrdup(tokens[5]); - if (DebugOpt) { - crondlog(LVL5 " command:%s", tokens[5]); - } - pline = &line->cl_Next; -//bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); - } - *pline = NULL; - - file->cf_Next = FileBase; - FileBase = file; - - if (maxLines == 0) { - crondlog(WARN9 "user %s: too many lines", fileName); - } - } - config_close(parser); -} - -static void CheckUpdates(void) -{ - FILE *fi; - char buf[256]; - - fi = fopen_for_read(CRONUPDATE); - if (fi != NULL) { - unlink(CRONUPDATE); - while (fgets(buf, sizeof(buf), fi) != NULL) { - /* use first word only */ - SynchronizeFile(strtok(buf, " \t\r\n")); - } - fclose(fi); - } -} - -static void SynchronizeDir(void) -{ - CronFile *file; - /* Attempt to delete the database. */ - again: - for (file = FileBase; file; file = file->cf_Next) { - if (!file->cf_Deleted) { - DeleteFile(file->cf_User); - goto again; - } - } - - /* - * Remove cron update file - * - * Re-chdir, in case directory was renamed & deleted, or otherwise - * screwed up. - * - * scan directory and add associated users - */ - unlink(CRONUPDATE); - if (chdir(CDir) < 0) { - crondlog(DIE9 "can't chdir(%s)", CDir); - } - { - DIR *dir = opendir("."); - struct dirent *den; - - if (!dir) - crondlog(DIE9 "can't chdir(%s)", "."); /* exits */ - while ((den = readdir(dir)) != NULL) { - if (strchr(den->d_name, '.') != NULL) { - continue; - } - if (getpwnam(den->d_name)) { - SynchronizeFile(den->d_name); - } else { - crondlog(LVL7 "ignoring %s", den->d_name); - } - } - closedir(dir); - } -} - -/* - * DeleteFile() - delete user database - * - * Note: multiple entries for same user may exist if we were unable to - * completely delete a database due to running processes. - */ -static void DeleteFile(const char *userName) -{ - CronFile **pfile = &FileBase; - CronFile *file; - - while ((file = *pfile) != NULL) { - if (strcmp(userName, file->cf_User) == 0) { - CronLine **pline = &file->cf_LineBase; - CronLine *line; - - file->cf_Running = 0; - file->cf_Deleted = 1; - - while ((line = *pline) != NULL) { - if (line->cl_Pid > 0) { - file->cf_Running = 1; - pline = &line->cl_Next; - } else { - *pline = line->cl_Next; - free(line->cl_Shell); - free(line); - } - } - if (file->cf_Running == 0) { - *pfile = file->cf_Next; - free(file->cf_User); - free(file); - } else { - pfile = &file->cf_Next; - } - } else { - pfile = &file->cf_Next; - } - } -} - -/* - * TestJobs() - * - * determine which jobs need to be run. Under normal conditions, the - * period is about a minute (one scan). Worst case it will be one - * hour (60 scans). - */ -static int TestJobs(time_t t1, time_t t2) -{ - int nJobs = 0; - time_t t; - - /* Find jobs > t1 and <= t2 */ - - for (t = t1 - t1 % 60; t <= t2; t += 60) { - struct tm *tp; - CronFile *file; - CronLine *line; - - if (t <= t1) - continue; - - tp = localtime(&t); - for (file = FileBase; file; file = file->cf_Next) { - if (DebugOpt) - crondlog(LVL5 "file %s:", file->cf_User); - if (file->cf_Deleted) - continue; - for (line = file->cf_LineBase; line; line = line->cl_Next) { - if (DebugOpt) - crondlog(LVL5 " line %s", line->cl_Shell); - if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour] - && (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday]) - && line->cl_Mons[tp->tm_mon] - ) { - if (DebugOpt) { - crondlog(LVL5 " job: %d %s", - (int)line->cl_Pid, line->cl_Shell); - } - if (line->cl_Pid > 0) { - crondlog(LVL8 "user %s: process already running: %s", - file->cf_User, line->cl_Shell); - } else if (line->cl_Pid == 0) { - line->cl_Pid = -1; - file->cf_Ready = 1; - ++nJobs; - } - } - } - } - } - return nJobs; -} - -static void RunJobs(void) -{ - CronFile *file; - CronLine *line; - - for (file = FileBase; file; file = file->cf_Next) { - if (!file->cf_Ready) - continue; - - file->cf_Ready = 0; - for (line = file->cf_LineBase; line; line = line->cl_Next) { - if (line->cl_Pid >= 0) - continue; - - RunJob(file->cf_User, line); - crondlog(LVL8 "USER %s pid %3d cmd %s", - file->cf_User, (int)line->cl_Pid, line->cl_Shell); - if (line->cl_Pid < 0) { - file->cf_Ready = 1; - } else if (line->cl_Pid > 0) { - file->cf_Running = 1; - } - } - } -} - -/* - * CheckJobs() - check for job completion - * - * Check for job completion, return number of jobs still running after - * all done. - */ -static int CheckJobs(void) -{ - CronFile *file; - CronLine *line; - int nStillRunning = 0; - - for (file = FileBase; file; file = file->cf_Next) { - if (file->cf_Running) { - file->cf_Running = 0; - - for (line = file->cf_LineBase; line; line = line->cl_Next) { - int status, r; - if (line->cl_Pid <= 0) - continue; - - r = waitpid(line->cl_Pid, &status, WNOHANG); - if (r < 0 || r == line->cl_Pid) { - EndJob(file->cf_User, line); - if (line->cl_Pid) { - file->cf_Running = 1; - } - } else if (r == 0) { - file->cf_Running = 1; - } - } - } - nStillRunning += file->cf_Running; - } - return nStillRunning; -} - -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL - -// TODO: sendmail should be _run-time_ option, not compile-time! - -static void -ForkJob(const char *user, CronLine *line, int mailFd, - const char *prog, const char *cmd, const char *arg, - const char *mail_filename) -{ - struct passwd *pas; - pid_t pid; - - /* prepare things before vfork */ - pas = getpwnam(user); - if (!pas) { - crondlog(LVL9 "can't get uid for %s", user); - goto err; - } - SetEnv(pas); - - pid = vfork(); - if (pid == 0) { - /* CHILD */ - /* change running state to the user in question */ - ChangeUser(pas); - if (DebugOpt) { - crondlog(LVL5 "child running %s", prog); - } - if (mailFd >= 0) { - xmove_fd(mailFd, mail_filename ? 1 : 0); - dup2(1, 2); - } - /* crond 3.0pl1-100 puts tasks in separate process groups */ - bb_setpgrp(); - execlp(prog, prog, cmd, arg, NULL); - crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg); - if (mail_filename) { - fdprintf(1, "Exec failed: %s -c %s\n", prog, arg); - } - _exit(EXIT_SUCCESS); - } - - line->cl_Pid = pid; - if (pid < 0) { - /* FORK FAILED */ - crondlog(ERR20 "can't vfork"); - err: - line->cl_Pid = 0; - if (mail_filename) { - unlink(mail_filename); - } - } else if (mail_filename) { - /* PARENT, FORK SUCCESS - * rename mail-file based on pid of process - */ - char mailFile2[128]; - - snprintf(mailFile2, sizeof(mailFile2), "%s/cron.%s.%d", TMPDIR, user, pid); - rename(mail_filename, mailFile2); // TODO: xrename? - } - - /* - * Close the mail file descriptor.. we can't just leave it open in - * a structure, closing it later, because we might run out of descriptors - */ - if (mailFd >= 0) { - close(mailFd); - } -} - -static void RunJob(const char *user, CronLine *line) -{ - char mailFile[128]; - int mailFd = -1; - - line->cl_Pid = 0; - line->cl_MailFlag = 0; - - if (line->cl_MailTo) { - /* open mail file - owner root so nobody can screw with it. */ - snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid()); - mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); - - if (mailFd >= 0) { - line->cl_MailFlag = 1; - fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_MailTo, - line->cl_Shell); - line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR); - } else { - crondlog(ERR20 "cannot create mail file %s for user %s, " - "discarding output", mailFile, user); - } - } - - ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile); -} - -/* - * EndJob - called when job terminates and when mail terminates - */ -static void EndJob(const char *user, CronLine *line) -{ - int mailFd; - char mailFile[128]; - struct stat sbuf; - - /* No job */ - if (line->cl_Pid <= 0) { - line->cl_Pid = 0; - return; - } - - /* - * End of job and no mail file - * End of sendmail job - */ - snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid); - line->cl_Pid = 0; - - if (line->cl_MailFlag == 0) { - return; - } - line->cl_MailFlag = 0; - - /* - * End of primary job - check for mail file. If size has increased and - * the file is still valid, we sendmail it. - */ - mailFd = open(mailFile, O_RDONLY); - unlink(mailFile); - if (mailFd < 0) { - return; - } - - if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid - || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos - || !S_ISREG(sbuf.st_mode) - ) { - close(mailFd); - return; - } - if (line->cl_MailTo) - ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); -} - -#else /* crond without sendmail */ - -static void RunJob(const char *user, CronLine *line) -{ - struct passwd *pas; - pid_t pid; - - /* prepare things before vfork */ - pas = getpwnam(user); - if (!pas) { - crondlog(LVL9 "can't get uid for %s", user); - goto err; - } - SetEnv(pas); - - /* fork as the user in question and run program */ - pid = vfork(); - if (pid == 0) { - /* CHILD */ - /* change running state to the user in question */ - ChangeUser(pas); - if (DebugOpt) { - crondlog(LVL5 "child running %s", DEFAULT_SHELL); - } - /* crond 3.0pl1-100 puts tasks in separate process groups */ - bb_setpgrp(); - execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL); - crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, - DEFAULT_SHELL, "-c", line->cl_Shell); - _exit(EXIT_SUCCESS); - } - if (pid < 0) { - /* FORK FAILED */ - crondlog(ERR20 "can't vfork"); - err: - pid = 0; - } - line->cl_Pid = pid; -} - -#endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */ diff --git a/miscutils/ooqd.c b/miscutils/ooqd.c index 4317e05..85114c9 100644 --- a/miscutils/ooqd.c +++ b/miscutils/ooqd.c @@ -29,6 +29,7 @@ int ooqd_main(int argc, char *argv[]) { char *queue_file; FILE *file; + struct stat sb; char curr_qfile[256]; if (argc != 2) @@ -50,17 +51,37 @@ int ooqd_main(int argc, char *argv[]) for(;;) { - /* Try to move queue_file to curr_qfile. This provide at most - * once behavior and allows producers to create a new - * queue_file while we process the old one. - */ - if (rename(queue_file, curr_qfile) == -1) + if (stat(queue_file, &sb) == -1) { if (errno == ENOENT) { sleep(WAIT_TIME); continue; } + report_err("stat failed"); + return 1; + } + + /* Remove curr_qfile. Renaming queue_file to curr_qfile + * will silently fail to delete queue_file if queue_file and + * curr_qfile are hard links. + */ + if (unlink(curr_qfile) == -1) + { + /* Expect ENOENT */ + if (errno != ENOENT) + { + report_err("unlink failed"); + return 1; + } + } + + /* Try to move queue_file to curr_qfile. This provide at most + * once behavior and allows producers to create a new + * queue_file while we process the old one. + */ + if (rename(queue_file, curr_qfile) == -1) + { report_err("rename failed"); return 1; } diff --git a/networking/atlasinit.c b/networking/atlasinit.c deleted file mode 100644 index 121b508..0000000 --- a/networking/atlasinit.c +++ /dev/null @@ -1,740 +0,0 @@ -/* 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/atlasinit.h b/networking/atlasinit.h deleted file mode 100644 index f7362a6..0000000 --- a/networking/atlasinit.h +++ /dev/null @@ -1,33 +0,0 @@ -/* RIPEAtlas - * All the configurable variables - and some non configurables too - * $Id: $ - */ - -#ifndef _ATLASINIT_H -#define _ATLASINIT_H - -#define ATLAS_BUF_SIZE 1024 -#define MAX_READ ATLAS_BUF_SIZE-2 /* should be enough to read controller keys */ - -/********************************************************************* - * Set these constants to your liking - */ - -extern const char atlas_log_file[]; -extern const int atlas_log_level; - -extern const char atlas_contr_known_hosts[]; -extern const char atlas_rereg_timestamp[]; - -extern const int max_lines; /* maximum lines we'll process */ -extern const int min_rereg_time; /* 12h */ -extern const int max_rereg_time; /* 28d */ -extern const int default_rereg_time; /* 7d */ - -/*********************************************************************/ - -enum { ALL, DEBUG, INFO, WARN, ERROR } error_level; - -void atlas_log( int level, const char *msg, ... ); - -#endif diff --git a/networking/rptaddr6.c b/networking/rptaddr6.c deleted file mode 100644 index 9c60425..0000000 --- a/networking/rptaddr6.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * rptaddr6.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 "../eperd/eperd.h" - -#include "libbb.h" - -#define IF_INET6_FILE "/proc/net/if_inet6" -#define IPV6_ROUTE_FILE "/proc/net/ipv6_route" -#define SUFFIX ".new" - -#define SAFE_PREFIX_O ATLAS_DATA_OUT -#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 int setup_ipv6_rpt(char *cache_name, int *need_report); -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 rptaddr6_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; - - 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_O)) - { - crondlog(LVL8 "insecure file '%s' : allowed '%s'", out_name, - SAFE_PREFIX_O); - 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; - - r= setup_ipv6_rpt(cache_name, &need_report); - if (r != 0) - return r; - if (need_report) - { - r = rpt_ipv6(cache_name, out_name, opt_atlas, opt_append); - if (r != 0) - return r; - } - - return 0; -} -static int setup_ipv6_rpt(char *cache_name, int *need_report) -{ - int i, r, n; - char *cp, *cp1; - 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 buf1[1024]; - char buf2[1024]; - FILE *in_file, *out_file, *cache_file; - - *need_report= 0; - - if (strlen(cache_name) + strlen(SUFFIX) + 1 > sizeof(filename)) - { - report("cache name '%s' too long", cache_name); - return 1; - } - - 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 1; - } - - /* Copy IF_INET6_FILE */ - in_file= fopen(IF_INET6_FILE, "r"); - if (in_file == NULL) - { - report_err("unable to open '%s'", IF_INET6_FILE); - fclose(out_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, out_file) != r) - { - report_err("error writing to '%s'", filename); - fclose(in_file); - fclose(out_file); - return 1; - } - - if (ferror(in_file)) - { - report_err("error reading from '%s'", IF_INET6_FILE); - fclose(in_file); - fclose(out_file); - return 1; - } - } - if ( n > 0 ) { - r = snprintf(buf2, 2, "]"); - } - if (fwrite(buf2, 1, r, out_file) != r) - { - report_err("error writing to '%s'", filename); - fclose(in_file); - fclose(out_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); - fclose(out_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); - fclose(out_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, out_file) != r) - { - report_err("error writing to '%s'", filename); - fclose(in_file); - fclose(out_file); - return 1; - } - n++; - } - if ( n > 0 ) { - r = snprintf(buf2, 2, "]"); - } - if (fwrite(buf2, 1, r, out_file) != r) - { - report_err("error writing to '%s'", filename); - fclose(in_file); - fclose(out_file); - return 1; - } - - - if (ferror(in_file)) - { - report_err("error reading from '%s'", IPV6_ROUTE_FILE); - fclose(in_file); - fclose(out_file); - return 1; - } - fclose(in_file); - - /* Now check if the new file is different from the cache one */ - fclose(out_file); - cache_file= fopen(cache_name, "r"); - if (cache_file == NULL) - { - /* Assume that any kind of error here calls for reporting */ - *need_report= 1; - } - - if (cache_file) - { - in_file= fopen(filename, "r"); - if (in_file == NULL) - { - report_err("unable to open '%s'", filename); - fclose(cache_file); - return 1; - } - - /* Compare them */ - while (r= fread(buf1, 1, sizeof(buf1), cache_file), r > 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 1; - } - } - else - { - if (unlink(filename) == -1) - { - report_err("unlinking '%s' failed", - filename); - } - } - - return 0; -} - - -static int rpt_ipv6(char *cache_name, char *out_name, char *opt_atlas, int opt_append) -{ - FILE *file; - FILE *fh; - char *cp; - 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, "w"); - else - fh= fopen(out_name, "w"); - - if (!fh) - crondlog(DIE9 "unable to append to '%s'", out_name); - } - 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, "rptaddr6: "); - 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, "rptaddr6: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, ": %s\n", strerror(t_errno)); - - va_end(ap); -} diff --git a/networking/rptaddrs.c b/networking/rptaddrs.c index 3285d36..33d20cf 100644 --- a/networking/rptaddrs.c +++ b/networking/rptaddrs.c @@ -285,6 +285,14 @@ static int setup_dhcpv4(FILE *of) in_file= fopen(NETWORK_INFO, "r"); if (in_file == NULL) { + if (errno == ENOENT) + { + /* Probe is configure for DHCP but didn't get a + * DHCP lease. + */ + fprintf(of, ", " DBQ(inet-dhcp) ": true"); + return 0; + } report_err("unable to open '%s'", NETWORK_INFO); return -1; } -- cgit v1.2.3