Vastly improve logging

This commit is contained in:
Christopher Wellons 2019-02-03 08:09:21 -05:00
parent 81046bcdec
commit 112e5b303f
2 changed files with 77 additions and 29 deletions

View File

@ -24,6 +24,12 @@ Usage: endlessh [-vh] [-d MSECS] [-m LIMIT] [-p PORT]
-v Print diagnostics to standard output (repeatable) -v Print diagnostics to standard output (repeatable)
``` ```
By default no log messages are produced. The first `-v` enables basic
logging and a second `-v` enables debug logging (noisy). All log
messages are sent to standard output.
endlessh -v >endlessh.log 2>endlessh.err
The purpose of limiting the number of clients (`-m`) is to avoid tying The purpose of limiting the number of clients (`-m`) is to avoid tying
up too many system resources with the tarpit. Clients beyond this limit up too many system resources with the tarpit. Clients beyond this limit
are left in the accept queue, not rejected instantly. are left in the accept queue, not rejected instantly.

View File

@ -12,6 +12,7 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#define DEFAULT_MAX_CLIENTS 4096 #define DEFAULT_MAX_CLIENTS 4096
@ -30,8 +31,12 @@ uepoch(void)
} }
struct client { struct client {
long long send_next; // epoch milliseconds for next line char ipaddr[INET6_ADDRSTRLEN];
long long connect_time;
long long send_next;
long long bytes_sent;
struct client *next; struct client *next;
int port;
int fd; int fd;
}; };
@ -40,9 +45,30 @@ client_new(int fd, long long send_next)
{ {
struct client *c = malloc(sizeof(*c)); struct client *c = malloc(sizeof(*c));
if (c) { if (c) {
c->connect_time = uepoch();
c->send_next = send_next; c->send_next = send_next;
c->bytes_sent = 0;
c->next = 0; c->next = 0;
c->fd = fd; c->fd = fd;
/* Get IP address */
struct sockaddr_storage addr;
socklen_t len = sizeof(addr);
if (getpeername(fd, (struct sockaddr*)&addr, &len) == -1) {
c->ipaddr[0] = 0;
} else {
if (addr.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
c->port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr,
c->ipaddr, sizeof(c->ipaddr));
} else {
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
c->port = ntohs(s->sin6_port);
inet_ntop(AF_INET6, &s->sin6_addr,
c->ipaddr, sizeof(c->ipaddr));
}
}
} }
return c; return c;
} }
@ -151,16 +177,26 @@ randline(char *line)
return len; return len;
} }
enum loglevel {
LOG_NONE,
LOG_INFO,
LOG_DEBUG
};
static enum loglevel loglevel = LOG_NONE;
static void static void
logmsg(const char *format, ...) logmsg(enum loglevel level, const char *format, ...)
{ {
long long now = uepoch(); if (loglevel >= level) {
fprintf(stderr, "%lld.%03lld: ", now / 1000, now % 1000); long long now = uepoch();
va_list ap; printf("%lld.%03lld: ", now / 1000, now % 1000);
va_start(ap, format); va_list ap;
vfprintf(stderr, format, ap); va_start(ap, format);
va_end(ap); vprintf(format, ap);
fputc('\n', stderr); va_end(ap);
fputc('\n', stdout);
}
} }
static void static void
@ -180,7 +216,6 @@ usage(FILE *f)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int verbose = 0;
int port = DEFAULT_PORT; int port = DEFAULT_PORT;
long delay = DEFAULT_DELAY; long delay = DEFAULT_DELAY;
long max_clients = DEFAULT_MAX_CLIENTS; long max_clients = DEFAULT_MAX_CLIENTS;
@ -218,7 +253,7 @@ main(int argc, char **argv)
port = tmp; port = tmp;
break; break;
case 'v': case 'v':
verbose++; loglevel++;
break; break;
default: default:
usage(stderr); usage(stderr);
@ -244,8 +279,7 @@ main(int argc, char **argv)
check(bind(server, (void *)&addr, sizeof(addr))); check(bind(server, (void *)&addr, sizeof(addr)));
check(listen(server, INT_MAX)); check(listen(server, INT_MAX));
if (verbose >= 1) logmsg(LOG_DEBUG, "listen(port=%d)", port);
logmsg("listen(port=%d)", port);
srand(time(0)); srand(time(0));
for (;;) { for (;;) {
@ -265,17 +299,14 @@ main(int argc, char **argv)
} }
/* Wait for next event */ /* Wait for next event */
if (verbose >= 2) logmsg(LOG_DEBUG, "poll(%zu, %d)%s", pollvec->fill, timeout,
logmsg("poll(%zu, %d)%s", pollvec->fill, timeout, nclients >= max_clients ? " (no accept)" : "");
nclients >= max_clients ? " (no accept)" : "");
int r = poll(pollvec->fds, pollvec->fill, timeout); int r = poll(pollvec->fds, pollvec->fill, timeout);
if (verbose >= 2) logmsg(LOG_DEBUG, "= %d", r);
logmsg("= %d", r);
if (r == -1) { if (r == -1) {
switch (errno) { switch (errno) {
case EINTR: case EINTR:
if (verbose >= 1) logmsg(LOG_DEBUG, "EINTR");
logmsg("EINTR");
continue; continue;
default: default:
fprintf(stderr, "endlessh: fatal: %s\n", strerror(errno)); fprintf(stderr, "endlessh: fatal: %s\n", strerror(errno));
@ -286,16 +317,16 @@ main(int argc, char **argv)
/* Check for new incoming connections */ /* Check for new incoming connections */
if (pollvec->fds[0].revents & POLLIN) { if (pollvec->fds[0].revents & POLLIN) {
int fd = accept(server, 0, 0); int fd = accept(server, 0, 0);
if (verbose >= 1) logmsg(LOG_DEBUG, "accept() = %d", fd);
logmsg("accept() = %d", fd);
if (fd == -1) { if (fd == -1) {
const char *msg = strerror(errno); const char *msg = strerror(errno);
switch (errno) { switch (errno) {
case EMFILE: case EMFILE:
case ENFILE: case ENFILE:
max_clients = nclients; max_clients = nclients;
if (verbose >= 1) logmsg(LOG_INFO,
logmsg("max clients reduced to %ld", nclients); "maximum number of clients reduced to %ld",
nclients);
break; break;
case ECONNABORTED: case ECONNABORTED:
case EINTR: case EINTR:
@ -314,8 +345,11 @@ main(int argc, char **argv)
fprintf(stderr, "endlessh: warning: out of memory\n"); fprintf(stderr, "endlessh: warning: out of memory\n");
close(fd); close(fd);
} }
queue_append(queue, client);
nclients++; nclients++;
logmsg(LOG_INFO, "ACCEPT host=%s:%d fd=%d n=%ld/%ld",
client->ipaddr, client->port, client->fd,
nclients, max_clients);
queue_append(queue, client);
} }
} }
@ -326,17 +360,25 @@ main(int argc, char **argv)
struct client *client = queue_remove(queue, fd); struct client *client = queue_remove(queue, fd);
if (revents & POLLHUP) { if (revents & POLLHUP) {
if (verbose >= 1) logmsg(LOG_DEBUG, "close(%d)", fd);
logmsg("close(%d)", fd); long long dt = uepoch() - client->connect_time;
logmsg(LOG_INFO,
"CLOSE host=%s:%d fd=%d "
"time=%lld.%03lld bytes=%lld",
client->ipaddr, client->port, fd,
dt / 1000, dt % 1000,
client->bytes_sent);
close(fd); close(fd);
free(client); free(client);
nclients--; nclients--;
} else if (revents & POLLOUT) { } else if (revents & POLLOUT) {
char line[255]; char line[256];
int len = randline(line); int len = randline(line);
/* Don't really care if this send fails */ /* Don't really care if this send fails */
send(fd, line, len, MSG_DONTWAIT); ssize_t out = send(fd, line, len, MSG_DONTWAIT);
logmsg(LOG_DEBUG, "send(%d) = %d", fd, (int)out);
client->bytes_sent += out > 0 ? out : out;
client->send_next = uepoch() + delay; client->send_next = uepoch() + delay;
queue_append(queue, client); queue_append(queue, client);
} }