Skip to content
Commits on Source (5)
For Release:
Fix SecondsPerDay in nts_cookie.c
It is set to 3600 for testing
That makes too-old cookies if the polling interval is long enough
BUGS:
timeout on client connect too long (system default)
Is 3 seconds timeout OK? (both client and server)
......@@ -5,12 +10,11 @@ BUGS:
nts_log_ssl_error() No SSL param ??
ERR_error_string_n
Fix SecondsPerDay in nts_cookie.c
Set to 3600 for testing
multithread msyslog
libntp/lib_strbuf.c is used by socktoa and sockporttoa
strerror
I think this has been fixed.
Hourly logging?
ntpq get totals vs recent
documentation:
HOWTO on NTS
......
......@@ -73,7 +73,13 @@ You can read POSIX-1.2001, with 2004 Corrigendum, online for free here:
You can see POSIX.1-2001, SUSv3, online for free here:
http://www.unix-systems.org/version3/
POSIX threads *are* considered part of the standardized API and may be used.
POSIX threads *are* considered part of the standardized API, but their
use requires extreme care. The main part of ntpd assumes it is the only
thread. One interesting area is msyslog. The DNS thread doesn't call msyslog.
That was impractical for NTS, so msyslog is thread safe as of 2019-Apr.
Beware of calling strerror() from non-main threads. Use strerror_r()
into a buffer on the stack. Similarly, use socktoa_r() and sockporttoa_r()
and don't call lib_getbuf().
You *may* assume the clock_gettime(2) and clock_settime(2) calls, and
the related getitimer(2)/setitimer(2), from POSIX-1.2008.
......
......@@ -99,7 +99,9 @@ extern const char * k_st_flags (uint32_t);
extern char * statustoa (int, int);
extern sockaddr_u * netof6 (sockaddr_u *);
extern const char * socktoa (const sockaddr_u *);
extern const char * socktoa_r (const sockaddr_u *sock, char *buf, size_t buflen);
extern const char * sockporttoa(const sockaddr_u *);
extern const char * sockporttoa_r(const sockaddr_u *sock, char *buf, size_t buflen);
extern unsigned short sock_hash(const sockaddr_u *) __attribute__((pure));
extern const char *refid_str (uint32_t, int);
......@@ -119,6 +121,7 @@ extern char * ntp_optarg; /* global argument pointer */
extern int ntp_optind; /* global argv index */
/* lib_strbuf.c */
extern void getbuf_init (void);
extern bool ipv4_works;
extern bool ipv6_works;
......
......@@ -7,6 +7,7 @@
#include "isc_netaddr.h"
#include "ntp_assert.h"
#include "ntp_fp.h"
#include "ntp_stdlib.h"
#include "lib_strbuf.h"
......@@ -16,6 +17,12 @@
*/
static pthread_mutex_t cookie_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t me;
void getbuf_init(void) {
me = pthread_self();
}
/*
* Function to get a pointer to the next buffer. Needs to be thread-safe because
* it's used in callers that need to be thread-safe, notably msyslog. For the
......@@ -26,13 +33,34 @@ static pthread_mutex_t cookie_lock = PTHREAD_MUTEX_INITIALIZER;
* language, at which point something with this behavior will be
* better than all the contortions we'd have to go through to get rid
* of it in C.
*
* HGM: But I'm not willing to ship a lurking time bomb,
* so I fixed the non-main threads (NTS, DNS) not to call
* lib_getbuf and added a trap to make sure I really fixed them all.
*/
char *lib_getbuf(void)
{
static libbufstr lib_stringbuf[LIB_NUMBUF];
static int lib_nextbuf;
char *bufp;
// FIXME - need this until python tests can call getbuf_init
static bool init_done = false;
if (!init_done) {
getbuf_init();
init_done = true;
}
if (pthread_self() != me) {
msyslog(LOG_ERR, "ERR: lib_getbuf() called from non-main thread.");
#ifndef BACKTRACE_DISABLED
// backtrace_log();
#endif
// exit(1);
}
pthread_mutex_lock(&cookie_lock);
ZERO(lib_stringbuf[lib_nextbuf]);
(bufp) = &lib_stringbuf[lib_nextbuf++][0];
......
......@@ -24,48 +24,53 @@ const char *
socktoa(
const sockaddr_u *sock
)
{
char *buf = lib_getbuf();
socktoa_r(sock, buf, LIB_BUFLENGTH);
return buf;
}
const char *
socktoa_r(
const sockaddr_u *sock, char *buf, size_t buflen
)
{
int saved_errno;
char * res;
char * addr;
unsigned long scope;
saved_errno = errno;
res = lib_getbuf();
if (NULL == sock) {
strlcpy(res, "(null)", LIB_BUFLENGTH);
strlcpy(buf, "(null)", buflen);
} else {
switch(AF(sock)) {
case AF_INET:
case AF_UNSPEC:
inet_ntop(AF_INET, PSOCK_ADDR4(sock), res,
LIB_BUFLENGTH);
inet_ntop(AF_INET, PSOCK_ADDR4(sock), buf, buflen);
break;
case AF_INET6:
inet_ntop(AF_INET6, PSOCK_ADDR6(sock), res,
LIB_BUFLENGTH);
inet_ntop(AF_INET6, PSOCK_ADDR6(sock), buf, buflen);
scope = SCOPE_VAR(sock);
if (0 != scope && !strchr(res, '%')) {
addr = res;
res = lib_getbuf();
snprintf(res, LIB_BUFLENGTH, "%s%%%lu",
addr, scope);
res[LIB_BUFLENGTH - 1] = '\0';
if (0 != scope && !strchr(buf, '%')) {
char buf2[LIB_BUFLENGTH];
snprintf(buf2, sizeof(buf2), "%s%%%lu",
buf, scope);
buf2[LIB_BUFLENGTH - 1] = '\0';
strlcpy(buf, buf2, buflen);
}
break;
default:
snprintf(res, LIB_BUFLENGTH,
snprintf(buf, buflen,
"(socktoa unknown family %d)",
AF(sock));
}
}
errno = saved_errno;
return res;
return buf;
}
......@@ -74,18 +79,26 @@ sockporttoa(
const sockaddr_u *sock
)
{
int saved_errno;
const char * atext;
char * buf;
char *buf = lib_getbuf();
sockporttoa_r(sock, buf, LIB_BUFLENGTH);
return buf;
}
const char *
sockporttoa_r(
const sockaddr_u *sock, char *buf, size_t buflen
)
{
int saved_errno;
char buf2[LIB_BUFLENGTH];
saved_errno = errno;
atext = socktoa(sock);
buf = lib_getbuf();
snprintf(buf, LIB_BUFLENGTH,
socktoa_r(sock, buf2, sizeof(buf2));
snprintf(buf, buflen,
(IS_IPV6(sock))
? "[%s]:%hu"
: "%s:%hu",
atext, SRCPORT(sock));
buf2, SRCPORT(sock));
errno = saved_errno;
return buf;
......
......@@ -25,6 +25,7 @@ def build(ctx):
]
libntp_source_sharable = [
"assert.c",
"clockwork.c",
"emalloc.c",
"hextolfp.c",
......
......@@ -512,6 +512,8 @@ ntpdmain(
saved_argc = argc;
saved_argv = argv;
progname = argv[0];
getbuf_init();
parse_cmdline_opts(argc, argv);
# ifdef DEBUG
setvbuf(stdout, NULL, _IOLBF, 0);
......
......@@ -207,9 +207,11 @@ bool nts_load_certificate(SSL_CTX *ctx) {
int nts_ssl_read(SSL *ssl, uint8_t *buff, int buff_length) {
int bytes_read;
char errbuf[100];
bytes_read = SSL_read(ssl, buff, buff_length);
if (0 >= bytes_read) {
msyslog(LOG_INFO, "NTS: SSL_read error: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_INFO, "NTS: SSL_read error: %s", errbuf);
nts_log_ssl_error();
return -1;
}
......@@ -218,9 +220,11 @@ int nts_ssl_read(SSL *ssl, uint8_t *buff, int buff_length) {
int nts_ssl_write(SSL *ssl, uint8_t *buff, int buff_length) {
int bytes_written;
char errbuf[100];
bytes_written = SSL_write(ssl, buff, buff_length);
if (0 >= bytes_written) {
msyslog(LOG_INFO, "NTS: SSL_write error: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_INFO, "NTS: SSL_write error: %s", errbuf);
nts_log_ssl_error();
return -1;
}
......
......@@ -62,6 +62,7 @@ bool nts_probe(struct peer * peer) {
struct timeval timeout = {.tv_sec = NTS_KE_TIMEOUT, .tv_usec = 0};
const char *hostname = peer->hostname;
char hostbuf[100];
char errbuf[100];
SSL *ssl;
int server;
l_fp start, finish;
......@@ -98,7 +99,8 @@ bool nts_probe(struct peer * peer) {
err = setsockopt(server, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
if (0 > err) {
msyslog(LOG_ERR, "NTSc: can't setsockopt: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSc: can't setsockopt: %s", errbuf);
close(server);
nts_ke_probes_bad++;
return false;
......@@ -179,7 +181,11 @@ bail:
}
bool nts_check(struct peer *peer) {
// msyslog(LOG_INFO, "NTSc: nts_check %s, %d", sockporttoa(&sockaddr), addrOK);
if (0) {
char errbuf[100];
sockporttoa_r(&sockaddr, errbuf, sizeof(errbuf));
msyslog(LOG_INFO, "NTSc: nts_check %s, %d", errbuf, addrOK);
}
if (addrOK) {
dns_take_server(peer, &sockaddr);
dns_take_status(peer, DNS_good);
......@@ -230,6 +236,7 @@ SSL_CTX* make_ssl_client_ctx(const char * filename) {
int open_TCP_socket(struct peer *peer, const char *hostname) {
char host[256], port[32];
char errbuf[100];
char *tmp;
struct addrinfo hints;
struct addrinfo *answer;
......@@ -273,20 +280,24 @@ int open_TCP_socket(struct peer *peer, const char *hostname) {
msyslog(LOG_INFO, "NTSc: DNS lookup of %s took %.3Lf sec",
hostname, lfptod(finish));
/* Save first answer for NTP */
/* Save first answer for NTP, switch to NTP port in case of server-name:port */
memcpy(&sockaddr, answer->ai_addr, answer->ai_addrlen);
msyslog(LOG_INFO, "NTSc: nts_probe connecting to %s:%s => %s",
host, port, sockporttoa(&sockaddr));
/* switch to NTP port in case of server-name:port */
SET_PORT(&sockaddr, NTP_PORT);
sockporttoa_r(&sockaddr, errbuf, sizeof(errbuf));
msyslog(LOG_INFO, "NTSc: nts_probe connecting to %s:%s => %s",
host, port, errbuf);
sockfd = socket(answer->ai_family, SOCK_STREAM, 0);
if (-1 == sockfd) {
msyslog(LOG_INFO, "NTSc: nts_probe: no socket: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_INFO, "NTSc: nts_probe: no socket: %s", errbuf);
} else {
// Use first answer
err = connect(sockfd, answer->ai_addr, answer->ai_addrlen);
if (-1 == err) {
msyslog(LOG_INFO, "NTSc: nts_probe: connect failed: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_INFO, "NTSc: nts_probe: connect failed: %s", errbuf);
close(sockfd);
sockfd = -1;
}
......@@ -395,6 +406,7 @@ bool nts_make_keys(SSL *ssl, uint16_t aead, uint8_t *c2s, uint8_t *s2c, int keyl
bool nts_client_send_request(SSL *ssl, struct peer* peer) {
uint8_t buff[1000];
char errbuf[100];
int used, transferred;
struct BufCtl_t buf;
uint16_t aead = NO_AEAD;
......@@ -421,8 +433,9 @@ bool nts_client_send_request(SSL *ssl, struct peer* peer) {
used = sizeof(buff)-buf.left;
if (used >= (int)(sizeof(buff)-10)) {
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSc: write failed: %d, %ld, %s",
used, (long)sizeof(buff), strerror(errno));
used, (long)sizeof(buff), errbuf);
return false;
}
......@@ -455,6 +468,7 @@ bool nts_client_process_response(SSL *ssl, struct peer* peer) {
uint16_t type, data, port;
bool critical = false;
int length, keylength;
char errbuf[100];
#define MAX_SERVER 100
char server[MAX_SERVER];
......@@ -526,7 +540,8 @@ bool nts_client_process_response(SSL *ssl, struct peer* peer) {
if (!nts_server_lookup(server, &sockaddr))
return false;
SET_PORT(&sockaddr, port);
msyslog(LOG_ERR, "NTSc: Using server %s=>%s", server, socktoa(&sockaddr));
socktoa_r(&sockaddr, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSc: Using server %s=>%s", server, errbuf);
break;
case nts_port_negotiation:
// FIXME check length
......@@ -572,6 +587,7 @@ bool nts_client_process_response(SSL *ssl, struct peer* peer) {
bool nts_set_cert_search(SSL_CTX *ctx, const char *filename) {
struct stat statbuf;
char errbuf[100];
if (NULL == filename) {
msyslog(LOG_INFO, "NTSc: Using system default root certificates.");
SSL_CTX_set_default_verify_paths(ctx); // Use system root certs
......@@ -592,7 +608,9 @@ bool nts_set_cert_search(SSL_CTX *ctx, const char *filename) {
filename, statbuf.st_mode);
return false;
}
msyslog(LOG_ERR, "NTSc: can't stat cert dir/file: %s, %s", ntsconfig.ca, strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSc: can't stat cert dir/file: %s, %s",
ntsconfig.ca, errbuf);
return false;
}
......
......@@ -200,16 +200,19 @@ bool nts_write_cookie_keys(void) {
const char *cookie_filename = NTS_COOKIE_KEY_FILE;
int fd;
FILE *out;
char errbuf[100];
if (NULL != ntsconfig.KI)
cookie_filename = ntsconfig.KI;
fd = open(cookie_filename, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
if (-1 == fd) {
msyslog(LOG_ERR, "ERR: can't open %s: %s", cookie_filename, strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "ERR: can't open %s: %s", cookie_filename, errbuf);
return false;
}
out = fdopen(fd, "w");
if (NULL == out) {
msyslog(LOG_ERR, "ERR: can't fdopen %s: %s", cookie_filename, strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "ERR: can't fdopen %s: %s", cookie_filename, errbuf);
close(fd);
return false;
}
......
......@@ -21,6 +21,9 @@
#include "nts.h"
#include "nts2.h"
/* Beware: bind and accept take type sockaddr, but that's not big
* enough for an IPv6 address.
*/
static int create_listener(int port, int family);
static void* nts_ke_listener(void*);
......@@ -87,16 +90,19 @@ bool nts_server_init2(void) {
pthread_t worker;
sigset_t block_mask, saved_sig_mask;
int rc;
char errbuf[100];
sigfillset(&block_mask);
pthread_sigmask(SIG_BLOCK, &block_mask, &saved_sig_mask);
rc = pthread_create(&worker, NULL, nts_ke_listener, &listner4_sock);
if (rc) {
msyslog(LOG_ERR, "NTSs: nts_start_server4: error from pthread_create: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: nts_start_server4: error from pthread_create: %s", errbuf);
}
rc = pthread_create(&worker, NULL, nts_ke_listener, &listner6_sock);
if (rc) {
msyslog(LOG_ERR, "NTSs: nts_start_server6: error from pthread_create: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: nts_start_server6: error from pthread_create: %s", errbuf);
}
pthread_sigmask(SIG_SETMASK, &saved_sig_mask, NULL);
......@@ -106,6 +112,7 @@ bool nts_server_init2(void) {
void* nts_ke_listener(void* arg) {
struct timeval timeout = {.tv_sec = NTS_KE_TIMEOUT, .tv_usec = 0};
int sock = *(int*)arg;
char errbuf[100];
while(1) {
sockaddr_u addr;
......@@ -116,7 +123,8 @@ void* nts_ke_listener(void* arg) {
client = accept(sock, &addr.sa, &len);
if (client < 0) {
msyslog(LOG_ERR, "NTSs: TCP accept failed: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: TCP accept failed: %s", errbuf);
if (EBADF == errno)
return NULL;
sleep(1); /* avoid log clutter on bug */
......@@ -124,11 +132,13 @@ void* nts_ke_listener(void* arg) {
}
nts_ke_serves++;
get_systime(&start);
msyslog(LOG_INFO, "NTSs: TCP accept-ed from %s",
sockporttoa((sockaddr_u *)&addr));
sockporttoa_r(&addr, errbuf, sizeof(errbuf));
msyslog(LOG_INFO, "NTSs: TCP accept-ed from %s", errbuf);
err = setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
if (0 > err) {
msyslog(LOG_ERR, "NTSs: can't setsockopt: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: can't setsockopt: %s", errbuf);
close(client);
nts_ke_serves_bad++;
continue;
......@@ -141,8 +151,9 @@ void* nts_ke_listener(void* arg) {
if (SSL_accept(ssl) <= 0) {
get_systime(&finish);
finish -= start;
sockporttoa_r(&addr, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: SSL accept from %s failed, %.3Lf sec",
sockporttoa((sockaddr_u *)&addr), lfptod(finish));
errbuf, lfptod(finish));
nts_log_ssl_error();
SSL_free(ssl);
close(client);
......@@ -219,70 +230,79 @@ bool nts_ke_request(SSL *ssl) {
int create_listener(int port, int family) {
int sock = -1;
struct sockaddr_in addr;
struct sockaddr_in6 addr6;
sockaddr_u addr;
int on = 1;
int err;
char errbuf[100];
switch (family) {
case AF_INET:
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr= htonl(INADDR_ANY);
addr.sa4.sin_family = AF_INET;
addr.sa4.sin_port = htons(port);
addr.sa4.sin_addr.s_addr= htonl(INADDR_ANY);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
msyslog(LOG_ERR, "NTSs: Can't create socket4: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: Can't create socket4: %s", errbuf);
return -1;
}
err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (0 > err) {
msyslog(LOG_ERR, "NTSs: can't setsockopt4: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: can't setsockopt4: %s", errbuf);
close(sock);
return -1;
}
err = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
err = bind(sock, &addr.sa, sizeof(addr.sa4));
if (0 > err) {
msyslog(LOG_ERR, "NTSs: can't bind4: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: can't bind4: %s", errbuf);
close(sock);
return -1;
}
if (listen(sock, 6) < 0) {
msyslog(LOG_ERR, "NTSs: can't listen4: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: can't listen4: %s", errbuf);
close(sock);
return -1;
}
msyslog(LOG_INFO, "NTSs: listen4 worked");
break;
case AF_INET6:
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
addr6.sin6_addr = in6addr_any;
addr.sa6.sin6_family = AF_INET6;
addr.sa6.sin6_port = htons(port);
addr.sa6.sin6_addr = in6addr_any;
sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock < 0) {
msyslog(LOG_ERR, "NTSs: Can't create socket6: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: Can't create socket6: %s", errbuf);
return -1;
}
/* Hack to keep IPV6 from listening on IPV4 too */
err = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (0 > err) {
msyslog(LOG_ERR, "NTSs: can't setsockopt6only: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: can't setsockopt6only: %s", errbuf);
close(sock);
return -1;
}
err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (0 > err) {
msyslog(LOG_ERR, "NTSs: can't setsockopt6: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: can't setsockopt6: %s", errbuf);
close(sock);
return -1;
}
err = bind(sock, (struct sockaddr*)&addr6, sizeof(addr6));
err = bind(sock, &addr.sa, sizeof(addr.sa6));
if (0 > err) {
msyslog(LOG_ERR, "NTSs: can't bind6: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: can't bind6: %s", errbuf);
close(sock);
return -1;
}
if (listen(sock, 6) < 0) {
msyslog(LOG_ERR, "NTSs: can't listen6: %s", strerror(errno));
strerror_r(errno, errbuf, sizeof(errbuf));
msyslog(LOG_ERR, "NTSs: can't listen6: %s", errbuf);
close(sock);
return -1;
}
......
......@@ -79,6 +79,7 @@ static void RunAllTests(void)
int main(int argc, const char * argv[]) {
getbuf_init();
ssl_init();
auth_init();
init_network();
......