summaryrefslogtreecommitdiffstats
path: root/client.c
diff options
context:
space:
mode:
authorSimon Rettberg2014-09-09 18:07:48 +0200
committerSimon Rettberg2014-09-09 18:07:48 +0200
commitbbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32 (patch)
tree0bad2dc5bb0112940272b22a31f5dc4a0e8b2840 /client.c
parentBail out on startup if an AD server is not reachable (diff)
downloadldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.tar.gz
ldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.tar.xz
ldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.zip
Add OpenSSL-Support (Client<->Proxy)
Diffstat (limited to 'client.c')
-rw-r--r--client.c196
1 files changed, 138 insertions, 58 deletions
diff --git a/client.c b/client.c
index b71b69e..e9e9453 100644
--- a/client.c
+++ b/client.c
@@ -3,20 +3,23 @@
#include "epoll.h"
#include "helper.h"
#include "asn1.h"
+#include "openssl.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
-#define MAX_SEND_BUFFER 100000
+#define MAX_SEND_BUFFER 150000
-static void client_flush(epoll_client_t *client);
+static void client_haveIn(epoll_client_t *client);
+static void client_haveOut(epoll_client_t *client);
static void client_free(epoll_client_t *client)
{
proxy_removeClient(client);
if (client->sendBuffer != NULL) free(client->sendBuffer);
+ if (client->ssl != NULL) SSL_free(client->ssl);
if (client->fd != -1) {
//ePoll_remove(client->fd); // epoll would remove closed descriptors automatically, but just to be sure we don't cause use after free, we remove it explicitly
close(client->fd);
@@ -27,110 +30,187 @@ static void client_free(epoll_client_t *client)
void client_callback(void *data, int haveIn, int haveOut, int doCleanup)
{
epoll_client_t *client = (epoll_client_t*)data;
- if (doCleanup) {
+ if (doCleanup || client->kill) {
printf("Client gone.\n");
client_free(client);
return;
}
- // Anything to read?
- if (haveIn) {
- for (;;) {
- if (client->rbPos >= REQLEN) {
- printf("[C->Proxy] Read buffer overflow. Disconnecting.\n");
- client_free(client);
- return;
- }
- const size_t buflen = REQLEN - client->rbPos;
- const ssize_t ret = read(client->fd, client->readBuffer + client->rbPos, buflen);
+ if (client->ssl == NULL) {
+ // Plain connection
+ if (haveIn) client_haveIn(client);
+ if (haveOut) client_haveOut(client);
+ if (client->kill) client_free(client);
+ return;
+ }
+ // SSL connection
+ if (!client->sslAccepted) {
+ // Still SSL-Connecting
+ if (!ssl_acceptClient(client)) {
+ printf("SSL Client accept failed.\n");
+ client_free(client);
+ return;
+ }
+ if (!client->sslAccepted) return;
+ }
+ // 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->kill) {
+ printf("Client killed.\n");
+ client_free(client);
+ }
+}
+
+static void client_haveIn(epoll_client_t *client)
+{
+ for (;;) {
+ if (client->rbPos >= REQLEN) {
+ printf("[C->Proxy] Read buffer overflow. Disconnecting.\n");
+ client->kill = TRUE;
+ return;
+ }
+ const size_t buflen = REQLEN - client->rbPos;
+ ssize_t ret;
+ if (client->ssl == NULL) {
+ // Plain
+ ret = read(client->fd, client->readBuffer + client->rbPos, buflen);
if (ret < 0 && errno == EINTR) continue;
if (ret < 0 && errno == EAGAIN) break;
if (ret <= 0) {
printf("Client gone while reading.\n");
- client_free(client);
+ client->kill = TRUE;
return;
}
- client->rbPos += ret;
- // Request complete?
- for (;;) {
- size_t consumed, len;
- consumed = scan_asn1SEQUENCE(client->readBuffer, client->readBuffer + client->rbPos, &len);
- if (consumed == 0) break; // Length-Header not complete
- len += consumed;
- if (len > client->rbPos) break; // Body not complete yet
- printf("Received complete requrest...\n");
- if (proxy_fromClient(client, len) == -1) {
- printf("Error parsing request from client.\n");
- client_free(client);
- return;
- }
- // Shift remaining buffer contents
- if (len == client->rbPos) {
- client->rbPos = 0;
- break;
- }
- memmove(client->readBuffer, client->readBuffer + len, client->rbPos - len);
- client->rbPos -= len;
+ } else {
+ // SSL
+ ret = SSL_read(client->ssl, client->readBuffer + client->rbPos, buflen);
+ if (ret <= 0) {
+ int err = SSL_get_error(client->ssl, ret);
+ if (SSL_BLOCKED(err)) break;
+ printf("Client gone while reading (%d, %d).\n", (int)ret, err);
+ client->kill = TRUE;
+ return;
}
- if ((ssize_t)buflen > ret) break; // Read less than buffer len, epoll will fire again
}
+ // We reach here if something was read (so ret > 0)
+ client->rbPos += ret;
+ // Request complete?
+ for (;;) {
+ size_t consumed, len;
+ consumed = scan_asn1SEQUENCE(client->readBuffer, client->readBuffer + client->rbPos, &len);
+ if (consumed == 0) break; // Length-Header not complete
+ len += consumed;
+ if (len > client->rbPos) break; // Body not complete yet
+ printf("Received complete requrest...\n");
+ if (!proxy_fromClient(client, len)) {
+ printf("Error parsing request from client.\n");
+ client->kill = TRUE;
+ return;
+ }
+ // Shift remaining buffer contents
+ if (len == client->rbPos) {
+ client->rbPos = 0;
+ break;
+ }
+ memmove(client->readBuffer, client->readBuffer + len, client->rbPos - len);
+ client->rbPos -= len;
+ }
+ if (client->ssl == NULL && (ssize_t)buflen > ret) break; // Read less than buffer len, epoll will fire again
}
- // Anything to send?
- if (haveOut) client_flush(client);
}
-static void client_flush(epoll_client_t *client)
+static void client_haveOut(epoll_client_t *client)
{
+ client->writeBlocked = FALSE;
while (client->sbPos < client->sbFill) {
const int tosend = client->sbFill - client->sbPos;
- const int ret = write(client->fd, client->sendBuffer + client->sbPos, tosend);
- if (ret < 0 && errno == EINTR) continue;
- if (ret < 0 && errno == EAGAIN) return;
- if (ret <= 0) {
- printf("Cannot send to client (ret: %d, errno: %d)\n", ret, errno);
- return;
+ ssize_t ret;
+ if (client->ssl == NULL) {
+ // 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) {
+ printf("Cannot send to client (ret: %d, errno: %d)\n", (int)ret, errno);
+ client->kill = TRUE;
+ return;
+ }
+ } else {
+ // SSL
+ ret = SSL_write(client->ssl, client->sendBuffer + client->sbPos, tosend);
+ if (ret <= 0) {
+ int err = SSL_get_error(client->ssl, ret);
+ if (SSL_BLOCKED(err)) {
+ client->writeBlocked = TRUE;
+ return; // Blocking
+ }
+ printf("SSL client gone while sending (%d)\n", err);
+ ERR_print_errors_fp(stdout);
+ client->kill = TRUE;
+ return; // Closed
+ }
}
client->sbPos += ret;
- if (ret != tosend) return; // Sent less than requested -> buffer full, epoll will trigger us again
+ if (client->ssl != NULL) {
+ memmove(client->sendBuffer, client->sendBuffer + client->sbPos, client->sbFill - client->sbPos);
+ 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
}
client->sbPos = client->sbFill = 0;
+ if (client->ssl == NULL && client->sbLen > MAX_SEND_BUFFER / 2) {
+ helper_realloc(&client->sendBuffer, &client->sbLen, 8000, "client_haveOut");
+ }
}
-int client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork)
+BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork)
{
- if (client->sbFill == 0 && !cork) {
+ if (client->ssl == NULL && client->sbFill == 0 && !cork) {
// Nothing in send buffer, fire away
const int ret = write(client->fd, buffer, len);
if (ret == 0 || (ret < 0 && errno != EINTR && errno != EAGAIN)) {
printf("Client gone when trying to send.\n");
- return -1;
+ client->kill = TRUE;
+ return FALSE;
}
- if (ret == (int)len) return 0;
+ if (ret == (int)len) return TRUE;
// Couldn't send everything, continue with buffering logic below
if (ret > 0) {
buffer += ret;
len -= (size_t)ret;
}
}
- // Sanity
- if ((client->sbLen - client->sbPos) + len > MAX_SEND_BUFFER) {
- printf("Dropping client as the send buffer would exceed %d bytes.\n", (int)MAX_SEND_BUFFER);
- return -1;
- }
// Buffer...
if (client->sbLen - client->sbFill < len) { // Buffer too small?
+ if (client->writeBlocked) {
+ printf("SSL Write blocked and buffer to small (%d)\n", (int)client->sbLen);
+ client->kill = TRUE;
+ return FALSE;
+ }
if (client->sbPos != 0) { // See if we can compact it
memmove(client->sendBuffer, client->sendBuffer + client->sbPos, client->sbFill - client->sbPos);
client->sbFill -= client->sbPos;
client->sbPos = 0;
}
+ // Sanity
+ if (client->sbFill + len > MAX_SEND_BUFFER) {
+ printf("Dropping client as the send buffer would exceed %d bytes.\n", (int)MAX_SEND_BUFFER);
+ client->kill = TRUE;
+ return FALSE;
+ }
if (client->sbLen - client->sbFill < len) { // Still too small after compacting? realloc
- if (helper_realloc(&client->sendBuffer, &client->sbLen, client->sbLen + len + 1500, "client_send") == -1) return -1;
+ if (helper_realloc(&client->sendBuffer, &client->sbLen, client->sbLen + len + (client->ssl && client->sbLen > 0 ? MAX_SEND_BUFFER : 4000), "client_send") == -1) {
+ client->kill = TRUE;
+ return FALSE;
+ }
+ printf("Send Buffer now %d\n", (int)client->sbLen);
}
}
// Finally append to buffer
memcpy(client->sendBuffer + client->sbFill, buffer, len);
client->sbFill += len;
- if (!cork) client_flush(client);
- return 0;
+ if (!cork) client_haveOut(client);
+ return TRUE;
}