From e53dfcbdbed04cad690823ce5def521fea7b5483 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 12 Mar 2018 15:28:33 +0100 Subject: 4s timeout when connecting to server; send error to client on failure --- client.c | 36 +++++++++++++++++++++++++++--------- client.h | 2 ++ helper.c | 16 ++++++++++++++-- helper.h | 1 + proxy.c | 4 ++-- server.c | 8 ++++---- 6 files changed, 50 insertions(+), 17 deletions(-) diff --git a/client.c b/client.c index 2fbc560..41cda25 100644 --- a/client.c +++ b/client.c @@ -13,7 +13,7 @@ #define MAX_SEND_BUFFER 150000 static void client_haveIn(epoll_client_t *client); -static void client_haveOut(epoll_client_t *client); +static BOOL client_haveOut(epoll_client_t *client); void client_free(epoll_client_t *client) { @@ -38,7 +38,9 @@ void client_callback(void *data, int haveIn, int haveOut, int doCleanup) if (client->ssl == NULL) { // Plain connection if (haveIn) client_haveIn(client); - if (haveOut) client_haveOut(client); + if (haveOut || client->kill) { + if (client_haveOut(client)) return; + } if (client->kill) { //printf("Client gone (2).\n"); client_free(client); @@ -57,7 +59,7 @@ void client_callback(void *data, int haveIn, int haveOut, int doCleanup) } // Since we don't know if the incoming data is just wrapped application data or ssl protocol stuff, we always call both client_haveIn(client); - client_haveOut(client); + if (client_haveOut(client)) return; if (client->kill) { //printf("Client gone (3).\n"); client_free(client); @@ -127,9 +129,15 @@ static void client_haveIn(epoll_client_t *client) } } -static void client_haveOut(epoll_client_t *client) +/** + * Send any queued data. + * Returns TRUE if anything has been sent, or the socket + * buffer is currently full (EAGAIN, non-blocking mode) + */ +static BOOL client_haveOut(epoll_client_t *client) { client->writeBlocked = FALSE; + if (client->sbPos >= client->sbFill) return FALSE; while (client->sbPos < client->sbFill) { const int tosend = client->sbFill - client->sbPos; ssize_t ret; @@ -137,11 +145,11 @@ static void client_haveOut(epoll_client_t *client) // Plain ret = write(client->fd, client->sendBuffer + client->sbPos, tosend); if (ret < 0 && errno == EINTR) continue; - if (ret < 0 && errno == EAGAIN) return; + if (ret < 0 && errno == EAGAIN) return TRUE; if (ret <= 0) { printf("[Proxy] Cannot send to client (ret=%d, errno=%d)\n", (int)ret, errno); client->kill = TRUE; - return; + return FALSE; } } else { // SSL @@ -150,12 +158,12 @@ static void client_haveOut(epoll_client_t *client) int err = SSL_get_error(client->ssl, ret); if (SSL_BLOCKED(err)) { client->writeBlocked = TRUE; - return; // Blocking + return TRUE; // Blocking } printf("[Proxy] SSL cannot send to client (ret=%d, err=%d)\n", (int)ret, err); ERR_print_errors_fp(stdout); client->kill = TRUE; - return; // Closed + return FALSE; // Closed } } client->sbPos += ret; @@ -164,12 +172,13 @@ static void client_haveOut(epoll_client_t *client) client->sbFill -= client->sbPos; client->sbPos = 0; } - if (client->ssl == NULL && ret != tosend) return; // Sent less than requested -> buffer full, epoll will trigger us again + if (client->ssl == NULL && ret != tosend) return TRUE; // Sent less than requested -> buffer full, epoll will trigger us again } client->sbPos = client->sbFill = 0; if (client->ssl == NULL && client->sbLen > MAX_SEND_BUFFER / 2) { helper_realloc(&client->sendBuffer, &client->sbLen, 8000, "client_haveOut"); } + return TRUE; } BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork) @@ -221,3 +230,12 @@ BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const B return TRUE; } +BOOL client_searchResultError(epoll_client_t *client, const unsigned long messageId, const int code, const char *message) +{ + const size_t doneLen = fmt_ldapsearchresultdone(NULL, code, "", message, ""); + const size_t doneHeaderLen = fmt_ldapmessage(NULL, messageId, SearchResultDone, doneLen); + char buffer[doneLen + doneHeaderLen]; + fmt_ldapsearchresultdone(buffer + doneHeaderLen, code, "", message, ""); + fmt_ldapmessage(buffer, messageId, SearchResultDone, doneLen); + return client_send(client, buffer, doneHeaderLen + doneLen, FALSE); +} diff --git a/client.h b/client.h index 2cc8090..cd595ce 100644 --- a/client.h +++ b/client.h @@ -9,4 +9,6 @@ void client_callback(void *data, int haveIn, int haveOut, int doCleanup); BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork); +BOOL client_searchResultError(epoll_client_t *client, const unsigned long messageId, const int code, const char *message); + #endif diff --git a/helper.c b/helper.c index 2dc907e..6c51bab 100644 --- a/helper.c +++ b/helper.c @@ -46,7 +46,7 @@ int helper_connect4(char *address, int port, char *ip) { if (sizeof(struct in_addr) != 4) bail("Ach nöö ach nöö"); if (inet_pton(AF_INET, address, ip) == 1) { - const int sock = socket_tcp4b(); + const int sock = helper_newSocket(); if (sock == -1) return -1; if (socket_connect4(sock, ip, port) == 0) { return sock; @@ -65,7 +65,7 @@ int helper_connect4(char *address, int port, char *ip) return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { - const int sock = socket_tcp4b(); + const int sock = helper_newSocket(); if (sock == -1) continue; if (rp->ai_addr != NULL) { memcpy(ip, &((struct sockaddr_in*)rp->ai_addr)->sin_addr, 4); @@ -80,6 +80,18 @@ int helper_connect4(char *address, int port, char *ip) return -1; } +int helper_newSocket() +{ + struct timeval tv; + int sock = socket_tcp4b(); + if (sock == -1) return -1; + tv.tv_sec = 4; + tv.tv_usec = 0; + setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv) ); + setsockopt( sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv) ); + return sock; +} + void helper_nonblock(const int fd) { fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); diff --git a/helper.h b/helper.h index f2c895b..7aaece7 100644 --- a/helper.h +++ b/helper.h @@ -7,6 +7,7 @@ void bail(char *args, ...); int helper_realloc(char **memory, size_t *curSize, const size_t newSize, const char *location); int helper_connect4(char *address, int port, char *ip); +int helper_newSocket(); void helper_nonblock(const int fd); void helper_printava(struct AttributeValueAssertion* a,const char* rel); diff --git a/proxy.c b/proxy.c index 36f7cac..afb1bd8 100644 --- a/proxy.c +++ b/proxy.c @@ -809,7 +809,6 @@ static void response_replaceAttribute(server_t *server, const struct string * co */ static BOOL response_filterHomeDir(struct PartialAttributeList *pal) { - helper_printpal(pal); for (struct AttributeDescriptionList *adl = pal->values; adl != NULL; adl = pal->values /* sic */) { if (adl->a.s != NULL) { if (adl->a.l > 0 && adl->a.s[0] == '\\') { @@ -904,6 +903,7 @@ static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned lon if (pending == NULL) { plog(DEBUG_WARNING, "Cannot handle incoming client request; too many pending requests on the wire."); free_ldapsearchrequest(&req); + client_searchResultError(client, messageId, busy, "I'm busy!"); return FALSE; } // In case of anonymous bind: Narrow down list of what the user can see to protect private data @@ -935,7 +935,7 @@ static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned lon pending->serverMessageId = server_searchRequestOnConnection(client->fixedServer, &req); } if (pending->serverMessageId == 0) { - // Failed to forward.. TODO: Fail client + client_searchResultError(client, messageId, unavailable, "Cannot contact upstream server."); plog(DEBUG_WARNING, "Failed to forward a search request to server."); pending->client = NULL; } diff --git a/server.c b/server.c index a4106f9..f22c5bf 100644 --- a/server.c +++ b/server.c @@ -696,17 +696,17 @@ static int server_connectInternal(server_t *server) if (server->lastLookup + 300 < time(NULL)) { sock = helper_connect4(server->addr, port, server->ip); if (sock == -1) { - printf("[Proxy] Could not resolve hostname or connect to AD server %s\n", server->addr); + printf("[Proxy] Could not resolve hostname or connect to AD server %s (errno=%d)\n", server->addr, errno); return -1; } } else { - sock = socket_tcp4b(); + sock = helper_newSocket(); if (sock == -1) { - printf("[Proxy] Could not allocate socket for connection to AD server %s\n", server->addr); + printf("[Proxy] Could not allocate socket for connection to AD server %s (errno=%d)\n", server->addr, errno); return -1; } if (socket_connect4(sock, server->ip, port) == -1) { - printf("[Proxy] Could not connect to cached IP (%s) of %s\n", server->ip, server->addr); + printf("[Proxy] Could not connect to cached IP (%s) of %s (errno=%d)\n", server->ip, server->addr, errno); server->lastLookup = 0; close(sock); return -1; -- cgit v1.2.3-55-g7522