diff --git a/src/lib/error.c b/src/lib/error.c index e39d61e..c58f43e 100644 --- a/src/lib/error.c +++ b/src/lib/error.c @@ -7,59 +7,23 @@ */ #include "error.h" -#include "http.h" +#include "../logger.h" #include #include -#include -#include -#include -static const char *error_ssl_strerror(int err) { - switch (err) { - case SSL_ERROR_ZERO_RETURN: - return "closed"; - case SSL_ERROR_WANT_READ: - return "want read"; - case SSL_ERROR_WANT_WRITE: - return "want write"; - case SSL_ERROR_WANT_CONNECT: - return "want connect"; - case SSL_ERROR_WANT_ACCEPT: - return "want accept"; - case SSL_ERROR_WANT_X509_LOOKUP: - return "want x509 lookup"; - case SSL_ERROR_WANT_ASYNC: - return "want async"; - case SSL_ERROR_WANT_ASYNC_JOB: - return "want async job"; - case SSL_ERROR_WANT_CLIENT_HELLO_CB: - return "want client hello callback"; - //case SSL_ERROR_WANT_RETRY_VERIFY: - // return "want retry verify"; - case SSL_ERROR_SSL: - return ERR_reason_error_string(ERR_get_error()); - default: - return "unknown error"; - } +extern const char *sock_error_str(unsigned long err); +extern const char *http_error_str(int err); +extern const char *MMDB_strerror(int err); +extern const char *ERR_reason_error_string(unsigned long err); + +static int error_compress(unsigned long err) { + if (err & 0xFF0000) warning("Lossy error code compression!"); + return ((int) err & 0xFFFF) | (((int) err >> 8) & 0xFF0000); } -static const char *error_http_strerror(int err) { - switch (err) { - case HTTP_ERROR_TOO_MANY_HEADER_FIELDS: - return "too many header fields"; - case HTTP_ERROR_EOH_NOT_FOUND: - return "end of http header not found"; - case HTTP_ERROR_HEADER_MALFORMED: - return "http header malformed"; - case HTTP_ERROR_INVALID_VERSION: - return "invalid http version"; - case HTTP_ERROR_URI_TOO_LONG: - return "uri too long"; - case HTTP_ERROR_GENERAL: - default: - return "unknown error"; - } +static unsigned long error_decompress(int err) { + return (err & 0xFFFF) | ((err << 8) & 0xFF000000); } const char *error_str(int err_no, char *buf, int buf_len) { @@ -72,46 +36,34 @@ const char *error_str(int err_no, char *buf, int buf_len) { return buf; } else if (mode == 0x01) { // ssl - return error_ssl_strerror(e); + return sock_error_str(error_decompress(e)); } else if (mode == 0x02) { + // ssl err + return ERR_reason_error_string(error_decompress(e)); + } else if (mode == 0x03) { // mmdb return MMDB_strerror(e); - } else if (mode == 0x03) { + } else if (mode == 0x04) { // http - return error_http_strerror(e); + return http_error_str(e); } return buf; } -void error_ssl(int err) { - if (err == SSL_ERROR_NONE) { - errno = 0; - } else if (err == SSL_ERROR_SYSCALL) { - // errno already set - } else { - errno = 0x01000000 | err; - } +void error_ssl(unsigned long err) { + errno = 0x01000000 | error_compress(err); +} + +void error_ssl_err(unsigned long err) { + errno = 0x02000000 | error_compress(err); } void error_mmdb(int err) { - if (err == MMDB_SUCCESS) { - errno = 0; - } else if (err == MMDB_IO_ERROR) { - // errno already set - } else { - errno = 0x02000000 | err; - } + errno = 0x03000000 | err; } -int error_http(int err) { - if (err == 0) { - errno = 0; - } else if (err == HTTP_ERROR_SYSCALL) { - // errno already set - } else { - errno = 0x03000000 | err; - } - return -1; +void error_http(int err) { + errno = 0x04000000 | err; } static int error_get(unsigned char prefix) { @@ -126,10 +78,14 @@ int error_get_ssl() { return error_get(0x01); } -int error_get_mmdb() { +int error_get_ssl_err() { return error_get(0x02); } -int error_get_http() { +int error_get_mmdb() { return error_get(0x03); } + +int error_get_http() { + return error_get(0x04); +} diff --git a/src/lib/error.h b/src/lib/error.h index cd57fab..60dc0b3 100644 --- a/src/lib/error.h +++ b/src/lib/error.h @@ -11,11 +11,13 @@ const char *error_str(int err_no, char *buf, int buf_len); -void error_ssl(int err); +void error_ssl(unsigned long err); + +void error_ssl_err(unsigned long err); void error_mmdb(int err); -int error_http(int err); +void error_http(int err); int error_get_sys(); diff --git a/src/lib/geoip.c b/src/lib/geoip.c index 6c95059..b612e87 100644 --- a/src/lib/geoip.c +++ b/src/lib/geoip.c @@ -10,12 +10,23 @@ #include "../logger.h" #include "error.h" #include "utils.h" + #include #include - +#include static MMDB_s mmdbs[GEOIP_MAX_MMDB]; +static void mmdb_error(int err) { + if (err == MMDB_SUCCESS) { + errno = 0; + } else if (err == MMDB_IO_ERROR) { + // errno already set + } else { + error_mmdb(err); + } +} + static MMDB_entry_data_list_s *geoip_json(MMDB_entry_data_list_s *list, char *str, long *str_off, long str_len) { switch (list->entry_data.type) { case MMDB_DATA_TYPE_MAP: @@ -103,7 +114,7 @@ int geoip_init(const char *directory) { sprintf(buf, "%s/%s", directory, entry->d_name); if ((status = MMDB_open(buf, 0, &mmdbs[i])) != MMDB_SUCCESS) { - error_mmdb(status); + mmdb_error(status); critical("Unable to initialize geoip: Unable to open .mmdb file"); closedir(geoip_dir); return 1; @@ -167,7 +178,7 @@ int geoip_lookup_json(struct sockaddr *addr, char *json, long len) { int mmdb_res; MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&mmdbs[i], addr, &mmdb_res); if (mmdb_res != MMDB_SUCCESS) { - error_mmdb(mmdb_res); + mmdb_error(mmdb_res); error("Unable to lookup geoip info"); continue; } else if (!result.found_entry) { @@ -176,7 +187,7 @@ int geoip_lookup_json(struct sockaddr *addr, char *json, long len) { MMDB_entry_data_list_s *list; if ((mmdb_res = MMDB_get_entry_data_list(&result.entry, &list)) != MMDB_SUCCESS) { - error_mmdb(mmdb_res); + mmdb_error(mmdb_res); error("Unable to lookup geoip info"); continue; } diff --git a/src/lib/http.c b/src/lib/http.c index 085117f..e1774e7 100644 --- a/src/lib/http.c +++ b/src/lib/http.c @@ -13,7 +13,36 @@ #include "error.h" #include +#include +static int http_error(int err) { + if (err == 0) { + errno = 0; + } else if (err == HTTP_ERROR_SYSCALL) { + // errno already set + } else { + error_http(err); + } + return -1; +} + +const char *http_error_str(int err) { + switch (err) { + case HTTP_ERROR_TOO_MANY_HEADER_FIELDS: + return "too many header fields"; + case HTTP_ERROR_EOH_NOT_FOUND: + return "end of http header not found"; + case HTTP_ERROR_HEADER_MALFORMED: + return "http header malformed"; + case HTTP_ERROR_INVALID_VERSION: + return "invalid http version"; + case HTTP_ERROR_URI_TOO_LONG: + return "uri too long"; + case HTTP_ERROR_GENERAL: + default: + return "unknown error"; + } +} void http_to_camel_case(char *str, int mode) { if (mode == HTTP_PRESERVE) @@ -91,19 +120,19 @@ int http_init_hdr(http_hdr *hdr) { hdr->last_field_num = -1; hdr->fields = list_create(sizeof(http_field), HTTP_INIT_HEADER_FIELD_NUM); if (hdr->fields == NULL) - return error_http(HTTP_ERROR_SYSCALL); + return http_error(HTTP_ERROR_SYSCALL); return 0; } int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr, int flags) { if (hdr->last_field_num > list_size(hdr->fields)) - return error_http(HTTP_ERROR_GENERAL); + return http_error(HTTP_ERROR_GENERAL); char *pos1 = (char *) buf, *pos2 = (char *) end_ptr; if (buf[0] == ' ' || buf[0] == '\t') { if (hdr->last_field_num == -1) - return error_http(HTTP_ERROR_GENERAL); + return http_error(HTTP_ERROR_GENERAL); http_field *f = &hdr->fields[(int) hdr->last_field_num]; @@ -115,7 +144,7 @@ int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr, pos1 = memchr(buf, ':', end_ptr - buf); if (pos1 == NULL) - return error_http(HTTP_ERROR_GENERAL); + return http_error(HTTP_ERROR_GENERAL); long len1 = pos1 - buf; @@ -130,7 +159,7 @@ int http_parse_header_field(http_hdr *hdr, const char *buf, const char *end_ptr, int found = http_get_header_field_num(hdr, header_name); if (!(flags & HTTP_MERGE_FIELDS) || found == -1) { if (http_add_header_field_len(hdr, buf, len1, pos1, len2 < 0 ? 0 : len2) != 0) - return error_http(HTTP_ERROR_TOO_MANY_HEADER_FIELDS); + return http_error(HTTP_ERROR_TOO_MANY_HEADER_FIELDS); } else { field_num = found; http_append_to_header_field(&hdr->fields[found], ", ", 2); @@ -147,44 +176,44 @@ int http_parse_request(char *buf, http_req *req) { unsigned long header_len = strstr(buf, "\r\n\r\n") - buf + 4; if (header_len <= 0) - return error_http(HTTP_ERROR_EOH_NOT_FOUND); + return http_error(HTTP_ERROR_EOH_NOT_FOUND); for (int i = 0; i < header_len; i++) { if ((buf[i] >= 0x00 && buf[i] <= 0x1F && buf[i] != '\r' && buf[i] != '\n') || buf[i] == 0x7F) - return error_http(HTTP_ERROR_HEADER_MALFORMED); + return http_error(HTTP_ERROR_HEADER_MALFORMED); } ptr = buf; while (header_len > (ptr - buf + 2)) { pos0 = strstr(ptr, "\r\n"); if (pos0 == NULL) - return error_http(HTTP_ERROR_HEADER_MALFORMED); + return http_error(HTTP_ERROR_HEADER_MALFORMED); if (req->version[0] == 0) { pos1 = (char *) strchr(ptr, ' ') + 1; if (pos1 == NULL) goto err_hdr_fmt; if (pos1 - ptr - 1 >= sizeof(req->method)) - return error_http(HTTP_ERROR_HEADER_MALFORMED); + return http_error(HTTP_ERROR_HEADER_MALFORMED); for (int i = 0; i < (pos1 - ptr - 1); i++) { if (ptr[i] < 'A' || ptr[i] > 'Z') - return error_http(HTTP_ERROR_HEADER_MALFORMED); + return http_error(HTTP_ERROR_HEADER_MALFORMED); } snprintf(req->method, sizeof(req->method), "%.*s", (int) (pos1 - ptr - 1), ptr); pos2 = (char *) strchr(pos1, ' ') + 1; if (pos2 == NULL) { err_hdr_fmt: - return error_http(HTTP_ERROR_HEADER_MALFORMED); + return http_error(HTTP_ERROR_HEADER_MALFORMED); } if (memcmp(pos2, "HTTP/", 5) != 0 || memcmp(pos2 + 8, "\r\n", 2) != 0) - return error_http(HTTP_ERROR_INVALID_VERSION); + return http_error(HTTP_ERROR_INVALID_VERSION); len = pos2 - pos1 - 1; if (len >= 2048) - return error_http(HTTP_ERROR_URI_TOO_LONG); + return http_error(HTTP_ERROR_URI_TOO_LONG); req->uri = malloc(len + 1); sprintf(req->uri, "%.*s", (int) len, pos1); @@ -200,7 +229,7 @@ int http_parse_request(char *buf, http_req *req) { return (int) header_len; } - return error_http(HTTP_ERROR_GENERAL); + return http_error(HTTP_ERROR_GENERAL); } int http_receive_request(sock *client, http_req *req) { diff --git a/src/lib/http.h b/src/lib/http.h index 9befbb7..8140a3c 100644 --- a/src/lib/http.h +++ b/src/lib/http.h @@ -134,6 +134,8 @@ extern const int http_status_messages_size; extern const char http_error_doc[], http_warning_doc[], http_success_doc[], http_info_doc[]; +const char *http_error_str(int err); + void http_to_camel_case(char *str, int mode); const char *http_field_get_name(const http_field *field); diff --git a/src/lib/proxy.c b/src/lib/proxy.c index 905577c..96ea864 100644 --- a/src/lib/proxy.c +++ b/src/lib/proxy.c @@ -383,7 +383,7 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu ret = SSL_do_handshake(proxy->proxy.ssl); if (ret != 1) { - error_ssl(SSL_get_error(proxy->proxy.ssl, (int) ret)); + sock_error(&proxy->proxy, ret); SSL_free(proxy->proxy.ssl); res->status = http_get_status(502); ctx->origin = SERVER_REQ; diff --git a/src/lib/sock.c b/src/lib/sock.c index de3e68d..6f2fe38 100644 --- a/src/lib/sock.c +++ b/src/lib/sock.c @@ -15,6 +15,50 @@ #include #include #include +#include + +static void ssl_error(unsigned long err) { + if (err == SSL_ERROR_NONE) { + errno = 0; + } else if (err == SSL_ERROR_SYSCALL) { + // errno already set + } else if (err == SSL_ERROR_SSL) { + error_ssl_err(ERR_get_error()); + } else { + error_ssl(err); + } +} + +void sock_error(sock *s, int ret) { + ssl_error(SSL_get_error(s->ssl, ret)); +} + +const char *sock_error_str(unsigned long err) { + switch (err) { + case SSL_ERROR_ZERO_RETURN: + return "closed"; + case SSL_ERROR_WANT_READ: + return "want read"; + case SSL_ERROR_WANT_WRITE: + return "want write"; + case SSL_ERROR_WANT_CONNECT: + return "want connect"; + case SSL_ERROR_WANT_ACCEPT: + return "want accept"; + case SSL_ERROR_WANT_X509_LOOKUP: + return "want x509 lookup"; + case SSL_ERROR_WANT_ASYNC: + return "want async"; + case SSL_ERROR_WANT_ASYNC_JOB: + return "want async job"; + case SSL_ERROR_WANT_CLIENT_HELLO_CB: + return "want client hello callback"; + //case SSL_ERROR_WANT_RETRY_VERIFY: + // return "want retry verify"; + default: + return "unknown error"; + } +} int sock_set_socket_timeout_micros(sock *s, long recv_micros, long send_micros) { struct timeval recv_to = {.tv_sec = recv_micros / 1000000, .tv_usec = recv_micros % 1000000}, @@ -49,7 +93,7 @@ long sock_send(sock *s, void *buf, unsigned long len, int flags) { long ret; if (s->enc) { ret = SSL_write(s->ssl, buf, (int) len); - if (ret <= 0) error_ssl(SSL_get_error(s->ssl, (int) ret)); + if (ret <= 0) sock_error(s, (int) ret); } else { ret = send(s->socket, buf, len, flags); } @@ -67,7 +111,7 @@ long sock_recv(sock *s, void *buf, unsigned long len, int flags) { if (s->enc) { int (*func)(SSL*, void*, int) = (flags & MSG_PEEK) ? SSL_peek : SSL_read; ret = func(s->ssl, buf, (int) len); - if (ret <= 0) error_ssl(SSL_get_error(s->ssl, (int) ret)); + if (ret <= 0) sock_error(s, (int) ret); } else { ret = recv(s->socket, buf, len, flags); } diff --git a/src/lib/sock.h b/src/lib/sock.h index cf4bcb2..1eada2f 100644 --- a/src/lib/sock.h +++ b/src/lib/sock.h @@ -26,6 +26,10 @@ typedef struct { long ts_start, ts_last, timeout_us; } sock; +void sock_error(sock *s, int ret); + +const char *sock_error_str(unsigned long err); + int sock_set_socket_timeout_micros(sock *s, long recv_micros, long send_micros); int sock_set_socket_timeout(sock *s, double sec); diff --git a/src/worker/tcp_acceptor.c b/src/worker/tcp_acceptor.c index b9a6876..2c94393 100644 --- a/src/worker/tcp_acceptor.c +++ b/src/worker/tcp_acceptor.c @@ -105,7 +105,7 @@ static int tcp_acceptor(client_ctx_t *ctx) { ret = SSL_accept(client->ssl); if (ret != 1) { - error_ssl(SSL_get_error(client->ssl, ret)); + sock_error(client, ret); info("Unable to perform handshake"); return -1; }