aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eperd/eperd.c2
-rw-r--r--eperd/eperd.h2
-rw-r--r--eperd/evtdig.c283
-rw-r--r--eperd/httpget.c123
-rw-r--r--eperd/ntp.c147
-rw-r--r--eperd/ping.c233
-rw-r--r--eperd/sslgetcert.c174
-rw-r--r--eperd/traceroute.c524
-rw-r--r--include/libbb.h2
-rw-r--r--shell/hush.c18
10 files changed, 1311 insertions, 197 deletions
diff --git a/eperd/eperd.c b/eperd/eperd.c
index 464cd6c..9c602c6 100644
--- a/eperd/eperd.c
+++ b/eperd/eperd.c
@@ -269,7 +269,7 @@ int eperd_main(int argc UNUSED_PARAM, char **argv)
/* "-b after -f is ignored", and so on for every pair a-b */
opt_complementary = "f-b:b-f:S-L:L-S" USE_FEATURE_PERD_D(":d-l")
- "i:+:l+:d+"; /* -i, -l and -d have numeric param */
+ ":i+:l+:d+"; /* -i, -l and -d have numeric param */
opt = getopt32(argv, "i:l:L:fc:A:DP:" USE_FEATURE_PERD_D("d:") "O:",
&instance_id, &LogLevel, &LogFile, &CDir,
&atlas_id, &PidFileName
diff --git a/eperd/eperd.h b/eperd/eperd.h
index 73b5cc6..2b5df6b 100644
--- a/eperd/eperd.h
+++ b/eperd/eperd.h
@@ -23,7 +23,7 @@ extern struct globals G;
#define LineBase (G.LineBase )
#define FileBase (G.FileBase )
#define oldLine (G.oldLine )
-#define instance_id (G.instance_id )
+#define instance_id (G.instance_id )
#define EventBase (G.EventBase )
#define DnsBase (G.DnsBase )
diff --git a/eperd/evtdig.c b/eperd/evtdig.c
index 299a79e..0303cfd 100644
--- a/eperd/evtdig.c
+++ b/eperd/evtdig.c
@@ -122,9 +122,6 @@
#define T_DNAME ns_t_dname
#endif
-
-
-
#ifndef ns_t_dlv
#define ns_t_dlv 32769
#endif
@@ -133,7 +130,6 @@
#define T_DLV ns_t_dlv
#endif
-
#ifndef ns_t_ds
#define ns_t_ds 43
#endif
@@ -231,8 +227,6 @@ typedef uint32_t counter_t;
struct tdig_base {
struct event_base *event_base;
- struct timeval tv_noreply; /* DNS query Reply timeout */
-
/* A circular list of user queries */
struct query_state *qry_head;
@@ -264,14 +258,10 @@ struct query_state {
struct tdig_base *base;
char * name; /* Host identifier as given by the user */
- char * fqname; /* Full qualified hostname */
- char * ipname; /* Remote address in dot notation */
char * infname; /* Bind to this interface (or address) */
u_int16_t qryid; /* query id 16 bit */
struct event event; /* Used to detect read events on udp socket */
- int udp_fd; /* udp_fd and tcp_fd should be merged */
- int tcp_fd;
- FILE *tcp_file;
+ int udp_fd; /* udp_fd */
int wire_size;
struct bufferevent *bev_tcp;
@@ -294,6 +284,7 @@ struct query_state {
int opt_rset;
int opt_retry_max;
int opt_query_arg;
+ unsigned opt_timeout;
int retry;
int resolv_i;
@@ -305,6 +296,10 @@ struct query_state {
char * server_name;
char *out_filename ;
+ /* For fuzzing */
+ char *response_out;
+ char *response_in;
+
uint32_t pktsize; /* Packet size in bytes */
struct addrinfo *res, *ressave, *ressent;
@@ -338,9 +333,10 @@ struct query_state {
unsigned short loc_ai_family ;
struct sockaddr_in6 loc_sin6;
socklen_t loc_socklen;
-
u_char *outbuff;
+
+ FILE *resp_file; /* Fuzzing */
};
//DNS header structure
struct DNS_HEADER
@@ -483,12 +479,16 @@ static struct option longopts[]=
{ "resolv", no_argument, NULL, O_RESOLV_CONF },
{ "qbuf", no_argument, NULL, 1001 },
{ "noabuf", no_argument, NULL, 1002 },
+ { "timeout", required_argument, NULL, 'T' },
{ "evdns", no_argument, NULL, O_EVDNS },
{ "out-file", required_argument, NULL, 'O' },
{ "p_probe_id", no_argument, NULL, O_PREPEND_PROBE_ID },
{ "c_output", no_argument, NULL, O_OUTPUT_COBINED},
-
+
+ { "write-response", required_argument, NULL, 200000 + 'W'},
+ { "read-response", required_argument, NULL, 200000 + 'R'},
+
{ NULL, }
};
static char line[(DEFAULT_LINE_LENGTH+1)];
@@ -797,7 +797,7 @@ 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 */
+/* Attempt to transmit a UDP DNS Request to a server. TCP is else where */
static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event UNUSED_PARAM, void *h)
{
int r, fd;
@@ -807,6 +807,7 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event
uint32_t nsent = 0;
u_char *outbuff= NULL;
int err = 0;
+ struct timeval tv_noreply;
/* Clean the no reply timer (if any was previously set) */
evtimer_del(&qry->noreply_timer);
@@ -828,7 +829,16 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event
af = ((struct sockaddr *)(qry->res->ai_addr))->sa_family;
- if ((fd = socket(af, SOCK_DGRAM, 0) ) < 0 )
+ if (qry->response_in)
+ {
+ fd= open(qry->response_in, O_RDONLY);
+ if (fd == -1)
+ {
+ crondlog(DIE9 "unable to open '%s': %s",
+ qry->response_in, strerror(errno));
+ }
+ }
+ else if ((fd = socket(af, SOCK_DGRAM, 0) ) < 0 )
{
snprintf(line, DEFAULT_LINE_LENGTH, "%s \"socket\" : \"socket failed %s\"", qry->err.size ? ", " : "", strerror(errno));
buf_add(&qry->err, line, strlen(line));
@@ -878,7 +888,9 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event
}
}
qry->loc_socklen = sizeof(qry->loc_sin6);
- if (connect(qry->udp_fd, qry->res->ai_addr, qry->res->ai_addrlen) == -1)
+ if (qry->response_in)
+ ; /* No need to connect */
+ else if (connect(qry->udp_fd, qry->res->ai_addr, qry->res->ai_addrlen) == -1)
{
snprintf(line, DEFAULT_LINE_LENGTH,
"%s \"socket\" : \"connect failed %s\"",
@@ -891,12 +903,18 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event
return;
}
- nsent = send(qry->udp_fd, outbuff,qry->pktsize, MSG_DONTWAIT);
+ if (qry->response_in)
+ nsent= qry->pktsize;
+ else
+ {
+ nsent = send(qry->udp_fd, outbuff,qry->pktsize,
+ MSG_DONTWAIT);
+ }
qry->ressent = qry->res;
if (nsent == qry->pktsize) {
- if (getsockname(qry->udp_fd, (struct sockaddr *)&qry->loc_sin6, &qry->loc_socklen) == -1) {
- snprintf(line, DEFAULT_LINE_LENGTH, "%s \"getscokname\" : \"%s\"", qry->err.size ? ", " : "", strerror(errno));
+ if (!qry->response_in && getsockname(qry->udp_fd, (struct sockaddr *)&qry->loc_sin6, &qry->loc_socklen) == -1) {
+ snprintf(line, DEFAULT_LINE_LENGTH, "%s \"getsockname\" : \"%s\"", qry->err.size ? ", " : "", strerror(errno));
buf_add(&qry->err, line, strlen(line));
}
@@ -905,7 +923,8 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event
base->sentbytes += nsent;
err = 0;
/* Add the timer to handle no reply condition in the given timeout */
- evtimer_add(&qry->noreply_timer, &base->tv_noreply);
+ msecstotv(qry->opt_timeout, &tv_noreply);
+ evtimer_add(&qry->noreply_timer, &tv_noreply);
if(qry->opt_qbuf) {
buf_init(&qry->qbuf, -1);
buf_add_b64(&qry->qbuf, outbuff, qry->pktsize, 0);
@@ -919,6 +938,8 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event
, strerror(errno) , qry->res->ai_family == AF_INET ? "AF_INET" :"NOT AF_INET");
buf_add(&qry->err, line, strlen(line));
}
+ if (qry->response_in)
+ ready_callback(0, 0, qry);
} while ((qry->res = qry->res->ai_next) != NULL);
free (outbuff);
outbuff = NULL;
@@ -946,8 +967,9 @@ static void noreply_callback(int unused UNUSED_PARAM, const short event UNUSED_
{
struct timeval asap = { 1, 1 };
struct query_state *qry = h;
+
qry->base->timeout++;
- snprintf(line, DEFAULT_LINE_LENGTH, "%s \"timeout\" : %d", qry->err.size ? ", " : "", DEFAULT_NOREPLY_TIMEOUT);
+ snprintf(line, DEFAULT_LINE_LENGTH, "%s \"timeout\" : %d", qry->err.size ? ", " : "", qry->opt_timeout);
buf_add(&qry->err, line, strlen(line));
BLURT(LVL5 "AAA timeout for %s retry %d/%d ", qry->server_name, qry->retry, qry->opt_retry_max);
@@ -1062,7 +1084,8 @@ static void tcp_connected(struct tu_env *env, struct bufferevent *bev)
qry = ENV2QRY(env);
qry->loc_socklen= sizeof(qry->loc_sin6);
- getsockname(bufferevent_getfd(bev), &qry->loc_sin6, &qry->loc_socklen);
+ if (!qry->response_in)
+ getsockname(bufferevent_getfd(bev), &qry->loc_sin6, &qry->loc_socklen);
qry->bev_tcp = bev;
outbuff = xzalloc(MAX_DNS_BUF_SIZE);
@@ -1072,7 +1095,11 @@ static void tcp_connected(struct tu_env *env, struct bufferevent *bev)
wire = xzalloc (payload_len + 4);
ldns_write_uint16(wire, qry->pktsize);
memcpy(wire + 2, outbuff, qry->pktsize);
- evbuffer_add(bufferevent_get_output(qry->bev_tcp), wire, (qry->pktsize +2));
+ if (!qry->response_in)
+ {
+ evbuffer_add(bufferevent_get_output(qry->bev_tcp), wire,
+ (qry->pktsize +2));
+ }
qry->base->sentok++;
qry->base->sentbytes+= (qry->pktsize +2);
BLURT(LVL5 "send %u bytes", payload_len );
@@ -1111,10 +1138,17 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr)
clock_gettime(CLOCK_MONOTONIC_RAW, &rectime);
bzero(qry->base->packet, MAX_DNS_BUF_SIZE);
- input = bufferevent_get_input(bev);
+ if (!qry->response_in)
+ input = bufferevent_get_input(bev);
if(qry->wire_size == 0) {
- n = evbuffer_remove(input, b2, 2 );
+ if (qry->response_in)
+ n= fread(b2, 1, 2, qry->resp_file);
+ else
+ n = evbuffer_remove(input, b2, 2 );
+ printf("got %d bytes for response size\n", n);
if(n == 2){
+ if (qry->response_out)
+ fwrite(b2, 2, 1, qry->resp_file);
qry->wire_size = ldns_read_uint16(b2);
buf_init(&qry->packet, -1);
}
@@ -1124,7 +1158,20 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr)
buf_add(&qry->err, line, strlen(line));
}
}
- while ((n = evbuffer_remove(input,line , DEFAULT_LINE_LENGTH )) > 0) {
+ for (;;) {
+ if (qry->response_in)
+ n= fread(line, 1, 1, qry->resp_file);
+ else
+ n = evbuffer_remove(input,line , DEFAULT_LINE_LENGTH );
+ printf("got %d bytes for data size\n", n);
+ if (n <= 0)
+ {
+ if (qry->response_in)
+ noreply_callback(0,0,qry);
+ break;
+ }
+ if (qry->response_out)
+ fwrite(line, n, 1, qry->resp_file);
buf_add(&qry->packet, line, n);
if(qry->wire_size == qry->packet.size) {
crondlog(LVL5 "in readcb %s %s red %d bytes ", qry->str_Atlas, qry->server_name, qry->wire_size);
@@ -1213,6 +1260,7 @@ static void ready_callback (int unused UNUSED_PARAM, const short event UNUSED_PA
struct query_state * qry;
int nrecv;
struct timespec rectime;
+ FILE *fh;
// printf("in ready_callback\n");
@@ -1223,13 +1271,30 @@ static void ready_callback (int unused UNUSED_PARAM, const short event UNUSED_PA
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);
+ if (qry->response_in)
+ {
+ nrecv= read(qry->udp_fd, qry->base->packet,
+ sizeof(qry->base->packet));
+ }
+ else
+ {
+ nrecv = recv(qry->udp_fd, qry->base->packet,
+ sizeof(qry->base->packet), MSG_DONTWAIT);
+ }
if (nrecv < 0) {
/* One more failure */
qry->base->recvfail++;
return ;
}
+ if (qry->response_out)
+ {
+ fh= fopen(qry->response_out, "w");
+ if (fh)
+ {
+ fwrite(qry->base->packet, nrecv, 1, fh);
+ fclose(fh);
+ }
+ }
process_reply(arg, nrecv, rectime);
return;
}
@@ -1309,6 +1374,25 @@ static bool argProcess (int argc, char *argv[], struct query_state *qry )
tdig_delete(qry);
return TRUE;
}
+ if (qry->response_in)
+ {
+ if (!validate_filename(qry->response_in, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", qry->response_in);
+ tdig_delete(qry);
+ return TRUE;
+ }
+ }
+ if (qry->response_out)
+ {
+ if (!validate_filename(qry->response_out, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", qry->response_out);
+ tdig_delete(qry);
+ return TRUE;
+ }
+ }
+
if(qry->opt_v6_only == 0)
@@ -1346,9 +1430,7 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state))
qry->str_Atlas = NULL;
qry->out_filename = NULL;
qry->opt_proto = 17;
- qry->tcp_file = NULL;
qry->udp_fd = -1;
- qry->tcp_fd = -1;
qry->server_name = NULL;
qry->str_Atlas = NULL;
qry->infname = NULL;
@@ -1381,6 +1463,7 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state))
qry->result.offset = qry->result.size = qry->result.maxsize= 0;
qry->result.buf = NULL;
qry->opt_query_arg = 0;
+ qry->opt_timeout= DEFAULT_NOREPLY_TIMEOUT;
/* initialize callbacks : */
/* sendpacket called by UDP send */
@@ -1471,6 +1554,10 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state))
qry->opt_proto = 6;
break;
+ case 'T' :
+ qry->opt_timeout = strtoul(optarg, NULL, 10);
+ break;
+
case 1001:
qry->opt_qbuf = 1;
break;
@@ -1733,6 +1820,18 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state))
qry->lookupname = strdup(optarg);
break;
+ case 200000 + 'W':
+ printf("write-response: to %s\n", optarg);
+ if (qry->response_out) free(qry->response_out);
+ qry->response_out= strdup(optarg);
+ break;
+
+ case 200000 + 'R':
+ printf("read-response: from %s\n", optarg);
+ if (qry->response_in) free(qry->response_in);
+ qry->response_in= strdup(optarg);
+ break;
+
default:
fprintf(stderr, "ERROR unknown option %d ??\n", c);
tdig_delete(qry);
@@ -1744,6 +1843,10 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state))
if(argProcess(argc, argv, qry))
return NULL;
+ qry->opt_evdns = 1; /* Always enabled, leave the old code in
+ * place for now.
+ */
+
qry->base = tdig_base;
/* insert this qry into the list of queries */
@@ -1805,8 +1908,6 @@ struct tdig_base * tdig_base_new(struct event_base *event_base)
evtimer_assign(&tdig_base->statsReportEvent, tdig_base->event_base, tdig_stats, tdig_base);
- msecstotv(DEFAULT_NOREPLY_TIMEOUT, &tdig_base->tv_noreply);
-
// Define the callback to handle UDP Reply
// add the raw file descriptor to those monitored for read events
@@ -1933,15 +2034,44 @@ void tdig_start (void *arg)
}
else { // TCP Query
+ if (qry->response_out)
+ {
+ qry->resp_file= fopen(qry->response_out, "w");
+ if (!qry->resp_file)
+ {
+ crondlog(DIE9 "unable to write to '%s'",
+ qry->response_out);
+ }
+ }
+
qry->wire_size = 0;
crondlog(LVL5 "TCP QUERY %s", qry->server_name);
interval.tv_sec = CONN_TO;
interval.tv_usec= 0;
- tu_connect_to_name (&qry->tu_env, qry->server_name, port_as_char,
- &interval, &hints, qry->infname,
- tcp_timeout_callback, tcp_reporterr,
- tcp_dnscount, tcp_beforeconnect,
- tcp_connected, tcp_readcb, tcp_writecb);
+
+ if (qry->response_in)
+ {
+ qry->resp_file= fopen(qry->response_in, "r");
+ if (!qry->resp_file)
+ {
+ crondlog(DIE9 "unable to read from '%s'",
+ qry->response_in);
+ }
+ tcp_connected(&qry->tu_env, NULL);
+ tcp_writecb(NULL, &qry->tu_env);
+ while(qry->resp_file != NULL)
+ tcp_readcb(NULL, &qry->tu_env);
+ // report(qry);
+ }
+ else
+ {
+ tu_connect_to_name (&qry->tu_env, qry->server_name,
+ port_as_char,
+ &interval, &hints, qry->infname,
+ tcp_timeout_callback, tcp_reporterr,
+ tcp_dnscount, tcp_beforeconnect,
+ tcp_connected, tcp_readcb, tcp_writecb);
+ }
}
return ;
@@ -2061,6 +2191,12 @@ static void free_qry_inst(struct query_state *qry)
struct timeval asap = { 1, 0 };
BLURT(LVL5 "freeing instance of %s ", qry->server_name);
+ if (qry->response_in)
+ {
+ asap.tv_sec= 0;
+ asap.tv_usec= 1;
+ }
+
if(qry->err.size)
{
buf_cleanup(&qry->err);
@@ -2120,6 +2256,11 @@ static void free_qry_inst(struct query_state *qry)
if(qry->base->done) {
evtimer_add(&qry->done_qry_timer, &asap);
}
+ if (qry->response_in && qry->resp_file)
+ {
+ fclose(qry->resp_file);
+ qry->resp_file= NULL;
+ }
break;
}
}
@@ -2254,7 +2395,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
u_int32_t serial;
int iMax ;
int flagAnswer = 0;
- int data_len;
+ int data_len, offset;
int write_out = FALSE;
int fw = get_atlas_fw_version();
@@ -2380,12 +2521,21 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
{
iMax = MIN(2, ntohs(dnsR->ans_count));
+ memset(answers, '\0', sizeof(answers));
+
for(i=0;i<iMax;i++)
{
answers[i].name=ReadName(result,wire_size,
reader-result,&stop);
reader = reader + stop;
+ if (reader + sizeof(answers[i].resource) >
+ result + wire_size)
+ {
+ /* Report error? */
+ break;
+ }
+
answers[i].resource = (struct R_DATA*)(reader);
reader = reader + sizeof(struct R_DATA);
@@ -2404,7 +2554,11 @@ 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], data_len, qry);
+ offset= reader-result;
+ if (offset+data_len > wire_size)
+ data_len= wire_size-offset;
+ print_txt_json(reader,
+ data_len, qry);
reader = reader + ntohs(answers[i].resource->data_len);
AS("}");
@@ -2514,7 +2668,8 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
int* count)
{
unsigned char *name;
- unsigned int p=0,jumped=0, len;
+ unsigned int p=0,jumped=0, jump_count=0, len;
+ size_t noffset;
*count = 0;
name = (unsigned char*)malloc(256);
@@ -2522,28 +2677,41 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
name[0]= '\0';
//read the names in 3www6google3com format
- while(len= base[offset], len !=0)
+ while(offset < size && (len= base[offset], len !=0))
{
if (len & 0xc0)
{
if ((len & 0xc0) != 0xc0)
{
/* Bad format */
- strcpy((char *)name, "format-error");
- printf("format-error: len = %d\n",
- len);
- abort();
+ snprintf((char *)name, sizeof(name),
+ "format-error at %lu: value 0x%x",
+ offset, len);
+ //abort();
return name;
}
- offset= ((len & ~0xc0) << 8) | base[offset+1];
- if (offset >= size)
+ noffset= ((len & ~0xc0) << 8) | base[offset+1];
+ if (noffset >= size)
{
- strcpy((char *)name, "offset-error");
- printf("offset-error\n");
- abort();
+ snprintf((char *)name, sizeof(name),
+ "offset-error at %lu: offset %lu",
+ offset, noffset);
+ //abort();
return name;
}
+
+ if (jump_count > 256)
+ {
+ /* Too many */
+ snprintf((char *)name, sizeof(name),
+ "too many redirects at %lu",
+ offset);
+ //abort();
+ return name;
+ }
+
+ offset= noffset;
if(jumped==0)
{
/* if we havent jumped to another location
@@ -2552,21 +2720,24 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
*count += 2;
}
jumped= 1;
+ jump_count++;
continue;
}
if (offset+len+1 > size)
{
- strcpy((char *)name, "buf-bounds-error");
- printf("buf-bounds-error\n");
- abort();
+ snprintf((char *)name, sizeof(name),
+ "buf-bounds-error at %lu: len %d",
+ offset, len);
+ //abort();
return name;
}
if (p+len+1 > 255)
{
- strcpy((char *)name, "name-length-error");
- printf("name-length-error\n");
- abort();
+ snprintf((char *)name, sizeof(name),
+ "name-length-error at %lu: len %d",
+ offset, p+len+1);
+ //abort();
return name;
}
memcpy(name+p, base+offset+1, len);
diff --git a/eperd/httpget.c b/eperd/httpget.c
index 92ce453..aed596e 100644
--- a/eperd/httpget.c
+++ b/eperd/httpget.c
@@ -92,6 +92,8 @@ struct hgstate
size_t read_limit;
unsigned timeout;
char *infname;
+ char *response_in; /* Fuzzing */
+ char *response_out;
/* State */
char busy;
@@ -150,6 +152,8 @@ struct hgstate
char *result2;
size_t reslen2;
size_t resmax2;
+
+ FILE *resp_file; /* Fuzzing */
};
static struct hgbase *hg_base;
@@ -332,7 +336,7 @@ static void timeout_callback(int __attribute((unused)) unused,
break;
case READ_HEADER:
if (state->max_headers)
- add_str(s, " ], ");
+ add_str(state, " ], ");
add_str(state, ", " DBQ(err) ":" DBQ(timeout reading headers));
report(state);
break;
@@ -381,7 +385,7 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[],
char *url, *check;
char *post_file, *output_file, *post_footer, *post_header,
*A_arg, *store_headers, *store_body, *read_limit_str,
- *timeout_str, *infname;
+ *timeout_str, *infname, *response_in, *response_out;
const char *user_agent;
char *host, *port, *hostport, *path;
struct hgstate *state;
@@ -404,6 +408,8 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[],
timeout_str= NULL;
A_arg= NULL;
infname= NULL;
+ response_in= NULL;
+ response_out= NULL;
only_v4= 0;
only_v6= 0;
do_etim= 0;
@@ -420,7 +426,8 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[],
/* Allow us to be called directly by another program in busybox */
optind= 0;
- while (c= getopt_long(argc, argv, "01aA:cI:O:46", longopts, NULL), c != -1)
+ while (c= getopt_long(argc, argv, "01aA:cI:O:R:W:46", longopts, NULL),
+ c != -1)
{
switch(c)
{
@@ -441,6 +448,12 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[],
case 'A':
A_arg= optarg;
break;
+ case 'R':
+ response_in= optarg;
+ break;
+ case 'W':
+ response_out= optarg;
+ break;
case 'a': /* --all */
do_all= 1;
break;
@@ -511,6 +524,23 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[],
}
url= argv[optind];
+ if (response_in)
+ {
+ if (!validate_filename(response_in, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_in);
+ return NULL;
+ }
+ }
+ if (response_out)
+ {
+ if (!validate_filename(response_out, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_out);
+ return NULL;
+ }
+ }
+
if (output_file)
{
if (!validate_filename(output_file, SAFE_PREFIX_OUT))
@@ -621,6 +651,8 @@ static void *httpget_init(int __attribute((unused)) argc, char *argv[],
state->base= hg_base;
state->atlas= A_arg ? strdup(A_arg) : NULL;
state->output_file= output_file ? strdup(output_file) : NULL;
+ state->response_in= response_in ? strdup(response_in) : NULL;
+ state->response_out= response_out ? strdup(response_out) : NULL;
state->host= host;
state->port= port;
state->hostport= hostport;
@@ -859,6 +891,12 @@ static void report(struct hgstate *state)
tu_cleanup(&state->tu_env);
+ if (state->resp_file)
+ {
+ fclose(state->resp_file);
+ state->resp_file= NULL;
+ }
+
state->busy= 0;
if (state->base->done)
state->base->done(state);
@@ -914,11 +952,33 @@ static int get_input(struct hgstate *state)
state->report_roffset= 0;
}
- n= bufferevent_read(state->bev,
- &state->line[state->linelen],
- state->linemax-state->linelen);
+ if (state->response_in)
+ {
+ if (!state->resp_file)
+ abort();
+ n= fread(&state->line[state->linelen], 1, 1, state->resp_file);
+ if (n == -1 || n == 0)
+ {
+ fclose(state->resp_file);
+ state->resp_file= NULL;
+ timeout_callback(0, 0, &state->tu_env);
+ report(state);
+ return -1;
+ }
+ }
+ else
+ {
+ n= bufferevent_read(state->bev,
+ &state->line[state->linelen],
+ state->linemax-state->linelen);
+ }
if (n < 0)
return -1;
+ if (state->response_out)
+ {
+ fwrite(&state->line[state->linelen], n, 1,
+ state->resp_file);
+ }
state->linelen += n;
state->roffset += n;
return 0;
@@ -1556,7 +1616,7 @@ static void readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr)
continue;
case READ_DONE:
- if (state->bev)
+ if (state->bev || state->response_in)
{
state->bev= NULL;
clock_gettime(CLOCK_MONOTONIC_RAW, &endtime);
@@ -1637,6 +1697,11 @@ static void writecb(struct bufferevent *bev, void *ptr)
state->writestate= WRITE_HEADER;
continue;
case WRITE_HEADER:
+ if (state->response_in)
+ {
+ state->writestate = WRITE_DONE;
+ continue;
+ }
output= bufferevent_get_output(bev);
evbuffer_add_printf(output, "%s %s HTTP/1.%c\r\n",
state->do_get ? "GET" :
@@ -1892,8 +1957,11 @@ static void connected(struct tu_env *env, struct bufferevent *bev)
state->bev= bev;
state->loc_socklen= sizeof(state->loc_sin6);
- getsockname(bufferevent_getfd(bev),
- &state->loc_sin6, &state->loc_socklen);
+ if (!state->response_in)
+ {
+ getsockname(bufferevent_getfd(bev),
+ &state->loc_sin6, &state->loc_socklen);
+ }
}
static void httpget_start(void *state)
@@ -1919,6 +1987,16 @@ static void httpget_start(void *state)
clock_gettime(CLOCK_MONOTONIC_RAW, &hgstate->start);
hgstate->first_connect= 1;
+ if (hgstate->response_out)
+ {
+ hgstate->resp_file= fopen(hgstate->response_out, "w");
+ if (!hgstate->resp_file)
+ {
+ crondlog(DIE9 "unable to write to '%s'",
+ hgstate->response_out);
+ }
+ }
+
memset(&hints, '\0', sizeof(hints));
hints.ai_socktype= SOCK_STREAM;
if (hgstate->only_v4)
@@ -1927,10 +2005,29 @@ static void httpget_start(void *state)
hints.ai_family= AF_INET6;
interval.tv_sec= hgstate->timeout / 1000;
interval.tv_usec= (hgstate->timeout % 1000) * 1000;
- tu_connect_to_name(&hgstate->tu_env, hgstate->host, hgstate->port,
- &interval, &hints, hgstate->infname, timeout_callback,
- reporterr, dnscount, beforeconnect,
- connected, readcb, writecb);
+
+ if (hgstate->response_in)
+ {
+ hgstate->resp_file= fopen(hgstate->response_in, "r");
+ if (!hgstate->resp_file)
+ {
+ crondlog(DIE9 "unable to read from '%s'",
+ hgstate->response_in);
+ }
+ connected(&hgstate->tu_env, NULL);
+ writecb(NULL, &hgstate->tu_env);
+ while(hgstate->resp_file != NULL)
+ readcb(NULL, &hgstate->tu_env);
+ report(hgstate);
+ }
+ else
+ {
+ tu_connect_to_name(&hgstate->tu_env, hgstate->host,
+ hgstate->port,
+ &interval, &hints, hgstate->infname, timeout_callback,
+ reporterr, dnscount, beforeconnect,
+ connected, readcb, writecb);
+ }
}
static int httpget_delete(void *state)
diff --git a/eperd/ntp.c b/eperd/ntp.c
index 7dc1109..0289f35 100644
--- a/eperd/ntp.c
+++ b/eperd/ntp.c
@@ -31,15 +31,10 @@
#define NTP_PORT 123
-#define NTP_OPT_STRING ("!46c:i:w:A:O:")
+#define NTP_OPT_STRING ("!46c:i:w:A:O:R:W:")
#define OPT_4 (1 << 0)
#define OPT_6 (1 << 1)
-#define OPT_I (1 << 2)
-#define OPT_U (1 << 3)
-#define OPT_F (1 << 4)
-#define OPT_r (1 << 5)
-#define OPT_T (1 << 6)
#define IPHDR 20
@@ -83,6 +78,8 @@ struct ntpstate
char do_v6;
char count;
unsigned timeout;
+ char *response_in; /* Fuzzing */
+ char *response_out;
/* Base and index in table */
struct ntpbase *base;
@@ -135,6 +132,8 @@ struct ntpstate
size_t reslen;
size_t resmax;
char open_result;
+
+ FILE *resp_file_out; /* Fuzzing */
};
static struct ntpbase *ntp_base;
@@ -182,6 +181,8 @@ struct ntphdr
#define NTP_4G 4294967296.0
+static void ready_callback(int __attribute((unused)) unused,
+ const short __attribute((unused)) event, void *s);
static int create_socket(struct ntpstate *state);
static void add_str(struct ntpstate *state, const char *str)
@@ -523,9 +524,14 @@ static void send_pkt(struct ntpstate *state)
((struct sockaddr_in *)&state->sin6)->sin_port=
htons(NTP_PORT);
- r= sendto(state->socket, base->packet, len, 0,
- (struct sockaddr *)&state->sin6,
- state->socklen);
+ if (state->response_in)
+ r= 0; /* No need to send */
+ else
+ {
+ r= sendto(state->socket, base->packet, len, 0,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
+ }
#if 0
{ static int doit=0; if (doit && r != -1)
@@ -563,6 +569,13 @@ static void send_pkt(struct ntpstate *state)
interval.tv_usec= state->timeout % 1000000;
evtimer_add(&state->timer, &interval);
+ if (state->response_in)
+ {
+ if (state->sin6.sin6_family == AF_INET6)
+ ready_callback(0, 0, state);
+ else
+ ready_callback(0, 0, state);
+ }
}
static void ready_callback(int __attribute((unused)) unused,
@@ -586,8 +599,49 @@ static void ready_callback(int __attribute((unused)) unused,
base= state->base;
slen= sizeof(remote);
- nrecv= recvfrom(state->socket, base->packet, sizeof(base->packet),
- MSG_DONTWAIT, (struct sockaddr *)&remote, &slen);
+ if (state->response_in)
+ {
+ uint32_t len;
+ if (read(state->socket, &len, sizeof(len)) != sizeof(len))
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ if (len > sizeof(base->packet))
+ {
+ //printf("ready_callback4: bad value for len: %u\n", len);
+ //abort();
+ crondlog(DIE9 "ready_callback4: bad value for len: %u",
+ len);
+ }
+ if (read(state->socket, base->packet, len) != len)
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ if (read(state->socket, &remote, sizeof(remote)) !=
+ sizeof(remote))
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ nrecv= len;
+ }
+ else
+ {
+ nrecv= recvfrom(state->socket, base->packet,
+ sizeof(base->packet),
+ MSG_DONTWAIT, (struct sockaddr *)&remote, &slen);
+ }
if (nrecv == -1)
{
/* Strange, read error */
@@ -596,6 +650,16 @@ static void ready_callback(int __attribute((unused)) unused,
}
// printf("ready_callback: got packet\n");
+ if (state->resp_file_out)
+ {
+ uint32_t len= nrecv;
+
+ fwrite(&len, sizeof(len), 1, state->resp_file_out);
+ fwrite(base->packet, len, 1, state->resp_file_out);
+ fwrite(&remote, sizeof(remote), 1, state->resp_file_out);
+ }
+
+
if (nrecv < sizeof(*ntphdr))
{
/* Short packet */
@@ -1622,6 +1686,7 @@ static void *ntp_init(int __attribute((unused)) argc, char *argv[],
char *out_filename;
const char *destportstr;
char *interface;
+ char *response_in, *response_out;
struct ntpstate *state;
FILE *fh;
@@ -1638,10 +1703,13 @@ static void *ntp_init(int __attribute((unused)) argc, char *argv[],
timeout= 1000;
str_Atlas= NULL;
out_filename= NULL;
+ response_in= NULL;
+ response_out= NULL;
opt_complementary = "=1:4--6:i--u:c+:w+:";
opt = getopt32(argv, NTP_OPT_STRING, &count,
- &interface, &timeout, &str_Atlas, &out_filename);
+ &interface, &timeout, &str_Atlas, &out_filename,
+ &response_in, &response_out);
hostname = argv[optind];
if (opt == 0xffffffff)
@@ -1652,6 +1720,23 @@ static void *ntp_init(int __attribute((unused)) argc, char *argv[],
do_v6= !!(opt & OPT_6);
+ if (response_in)
+ {
+ if (!validate_filename(response_in, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_in);
+ return NULL;
+ }
+ }
+ if (response_out)
+ {
+ if (!validate_filename(response_out, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_out);
+ return NULL;
+ }
+ }
+
if (out_filename)
{
if (!validate_filename(out_filename, SAFE_PREFIX))
@@ -1689,6 +1774,8 @@ static void *ntp_init(int __attribute((unused)) argc, char *argv[],
state->hostname= strdup(hostname);
state->do_v6= do_v6;
state->out_filename= out_filename ? strdup(out_filename) : NULL;
+ state->response_in= response_in ? strdup(response_in) : NULL;
+ state->response_out= response_out ? strdup(response_out) : NULL;
state->base= ntp_base;
state->busy= 0;
state->result= NULL;
@@ -1785,7 +1872,17 @@ static int create_socket(struct ntpstate *state)
type= SOCK_DGRAM;
protocol= 0;
- state->socket= xsocket(af, type, protocol);
+ if (state->response_in)
+ {
+ state->socket= open(state->response_in, O_RDONLY);
+ if (state->socket == -1)
+ {
+ crondlog(DIE9 "unable to open '%s'",
+ state->response_in);
+ }
+ }
+ else
+ state->socket= xsocket(af, type, protocol);
#if 0
{ errno= ENOSYS; state->socket= -1; }
#endif
@@ -1814,9 +1911,14 @@ static int create_socket(struct ntpstate *state)
}
}
- r= connect(state->socket,
- (struct sockaddr *)&state->sin6,
- state->socklen);
+ if (state->response_in)
+ r= 0; /* No need to connect */
+ else
+ {
+ r= connect(state->socket,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
+ }
#if 0
{ errno= ENOSYS; r= -1; }
#endif
@@ -1832,7 +1934,7 @@ static int create_socket(struct ntpstate *state)
return -1;
}
state->loc_socklen= sizeof(state->loc_sin6);
- if (getsockname(state->socket,
+ if (!state->response_in && getsockname(state->socket,
&state->loc_sin6,
&state->loc_socklen) == -1)
{
@@ -1954,6 +2056,17 @@ static void ntp_start(void *state)
ntpstate= state;
+ if (ntpstate->response_out)
+ {
+ ntpstate->resp_file_out= fopen(ntpstate->response_out, "w");
+ if (!ntpstate->resp_file_out)
+ {
+ crondlog(DIE9 "unable to write to '%s'",
+ ntpstate->response_out);
+ }
+ }
+
+
memset(&hints, '\0', sizeof(hints));
hints.ai_socktype= SOCK_DGRAM;
hints.ai_family= ntpstate->do_v6 ? AF_INET6 : AF_INET;
diff --git a/eperd/ping.c b/eperd/ping.c
index 0b8d1b2..3f03bf8 100644
--- a/eperd/ping.c
+++ b/eperd/ping.c
@@ -26,7 +26,7 @@
#define DBQ(str) "\"" #str "\""
-#define PING_OPT_STRING ("!46rc:s:A:O:i:I:")
+#define PING_OPT_STRING ("!46rc:s:A:O:i:I:R:W:")
enum
{
@@ -148,6 +148,11 @@ struct pingstate
/* Packets Counters */
size_t cursize;
counter_t sentpkts; /* Total # of ICMP Echo Requests sent */
+
+ /* For fuzzing */
+ char *response_in;
+ char *response_out;
+ FILE *resp_file_out;
};
/* User Data added to the ICMP header
@@ -165,6 +170,10 @@ struct evdata {
};
+static void ready_callback4(int __attribute((unused)) unused,
+ const short __attribute((unused)) event, void * arg);
+static void ready_callback6(int __attribute((unused)) unused,
+ const short __attribute((unused)) event, void * arg);
/* Initialize a struct timeval by converting milliseconds */
static void
@@ -587,10 +596,18 @@ static void ping_xmit(struct pingstate *host)
host->loc_socklen= sizeof(host->loc_sin6);
getsockname(host->socket, &host->loc_sin6, &host->loc_socklen);
- nsent = sendto(host->socket, base->packet,
- host->cursize+ICMP6_HDRSIZE,
- MSG_DONTWAIT, (struct sockaddr *)&host->sin6,
- host->socklen);
+ if (host->response_in)
+ {
+ /* Assume the send succeeded */
+ nsent= host->cursize+ICMP6_HDRSIZE;
+ }
+ else
+ {
+ nsent = sendto(host->socket, base->packet,
+ host->cursize+ICMP6_HDRSIZE,
+ MSG_DONTWAIT, (struct sockaddr *)&host->sin6,
+ host->socklen);
+ }
}
else
@@ -602,10 +619,18 @@ static void ping_xmit(struct pingstate *host)
host->loc_socklen= sizeof(host->loc_sin6);
getsockname(host->socket, &host->loc_sin6, &host->loc_socklen);
- nsent = sendto(host->socket, base->packet,
- host->cursize+ICMP_MINLEN,
- MSG_DONTWAIT, (struct sockaddr *)&host->sin6,
- host->socklen);
+ if (host->response_in)
+ {
+ /* Assume the send succeeded */
+ nsent= host->cursize+ICMP_MINLEN;
+ }
+ else
+ {
+ nsent = sendto(host->socket, base->packet,
+ host->cursize+ICMP_MINLEN,
+ MSG_DONTWAIT, (struct sockaddr *)&host->sin6,
+ host->socklen);
+ }
}
if (nsent > 0)
@@ -631,6 +656,14 @@ static void ping_xmit(struct pingstate *host)
/* Add the timer to handle no reply condition in the given timeout */
msecstotv(host->interval, &tv_interval);
evtimer_add(&host->ping_timer, &tv_interval);
+
+ if (host->response_in)
+ {
+ if (host->sin6.sin6_family == AF_INET6)
+ ready_callback6(0, 0, host);
+ else
+ ready_callback4(0, 0, host);
+ }
}
@@ -690,12 +723,58 @@ static void ready_callback4 (int __attribute((unused)) unused,
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);
+ if (state->response_in)
+ {
+ uint32_t len;
+ if (read(state->socket, &len, sizeof(len)) != sizeof(len))
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ if (len > sizeof(base->packet))
+ {
+ //printf("ready_callback4: bad value for len: %u\n", len);
+ //abort();
+ crondlog(DIE9 "ready_callback4: bad value for len: %u",
+ len);
+ }
+ if (read(state->socket, base->packet, len) != len)
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ if (read(state->socket, &remote, sizeof(remote)) !=
+ sizeof(remote))
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ nrecv= len;
+ }
+ else nrecv = recvfrom(state->socket, base->packet, sizeof(base->packet), MSG_DONTWAIT, (struct sockaddr *) &remote, &slen);
if (nrecv < 0)
{
goto done;
}
+ if (state->resp_file_out)
+ {
+ uint32_t len= nrecv;
+
+ fwrite(&len, sizeof(len), 1, state->resp_file_out);
+ fwrite(base->packet, len, 1, state->resp_file_out);
+ fwrite(&remote, sizeof(remote), 1, state->resp_file_out);
+ }
+
#if 0
{ int i;
printf("received:");
@@ -712,7 +791,6 @@ static void ready_callback4 (int __attribute((unused)) unused,
if (nrecv < hlen + ICMP_MINLEN || ip->ip_hl < 5)
{
/* One more too short packet */
-printf("ready_callback4: too short\n");
goto done;
}
@@ -731,9 +809,7 @@ printf("ready_callback4: too short\n");
/* Check the ICMP payload for legal values of the 'index' portion */
if (data->index >= base->tabsiz || base->table[data->index] == NULL)
- {
goto done;
- }
/* Get the pointer to the host descriptor in our internal table */
if (state != base->table[data->index])
@@ -794,7 +870,6 @@ printf("ready_callback4: too short\n");
}
else
{
-printf("ready_callback4: not an echo reply\n");
/* Handle this condition exactly as the request has expired */
noreply_callback (-1, -1, state);
}
@@ -857,12 +932,66 @@ static void ready_callback6 (int __attribute((unused)) unused,
msg.msg_flags= 0; /* Not really needed */
/* Receive data from the network */
- nrecv= recvmsg(state->socket, &msg, MSG_DONTWAIT);
+ if (state->response_in)
+ {
+ uint32_t len;
+ if (read(state->socket, &len, sizeof(len)) != sizeof(len))
+ {
+ //printf("ready_callback6: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback6: error reading from '%s'",
+ state->response_in);
+ }
+ if (len > sizeof(base->packet))
+ {
+ //printf("ready_callback6: bad value for len: %u\n", len);
+ //abort();
+ crondlog(DIE9 "ready_callback6: bad value for len: %u",
+ len);
+ }
+ if (read(state->socket, base->packet, len) != len)
+ {
+ //printf("ready_callback6: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback6: error reading from '%s'",
+ state->response_in);
+ }
+ if (read(state->socket, &remote, sizeof(remote)) !=
+ sizeof(remote))
+ {
+ //printf("ready_callback6: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback6: error reading from '%s'",
+ state->response_in);
+ }
+
+ nrecv= len;
+
+ /* Do not try to fuzz the cmsgbuf. We assume stuff returned by
+ * the kernel can be trusted.
+ */
+ memset(cmsgbuf, '\0', sizeof(cmsgbuf));
+ }
+ else
+ nrecv= recvmsg(state->socket, &msg, MSG_DONTWAIT);
+
if (nrecv < 0)
{
goto done;
}
+ if (state->resp_file_out)
+ {
+ uint32_t len= nrecv;
+
+ fwrite(&len, sizeof(len), 1, state->resp_file_out);
+ fwrite(base->packet, len, 1, state->resp_file_out);
+ fwrite(&remote, sizeof(remote), 1, state->resp_file_out);
+ }
+
/* Check the ICMP header to drop unexpected packets due to
* unrecognized id
*/
@@ -970,6 +1099,7 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[],
char *str_Atlas;
char *out_filename;
char *interface;
+ char *response_in, *response_out;
struct pingstate *state;
len_and_sockaddr *lsa;
FILE *fh;
@@ -1016,10 +1146,13 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[],
out_filename= NULL;
interval= DEFAULT_PING_INTERVAL;
interface= NULL;
+ response_in= NULL;
+ response_out= NULL;
/* exactly one argument needed; -c NUM */
opt_complementary = "=1:c+:s+:i+";
opt = getopt32(argv, PING_OPT_STRING, &pingcount, &size,
- &str_Atlas, &out_filename, &interval, &interface);
+ &str_Atlas, &out_filename, &interval, &interface,
+ &response_in, &response_out);
hostname = argv[optind];
if (opt == 0xffffffff)
@@ -1034,6 +1167,23 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[],
return NULL;
}
+ if (response_in)
+ {
+ if (!validate_filename(response_in, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_in);
+ return NULL;
+ }
+ }
+ if (response_out)
+ {
+ if (!validate_filename(response_out, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_out);
+ return NULL;
+ }
+ }
+
if (out_filename)
{
if (!validate_filename(out_filename, SAFE_PREFIX))
@@ -1065,6 +1215,9 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[],
else
af= AF_INET6;
delay_name_res= !!(opt & opt_r);
+ delay_name_res= 1; /* Always enabled, leave the old code in
+ * place for now.
+ */
if (!delay_name_res)
{
@@ -1103,6 +1256,14 @@ static void *ping_init(int __attribute((unused)) argc, char *argv[],
state->interval= interval;
state->interface= interface;
state->socket= -1;
+ state->response_in= response_in ? strdup(response_in) : NULL;
+ state->response_out= response_out ? strdup(response_out) : NULL;
+
+ if (state->response_in || state->response_out)
+ {
+ ping_base->pid= 42;
+ memset(&cookie, 42, sizeof(cookie));
+ }
state->seq = 1;
@@ -1166,9 +1327,18 @@ static void ping_start2(void *state)
/* Check if the ICMP protocol is available on this system */
p_proto= IPPROTO_ICMP;
- /* Create an endpoint for communication using raw socket for
- * ICMP calls */
- if ((fd = socket(AF_INET, SOCK_RAW, p_proto)) == -1) {
+ if (pingstate->response_in)
+ {
+ fd= open(pingstate->response_in, O_RDONLY);
+ if (fd == -1)
+ {
+ crondlog(DIE9 "unable to open '%s'",
+ pingstate->response_in);
+ }
+ }
+ else if ((fd = socket(AF_INET, SOCK_RAW, p_proto)) == -1) {
+ /* Create an endpoint for communication using raw
+ * socket for ICMP calls */
snprintf(line, sizeof(line),
"{ " DBQ(error) ":" DBQ(socket failed: %s)
" }", strerror(errno));
@@ -1191,7 +1361,16 @@ static void ping_start2(void *state)
/* Check if the ICMP6 protocol is available on this system */
p_proto= IPPROTO_ICMPV6;
- if ((fd = socket(AF_INET6, SOCK_RAW, p_proto)) == -1) {
+ if (pingstate->response_in)
+ {
+ fd= open(pingstate->response_in, O_RDONLY);
+ if (fd == -1)
+ {
+ crondlog(DIE9 "unable to open '%s'",
+ pingstate->response_in);
+ }
+ }
+ else if ((fd = socket(AF_INET6, SOCK_RAW, p_proto)) == -1) {
snprintf(line, sizeof(line),
"{ " DBQ(error) ":" DBQ(socket failed: %s)
" }", strerror(errno));
@@ -1238,7 +1417,8 @@ static void ping_start2(void *state)
}
}
- if (connect(pingstate->socket, &pingstate->sin6,
+ if (!pingstate->response_in &&
+ connect(pingstate->socket, &pingstate->sin6,
pingstate->socklen) == -1)
{
snprintf(line, sizeof(line),
@@ -1362,6 +1542,7 @@ static void ping_start(void *state)
pingstate->resmax= 80;
pingstate->result= xmalloc(pingstate->resmax);
pingstate->reslen= 0;
+ pingstate->resp_file_out= NULL;
pingstate->first= 1;
pingstate->got_reply= 0;
@@ -1370,6 +1551,16 @@ static void ping_start(void *state)
pingstate->maxpkts= pingstate->pingcount;
+ if (pingstate->response_out)
+ {
+ pingstate->resp_file_out= fopen(pingstate->response_out, "w");
+ if (!pingstate->resp_file_out)
+ {
+ crondlog(DIE9 "unable to write to '%s'",
+ pingstate->response_out);
+ }
+ }
+
if (!pingstate->delay_name_res)
{
ping_start2(state);
diff --git a/eperd/sslgetcert.c b/eperd/sslgetcert.c
index 91dea01..e457106 100644
--- a/eperd/sslgetcert.c
+++ b/eperd/sslgetcert.c
@@ -74,6 +74,8 @@ struct state
char *output_file;
char *atlas;
char *infname;
+ char *response_in; /* Fuzzing */
+ char *response_out;
char only_v4;
char only_v6;
char major_version;
@@ -129,6 +131,8 @@ struct state
char *result;
size_t reslen;
size_t resmax;
+
+ FILE *resp_file; /* Fuzzing */
};
#define BUF_CHUNK 4096
@@ -152,6 +156,8 @@ static int eat_server_hello(struct state *state);
static int eat_certificate(struct state *state);
static void report(struct state *state);
static void add_str(struct state *state, const char *str);
+static void timeout_callback(int __attribute((unused)) unused,
+ const short __attribute((unused)) event, void *s);
static void buf_init(struct buf *buf, struct bufferevent *bev)
{
@@ -253,10 +259,10 @@ static void buf_add_b64(struct buf *buf, void *data, size_t len)
}
}
-static int buf_read(struct buf *buf)
+static int buf_read(struct state *state, struct buf *buf)
{
int r;
- size_t maxsize;
+ size_t len, maxsize;
void *newbuf;
if (buf->size >= buf->maxsize)
@@ -264,9 +270,14 @@ static int buf_read(struct buf *buf)
if (buf->size-buf->offset + BUF_CHUNK <= buf->maxsize)
{
/* The buffer is big enough, just need to compact */
- fprintf(stderr, "buf_read: should compact");
- errno= ENOSYS;
- return -1;
+ len= buf->size-buf->offset;
+ if (len != 0)
+ {
+ memmove(buf->buf, &buf->buf[buf->offset],
+ len);
+ }
+ buf->size -= buf->offset;
+ buf->offset= 0;
}
else
{
@@ -297,10 +308,27 @@ static int buf_read(struct buf *buf)
}
}
- r= bufferevent_read(buf->bev,
- buf->buf+buf->size, buf->maxsize-buf->size);
+ if (state->response_in)
+ {
+ r= fread(buf->buf+buf->size, 1, 1, state->resp_file);
+ if (r == -1 || r == 0)
+ {
+ timeout_callback(0, 0, &state->tu_env);
+ return -1;
+ }
+ }
+ else
+ {
+ r= bufferevent_read(buf->bev,
+ buf->buf+buf->size, buf->maxsize-buf->size);
+ }
if (r > 0)
{
+ if (state->response_out)
+ {
+ fwrite(buf->buf+buf->size, r, 1,
+ state->resp_file);
+ }
buf->size += r;
return 0;
}
@@ -356,7 +384,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 *typep,
+static int msgbuf_read(struct state *state, struct msgbuf *msgbuf, int *typep,
char *majorp, char *minorp)
{
int r;
@@ -367,12 +395,11 @@ static int msgbuf_read(struct msgbuf *msgbuf, int *typep,
{
if (msgbuf->inbuf->size - msgbuf->inbuf->offset < 5)
{
- r= buf_read(msgbuf->inbuf);
+ r= buf_read(state, msgbuf->inbuf);
if (r < 0)
{
fprintf(stderr,
- "msgbuf_read: buf_read failed: %s\n",
- strerror(errno));
+ "msgbuf_read: buf_read failed\n");
return -1;
}
continue;
@@ -384,7 +411,7 @@ static int msgbuf_read(struct msgbuf *msgbuf, int *typep,
len= (p[3] << 8) + p[4];
if (msgbuf->inbuf->size - msgbuf->inbuf->offset < 5 + len)
{
- r= buf_read(msgbuf->inbuf);
+ r= buf_read(state, msgbuf->inbuf);
if (r < 0)
{
if (errno != EAGAIN)
@@ -608,6 +635,7 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
size_t newsiz;
char *hostname, *str_port, *infname, *version_str;
char *output_file, *A_arg;
+ char *response_in, *response_out;
struct state *state;
FILE *fh;
@@ -617,6 +645,8 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
A_arg= NULL;
infname= NULL;
str_port= NULL;
+ response_in= NULL;
+ response_out= NULL;
only_v4= 0;
only_v6= 0;
@@ -630,7 +660,7 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
/* Allow us to be called directly by another program in busybox */
optind= 0;
- while (c= getopt_long(argc, argv, "A:O:V:i:p:46", longopts, NULL), c != -1)
+ while (c= getopt_long(argc, argv, "A:O:R:V:W:i:p:46", longopts, NULL), c != -1)
{
switch(c)
{
@@ -640,9 +670,15 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
case 'O':
output_file= optarg;
break;
+ case 'R':
+ response_in= optarg;
+ break;
case 'V':
version_str= optarg;
break;
+ case 'W':
+ response_out= optarg;
+ break;
case 'i':
infname= optarg;
break;
@@ -670,6 +706,23 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
}
hostname= argv[optind];
+ if (response_in)
+ {
+ if (!validate_filename(response_in, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_in);
+ return NULL;
+ }
+ }
+ if (response_out)
+ {
+ if (!validate_filename(response_out, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_out);
+ return NULL;
+ }
+ }
+
if (output_file)
{
if (!validate_filename(output_file, SAFE_PREFIX_OUT))
@@ -726,6 +779,8 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
state->base= hg_base;
state->atlas= A_arg ? strdup(A_arg) : NULL;
state->output_file= output_file ? strdup(output_file) : NULL;
+ state->response_in= response_in ? strdup(response_in) : NULL;
+ state->response_out= response_out ? strdup(response_out) : NULL;
state->infname= infname ? strdup(infname) : NULL;
state->hostname= strdup(hostname);
state->major_version= major;
@@ -839,6 +894,12 @@ static void report(struct state *state)
tu_cleanup(&state->tu_env);
+ if (state->resp_file)
+ {
+ fclose(state->resp_file);
+ state->resp_file= NULL;
+ }
+
state->busy= 0;
if (state->base->done)
state->base->done(state);
@@ -1016,7 +1077,7 @@ static int eat_alert(struct state *state)
{
if (msgbuf->buffer.size - msgbuf->buffer.offset < 2)
{
- r= msgbuf_read(msgbuf, &type,
+ r= msgbuf_read(state, msgbuf, &type,
&state->recv_major, &state->recv_minor);
if (r < 0)
{
@@ -1074,7 +1135,7 @@ static int eat_server_hello(struct state *state)
{
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4)
{
- r= msgbuf_read(msgbuf, &type,
+ r= msgbuf_read(state, msgbuf, &type,
&state->recv_major, &state->recv_minor);
if (r < 0)
{
@@ -1095,6 +1156,8 @@ static int eat_server_hello(struct state *state)
fprintf(stderr,
"eat_server_hello: got bad type %d from msgbuf_read\n",
type);
+ add_str(state, DBQ(err) ":" DBQ(bad type));
+ report(state);
return -1;
}
continue;
@@ -1104,12 +1167,14 @@ static int eat_server_hello(struct state *state)
{
fprintf(stderr, "eat_server_hello: got type %d\n",
p[0]);
+ add_str(state, DBQ(err) ":" DBQ(bad type));
+ report(state);
return -1;
}
len= (p[1] << 16) + (p[2] << 8) + p[3];
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4+len)
{
- r= msgbuf_read(msgbuf, &type,
+ r= msgbuf_read(state, msgbuf, &type,
&state->recv_major, &state->recv_minor);
if (r < 0)
{
@@ -1122,6 +1187,8 @@ static int eat_server_hello(struct state *state)
fprintf(stderr,
"eat_server_hello: got bad type %d from msgbuf_read\n",
type);
+ add_str(state, DBQ(err) ":" DBQ(bad type));
+ report(state);
return -1;
}
continue;
@@ -1147,7 +1214,7 @@ static int eat_certificate(struct state *state)
{
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4)
{
- r= msgbuf_read(msgbuf, &type,
+ r= msgbuf_read(state, msgbuf, &type,
&state->recv_major, &state->recv_minor);
if (r < 0)
{
@@ -1164,6 +1231,8 @@ static int eat_certificate(struct state *state)
fprintf(stderr,
"eat_certificate: got bad type %d from msgbuf_read\n",
type);
+ add_str(state, DBQ(err) ":" DBQ(bad type));
+ report(state);
return -1;
}
continue;
@@ -1172,12 +1241,14 @@ static int eat_certificate(struct state *state)
if (p[0] != HS_CERTIFICATE)
{
fprintf(stderr, "eat_certificate: got type %d\n", p[0]);
+ add_str(state, DBQ(err) ":" DBQ(bad type));
+ report(state);
return -1;
}
len= (p[1] << 16) + (p[2] << 8) + p[3];
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4+len)
{
- r= msgbuf_read(msgbuf, &type,
+ r= msgbuf_read(state, msgbuf, &type,
&state->recv_major, &state->recv_minor);
if (r < 0)
{
@@ -1190,6 +1261,8 @@ static int eat_certificate(struct state *state)
fprintf(stderr,
"eat_certificate: got bad type %d from msgbuf_read\n",
type);
+ add_str(state, DBQ(err) ":" DBQ(bad type));
+ report(state);
return -1;
}
continue;
@@ -1209,6 +1282,17 @@ static int eat_certificate(struct state *state)
while (o < 3+n)
{
slen= (p[o] << 16) + (p[o+1] << 8) + p[o+2];
+ if (o+3+slen > len)
+ {
+ fprintf(stderr,
+ "eat_certificate: got bad len %d\n",
+ slen);
+ msgbuf->buffer.offset=
+ msgbuf->buffer.size;
+ add_str(state, DBQ(err) ":" DBQ(bad len));
+ report(state);
+ return -1;
+ }
buf_add_b64(&tmpbuf, p+o+3, slen);
fprintf(fh, "%s\"-----BEGIN CERTIFICATE-----\\n",
!first ? ", " : "");
@@ -1239,12 +1323,18 @@ static int eat_certificate(struct state *state)
{
fprintf(stderr,
"do_certificate: bad amount of cert data\n");
+ add_str(state, DBQ(err) ":"
+ DBQ(bad amount of cert data));
+ report(state);
return -1;
}
if (o != len)
{
fprintf(stderr,
"do_certificate: bad amount of cert data\n");
+ add_str(state, DBQ(err) ":"
+ DBQ(bad amount of cert data));
+ report(state);
return -1;
}
msgbuf->buffer.offset += 4+len;
@@ -1295,7 +1385,8 @@ static void writecb(struct bufferevent *bev, void *ptr)
msgbuf_final(&msgoutbuf, MSG_HANDSHAKE);
/* Ignore error */
- (void) buf_write(&outbuf);
+ if (!state->response_in)
+ (void) buf_write(&outbuf);
hsbuf_cleanup(&hsbuf);
msgbuf_cleanup(&msgoutbuf);
@@ -1434,8 +1525,11 @@ static void connected(struct tu_env *env, struct bufferevent *bev)
msgbuf_init(&state->msginbuf, &state->inbuf, NULL);
state->loc_socklen= sizeof(state->loc_sin6);
- getsockname(bufferevent_getfd(bev),
- &state->loc_sin6, &state->loc_socklen);
+ if (!state->response_in)
+ {
+ getsockname(bufferevent_getfd(bev),
+ &state->loc_sin6, &state->loc_socklen);
+ }
}
static void sslgetcert_start(void *vstate)
@@ -1459,6 +1553,17 @@ static void sslgetcert_start(void *vstate)
state->writestate= WRITE_HELLO;
state->gstart= time(NULL);
+ if (state->response_out)
+ {
+ state->resp_file= fopen(state->response_out, "w");
+ if (!state->resp_file)
+ {
+ crondlog(DIE9 "unable to write to '%s'",
+ state->response_out);
+ }
+ }
+
+
memset(&hints, '\0', sizeof(hints));
hints.ai_socktype= SOCK_STREAM;
if (state->only_v4)
@@ -1468,11 +1573,28 @@ static void sslgetcert_start(void *vstate)
interval.tv_sec= CONN_TO;
interval.tv_usec= 0;
- tu_connect_to_name(&state->tu_env, state->hostname,
- state->portname,
- &interval, &hints, state->infname, timeout_callback,
- reporterr, dnscount, beforeconnect,
- connected, readcb, writecb);
+ if (state->response_in)
+ {
+ state->resp_file= fopen(state->response_in, "r");
+ if (!state->resp_file)
+ {
+ crondlog(DIE9 "unable to read from '%s'",
+ state->response_in);
+ }
+ connected(&state->tu_env, NULL);
+ writecb(NULL, &state->tu_env);
+ while(state->resp_file != NULL)
+ readcb(NULL, &state->tu_env);
+ report(state);
+ }
+ else
+ {
+ tu_connect_to_name(&state->tu_env, state->hostname,
+ state->portname,
+ &interval, &hints, state->infname, timeout_callback,
+ reporterr, dnscount, beforeconnect,
+ connected, readcb, writecb);
+ }
}
static int sslgetcert_delete(void *vstate)
diff --git a/eperd/traceroute.c b/eperd/traceroute.c
index 4875721..c446d8e 100644
--- a/eperd/traceroute.c
+++ b/eperd/traceroute.c
@@ -28,7 +28,7 @@
#define uh_sum check
#endif
-#define TRACEROUTE_OPT_STRING ("!46IUFrTa:b:c:f:g:i:m:p:w:z:A:O:S:H:D:")
+#define TRACEROUTE_OPT_STRING ("!46IUFrTa:b:c:f:g:i:m:p:w:z:A:O:S:H:D:R:W:")
#define OPT_4 (1 << 0)
#define OPT_6 (1 << 1)
@@ -103,6 +103,9 @@ struct trtstate
unsigned duptimeout;
unsigned timeout;
+ char *response_in; /* Fuzzing */
+ char *response_out;
+
/* Base and index in table */
struct trtbase *base;
int index;
@@ -157,6 +160,8 @@ struct trtstate
size_t reslen;
size_t resmax;
char open_result;
+
+ FILE *resp_file_out; /* Fuzzing */
};
static struct trtbase *trt_base;
@@ -189,6 +194,12 @@ struct v6info
};
static int create_socket(struct trtstate *state, int do_tcp);
+static void ready_callback4(int __attribute((unused)) unused,
+ const short __attribute((unused)) event, void *s);
+static void ready_tcp4(int __attribute((unused)) unused,
+ const short __attribute((unused)) event, void *s);
+static void ready_callback6(int __attribute((unused)) unused,
+ const short __attribute((unused)) event, void *s);
#define OPT_PAD1 0
#define OPT_PADN 1
@@ -528,7 +539,12 @@ static void send_pkt(struct trtstate *state)
if (state->do_tcp)
{
- sock= socket(AF_INET6, SOCK_RAW, IPPROTO_TCP);
+ if (state->response_in)
+ sock= open("/dev/null", O_RDWR);
+ else
+ {
+ sock= socket(AF_INET6, SOCK_RAW, IPPROTO_TCP);
+ }
if (sock == -1)
{
crondlog(DIE9 "socket failed");
@@ -552,9 +568,14 @@ static void send_pkt(struct trtstate *state)
#endif
/* Bind to source addr/port */
- r= bind(sock,
- (struct sockaddr *)&state->loc_sin6,
- state->loc_socklen);
+ if (state->response_in)
+ r= 0; /* No need to bind */
+ else
+ {
+ r= bind(sock,
+ (struct sockaddr *)&state->loc_sin6,
+ state->loc_socklen);
+ }
if (r == -1)
{
serrno= errno;
@@ -618,9 +639,14 @@ static void send_pkt(struct trtstate *state)
sin6copy= state->sin6;
sin6copy.sin6_port= 0;
- r= sendto(sock, base->packet, len, 0,
- (struct sockaddr *)&sin6copy,
- state->socklen);
+ if (state->response_in)
+ r= 0; /* No need to send anything */
+ else
+ {
+ r= sendto(sock, base->packet, len, 0,
+ (struct sockaddr *)&sin6copy,
+ state->socklen);
+ }
#if 0
{ static int doit=1; if (doit && r != -1)
@@ -725,9 +751,15 @@ static void send_pkt(struct trtstate *state)
memset(&sin6copy, '\0', sizeof(sin6copy));
sin6copy.sin6_family= AF_INET6;
sin6copy.sin6_addr= state->sin6.sin6_addr;
- r= sendto(state->socket_icmp, base->packet, len, 0,
- (struct sockaddr *)&sin6copy,
- sizeof(sin6copy));
+
+ if (state->response_in)
+ r= 0;
+ else
+ {
+ r= sendto(state->socket_icmp, base->packet,
+ len, 0, (struct sockaddr *)&sin6copy,
+ sizeof(sin6copy));
+ }
#if 0
{ static int doit=1; if (doit && r != -1)
@@ -752,7 +784,12 @@ static void send_pkt(struct trtstate *state)
}
else if (state->do_udp)
{
- sock= socket(AF_INET6, SOCK_DGRAM, 0);
+ if (state->response_in)
+ sock= open("/dev/null", O_RDWR);
+ else
+ {
+ sock= socket(AF_INET6, SOCK_DGRAM, 0);
+ }
if (sock == -1)
{
crondlog(DIE9 "socket failed");
@@ -774,9 +811,14 @@ static void send_pkt(struct trtstate *state)
}
/* Bind to source addr/port */
- r= bind(sock,
- (struct sockaddr *)&state->loc_sin6,
- state->loc_socklen);
+ if (state->response_in)
+ r= 0; /* No need to bind */
+ else
+ {
+ r= bind(sock,
+ (struct sockaddr *)&state->loc_sin6,
+ state->loc_socklen);
+ }
if (r == -1)
{
serrno= errno;
@@ -840,9 +882,14 @@ static void send_pkt(struct trtstate *state)
len= state->curpacksize;
}
- r= sendto(sock, base->packet, len, 0,
- (struct sockaddr *)&state->sin6,
- state->socklen);
+ if (state->response_in)
+ r= 0; /* No need to bind */
+ else
+ {
+ r= sendto(sock, base->packet, len, 0,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
+ }
#if 0
{ static int doit=1; if (doit && r != -1)
@@ -878,7 +925,12 @@ static void send_pkt(struct trtstate *state)
if (state->do_tcp)
{
- sock= socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
+ if (state->response_in)
+ sock= open("/dev/null", O_RDWR);
+ else
+ {
+ sock= socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
+ }
if (sock == -1)
{
crondlog(DIE9 "socket failed");
@@ -889,9 +941,14 @@ static void send_pkt(struct trtstate *state)
sizeof(on));
/* Bind to source addr/port */
- r= bind(sock,
- (struct sockaddr *)&state->loc_sin6,
- state->loc_socklen);
+ if (state->response_in)
+ r= 0;
+ else
+ {
+ r= bind(sock,
+ (struct sockaddr *)&state->loc_sin6,
+ state->loc_socklen);
+ }
#if 0
{ static int doit=1; if (doit && r != -1)
{ errno= ENOSYS; r= -1; } doit= !doit; }
@@ -986,9 +1043,14 @@ static void send_pkt(struct trtstate *state)
setsockopt(sock, IPPROTO_IP,
IP_MTU_DISCOVER, &on, sizeof(on));
- r= sendto(sock, base->packet, len, 0,
- (struct sockaddr *)&state->sin6,
- state->socklen);
+ if (state->response_in)
+ r= 0; /* No need to send */
+ else
+ {
+ r= sendto(sock, base->packet, len, 0,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
+ }
#if 0
{ static int doit=0; if (doit && r != -1)
@@ -1071,9 +1133,14 @@ static void send_pkt(struct trtstate *state)
setsockopt(state->socket_icmp, IPPROTO_IP,
IP_MTU_DISCOVER, &on, sizeof(on));
- r= sendto(state->socket_icmp, base->packet, len, 0,
- (struct sockaddr *)&state->sin6,
- state->socklen);
+ if (state->response_in)
+ r= 0; /* No need to send packet */
+ else
+ {
+ r= sendto(state->socket_icmp, base->packet, len, 0,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
+ }
#if 0
{ static int doit=1; if (doit && r != -1)
@@ -1254,6 +1321,13 @@ static void send_pkt(struct trtstate *state)
interval.tv_usec= state->timeout % 1000000;
evtimer_add(&state->timer, &interval);
+ if (state->response_in)
+ {
+ if (state->sin6.sin6_family == AF_INET6)
+ ready_callback6(0, 0, state);
+ else
+ ready_callback4(0, 0, state);
+ }
}
static void do_mpls(struct trtstate *state, unsigned char *packet,
@@ -1373,8 +1447,75 @@ static void ready_callback4(int __attribute((unused)) unused,
base= state->base;
slen= sizeof(remote);
- nrecv= recvfrom(state->socket_icmp, base->packet, sizeof(base->packet),
- MSG_DONTWAIT, (struct sockaddr *)&remote, &slen);
+ if (state->response_in)
+ {
+ uint8_t proto;
+ uint32_t len;
+
+ if (read(state->socket_icmp, &proto, sizeof(proto)) != sizeof(proto))
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ if (proto == 0)
+ {
+ printf("ready_callback4: proto 0 -> timeout\n");
+ return; /* Timeout */
+ }
+ if (proto == 6)
+ {
+ printf("ready_callback4: proto 6 -> TCP\n");
+ ready_tcp4(0, 0, s);
+ return;
+ }
+ if (proto != 1)
+ {
+ printf("ready_callback4: proto != 1\n");
+ return;
+ }
+
+ if (read(state->socket_icmp, &len, sizeof(len)) != sizeof(len))
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ if (len > sizeof(base->packet))
+ {
+ //printf("ready_callback4: bad value for len: %u\n", len);
+ //abort();
+ crondlog(DIE9 "ready_callback4: bad value for len: %u",
+ len);
+ }
+ if (read(state->socket_icmp, base->packet, len) != len)
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ if (read(state->socket_icmp, &remote, sizeof(remote)) !=
+ sizeof(remote))
+ {
+ //printf("ready_callback4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback4: error reading from '%s'",
+ state->response_in);
+ }
+ nrecv= len;
+ }
+ else
+ {
+ nrecv= recvfrom(state->socket_icmp, base->packet, sizeof(base->packet),
+ MSG_DONTWAIT, (struct sockaddr *)&remote, &slen);
+ }
if (nrecv == -1)
{
/* Strange, read error */
@@ -1383,6 +1524,17 @@ static void ready_callback4(int __attribute((unused)) unused,
}
// printf("ready_callback4: got packet\n");
+ if (state->resp_file_out)
+ {
+ uint8_t proto= 1;
+ uint32_t len= nrecv;
+
+ fwrite(&proto, sizeof(proto), 1, state->resp_file_out);
+ fwrite(&len, sizeof(len), 1, state->resp_file_out);
+ fwrite(base->packet, len, 1, state->resp_file_out);
+ fwrite(&remote, sizeof(remote), 1, state->resp_file_out);
+ }
+
ip= (struct ip *)base->packet;
hlen= ip->ip_hl*4;
@@ -1541,6 +1693,8 @@ static void ready_callback4(int __attribute((unused)) unused,
{
printf("ready_callback4: changed source %s\n",
inet_ntoa(eip->ip_src));
+ printf("ready_callback4: expected %s\n",
+ inet_ntoa(((struct sockaddr_in *)&state->loc_sin6)->sin_addr));
}
if (memcmp(&eip->ip_dst,
&((struct sockaddr_in *)&state->sin6)->
@@ -1607,7 +1761,6 @@ static void ready_callback4(int __attribute((unused)) unused,
nextmtu;
}
}
-printf("curpacksize: %d\n", state->curpacksize);
if (!late)
state->not_done= 1;
break;
@@ -1820,7 +1973,6 @@ printf("curpacksize: %d\n", state->curpacksize);
nextmtu;
}
}
-printf("curpacksize: %d\n", state->curpacksize);
if (!late)
state->not_done= 1;
break;
@@ -1903,7 +2055,6 @@ printf("curpacksize: %d\n", state->curpacksize);
}
if (!state->busy)
{
-printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family);
printf(
"ready_callback4: index (%d) is not busy\n",
ind);
@@ -1983,6 +2134,8 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
{
printf("ready_callback4: changed source %s\n",
inet_ntoa(eip->ip_src));
+ printf("ready_callback4: expected %s\n",
+ inet_ntoa(((struct sockaddr_in *)&state->loc_sin6)->sin_addr));
}
if (memcmp(&eip->ip_dst,
&((struct sockaddr_in *)&state->sin6)->
@@ -2179,7 +2332,6 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
if (!state->busy)
{
-printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family);
printf(
"ready_callback4: index (%d) is not busy\n",
ind);
@@ -2344,8 +2496,51 @@ static void ready_tcp4(int __attribute((unused)) unused,
base= state->base;
slen= sizeof(remote);
- nrecv= recvfrom(state->socket_tcp, base->packet, sizeof(base->packet),
- MSG_DONTWAIT, (struct sockaddr *)&remote, &slen);
+
+ if (state->response_in)
+ {
+ uint32_t len;
+
+ /* Proto is eaten by ready_callback4 */
+ if (read(state->socket_icmp, &len, sizeof(len)) != sizeof(len))
+ {
+ //printf("ready_tcp4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_tcp4: error reading from '%s'",
+ state->response_in);
+ }
+ if (len > sizeof(base->packet))
+ {
+ //printf("ready_tcp4: bad value for len: %u\n", len);
+ //abort();
+ crondlog(DIE9 "ready_tcp4: bad value for len: %u",
+ len);
+ }
+ if (read(state->socket_icmp, base->packet, len) != len)
+ {
+ //printf("ready_tcp4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_tcp4: error reading from '%s'",
+ state->response_in);
+ }
+ if (read(state->socket_icmp, &remote, sizeof(remote)) !=
+ sizeof(remote))
+ {
+ //printf("ready_tcp4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_tcp4: error reading from '%s'",
+ state->response_in);
+ }
+ nrecv= len;
+ }
+ else
+ {
+ nrecv= recvfrom(state->socket_tcp, base->packet, sizeof(base->packet),
+ MSG_DONTWAIT, (struct sockaddr *)&remote, &slen);
+ }
if (nrecv == -1)
{
/* Strange, read error */
@@ -2353,6 +2548,17 @@ static void ready_tcp4(int __attribute((unused)) unused,
return;
}
+ if (state->resp_file_out)
+ {
+ uint8_t proto= 6;
+ uint32_t len= nrecv;
+
+ fwrite(&proto, sizeof(proto), 1, state->resp_file_out);
+ fwrite(&len, sizeof(len), 1, state->resp_file_out);
+ fwrite(base->packet, len, 1, state->resp_file_out);
+ fwrite(&remote, sizeof(remote), 1, state->resp_file_out);
+ }
+
ip= (struct ip *)base->packet;
hlen= ip->ip_hl*4;
@@ -2399,7 +2605,6 @@ static void ready_tcp4(int __attribute((unused)) unused,
if (!state->busy)
{
-printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family);
printf(
"ready_callback4: index (%d) is not busy\n",
ind);
@@ -2416,7 +2621,6 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
seq= ntohl(tcphdr->ack_seq) & 0xffff;
if (seq-state->seq > 0x2000)
{
-printf("got seq %d, expected %d\n", seq, state->seq);
if (seq > state->seq)
{
#if 0
@@ -2537,7 +2741,47 @@ static void ready_tcp6(int __attribute((unused)) unused,
msg.msg_controllen= sizeof(cmsgbuf);
msg.msg_flags= 0; /* Not really needed */
- nrecv= recvmsg(state->socket_tcp, &msg, MSG_DONTWAIT);
+ if (state->response_in)
+ {
+ uint32_t len;
+
+ /* Proto is eaten by ready_callback4 */
+ if (read(state->socket_icmp, &len, sizeof(len)) != sizeof(len))
+ {
+ //printf("ready_tcp4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_tcp4: error reading from '%s'",
+ state->response_in);
+ }
+ if (len > sizeof(base->packet))
+ {
+ //printf("ready_tcp4: bad value for len: %u\n", len);
+ //abort();
+ crondlog(DIE9 "ready_tcp4: bad value for len: %u",
+ len);
+ }
+ if (read(state->socket_icmp, base->packet, len) != len)
+ {
+ //printf("ready_tcp4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_tcp4: error reading from '%s'",
+ state->response_in);
+ }
+ if (read(state->socket_icmp, &remote, sizeof(remote)) !=
+ sizeof(remote))
+ {
+ //printf("ready_tcp4: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_tcp4: error reading from '%s'",
+ state->response_in);
+ }
+ nrecv= len;
+ }
+ else
+ nrecv= recvmsg(state->socket_tcp, &msg, MSG_DONTWAIT);
if (nrecv == -1)
{
/* Strange, read error */
@@ -2545,6 +2789,17 @@ static void ready_tcp6(int __attribute((unused)) unused,
return;
}
+ if (state->resp_file_out)
+ {
+ uint8_t proto= 6;
+ uint32_t len= nrecv;
+
+ fwrite(&proto, sizeof(proto), 1, state->resp_file_out);
+ fwrite(&len, sizeof(len), 1, state->resp_file_out);
+ fwrite(base->packet, len, 1, state->resp_file_out);
+ fwrite(&remote, sizeof(remote), 1, state->resp_file_out);
+ }
+
rcvdttl= -42; /* To spot problems */
memset(&dstaddr, '\0', sizeof(dstaddr));
for (cmsgptr= CMSG_FIRSTHDR(&msg); cmsgptr;
@@ -2601,7 +2856,6 @@ static void ready_tcp6(int __attribute((unused)) unused,
if (!state->busy)
{
-printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family);
printf("ready_tcp6: index (%d) is not busy\n", ind);
return;
}
@@ -2616,7 +2870,6 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
seq= ntohl(tcphdr->ack_seq) & 0xffff;
if (seq-state->seq > 0x2000)
{
-printf("got seq %d, expected %d\n", seq, state->seq);
if (seq > state->seq)
{
#if 0
@@ -2717,7 +2970,7 @@ static void ready_callback6(int __attribute((unused)) unused,
struct v6info *v6info;
struct cmsghdr *cmsgptr;
void *ptr;
- double ms;
+ double ms= -42; /* lint, to spot problems */
struct timespec now;
struct sockaddr_in6 remote;
struct in6_addr dstaddr;
@@ -2743,7 +2996,76 @@ static void ready_callback6(int __attribute((unused)) unused,
msg.msg_controllen= sizeof(cmsgbuf);
msg.msg_flags= 0; /* Not really needed */
- nrecv= recvmsg(state->socket_icmp, &msg, MSG_DONTWAIT);
+ /* Receive data from the network */
+ if (state->response_in)
+ {
+ uint8_t proto;
+ uint32_t len;
+
+ if (read(state->socket_icmp, &proto, sizeof(proto)) != sizeof(proto))
+ {
+ crondlog(DIE9 "ready_callback6: error reading from '%s'",
+ state->response_in);
+ }
+ if (proto == 0)
+ {
+ printf("ready_callback6: proto 0 -> timeout\n");
+ return; /* Timeout */
+ }
+ if (proto == 6)
+ {
+ printf("ready_callback6: proto 6 -> TCP\n");
+ ready_tcp6(0, 0, s);
+ return;
+ }
+ if (proto != 1)
+ {
+ printf("ready_callback6: proto != 1\n");
+ return;
+ }
+
+ if (read(state->socket_icmp, &len, sizeof(len)) != sizeof(len))
+ {
+ //printf("ready_callback6: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback6: error reading from '%s'",
+ state->response_in);
+ }
+ if (len > sizeof(base->packet))
+ {
+ //printf("ready_callback6: bad value for len: %u\n", len);
+ //abort();
+ crondlog(DIE9 "ready_callback6: bad value for len: %u",
+ len);
+ }
+ if (read(state->socket_icmp, base->packet, len) != len)
+ {
+ //printf("ready_callback6: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback6: error reading from '%s'",
+ state->response_in);
+ }
+ if (read(state->socket_icmp, &remote, sizeof(remote)) !=
+ sizeof(remote))
+ {
+ //printf("ready_callback6: error reading from '%s'\n",
+ // state->response_in);
+ //abort();
+ crondlog(DIE9 "ready_callback6: error reading from '%s'",
+ state->response_in);
+ }
+
+ nrecv= len;
+
+ /* Do not try to fuzz the cmsgbuf. We assume stuff returned by
+ * the kernel can be trusted.
+ */
+ memset(cmsgbuf, '\0', sizeof(cmsgbuf));
+ }
+ else
+ nrecv= recvmsg(state->socket_icmp, &msg, MSG_DONTWAIT);
if (nrecv == -1)
{
/* Strange, read error */
@@ -2751,6 +3073,17 @@ static void ready_callback6(int __attribute((unused)) unused,
return;
}
+ if (state->response_out)
+ {
+ uint8_t proto= 1;
+ uint32_t len= nrecv;
+
+ fwrite(&proto, sizeof(proto), 1, state->resp_file_out);
+ fwrite(&len, sizeof(len), 1, state->resp_file_out);
+ fwrite(base->packet, len, 1, state->resp_file_out);
+ fwrite(&remote, sizeof(remote), 1, state->resp_file_out);
+ }
+
rcvdttl= -42; /* To spot problems */
memset(&dstaddr, '\0', sizeof(dstaddr));
for (cmsgptr= CMSG_FIRSTHDR(&msg); cmsgptr;
@@ -3003,7 +3336,6 @@ static void ready_callback6(int __attribute((unused)) unused,
if (!state->busy)
{
-printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family);
printf(
"ready_callback6: index (%d) is not busy\n",
ind);
@@ -3316,7 +3648,6 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
if (!state->busy)
{
-printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family);
printf(
"ready_callback6: index (%d) is not busy\n",
ind);
@@ -3452,8 +3783,7 @@ static void noreply_callback(int __attribute((unused)) unused,
state= s;
#if 0
- printf("noreply_callback: gotresp = %d\n",
- state->gotresp);
+ printf("noreply_callback: gotresp = %d\n", state->gotresp);
#endif
if (!state->gotresp)
@@ -3462,6 +3792,14 @@ static void noreply_callback(int __attribute((unused)) unused,
add_str(state, " }, { ");
add_str(state, DBQ(x) ":" DBQ(*));
state->open_result= 1;
+
+ if (state->resp_file_out)
+ {
+ uint32_t len= 0;
+
+ /* Use a zero length packet to signal a timeout */
+ fwrite(&len, sizeof(len), 1, state->resp_file_out);
+ }
}
send_pkt(state);
@@ -3481,6 +3819,7 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[],
const char *hostname;
char *out_filename;
const char *destportstr;
+ char *response_in, *response_out;
char *interface;
char *check;
struct trtstate *state;
@@ -3511,6 +3850,8 @@ static void *traceroute_init(int __attribute((unused)) argc, char *argv[],
destoptsize= 0;
str_Atlas= NULL;
out_filename= NULL;
+ response_in= NULL;
+ response_out= NULL;
opt_complementary = "=1:4--6:i--u:a+:b+:c+:f+:g+:m+:w+:z+:S+:H+:D+";
for (i= 0; argv[i] != NULL; i++)
@@ -3521,7 +3862,7 @@ for (i= 0; argv[i] != NULL; i++)
&firsthop, &gaplimit, &interface, &maxhops, &destportstr,
&timeout,
&duptimeout, &str_Atlas, &out_filename, &maxpacksize,
- &hbhoptsize, &destoptsize);
+ &hbhoptsize, &destoptsize, &response_in, &response_out);
hostname = argv[optind];
if (opt == 0xffffffff)
@@ -3534,11 +3875,31 @@ for (i= 0; argv[i] != NULL; i++)
do_v6= !!(opt & OPT_6);
dont_fragment= !!(opt & OPT_F);
delay_name_res= !!(opt & OPT_r);
+ delay_name_res= 1; /* Always enabled, leave the old code in
+ * place for now.
+ */
do_tcp= !!(opt & OPT_T);
do_udp= !(do_icmp || do_tcp);
if (maxpacksize > sizeof(trt_base->packet))
maxpacksize= sizeof(trt_base->packet);
+ if (response_in)
+ {
+ if (!validate_filename(response_in, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_in);
+ return NULL;
+ }
+ }
+ if (response_out)
+ {
+ if (!validate_filename(response_out, ATLAS_FUZZING))
+ {
+ crondlog(LVL8 "insecure fuzzing file '%s'", response_out);
+ return NULL;
+ }
+ }
+
if (out_filename)
{
if (!validate_filename(out_filename, SAFE_PREFIX))
@@ -3618,6 +3979,8 @@ for (i= 0; argv[i] != NULL; i++)
state->hbhoptsize= hbhoptsize;
state->destoptsize= destoptsize;
state->out_filename= out_filename ? strdup(out_filename) : NULL;
+ state->response_in= response_in;
+ state->response_out= response_out;
state->base= trt_base;
state->paris= 0;
state->busy= 0;
@@ -3627,6 +3990,9 @@ for (i= 0; argv[i] != NULL; i++)
state->socket_icmp= -1;
state->socket_tcp= -1;
+ if (response_in || response_out)
+ trt_base->my_pid= 42;
+
for (i= 0; i<trt_base->tabsiz; i++)
{
if (trt_base->table[i] == NULL)
@@ -3772,7 +4138,17 @@ static int create_socket(struct trtstate *state, int do_tcp)
type= SOCK_RAW;
protocol= (af == AF_INET6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP);
- state->socket_icmp= xsocket(af, type, protocol);
+ if (state->response_in)
+ {
+ state->socket_icmp= open(state->response_in, O_RDONLY);
+ if (state->socket_icmp == -1)
+ {
+ crondlog(DIE9 "unable to open '%s'",
+ state->response_in);
+ }
+ }
+ else
+ state->socket_icmp= xsocket(af, type, protocol);
if (state->socket_icmp == -1)
{
serrno= errno;
@@ -3798,9 +4174,14 @@ static int create_socket(struct trtstate *state, int do_tcp)
}
}
- r= connect(state->socket_icmp,
- (struct sockaddr *)&state->sin6,
- state->socklen);
+ if (state->response_in)
+ r= 0; /* Don't try to connect when reading from a file */
+ else
+ {
+ r= connect(state->socket_icmp,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
+ }
#if 0
{ errno= ENOSYS; r= -1; }
#endif
@@ -3816,7 +4197,7 @@ static int create_socket(struct trtstate *state, int do_tcp)
return -1;
}
state->loc_socklen= sizeof(state->loc_sin6);
- if (getsockname(state->socket_icmp,
+ if (!state->response_in && getsockname(state->socket_icmp,
&state->loc_sin6,
&state->loc_socklen) == -1)
{
@@ -3829,9 +4210,12 @@ static int create_socket(struct trtstate *state, int do_tcp)
buf, sizeof(buf)));
#endif
- close(state->socket_icmp);
- state->socket_icmp= xsocket(af, type,
- protocol);
+ if (!state->response_in)
+ {
+ close(state->socket_icmp);
+ state->socket_icmp= xsocket(af, type,
+ protocol);
+ }
if (state->socket_icmp == -1)
{
serrno= errno;
@@ -3877,8 +4261,10 @@ static int create_socket(struct trtstate *state, int do_tcp)
if (do_tcp)
{
- state->socket_tcp= xsocket(af, SOCK_RAW,
- IPPROTO_TCP);
+ if (state->response_in)
+ state->socket_tcp= open("/dev/null", O_RDWR);
+ else
+ state->socket_tcp= xsocket(af, SOCK_RAW, IPPROTO_TCP);
if (state->socket_tcp == -1)
{
serrno= errno;
@@ -3911,9 +4297,14 @@ static int create_socket(struct trtstate *state, int do_tcp)
}
}
- r= connect(state->socket_tcp,
- (struct sockaddr *)&state->sin6,
- state->socklen);
+ if (state->response_in)
+ r= 0; /* No need to connect */
+ else
+ {
+ r= connect(state->socket_tcp,
+ (struct sockaddr *)&state->sin6,
+ state->socklen);
+ }
#if 0
{ errno= ENOSYS; r= -1; }
#endif
@@ -4038,6 +4429,17 @@ static void traceroute_start(void *state)
trtstate= state;
+ if (trtstate->response_out)
+ {
+ trtstate->resp_file_out= fopen(trtstate->response_out, "w");
+ if (!trtstate->resp_file_out)
+ {
+ crondlog(DIE9 "unable to write to '%s'",
+ trtstate->response_out);
+ }
+ }
+
+
if (!trtstate->delay_name_res)
{
traceroute_start2(state);
diff --git a/include/libbb.h b/include/libbb.h
index 3c8ad56..7325ede 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -310,11 +310,13 @@ extern char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC;
#define ATLAS_DATA_OOQ_OUT ATLAS_HOME "/data/ooq.out"
#define ATLAS_DATA_NEW ATLAS_HOME "/data/new"
#define ATLAS_TIMESYNC_FILE ATLAS_DATA_NEW "/timesync.vol"
+#define ATLAS_FUZZING ATLAS_HOME "/data"
extern int validate_filename(const char *path, const char *prefix);
extern int validate_atlas_id(const char *atlas_id);
extern int get_probe_id(void);
extern int get_timesync(void);
+extern int get_atlas_fw_version(void);
extern int bind_interface(int socket, int af, char *name);
extern int atlas_check_addr(const struct sockaddr *sa, socklen_t len);
diff --git a/shell/hush.c b/shell/hush.c
index 10cab48..54d0c55 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -771,6 +771,7 @@ static int builtin_condmv(char **argv);
static int builtin_dfrm(char **argv);
static int builtin_rxtxrpt(char **argv);
static int builtin_rptaddrs(char **argv);
+static int builtin_rptuptime(char **argv);
static int builtin_true(char **argv);
static int builtin_set(char **argv);
static int builtin_shift(char **argv);
@@ -831,6 +832,7 @@ static const struct built_in_command bltins[] = {
BLTIN("dfrm" , builtin_dfrm, "cleanup if free space gets too low"),
BLTIN("rxtxrpt" , builtin_rxtxrpt, "report RX and TX"),
BLTIN("rptaddrs" , builtin_rptaddrs, "report address(es), route(s), and dns"),
+ BLTIN("rptuptime" , builtin_rptuptime, "report uptime"),
BLTIN("echo" , builtin_echo, "Write to stdout"),
BLTIN("eval" , builtin_eval, "Construct and run shell command"),
BLTIN("exec" , builtin_exec, "Execute command, don't return to shell"),
@@ -4682,7 +4684,7 @@ static int builtin_rxtxrpt(char **argv)
return rxtxrpt_main(argc, argv);
}
-int builitin_rptaddrs(int argc, char *argv[]);
+int rptaddrs_main(int argc, char *argv[]);
static int builtin_rptaddrs(char **argv)
{
@@ -4693,6 +4695,20 @@ static int builtin_rptaddrs(char **argv)
return rptaddrs_main(argc, argv);
}
+#define DBQ(str) "\"" #str "\""
+static int builtin_rptuptime(char **argv __attribute((unused)))
+{
+ struct sysinfo info;
+
+ printf("RESULT { " DBQ(id) ": " DBQ(7001) ", ");
+ printf(DBQ(fw) ": %d, ", get_atlas_fw_version());
+ printf(DBQ(time) ": %ld, ", (long)time(NULL));
+ printf(DBQ(lts) ": %d, ", get_timesync());
+ sysinfo(&info);
+ printf(DBQ(uptime) ": %ld }\n", (long)info.uptime);
+
+ return 0;
+}
static int builtin_rchoose(char **argv)
{