Rob Seaman <[email protected]> wrote:
|I think it’s clear that DNS won’t support all leap second \
|use cases, but that it may provide a high reliability / low \
|latency method for some specific purposes. Here is PHK’s specific example:
|
| $ dig +short leap.net-tid.dk a | ./leapdecode.py
| 248.40.141.250 -> OK 2015 7 +35 +1
|
|(dig might be useful for some script, but most usage will \
|be more direct methods, of course) Leapdecode.py is PHK’s \
|crc8() and dec() functions with:
|The next.leapsec.com <http://next.leapsec.com/> address could \
|be coupled with prev.leapsec.com <http://prev.leapsec.com/> \
|and other options. Etc and so forth.
Cool!
Below a simple C version for the interested. It doesn't iterate
over the results but only uses the first; it also doesn't provide
an encode mode. Compile with either of (dependend on wether you
want gethostbyname(3) or getaddrinfo(3), written with the former):
$0[]$ cc -o leapsec phk-utcdrift.c
$0[]$ cc -DWANT_GETHOSTBYNAME -o leapsec phk-utcdrift.c
?0[]$ ./leapsec 248.40.141.250
248.40.141.250 -> OK 2015-07 +35 +1
?0[]$ ./leapsec next.leapsec.com
248.40.141.250 -> OK 2015-07 +35 +1
?0[]$ ./leapsec leap.net-tid.dk
248.40.141.250 -> OK 2015-07 +35 +1
?0[]$ ./leapsec prev.leapsec.com
247.152.137.102 -> OK 2012-07 +34 +1
?0[]$ ./leapsec google.com
! CRC checksum failure
216.58.211.14 -> BAD 0000-00 +0 +0
?65[]$
Errors go to standard error, exit status uses BSD sysexits.h
constants.
--steffen
/*@ Fetch a PHK DNS A record and calculate current leapsecond status.
*@ Compile: $ cc -o leapsec phk-utcdrift.c
*@ Fallback: $ cc -DWANT_GETHOSTBYNAME -o leapsec phk-utcdrift.c
*@ Synopsis: $ leapsec SERVER
*
* Public Domain.
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#ifndef NI_MAXHOST
# define NI_MAXHOST 1025
#endif
#define _EX_OK EXIT_SUCCESS
#define _EX_USAGE 64
#define _EX_DATAERR 65
#define _EX_NOHOST 68
#ifndef NELEM
# define NELEM(X) (sizeof(X) / sizeof((X)[0]))
#endif
typedef unsigned long ul_i;
typedef unsigned int ui_i;
typedef signed int si_i;
typedef unsigned short us_i;
typedef unsigned char uc_i;
typedef signed char sc_i;
typedef enum {FAL0, TRU1} bool_t;
struct dns_leapinfo {
ul_i dl_addr_parts[4];
char _dl_pad1[1];
sc_i dl_adjust;
sc_i dl_drift;
uc_i dl_month;
us_i dl_year;
char _dl_pad2[2];
char dl_addr[NI_MAXHOST];
};
static ul_i _fetch_addr(char const *host, struct dns_leapinfo *dlp);
static bool_t _dl_addr_to_aparts(struct dns_leapinfo *dlp);
static bool_t _dl_crc8_phk(struct dns_leapinfo const *dlp);
static bool_t _dl_explode(struct dns_leapinfo *dlp);
int
main(int argc, char **argv)
{
struct dns_leapinfo dl;
ul_i addr;
int rv;
rv = _EX_USAGE;
if (argc != 2) {
fprintf(stderr, "Synopsis: %s INET-ADDR\n", argv[0]);
goto jleave;
}
rv = _EX_NOHOST;
if ((addr = _fetch_addr(argv[1], &dl)) == -1) {
fprintf(stderr, "! DNS failed to resolve `%s'\n", argv[1]);
goto jleave;
}
rv = _EX_DATAERR;
if (!_dl_addr_to_aparts(&dl)) {
fprintf(stderr, "! Bogus IP address content: `%s'\n", dl.dl_addr);
goto jprint;
}
if (!_dl_crc8_phk(&dl)) {
fprintf(stderr, "! CRC checksum failure\n");
goto jprint;
}
if (!_dl_explode(&dl)) {
fprintf(stderr,
"! Bogus leapsecond data / non-class E address: `%s'\n",
dl.dl_addr);
goto jprint;
}
rv = _EX_OK;
jprint:
printf("%s -> %s %04u-%02u %c%d %c%d\n",
dl.dl_addr,
(rv == _EX_OK ? "OK" : "BAD"),
(ui_i)dl.dl_year, (ui_i)dl.dl_month,
(dl.dl_drift < 0 ? '-' : '+'), (si_i)dl.dl_drift,
(dl.dl_adjust < 0 ? '-' : '+'), (si_i)dl.dl_adjust);
jleave:
return rv;
}
#ifndef WANT_GETHOSTBYNAME
static ul_i
_fetch_addr(char const *host, struct dns_leapinfo *dlp)
{
struct addrinfo hints, *res;
int i;
ul_i rv = (ul_i)-1;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
res = NULL;
if ((i = getaddrinfo(host, NULL, &hints, &res)) != 0) {
fprintf(stderr, "! Cannot resolve `%s': %s\n",
host, gai_strerror(i));
goto jleave;
}
if ((i = getnameinfo(res->ai_addr, res->ai_addrlen,
dlp->dl_addr, sizeof dlp->dl_addr,
NULL, 0, NI_NUMERICHOST)) != 0) {
fprintf(stderr, "! Cannot resolve name `%s': %s\n",
host, gai_strerror(i));
goto jleave;
}
rv = inet_addr(dlp->dl_addr);
jleave:
if (res != NULL)
freeaddrinfo(res);
return rv;
}
#else /* !WANT_GETHOSTBYNAME */
static ul_i
_fetch_addr(char const *host, struct dns_leapinfo *dlp)
{
struct hostent *hp;
struct in_addr *iaddr;
char const *saddr;
ul_i rv = (ul_i)-1;
if ((hp = gethostbyname(host)) == NULL) {
char const *emsg;
switch (h_errno) {
case HOST_NOT_FOUND:
emsg = "host not found";
break;
default:
case TRY_AGAIN:
emsg = "(maybe) try again later";
break;
case NO_RECOVERY:
emsg = "non-recoverable server error";
break;
case NO_DATA:
emsg = "valid name without IP address";
break;
}
fprintf(stderr, "! Cannot resolve `%s': %s\n", host, emsg);
goto jleave;
}
if (hp->h_addrtype != AF_INET) {
fprintf(stderr, "! DNS didn't return IPv4 address for `%s'\n",
host);
goto jleave;
}
/* (Don't check h_length etc..) */
iaddr = (struct in_addr*)hp->h_addr_list[0];
saddr = inet_ntoa(*iaddr);
strncpy(dlp->dl_addr, saddr, sizeof dlp->dl_addr);
rv = inet_addr(saddr);
jleave:
return rv;
}
#endif /* WANT_GETHOSTBYNAME */
static bool_t
_dl_addr_to_aparts(struct dns_leapinfo *dlp)
{
ul_i i;
char *eptr;
char const *sptr = dlp->dl_addr;
bool_t rv = FAL0;
for (i = 0;; ++i) {
dlp->dl_addr_parts[i] = strtoul(sptr, &eptr, 10);
if (sptr == eptr)
goto jleave;
switch (*eptr) {
case '\0':
if (i == 3)
rv = TRU1;
goto jleave;
case '.':
if (i == 3)
goto jleave;
sptr = eptr + 1;
break;
default:
goto jleave;
}
}
rv = TRU1;
jleave:
return rv;
}
static bool_t
_dl_crc8_phk(struct dns_leapinfo const *dlp)
{
ul_i const poly = 0xCF;
ul_i crc, i, slot, j, mix;
for (crc = i = 0; i < NELEM(dlp->dl_addr_parts); ++i)
for (slot = dlp->dl_addr_parts[i], j = 0; j < 8; ++j) {
mix = (crc ^ slot) & 0x01;
crc >>= 1;
if (mix != 0)
crc ^= poly;
slot >>= 1;
}
return (crc == 0 ? TRU1 : FAL0);
}
static bool_t
_dl_explode(struct dns_leapinfo *dlp)
{
ul_i i;
bool_t rv = FAL0;
i = dlp->dl_addr_parts[0] << 16;
i |= dlp->dl_addr_parts[1] << 8;
i |= dlp->dl_addr_parts[2];
/* Must be class E address */
if ((i & 0xF00000) != 0xF00000)
goto jleave;
i &= ~0xF00000;
switch ((dlp->dl_adjust = (sc_i)(i & 0x03))) {
case 0x00:
case 0x02:
goto jleave;
case 0x03:
dlp->dl_adjust = -1;
default:
break;
}
i >>= 2;
dlp->dl_drift = (sc_i)(i & 0xFF);
i >>= 8;
dlp->dl_month = (uc_i)(i % 12) + 1;
dlp->dl_year = (us_i)(i / 12) + 1972;
rv = TRU1;
jleave:
return rv;
}
_______________________________________________
LEAPSECS mailing list
[email protected]
https://pairlist6.pair.net/mailman/listinfo/leapsecs