2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 22:45:39 +00:00

Rewrite isc_httpd using picohttpparser and isc_url_parse

Rewrite the isc_httpd to be more robust.

1. Replace the hand-crafted HTTP request parser with picohttpparser for
   parsing the whole HTTP/1.0 and HTTP/1.1 requests.  Limit the number
   of allowed headers to 10 (arbitrary number).

2. Replace the hand-crafted URL parser with isc_url_parse for parsing
   the URL from the HTTP request.

3. Increase the receive buffer to match the isc_netmgr buffers, so we
   can at least receive two full isc_nm_read()s.  This makes the
   truncation processing much simpler.

4. Process the received buffer from single isc_nm_read() in a single
   loop and schedule the sends to be independent of each other.

The first two changes makes the code simpler and rely on already
existing libraries that we already had (isc_url based on nodejs) or are
used elsewhere (picohttpparser).

The second two changes remove the artificial "truncation" limit on
parsing multiple request.  Now only a request that has too many
headers (currently 10) or is too big (so, the receive buffer fills up
without reaching end of the request) will end the connection.

We can be benevolent here with the limites, because the statschannel
channel is by definition private and access must be allowed only to
administrators of the server.  There are no timers, no rate-limiting, no
upper limit on the number of requests that can be served, etc.
This commit is contained in:
Ondřej Surý
2022-10-06 12:56:25 +02:00
committed by Ondřej Surý
parent 3a8884f024
commit beecde7120
5 changed files with 578 additions and 802 deletions

View File

@@ -2376,20 +2376,14 @@ wrap_xmlfree(isc_buffer_t *buffer, void *arg) {
}
static isc_result_t
render_xml(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg, const char **mimetype,
isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) {
render_xml(uint32_t flags, void *arg, unsigned int *retcode,
const char **retmsg, const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
unsigned char *msg = NULL;
int msglen;
named_server_t *server = arg;
isc_result_t result;
UNUSED(url);
UNUSED(urlinfo);
UNUSED(headers);
UNUSED(querystring);
result = generatexml(server, flags, &msglen, &msg);
if (result == ISC_R_SUCCESS) {
@@ -2410,91 +2404,91 @@ render_xml(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
}
static isc_result_t
render_xml_all(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_xml_all(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb,
void **freecb_args) {
return (render_xml(STATS_XML_ALL, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_xml(STATS_XML_ALL, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_xml_status(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_xml_status(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_xml(STATS_XML_STATUS, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_xml(STATS_XML_STATUS, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_xml_server(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_xml_server(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_xml(STATS_XML_SERVER, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_xml(STATS_XML_SERVER, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_xml_zones(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_xml_zones(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_xml(STATS_XML_ZONES, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_xml(STATS_XML_ZONES, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_xml_net(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_xml_net(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb,
void **freecb_args) {
return (render_xml(STATS_XML_NET, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_xml(STATS_XML_NET, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_xml_tasks(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_xml_tasks(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_xml(STATS_XML_TASKS, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_xml(STATS_XML_TASKS, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_xml_mem(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_xml_mem(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb,
void **freecb_args) {
return (render_xml(STATS_XML_MEM, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_xml(STATS_XML_MEM, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_xml_traffic(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_xml_traffic(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_xml(STATS_XML_TRAFFIC, url, urlinfo, querystring,
headers, arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_xml(STATS_XML_TRAFFIC, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
#endif /* HAVE_LIBXML2 */
@@ -3320,10 +3314,9 @@ cleanup:
}
static isc_result_t
render_json(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg, const char **mimetype,
isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) {
render_json(uint32_t flags, void *arg, unsigned int *retcode,
const char **retmsg, const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
isc_result_t result;
json_object *bindstats = NULL;
named_server_t *server = arg;
@@ -3331,11 +3324,6 @@ render_json(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
size_t msglen = 0;
char *p;
UNUSED(url);
UNUSED(urlinfo);
UNUSED(headers);
UNUSED(querystring);
result = generatejson(server, &msglen, &msg, &bindstats, flags);
if (result == ISC_R_SUCCESS) {
*retcode = 200;
@@ -3356,156 +3344,139 @@ render_json(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
}
static isc_result_t
render_json_all(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_json_all(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_json(STATS_JSON_ALL, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_json(STATS_JSON_ALL, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_status(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_json_status(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_json(STATS_JSON_STATUS, url, urlinfo, querystring,
headers, arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_json(STATS_JSON_STATUS, arg, retcode, retmsg, mimetype,
b, freecb, freecb_args));
}
static isc_result_t
render_json_server(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_json_server(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_json(STATS_JSON_SERVER, url, urlinfo, querystring,
headers, arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_json(STATS_JSON_SERVER, arg, retcode, retmsg, mimetype,
b, freecb, freecb_args));
}
static isc_result_t
render_json_zones(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_json_zones(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_json(STATS_JSON_ZONES, url, urlinfo, querystring,
headers, arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_json(STATS_JSON_ZONES, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_mem(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_json_mem(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_json(STATS_JSON_MEM, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_json(STATS_JSON_MEM, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_tasks(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_json_tasks(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_json(STATS_JSON_TASKS, url, urlinfo, querystring,
headers, arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_json(STATS_JSON_TASKS, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_net(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_json_net(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_json(STATS_JSON_NET, url, urlinfo, querystring, headers,
arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_json(STATS_JSON_NET, arg, retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_traffic(const char *url, isc_httpdurl_t *urlinfo,
const char *querystring, const char *headers, void *arg,
unsigned int *retcode, const char **retmsg,
render_json_traffic(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
return (render_json(STATS_JSON_TRAFFIC, url, urlinfo, querystring,
headers, arg, retcode, retmsg, mimetype, b, freecb,
freecb_args));
UNUSED(httpd);
UNUSED(urlinfo);
return (render_json(STATS_JSON_TRAFFIC, arg, retcode, retmsg, mimetype,
b, freecb, freecb_args));
}
#endif /* HAVE_JSON_C */
static isc_result_t
render_xsl(const char *url, isc_httpdurl_t *urlinfo, const char *querystring,
const char *headers, void *args, unsigned int *retcode,
const char **retmsg, const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args) {
render_xsl(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, void *args,
unsigned int *retcode, const char **retmsg, const char **mimetype,
isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) {
isc_result_t result;
char *_headers = NULL;
char *p;
char *p = NULL;
UNUSED(url);
UNUSED(querystring);
UNUSED(httpd);
UNUSED(args);
*freecb = NULL;
*freecb_args = NULL;
*mimetype = "text/xslt+xml";
if (urlinfo->isstatic) {
isc_time_t when;
char *line, *saveptr;
const char *if_modified_since = "If-Modified-Since: ";
_headers = strdup(headers);
if (isc_httpdurl_isstatic(urlinfo)) {
time_t t1, t2;
const isc_time_t *when;
const isc_time_t *loadtime;
if (_headers == NULL) {
when = isc_httpd_if_modified_since(httpd);
if (isc_time_isepoch(when)) {
goto send;
}
saveptr = NULL;
for (line = strtok_r(_headers, "\n", &saveptr); line;
line = strtok_r(NULL, "\n", &saveptr))
{
if (strncasecmp(line, if_modified_since,
strlen(if_modified_since)) == 0) {
time_t t1, t2;
line += strlen(if_modified_since);
result = isc_time_parsehttptimestamp(line,
&when);
if (result != ISC_R_SUCCESS) {
goto send;
}
result = isc_time_secondsastimet(&when, &t1);
if (result != ISC_R_SUCCESS) {
goto send;
}
result = isc_time_secondsastimet(
&urlinfo->loadtime, &t2);
if (result != ISC_R_SUCCESS) {
goto send;
}
if (t1 < t2) {
goto send;
}
*retcode = 304;
*retmsg = "Not modified";
goto end;
}
result = isc_time_secondsastimet(when, &t1);
if (result != ISC_R_SUCCESS) {
goto send;
}
loadtime = isc_httpdurl_loadtime(urlinfo);
result = isc_time_secondsastimet(loadtime, &t2);
if (result != ISC_R_SUCCESS) {
goto send;
}
if (t1 < t2) {
goto send;
}
*retcode = 304;
*retmsg = "Not modified";
goto end;
}
send:
@@ -3515,7 +3486,6 @@ send:
isc_buffer_reinit(b, p, strlen(xslmsg));
isc_buffer_add(b, strlen(xslmsg));
end:
free(_headers);
return (ISC_R_SUCCESS);
}

File diff suppressed because it is too large Load Diff

View File

@@ -23,28 +23,20 @@
#include <isc/task.h>
#include <isc/time.h>
#include <isc/types.h>
/*%
* HTTP urls. These are the URLs we manage, and the function to call to
* provide the data for it. We pass in the base url (so the same function
* can handle multiple requests), and a structure to fill in to return a
* result to the client. We also pass in a pointer to be filled in for
* the data cleanup function.
*/
struct isc_httpdurl {
char *url;
isc_httpdaction_t *action;
void *action_arg;
bool isstatic;
isc_time_t loadtime;
ISC_LINK(isc_httpdurl_t) link;
};
#include <isc/url.h>
#define HTTPD_EVENTCLASS ISC_EVENTCLASS(4300)
#define HTTPD_SHUTDOWN (HTTPD_EVENTCLASS + 0x0001)
#define ISC_HTTPDMGR_SHUTTINGDOWN 0x00000001
typedef isc_result_t(isc_httpdaction_t)(
const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, void *arg,
unsigned int *retcode, const char **retmsg, const char **mimetype,
isc_buffer_t *body, isc_httpdfree_t **freecb, void **freecb_args);
typedef bool(isc_httpdclientok_t)(const isc_sockaddr_t *, void *);
isc_result_t
isc_httpdmgr_create(isc_nm_t *nm, isc_mem_t *mctx, isc_sockaddr_t *addr,
isc_httpdclientok_t *client_ok,
@@ -60,3 +52,12 @@ isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url, bool isstatic,
void
isc_httpd_setfinishhook(void (*fn)(void));
bool
isc_httpdurl_isstatic(const isc_httpdurl_t *url);
const isc_time_t *
isc_httpdurl_loadtime(const isc_httpdurl_t *url);
const isc_time_t *
isc_httpd_if_modified_since(const isc_httpd_t *httpd);

View File

@@ -96,14 +96,6 @@ typedef struct isc_nm_http_endpoints isc_nm_http_endpoints_t;
typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
/* The following cannot be listed alphabetically due to forward reference */
typedef isc_result_t(isc_httpdaction_t)(
const char *url, isc_httpdurl_t *urlinfo, const char *querystring,
const char *headers, void *arg, unsigned int *retcode,
const char **retmsg, const char **mimetype, isc_buffer_t *body,
isc_httpdfree_t **freecb, void **freecb_args);
typedef bool(isc_httpdclientok_t)(const isc_sockaddr_t *, void *);
/*% Resource */
typedef enum {
isc_resource_coresize = 1,

View File

@@ -36,6 +36,7 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <isc/result.h>