X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuhttpd.git;a=blobdiff_plain;f=client.c;h=4d8b17b0d1b9279040daefc1a5581e8a047b1661;hp=a76d11e61ddd2eb4ae52c1b0acf3befaa69da5b8;hb=0a6fa62baa6d21455485bc6669f4e5f3b6608487;hpb=e4c4aca65fa95b9530d1fb8d2d9e2ac9acb32770 diff --git a/client.c b/client.c index a76d11e..4d8b17b 100644 --- a/client.c +++ b/client.c @@ -134,6 +134,7 @@ static int client_parse_request(struct client *cl, char *data) { struct http_request *req = &cl->request; char *type, *path, *version; + int h_method, h_version; type = strtok(data, " "); path = strtok(NULL, " "); @@ -141,14 +142,18 @@ static int client_parse_request(struct client *cl, char *data) if (!type || !path || !version) return CLIENT_STATE_DONE; + memset(&cl->request, 0, sizeof(cl->request)); req->url = path; - req->method = find_idx(http_methods, ARRAY_SIZE(http_methods), type); - if (req->method < 0) - return CLIENT_STATE_DONE; - req->version = find_idx(http_versions, ARRAY_SIZE(http_versions), version); - if (cl->request.version < 0) + h_method = find_idx(http_methods, ARRAY_SIZE(http_methods), type); + h_version = find_idx(http_versions, ARRAY_SIZE(http_versions), version); + if (h_method < 0 || h_version < 0) { + req->version = UH_HTTP_VER_1_0; return CLIENT_STATE_DONE; + } + + req->method = h_method; + req->version = h_version; return CLIENT_STATE_HEADER; } @@ -172,8 +177,28 @@ static bool client_init_cb(struct client *cl, char *buf, int len) return true; } +static bool rfc1918_filter_check(struct client *cl) +{ + if (!conf.rfc1918_filter) + return true; + + if (!uh_addr_rfc1918(&cl->peer_addr) || uh_addr_rfc1918(&cl->srv_addr)) + return true; + + uh_client_error(cl, 403, "Forbidden", + "Rejected request from RFC1918 IP " + "to public server address"); + return false; +} + static void client_header_complete(struct client *cl) { + if (!rfc1918_filter_check(cl)) + return; + + if (cl->request.expect_cont) + ustream_printf(cl->us, "HTTP/1.1 100 Continue\r\n\r\n"); + uh_handle_request(cl); } @@ -199,6 +224,16 @@ static void client_parse_header(struct client *cl, char *data) if (isupper(*name)) *name = tolower(*name); + if (!strcasecmp(data, "Expect")) { + if (!strcasecmp(val, "100-continue")) + cl->request.expect_cont = true; + else { + uh_header_error(cl, 412, "Precondition Failed"); + return; + } + } + + blobmsg_add_string(&cl->hdr, data, val); cl->state = CLIENT_STATE_HEADER; @@ -300,6 +335,21 @@ static void client_notify_state(struct ustream *s) return client_close(cl); } +static void set_addr(struct uh_addr *addr, void *src) +{ + struct sockaddr_in *sin = src; + struct sockaddr_in6 *sin6 = src; + + addr->family = sin->sin_family; + if (addr->family == AF_INET) { + addr->port = ntohs(sin->sin_port); + memcpy(&addr->in, &sin->sin_addr, sizeof(addr->in)); + } else { + addr->port = ntohs(sin6->sin6_port); + memcpy(&addr->in6, &sin6->sin6_addr, sizeof(addr->in6)); + } +} + void uh_accept_client(int fd) { static struct client *next_client; @@ -307,19 +357,22 @@ void uh_accept_client(int fd) unsigned int sl; int sfd; static int client_id = 0; + struct sockaddr_in6 addr; if (!next_client) next_client = calloc(1, sizeof(*next_client)); cl = next_client; - sl = sizeof(cl->peeraddr); - sfd = accept(fd, (struct sockaddr *) &cl->peeraddr, &sl); + sl = sizeof(addr); + sfd = accept(fd, (struct sockaddr *) &addr, &sl); if (sfd < 0) return; - sl = sizeof(cl->servaddr); - getsockname(fd, (struct sockaddr *) &cl->servaddr, &sl); + set_addr(&cl->peer_addr, &addr); + sl = sizeof(addr); + getsockname(fd, (struct sockaddr *) &addr, &sl); + set_addr(&cl->srv_addr, &addr); cl->us = &cl->sfd.stream; cl->us->string_data = true; cl->us->notify_read = client_ustream_read_cb;