diff --git a/src/cinderproxy.c b/src/cinderproxy.c index 3a29e46..33ddfdf 100644 --- a/src/cinderproxy.c +++ b/src/cinderproxy.c @@ -23,6 +23,13 @@ #define QUEUE_CAPACITY 256 #define BODY_CHUNK 16384 +static int headers_complete(const char *buf, size_t len) { + for (size_t i = 0; i + 3 < len; i++) { + if (memcmp(buf + i, "\r\n\r\n", 4) == 0) return 1; + } + return 0; +} + typedef struct { char ip[64]; time_t start; int count; int used; } rate_entry_t; typedef struct { rate_entry_t e[RATE_SLOTS]; pthread_mutex_t lock; int limit; int window; } limiter_t; typedef struct backend_health backend_health_t; @@ -284,9 +291,9 @@ static void handle_client(client_t *c) { if (n <= 0) { free(buf); goto done; } used += (size_t)n; buf[used] = '\0'; - if (strstr(buf, "\r\n\r\n")) break; + if (headers_complete(buf, used)) break; } - if (!strstr(buf, "\r\n\r\n")) { + if (!headers_complete(buf, used)) { error_resp(fd, tls, 431, "Request Header Fields Too Large"); free(buf); goto done; diff --git a/src/http.c b/src/http.c index 82b2cbd..4ead51b 100644 --- a/src/http.c +++ b/src/http.c @@ -71,6 +71,7 @@ http_parse_result_t http_parse_request(const char *buf,size_t len,size_t max_hea if(len>max_header_bytes) return HTTP_PARSE_TOO_LARGE; memset(out,0,sizeof(*out)); out->content_length=0; const char *end=buf+len,*line=find_crlf(buf,end); if(!line) return HTTP_PARSE_BAD_REQUEST; + if(memchr(buf,'\0',(size_t)(line-buf))) return HTTP_PARSE_BAD_REQUEST; const char *sp1=memchr(buf,' ',(size_t)(line-buf)); if(!sp1||sp1==buf) return HTTP_PARSE_BAD_REQUEST; const char *sp2=memchr(sp1+1,' ',(size_t)(line-(sp1+1))); if(!sp2) return HTTP_PARSE_BAD_REQUEST; if(memchr(sp2+1,' ',(size_t)(line-(sp2+1)))) return HTTP_PARSE_BAD_REQUEST; @@ -81,6 +82,7 @@ http_parse_result_t http_parse_request(const char *buf,size_t len,size_t max_hea int host_count=0,cl_seen=0; const char *p=line+2; while(pversion,"HTTP/1.1")&&host_count!=1) return HTTP_PARSE_BAD_REQUEST; return HTTP_PARSE_OK; } if(out->header_count>=HTTP_MAX_HEADERS) return HTTP_PARSE_TOO_LARGE; const char *colon=memchr(p,':',(size_t)(eol-p)); if(!colon||colon==p) return HTTP_PARSE_BAD_REQUEST; diff --git a/tests/test_http.c b/tests/test_http.c index f914cae..e44e23e 100644 --- a/tests/test_http.c +++ b/tests/test_http.c @@ -5,6 +5,27 @@ static http_parse_result_t parse(const char *s){ http_request_t r; size_t e=0; return http_parse_request(s,strlen(s),16384,&r,&e); } int main(void){ + { + const char *requests[]={ + "GET\0X / HTTP/1.1\r\nHost: localhost\r\n\r\n", + "GET /ok\0hidden HTTP/1.1\r\nHost: localhost\r\n\r\n", + "GET / HTTP/1.1\0hidden\r\nHost: localhost\r\n\r\n", + "GET / HTTP/1.1\r\nHost\0hidden: localhost\r\n\r\n", + "GET / HTTP/1.1\r\nHost: localhost\0hidden\r\n\r\n" + }; + const size_t lengths[]={ + sizeof("GET\0X / HTTP/1.1\r\nHost: localhost\r\n\r\n")-1, + sizeof("GET /ok\0hidden HTTP/1.1\r\nHost: localhost\r\n\r\n")-1, + sizeof("GET / HTTP/1.1\0hidden\r\nHost: localhost\r\n\r\n")-1, + sizeof("GET / HTTP/1.1\r\nHost\0hidden: localhost\r\n\r\n")-1, + sizeof("GET / HTTP/1.1\r\nHost: localhost\0hidden\r\n\r\n")-1 + }; + http_request_t r; size_t e=0; + for(size_t i=0;i