commit 3d1ff5c2df0dd3ee4fd3dad597ea421dbc9ab26c from: the xhr date: Thu Aug 19 15:11:56 2021 UTC Merge branch 'master' of ssh://git.xosc.org:/var/www/git/twind * 'master' of ssh://git.xosc.org:/var/www/git/twind: Implement function to close both access and error logs Implement error logging Remove commented line Next part of access logging Add first support for client access/error logs commit - 9833f63a2064eadd4c4cf2061124d5131613425f commit + 3d1ff5c2df0dd3ee4fd3dad597ea421dbc9ab26c blob - 338a860e245c0825b3f31415366d9daf45e0fec7 blob + 20824e63b2355b7204e92a3d14dd59a15808a677 --- Makefile +++ Makefile @@ -29,6 +29,7 @@ install: all $(INSTALL) -d -m 755 -o root $(MAN)/man8 $(INSTALL) -d -m 750 -o root $(CONFDIR) $(INSTALL) -d -m 755 -o root $(GEMINIDIR) + $(INSTALL) -d -m 755 -o _twind -g _twind $(GEMINIDIR)/logs $(INSTALL) -m 644 -o root twind.8 $(MAN)/man8 $(INSTALL) -m 755 -o root twind $(SBIN) blob - c8df8c1cde601d1c43bd25de8299c5ea99716b6e blob + 264f82269384d4b7fee7add1d3b756432256ccf8 --- log.c +++ log.c @@ -18,16 +18,24 @@ #define _GNU_SOURCE +#include +#include + #include #include #include #include #include #include +#include +#include #include #include "log.h" +#include "twind.h" +#define MAXLOGLINE 1024 + static int debug; static int verbose; static const char *log_procname; @@ -199,3 +207,78 @@ fatalx(const char *emsg, ...) va_end(ap); exit(1); } + +void +open_twind_logs(void) +{ + if ((access_fd = open(_PATH_TWIND_ACCESS_LOG, O_WRONLY|O_APPEND|O_CREAT, 0644)) + == -1) + fatalx("Cannot open access log: %s", _PATH_TWIND_ACCESS_LOG); + + if ((error_fd = open(_PATH_TWIND_ERROR_LOG, O_WRONLY|O_APPEND|O_CREAT, 0644)) + == -1) + fatalx("Cannot open error log: %s", _PATH_TWIND_ACCESS_LOG); + + return; +} + +void +close_twind_logs(void) +{ + close(access_fd); + close(error_fd); +} + +void +log_access(const struct client_connection *cc, const char *fmt, ...) +{ + struct tm tm; + time_t t; + + t = time(NULL); + tm = *localtime(&t); + + user_log(0, "%s - - [%d/%d/%d:%d:%d:%d %s] %s", cc->client_addr, + tm.tm_mday, tm.tm_mon, tm.tm_year+1900, + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_zone, fmt); +} + +void +log_error(const struct client_connection *cc, const char *fmt, ...) +{ + struct tm tm; + time_t t; + + t = time(NULL); + tm = *localtime(&t); + + user_log(1, "[%d/%d/%d:%d:%d:%d %s] [error] [client %s] %s", + tm.tm_mday, tm.tm_mon, tm.tm_year+1900, + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_zone, + cc->client_addr, + fmt); +} + +void +user_log(int target, const char *fmt, ...) +{ + va_list ap; + int fd = -1; + + va_start(ap, fmt); + if (target == 0) + fd = access_fd; + else if (target == 1) + fd = error_fd; + else { + log_warn("Non-existent user log target"); + return; + } + + vdprintf(fd, fmt, ap); + dprintf(fd, "\n"); + + va_end(ap); +} blob - 6d100a48988fc5bde78793af99c23abcf20445f5 blob + 496672085297e44af8d752fe6813ac15150ba64e --- twind.c +++ twind.c @@ -154,6 +154,8 @@ main(int argc, char *argv[]) log_init(debug_flag, LOG_DAEMON); log_setverbose(verbose_flag); + open_twind_logs(); + #ifdef __OpenBSD__ if (pledge("stdio inet dns proc rpath", NULL) == -1) fatalx("pledge"); @@ -181,6 +183,7 @@ organize_termination(void) if (sub_pid == -1) { if (errno == ECHILD) { /* All sub processes are terminated */ + close_twind_logs(); log_debug("twind turns to dust"); exit(0); } else { @@ -225,9 +228,9 @@ handle_incoming_connections(int counter, int tcpsock, struct sockaddr_storage addr; struct sockaddr_in clientaddr; struct sockaddr_in6 clientaddr6; + struct client_connection *cc; char str[INET6_ADDRSTRLEN]; pthread_t thread_id; - SSL *ssl_peer; socklen_t len = sizeof(addr); int ret, ssl_err; @@ -242,50 +245,57 @@ handle_incoming_connections(int counter, int tcpsock, if (ret < 0) fatalx("Error when accepting connection"); + if ((cc = calloc(1, sizeof(struct client_connection))) == NULL) + fatalx("Cannot allocate memory for client structure"); + getpeername(ret, (struct sockaddr *)&clientaddr, &len); if (clientaddr.sin_family == AF_INET) { - if (inet_ntop(AF_INET, &clientaddr.sin_addr, str, sizeof(str))) + if (inet_ntop(AF_INET, &clientaddr.sin_addr, cc->client_addr, sizeof(str))) log_info("Connection from %s on Port %d", - str, ntohs(clientaddr.sin_port)); + cc->client_addr, ntohs(clientaddr.sin_port)); } else if (clientaddr.sin_family == AF_INET6) { getpeername(ret, (struct sockaddr *)&clientaddr6, &len); - if (inet_ntop(AF_INET6, &clientaddr6.sin6_addr, str, sizeof(str))) + if (inet_ntop(AF_INET6, &clientaddr6.sin6_addr, cc->client_addr, sizeof(str))) log_info("Connection from %s on Port %d", - str, ntohs(clientaddr6.sin6_port)); + cc->client_addr, ntohs(clientaddr6.sin6_port)); } - if ((ssl_peer = SSL_new(sslctx)) == NULL) { + if ((cc->ssl_peer = SSL_new(sslctx)) == NULL) { log_warn("Creating new TLS structure failed"); + free(cc); close(ret); continue; } - if (SSL_set_fd(ssl_peer, ret) == 0) { + if (SSL_set_fd(cc->ssl_peer, ret) == 0) { log_warn("TLS cannot set file descriptor"); - SSL_free(ssl_peer); + SSL_free(cc->ssl_peer); + free(cc); close(ret); continue; } - ssl_err = SSL_accept(ssl_peer); + ssl_err = SSL_accept(cc->ssl_peer); if (ssl_err < 0) { ERR_print_errors_fp(stderr); log_warn("Fatal TLS error. Cannot accept TLS connection"); - SSL_shutdown(ssl_peer); - SSL_free(ssl_peer); + SSL_shutdown(cc->ssl_peer); + SSL_free(cc->ssl_peer); + free(cc); close(ret); continue; } else if (ssl_err == 0) { log_warn("TLS handshake not successful"); - SSL_shutdown(ssl_peer); - SSL_free(ssl_peer); + SSL_shutdown(cc->ssl_peer); + SSL_free(cc->ssl_peer); + free(cc); close(ret); continue; } - log_debug("SSL connection using %s\n", SSL_get_cipher (ssl_peer)); + log_debug("SSL connection using %s\n", SSL_get_cipher(cc->ssl_peer)); - if (pthread_create(&thread_id, NULL, main_request_handler, ((void*)ssl_peer)) + if (pthread_create(&thread_id, NULL, main_request_handler, ((void*)cc)) != 0) { log_warn("Cannot create handling thread"); return -1; @@ -293,8 +303,9 @@ handle_incoming_connections(int counter, int tcpsock, pthread_join(thread_id, NULL); - SSL_shutdown(ssl_peer); - SSL_free(ssl_peer); + SSL_shutdown(cc->ssl_peer); + SSL_free(cc->ssl_peer); + free(cc); close(ret); } @@ -327,7 +338,7 @@ fork_main_process(int tcpsock[2], SSL_CTX *sslctx) void * main_request_handler(void *argp) { - SSL *ssl_peer = (SSL*)argp; + struct client_connection *cc = (struct client_connection *)argp; char finalpath[MAXREQLEN]; char temp[MAXREQLEN]; char request[MAXREQLEN]; @@ -339,14 +350,16 @@ main_request_handler(void *argp) memset(request, 0, sizeof(request)); memset(temp, 0, sizeof(temp)); - receive_gemini_request(ssl_peer, request); + receive_gemini_request(cc->ssl_peer, request); ret = get_path_from_request(request, finalpath); if (ret == -1) { /* Malformed request */ - send_non_success_response(ssl_peer, STATUS_BAD_REQUEST); + log_error(cc, "Malformed request"); + send_non_success_response(cc->ssl_peer, STATUS_BAD_REQUEST); return NULL; } else if (ret == -2) { /* 404 */ - send_non_success_response(ssl_peer, STATUS_NOT_FOUND); + log_error(cc, "Request file not found"); + send_non_success_response(cc->ssl_peer, STATUS_NOT_FOUND); return NULL; } @@ -357,7 +370,9 @@ main_request_handler(void *argp) log_debug("Cannot get MIME type for %s", ext); } - if (send_response(ssl_peer, STATUS_SUCCESS, finalpath, mime) < 0) { + log_access(cc, finalpath); + + if (send_response(cc->ssl_peer, STATUS_SUCCESS, finalpath, mime) < 0) { log_warn("Sending response to client failed"); return NULL; } blob - cb93f4a30e0baa7e6ad993f3793bb5d472bc9836 blob + 04544300ea5a27dd7c3abc7466ea3261042fb118 --- twind.h +++ twind.h @@ -17,28 +17,18 @@ #ifndef _TWIND_H #define _TWIND_H +#include + #include #define VERSION "2021.a" #define MAXREQLEN 1025 +#define _PATH_TWIND_ACCESS_LOG "logs/access.log" +#define _PATH_TWIND_ERROR_LOG "logs/error.log" -/* gemini.c */ -int check_gemini_file(const char *); -int send_response(SSL*, int, const char *, const char *); -int send_non_success_response(SSL*, int); +int access_fd; +int error_fd; -/* request.c */ -int get_path_from_request(char *, char *); - -/* mime.c */ -char* get_file_extension(const char*); -char* get_mime_type(const char *); - -/* util.c */ -void* xmalloc(size_t); -char* xstrdup(const char *); -size_t strlcpy(char *, const char *, size_t); - enum status_codes { STATUS_INPUT = 10, STATUS_SENSITIVE_INPUT = 11, @@ -60,4 +50,33 @@ enum status_codes { STATUS_CERT_NOT_VALID = 62, }; +struct client_connection { + SSL *ssl_peer; + char client_addr[INET6_ADDRSTRLEN]; +}; + +/* gemini.c */ +int check_gemini_file(const char *); +int send_response(SSL*, int, const char *, const char *); +int send_non_success_response(SSL*, int); + +/* request.c */ +int get_path_from_request(char *, char *); + +/* mime.c */ +char* get_file_extension(const char*); +char* get_mime_type(const char *); + +/* util.c */ +void* xmalloc(size_t); +char* xstrdup(const char *); +size_t strlcpy(char *, const char *, size_t); + +/* log.c */ +void open_twind_logs(void); +void close_twind_logs(void); +void log_access(const struct client_connection *, const char *, ...); +void log_error(const struct client_connection *, const char *, ...); +void user_log(int, const char *, ...); + #endif