From 9f40e8f91ec6475308c265ea37b25033f616ce48 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 30 May 2015 18:25:39 +0200 Subject: [PATCH] add support for enforcing HTTPS Signed-off-by: Jo-Philipp Wich --- client.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ listen.c | 19 +++++++++++++++++++ main.c | 8 +++++++- uhttpd.h | 3 +++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/client.c b/client.c index 85d4625..3dbeb6d 100644 --- a/client.c +++ b/client.c @@ -230,6 +230,52 @@ static bool rfc1918_filter_check(struct client *cl) return false; } +static bool tls_redirect_check(struct client *cl) +{ + int rem, port; + struct blob_attr *cur; + char *ptr, *url = NULL, *host = NULL; + + if (cl->tls || !conf.tls_redirect) + return true; + + if ((port = uh_first_tls_port(cl->srv_addr.family)) == -1) + return true; + + blob_for_each_attr(cur, cl->hdr.head, rem) { + if (!strcmp(blobmsg_name(cur), "host")) + host = blobmsg_get_string(cur); + + if (!strcmp(blobmsg_name(cur), "URL")) + url = blobmsg_get_string(cur); + + if (url && host) + break; + } + + if (!url || !host) + return true; + + if ((ptr = strchr(host, ']')) != NULL) + *(ptr+1) = 0; + else if ((ptr = strchr(host, ':')) != NULL) + *ptr = 0; + + cl->request.respond_chunked = false; + cl->request.connection_close = true; + + uh_http_header(cl, 302, "Found"); + + if (port != 443) + ustream_printf(cl->us, "Location: https://%s:%d%s\r\n\r\n", host, port, url); + else + ustream_printf(cl->us, "Location: https://%s%s\r\n\r\n", host, url); + + uh_request_done(cl); + + return false; +} + static void client_header_complete(struct client *cl) { struct http_request *r = &cl->request; @@ -237,6 +283,9 @@ static void client_header_complete(struct client *cl) if (!rfc1918_filter_check(cl)) return; + if (!tls_redirect_check(cl)) + return; + if (r->expect_cont) ustream_printf(cl->us, "HTTP/1.1 100 Continue\r\n\r\n"); diff --git a/listen.c b/listen.c index adf8b16..92ca680 100644 --- a/listen.c +++ b/listen.c @@ -187,6 +187,7 @@ int uh_socket_bind(const char *host, const char *port, bool tls) l->fd.fd = sock; l->tls = tls; + l->addr = *(struct sockaddr_in6 *)p->ai_addr; list_add_tail(&l->list, &listeners); bound++; @@ -201,3 +202,21 @@ error: return bound; } + +int uh_first_tls_port(int family) +{ + struct listener *l; + int tls_port = -1; + + list_for_each_entry(l, &listeners, list) { + if (!l->tls || l->addr.sin6_family != family) + continue; + + if (tls_port != -1 && ntohs(l->addr.sin6_port) != 443) + continue; + + tls_port = ntohs(l->addr.sin6_port); + } + + return tls_port; +} diff --git a/main.c b/main.c index fba5f80..ed47486 100644 --- a/main.c +++ b/main.c @@ -134,6 +134,7 @@ static int usage(const char *name) " -s [addr:]port Like -p but provide HTTPS on this port\n" " -C file ASN.1 server certificate file\n" " -K file ASN.1 server private key file\n" + " -q Redirect all HTTP requests to HTTPS\n" #endif " -h directory Specify the document root, default is '.'\n" " -E string Use given virtual URL as 404 error handler\n" @@ -227,7 +228,7 @@ int main(int argc, char **argv) init_defaults_pre(); signal(SIGPIPE, SIG_IGN); - while ((ch = getopt(argc, argv, "afSDRXC:K:E:I:p:s:h:c:l:L:d:r:m:n:N:x:i:t:k:T:A:u:U:")) != -1) { + while ((ch = getopt(argc, argv, "afqSDRXC:K:E:I:p:s:h:c:l:L:d:r:m:n:N:x:i:t:k:T:A:u:U:")) != -1) { switch(ch) { #ifdef HAVE_TLS case 'C': @@ -238,12 +239,17 @@ int main(int argc, char **argv) tls_key = optarg; break; + case 'q': + conf.tls_redirect = 1; + break; + case 's': n_tls++; /* fall through */ #else case 'C': case 'K': + case 'q': case 's': fprintf(stderr, "uhttpd: TLS support not compiled, " "ignoring -%c\n", ch); diff --git a/uhttpd.h b/uhttpd.h index 42385a6..fbcb1ed 100644 --- a/uhttpd.h +++ b/uhttpd.h @@ -62,6 +62,7 @@ struct config { int no_dirlists; int network_timeout; int rfc1918_filter; + int tls_redirect; int tcp_keepalive; int max_script_requests; int max_connections; @@ -267,6 +268,8 @@ void uh_unblock_listeners(void); void uh_setup_listeners(void); int uh_socket_bind(const char *host, const char *port, bool tls); +int uh_first_tls_port(int family); + bool uh_use_chunked(struct client *cl); void uh_chunk_write(struct client *cl, const void *data, int len); void uh_chunk_vprintf(struct client *cl, const char *format, va_list arg); -- 2.11.0