From d1b5e0346ac271397d4d1df2417c3378f46ef4cb Mon Sep 17 00:00:00 2001 From: Nate Straz Date: Thu, 3 Aug 2006 14:48:40 +0000 Subject: Add cookies to the heartbeat packet for added safety. Two factors forced this change. 1. ports were being re-used so quickly that we could get lingering packets from past hosts when getting the btime for a new host. 2. We can't control which IP a btime response is sent from if a system has more than one interface. Adding a cookie allows us to know that a response came from whom we sent it. --- btime.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++-------------- btime_int.h | 2 ++ btimed.c | 23 ++++++++++++++++++----- qarsh.spec | 7 +++++-- 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/btime.c b/btime.c index bb0857e..5e151be 100644 --- a/btime.c +++ b/btime.c @@ -13,6 +13,7 @@ #include "btime_int.h" static int same_addr(struct sockaddr_in *a, struct sockaddr_in *b); +static void gen_cookie(char *s); /* * btime -- * @@ -27,15 +28,16 @@ unsigned int btime(const char *host) { int sd; - char msg[BTIME_MSGLEN]; + char cookie[BTIME_MSGLEN]; + char response[BTIME_MSGLEN]; struct sockaddr_in serv_addr; struct sockaddr_in my_addr; struct sockaddr_in resp_addr; - int serv_addr_len; - int resp_addr_len; + socklen_t serv_addr_len; + socklen_t resp_addr_len; struct hostent *hostent; in_addr_t inaddr; - unsigned int btime; + unsigned int btime = 0; ssize_t nbytes; int retry; @@ -69,10 +71,11 @@ btime(const char *host) return 0; } - memset(msg, 0, BTIME_MSGLEN); + memset(cookie, 0, BTIME_MSGLEN); + gen_cookie(cookie); for (retry = 0; retry < MAX_RETRY; retry++) { serv_addr_len = sizeof serv_addr; - if ((nbytes = sendto(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, + if ((nbytes = sendto(sd, &cookie, BTIME_MSGLEN, MSG_DONTWAIT, (struct sockaddr *)&serv_addr, serv_addr_len)) < 0) { if (errno == EAGAIN) { usleep(retry * 100); @@ -87,18 +90,34 @@ btime(const char *host) memset(&resp_addr, 0, sizeof resp_addr); - memset(msg, 0, BTIME_MSGLEN); + memset(response, 0, BTIME_MSGLEN); for (retry = 0; retry < MAX_RETRY; retry++) { resp_addr_len = sizeof resp_addr; - if ((nbytes = recvfrom(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, + if ((nbytes = recvfrom(sd, &response, BTIME_MSGLEN, MSG_DONTWAIT, (struct sockaddr *)&resp_addr, &resp_addr_len)) < 0) { if (errno == EAGAIN) { usleep(retry * 100); + continue; } else { /* Non EAGAIN error... */ break; } + } + + if (nbytes == 0) { + /* Nothing received, try again */ + continue; + } else if (response[0] == 'B' && response[1] == 'T') { + /* Check for new style cookie */ + if (memcmp(cookie, response, COOKIE_LEN) == 0) { + btime = strtoul(response+COOKIE_LEN, NULL, 10); + break; + } else { + fprintf(stderr, "Ignoring invalid cookie\n"); + continue; + } } else if (!same_addr(&serv_addr, &resp_addr)) { + /* If no cookie, check peer */ char *rstr = strdup(inet_ntoa(resp_addr.sin_addr)); char *sstr = strdup(inet_ntoa(serv_addr.sin_addr)); fprintf(stderr, "Got response from %s instead of %s\n", @@ -107,16 +126,12 @@ btime(const char *host) free(sstr); continue; } else { + /* If peer matches, accept the bare btime */ + btime = strtoul(response, (char **)NULL, 10); break; } } - if (nbytes == 0) { - btime = 0; - } else { - btime = strtoul(msg, (char **)NULL, 10); - } - close(sd); return btime; @@ -141,3 +156,20 @@ same_addr(struct sockaddr_in *a, struct sockaddr_in *b) return 1; } } +/* gen_cookie + * + * Generate a random string that btimed will send back to us. + */ +static void gen_cookie(char *s) +{ + char *a = s; + int i; + + *a++ = 'B'; + *a++ = 'T'; + for (i = 0; i < COOKIE_RANDOM_PARTS; i++) { + *(int *)a = random(); + a += sizeof(int); + } + *a = '\n'; +} diff --git a/btime_int.h b/btime_int.h index b2cafcd..73adaa4 100644 --- a/btime_int.h +++ b/btime_int.h @@ -9,4 +9,6 @@ #define BTIME_MSGLEN 128 #define MAX_RETRY 5 +#define COOKIE_RANDOM_PARTS 4 +#define COOKIE_LEN (3 + (COOKIE_RANDOM_PARTS * sizeof(int))) #endif /* __BTIME_INT_H */ diff --git a/btimed.c b/btimed.c index 544d108..c02b0bc 100644 --- a/btimed.c +++ b/btimed.c @@ -22,9 +22,11 @@ main(int argc, char **argv) { int sd; char inmsg[BTIME_MSGLEN]; - char outmsg[BTIME_MSGLEN]; + char btimeonly[BTIME_MSGLEN]; + char cookiemsg[BTIME_MSGLEN]; + char *outmsg; struct sockaddr_in cli_addr; - int cli_addr_len; + socklen_t cli_addr_len; ssize_t nbytes; unsigned int local_btime; @@ -37,13 +39,14 @@ main(int argc, char **argv) alarm(30); /* Generate the standard btime message */ - memset(outmsg, 0, BTIME_MSGLEN); + memset(btimeonly, 0, BTIME_MSGLEN); local_btime = get_btime(); - sprintf(outmsg, "%u\n", local_btime); + sprintf(btimeonly, "%u\n", local_btime); syslog(LOG_INFO, "started with btime = %u", local_btime); for (;;) { memset(&cli_addr, 0, sizeof cli_addr); + memset(inmsg, 0, BTIME_MSGLEN); cli_addr_len = sizeof cli_addr; nbytes = recvfrom(sd, &inmsg, BTIME_MSGLEN, MSG_WAITALL, (struct sockaddr *)&cli_addr, &cli_addr_len); @@ -55,8 +58,18 @@ main(int argc, char **argv) syslog(LOG_INFO, "exitting"); exit(0); } + if (inmsg[0] == 'B' && inmsg[1] == 'T' ) { + /* New style heartbeat with cookie */ + /* Copy cookie to message and append timestamp */ + memset(cookiemsg, 0, BTIME_MSGLEN); + memcpy(cookiemsg, inmsg, COOKIE_LEN); + strcpy(cookiemsg + COOKIE_LEN, btimeonly); + outmsg = cookiemsg; + } else { + outmsg = btimeonly; + } - sendto(sd, &outmsg, BTIME_MSGLEN, MSG_DONTWAIT, + sendto(sd, outmsg, BTIME_MSGLEN, MSG_DONTWAIT, (struct sockaddr *)&cli_addr, cli_addr_len); /* We want to exit after 30 seconds of inactivity */ alarm(30); diff --git a/qarsh.spec b/qarsh.spec index 21a0105..da03625 100644 --- a/qarsh.spec +++ b/qarsh.spec @@ -1,7 +1,7 @@ Summary: QA Remote Shell Name: qarsh -Version: 1.9 -Release: 2 +Version: 1.10 +Release: 1 Group: QA License: GPL Buildroot: %{_tmppath}/%{name}-%{version}-root @@ -67,6 +67,9 @@ fi %config /etc/xinetd.d/btimed %changelog +* Thu Aug 03 2006 Nathan Straz 1.10-1 +- Add cookies to the heartbeat packet. + * Thu Jun 08 2006 1.9-2 - Add some debugging messages to find the mysterious client rebooted bug. -- cgit