1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-07 15:43:14 +02:00

Fix frame reassembly in webserver_handle_request_header()

Previously the same code caused no problem, but then
2fcb5b4669 changed the read buffer
size to 16384.
Since then (6.1.2.x) the webserver_handle_request_header() function
was sometimes cutting 1 byte off the packet due to sizeof(netbuf)-1
which was 16383 bytes. We now no longer use a fixed value and
allocate memory dynamically on the heap.

This fixes the bug that I was seeing but this change still needs
serious extra testing as it may affect websockets and RPC!
This commit is contained in:
Bram Matthys
2023-12-06 18:14:43 +01:00
parent 49614fc891
commit 4178cb3f81
+22 -30
View File
@@ -183,7 +183,7 @@ int webserver_packet_in(Client *client, const char *readbuf, int *length)
/** Helper function to parse the HTTP header consisting of multiple 'Key: value' pairs */
int webserver_handshake_helper(char *buffer, int len, char **key, char **value, char **lastloc, int *end_of_request)
{
static char buf[4096], *nextptr;
static char buf[16384], *nextptr;
char *p;
char *k = NULL, *v = NULL;
int foundlf = 0;
@@ -351,48 +351,31 @@ char *find_end_of_request(char *header, int totalsize, int *remaining_bytes)
}
/** Handle HTTP request
* Yes, I'm going to assume that the header fits in one packet and one packet only.
*/
int webserver_handle_request_header(Client *client, const char *readbuf, int *length)
{
char *key, *value;
int r, end_of_request;
static char netbuf[16384];
static char netbuf2[16384];
char *netbuf;
char *lastloc = NULL;
int n, maxcopy, nprefix=0;
int totalsize;
/* Totally paranoid: */
memset(netbuf, 0, sizeof(netbuf));
memset(netbuf2, 0, sizeof(netbuf2));
/** Frame re-assembling starts here **/
totalsize = WEB(client)->lefttoparselen + *length;
netbuf = safe_alloc(totalsize+1);
if (WEB(client)->lefttoparse)
{
strlcpy(netbuf, WEB(client)->lefttoparse, sizeof(netbuf));
nprefix = strlen(netbuf);
memcpy(netbuf, WEB(client)->lefttoparse, WEB(client)->lefttoparselen);
memcpy(netbuf + WEB(client)->lefttoparselen, readbuf, *length);
} else {
memcpy(netbuf, readbuf, *length);
}
maxcopy = sizeof(netbuf) - nprefix - 1;
/* (Need to do some manual checking here as strlen() can't be safely used
* on readbuf. Same is true for strlncat since it uses strlen().)
*/
n = *length;
if (n > maxcopy)
n = maxcopy;
if (n <= 0)
{
webserver_close_client(client); // Oversized line
return -1;
}
memcpy(netbuf+nprefix, readbuf, n); /* SAFE: see checking above */
totalsize = n + nprefix;
netbuf[totalsize] = '\0';
memcpy(netbuf2, netbuf, totalsize+1); // copy, including the "always present \0 at the end just in case we use strstr etc".
safe_free(WEB(client)->lefttoparse);
WEB(client)->lefttoparselen = 0;
// remember to always safe_free(netbuf); below BEFORE RETURNING !!!
/** Now step through the lines.. **/
for (r = webserver_handshake_helper(netbuf, strlen(netbuf), &key, &value, &lastloc, &end_of_request);
for (r = webserver_handshake_helper(netbuf, totalsize, &key, &value, &lastloc, &end_of_request);
r;
r = webserver_handshake_helper(NULL, 0, &key, &value, &lastloc, &end_of_request))
{
@@ -427,6 +410,7 @@ int webserver_handle_request_header(Client *client, const char *readbuf, int *le
if (!WEB(client)->uri)
{
webserver_send_response(client, 400, "Malformed HTTP request");
safe_free(netbuf);
return -1;
}
@@ -434,14 +418,21 @@ int webserver_handle_request_header(Client *client, const char *readbuf, int *le
parse_proxy_header(client);
n = WEBSERVER(client)->handle_request(client, WEB(client));
if ((n <= 0) || IsDead(client))
{
safe_free(netbuf);
return n; /* byebye */
}
/* There could be data directly after the request header (eg for
* a POST or PUT), check for it here so it isn't lost.
*/
nextframe = find_end_of_request(netbuf2, totalsize, &remaining_bytes);
nextframe = find_end_of_request(netbuf, totalsize, &remaining_bytes);
if (nextframe)
{
return WEBSERVER(client)->handle_body(client, WEB(client), nextframe, remaining_bytes);
safe_free(netbuf);
}
safe_free(netbuf);
return 0;
}
@@ -450,6 +441,7 @@ int webserver_handle_request_header(Client *client, const char *readbuf, int *le
/* Last line was cut somewhere, save it for next round. */
safe_strdup(WEB(client)->lefttoparse, lastloc);
}
safe_free(netbuf);
return 0; /* don't let UnrealIRCd process this */
}