mirror of
https://github.com/nmap/nmap.git
synced 2026-08-04 14:49:29 +00:00
Tighten HTTP parsing
* HTTP version strictly digits * Status code strictly 3-digit number
This commit is contained in:
parent
18b3db3d67
commit
5001a59a87
1 changed files with 42 additions and 11 deletions
53
ncat/http.c
53
ncat/http.c
|
|
@ -503,8 +503,7 @@ static const char *skip_crlf(const char *s)
|
|||
else if (*s == '\r' && *(s + 1) == '\n')
|
||||
return s + 2;
|
||||
|
||||
ncat_assert(0);
|
||||
return NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
static int field_name_equal(const char *a, const char *b)
|
||||
|
|
@ -627,7 +626,7 @@ static const char *read_quoted_string(const char *s, char **quoted_string)
|
|||
/* Get a block of normal characters. */
|
||||
while (*t != '"' && *t != '\\') {
|
||||
/* This is qdtext, which is TEXT except for CTL. */
|
||||
if (is_ctl_char(*t)) {
|
||||
if (is_ctl_char(*t) && !is_space_char(*t)) {
|
||||
FREE_AND_NULL(free, buf);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1082,9 +1081,11 @@ int http_read_request_line(struct socket_buffer *buf, char **line)
|
|||
parse error. */
|
||||
static const char *parse_http_version(const char *s, enum http_version *version)
|
||||
{
|
||||
/* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
|
||||
static const char PREFIX[] = "HTTP/";
|
||||
const size_t prefixlen = sizeof(PREFIX) - 1;
|
||||
const char *p, *q;
|
||||
int dot = 0;
|
||||
|
||||
*version = HTTP_UNKNOWN;
|
||||
|
||||
|
|
@ -1093,12 +1094,16 @@ static const char *parse_http_version(const char *s, enum http_version *version)
|
|||
return s;
|
||||
p += sizeof(PREFIX) - 1;
|
||||
|
||||
q = strpbrk(p, " \t\r\n");
|
||||
if (!q)
|
||||
q = p + strlen(p);
|
||||
|
||||
/* Any version is accepted and not a parse error,
|
||||
* but only 1.0 and 1.1 are understood. */
|
||||
q = p;
|
||||
while (*q && (isdigit(*q) || (*q == '.' && dot++ == 0))) {
|
||||
q++;
|
||||
}
|
||||
if (*q != '\0' && *q != ' ' && !is_crlf(q)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
if ((q - p) != 3)
|
||||
return q;
|
||||
if (0 == strncmp(p, "1.0", 3))
|
||||
|
|
@ -1159,7 +1164,7 @@ int http_parse_request_line(const char *line, struct http_request *request)
|
|||
p = q;
|
||||
while (*p == ' ')
|
||||
p++;
|
||||
if (*p == '\0') {
|
||||
if (*p == '\0' || is_crlf(p)) {
|
||||
/* No HTTP/X.X version number indicates version 0.9. */
|
||||
request->version = HTTP_09;
|
||||
} else {
|
||||
|
|
@ -1194,6 +1199,28 @@ int http_read_status_line(struct socket_buffer *buf, char **line)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int parse_code(const char *p, const char **tail) {
|
||||
int code = 0;
|
||||
#define CODE_DIGIT(_Place) do { \
|
||||
if (!isdigit((int) (unsigned char) *p)) { \
|
||||
*tail = p; \
|
||||
return -1; \
|
||||
} \
|
||||
code += (*p - 0x30) * _Place; \
|
||||
p++; \
|
||||
} while (0)
|
||||
|
||||
CODE_DIGIT(100);
|
||||
CODE_DIGIT(10);
|
||||
CODE_DIGIT(1);
|
||||
|
||||
*tail = p;
|
||||
if (*p != '\0' && !isspace((int) (unsigned char) *p)) {
|
||||
return -1;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
/* Returns 0 on success and nonzero on failure. */
|
||||
int http_parse_status_line(const char *line, struct http_response *response)
|
||||
{
|
||||
|
|
@ -1210,8 +1237,8 @@ int http_parse_status_line(const char *line, struct http_response *response)
|
|||
|
||||
/* Status code. */
|
||||
errno = 0;
|
||||
response->code = parse_long(p, &q);
|
||||
if (errno != 0 || q == p)
|
||||
response->code = parse_code(p, &q);
|
||||
if (response->code < 0)
|
||||
return -1;
|
||||
p = q;
|
||||
|
||||
|
|
@ -1219,8 +1246,12 @@ int http_parse_status_line(const char *line, struct http_response *response)
|
|||
while (*p == ' ')
|
||||
p++;
|
||||
q = p;
|
||||
while (!is_crlf(q))
|
||||
while (*q != '\0' && !is_crlf(q)) {
|
||||
if (is_ctl_char(*q) && !is_space_char(*q)) {
|
||||
return -1;
|
||||
}
|
||||
q++;
|
||||
}
|
||||
/* We expect that the CRLF ends the string. */
|
||||
if (*skip_crlf(q) != '\0')
|
||||
return -1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue