From 25115a694cae135889bbcf5f8ecfe9ecd67b28f8 Mon Sep 17 00:00:00 2001 From: Daniel O'Connell <doconn1701@gmail.com> Date: Thu, 29 May 2014 17:04:13 +0100 Subject: [PATCH] proxy support changes --- mongoose.c | 154 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 59 deletions(-) diff --git a/mongoose.c b/mongoose.c index f4e1642dd..9ff2b54ae 100644 --- a/mongoose.c +++ b/mongoose.c @@ -19,7 +19,6 @@ #include "net_skeleton.h" #else // net_skeleton start - // Copyright (c) 2014 Cesanta Software Limited // All rights reserved // @@ -39,7 +38,7 @@ #ifndef NS_SKELETON_HEADER_INCLUDED #define NS_SKELETON_HEADER_INCLUDED -#define NS_SKELETON_VERSION "1.0" +#define NS_SKELETON_VERSION "1.1" #undef UNICODE // Use ANSI WinAPI functions #undef _UNICODE // Use multibyte encoding on Windows @@ -72,7 +71,9 @@ #include <signal.h> #ifdef _WIN32 +#ifdef _MSC_VER #pragma comment(lib, "ws2_32.lib") // Linking with winsock library +#endif #include <windows.h> #include <process.h> #ifndef EINPROGRESS @@ -91,6 +92,7 @@ #endif // MINGW #defines va_copy #define snprintf _snprintf #define vsnprintf _vsnprintf +#define sleep(x) Sleep((x) * 1000) #define to64(x) _atoi64(x) typedef int socklen_t; typedef unsigned char uint8_t; @@ -883,6 +885,7 @@ int ns_server_poll(struct ns_server *server, int milli) { for (conn = server->active_connections; conn != NULL; conn = tmp_conn) { tmp_conn = conn->next; + //DBG(("%p LOOP %p", conn, conn->ssl)); if (FD_ISSET(conn->sock, &read_set)) { conn->last_io_time = current_time; ns_read_from_socket(conn); @@ -1052,7 +1055,6 @@ void ns_server_free(struct ns_server *s) { s->ssl_ctx = s->client_ssl_ctx = NULL; #endif } - // net_skeleton end #endif // NOEMBED_NET_SKELETON @@ -1064,7 +1066,18 @@ void ns_server_free(struct ns_server *s) { #ifndef S_ISDIR #define S_ISDIR(x) ((x) & _S_IFDIR) #endif -#define sleep(x) Sleep((x) * 1000) +#ifdef stat +#undef stat +#endif +#ifdef lseek +#undef lseek +#endif +#ifdef popen +#undef popen +#endif +#ifdef pclose +#undef pclose +#endif #define stat(x, y) mg_stat((x), (y)) #define fopen(x, y) mg_fopen((x), (y)) #define open(x, y) mg_open((x), (y)) @@ -1072,7 +1085,6 @@ void ns_server_free(struct ns_server *s) { #define popen(x, y) _popen((x), (y)) #define pclose(x) _pclose(x) #define mkdir(x, y) _mkdir(x) -#define to64(x) _atoi64(x) #ifndef __func__ #define STRX(x) #x #define STR(x) STRX(x) @@ -1624,7 +1636,7 @@ static int wait_until_ready(sock_t sock, int for_read) { } static void *push_to_stdin(void *arg) { - struct threadparam *tp = arg; + struct threadparam *tp = (struct threadparam *)arg; int n, sent, stop = 0; DWORD k; char buf[IOBUF_SIZE]; @@ -1644,7 +1656,7 @@ static void *push_to_stdin(void *arg) { } static void *pull_from_stdout(void *arg) { - struct threadparam *tp = arg; + struct threadparam *tp = (struct threadparam *)arg; int k, stop = 0; DWORD n, sent; char buf[IOBUF_SIZE]; @@ -1666,7 +1678,7 @@ static void *pull_from_stdout(void *arg) { static void spawn_stdio_thread(sock_t sock, HANDLE hPipe, void *(*func)(void *)) { - struct threadparam *tp = malloc(sizeof(*tp)); + struct threadparam *tp = (struct threadparam *)malloc(sizeof(*tp)); if (tp != NULL) { tp->s = sock; tp->hPipe = hPipe; @@ -2410,7 +2422,7 @@ void mg_printf_data(struct mg_connection *c, const char *fmt, ...) { len = ns_avprintf(&buf, sizeof(mem), fmt, ap); va_end(ap); - if (len > 0) { + if (len >= 0) { write_chunk((struct connection *) conn, buf, len); } if (buf != mem && buf != NULL) { @@ -4004,13 +4016,37 @@ static int parse_url(const char *url, char *proto, size_t plen, return 0; } +static void proxy_request(struct ns_connection *pc, struct mg_connection *c) { + int i, sent_close_header = 0; + + ns_printf(pc, "%s %s HTTP/%s\r\n", c->request_method, c->uri, + c->http_version); + for (i = 0; i < c->num_headers; i++) { + if (mg_strcasecmp(c->http_headers[i].name, "Connection") == 0) { + // Force connection close, cause we don't parse proxy replies + // therefore we don't know message boundaries + //ns_printf(pc, "%s: %s\r\n", "Connection", "close"); + sent_close_header = 1; + //} else { + } + ns_printf(pc, "%s: %s\r\n", c->http_headers[i].name, + c->http_headers[i].value); + } + if (!sent_close_header) { + ns_printf(pc, "%s: %s\r\n", "Connection", "close"); + } + ns_printf(pc, "%s", "\r\n"); + ns_send(pc, c->content, c->content_len); + +} + static void proxify_connection(struct connection *conn) { char proto[10], host[500], cert[500]; - unsigned short port; + unsigned short port = 80; struct mg_connection *c = &conn->mg_conn; struct ns_server *server = &conn->server->ns_server; struct ns_connection *pc; - int i, n, sent_close_header = 0; + int n, use_ssl; proto[0] = host[0] = cert[0] = '\0'; n = parse_url(c->uri, proto, sizeof(proto), host, sizeof(host), &port); @@ -4031,21 +4067,27 @@ static void proxify_connection(struct connection *conn) { } #endif + use_ssl = port != 80 && cert[0] != '\0'; + if (n > 0 && - (pc = ns_connect(server, host, port, cert[0] != '\0', conn)) != NULL) { + (pc = ns_connect(server, host, port, use_ssl, conn)) != NULL) { // Interlink two connections pc->flags |= MG_PROXY_CONN; conn->endpoint_type = EP_PROXY; conn->endpoint.nc = pc; - DBG(("%p [%s] -> %p", conn, c->uri, pc)); + DBG(("%p [%s] -> %p %d", conn, c->uri, pc, use_ssl)); if (strcmp(c->request_method, "CONNECT") == 0) { // For CONNECT request, reply with 200 OK. Tunnel is established. mg_printf(c, "%s", "HTTP/1.1 200 OK\r\n\r\n"); + conn->request_len = 0; + free(conn->request); + conn->request = NULL; #ifdef NS_ENABLE_SSL - if (cert[0] != '\0') { + if (use_ssl) { SSL_CTX *ctx; + DBG(("%s", "Triggering MITM mode: terminating SSL connection")); SSL_library_init(); ctx = SSL_CTX_new(SSLv23_server_method()); @@ -4056,10 +4098,14 @@ static void proxify_connection(struct connection *conn) { SSL_CTX_use_PrivateKey_file(ctx, cert, 1); SSL_CTX_use_certificate_chain_file(ctx, cert); - // When clear-text reply is pushed to client, - // we will switch to SSL mode. - if ((c->connection_param = SSL_new(ctx)) != NULL) { - SSL_set_fd((SSL *) c->connection_param, conn->ns_conn->sock); + // When clear-text reply is pushed to client, switch to SSL mode. + n = send(conn->ns_conn->sock, conn->ns_conn->send_iobuf.buf, + conn->ns_conn->send_iobuf.len, 0); + DBG(("%p %lu %d SEND", c, conn->ns_conn->send_iobuf.len, n)); + conn->ns_conn->send_iobuf.len = 0; + if ((conn->ns_conn->ssl = SSL_new(ctx)) != NULL) { + //SSL_set_fd((SSL *) c->connection_param, conn->ns_conn->sock); + SSL_set_fd(conn->ns_conn->ssl, conn->ns_conn->sock); } SSL_CTX_free(ctx); } @@ -4067,24 +4113,8 @@ static void proxify_connection(struct connection *conn) { #endif } else { // For other methods, forward the request to the target host. - ns_printf(pc, "%s %s HTTP/%s\r\n", c->request_method, c->uri + n, - c->http_version); - for (i = 0; i < c->num_headers; i++) { - if (mg_strcasecmp(c->http_headers[i].name, "Connection") == 0) { - // Force connection close, cause we don't parse proxy replies - // therefore we don't know message boundaries - ns_printf(pc, "%s: %s\r\n", "Connection", "close"); - sent_close_header = 1; - } else { - ns_printf(pc, "%s: %s\r\n", c->http_headers[i].name, - c->http_headers[i].value); - } - } - if (!sent_close_header) { - ns_printf(pc, "%s: %s\r\n", "Connection", "close"); - } - ns_printf(pc, "%s", "\r\n"); - ns_send(pc, c->content, c->content_len); + c->uri += n; + proxy_request(pc, c); } } else { conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY; @@ -4253,13 +4283,30 @@ static void try_parse(struct connection *conn) { } } -static void proxy_from_client_to_target_host(struct connection *conn) { - ns_forward(conn->ns_conn, conn->endpoint.nc); +static void do_proxy(struct connection *conn) { + if (conn->request_len == 0) { + DBG(("%p parsing", conn)); + try_parse(conn); + if (conn->request_len > 0 && + call_user(conn, MG_REQUEST) == MG_FALSE) { + proxy_request(conn->endpoint.nc, &conn->mg_conn); + } else if (conn->request_len < 0) { + ns_forward(conn->ns_conn, conn->endpoint.nc); + } + } else { + DBG(("%p forwarding", conn)); + ns_forward(conn->ns_conn, conn->endpoint.nc); + } } static void on_recv_data(struct connection *conn) { struct iobuf *io = &conn->ns_conn->recv_iobuf; + if (conn->endpoint_type == EP_PROXY && conn->endpoint.nc != NULL) { + do_proxy(conn); + return; + } + try_parse(conn); DBG(("%p %d %zu %d", conn, conn->request_len, io->len, conn->ns_conn->flags)); if (conn->request_len < 0 || @@ -4279,9 +4326,6 @@ static void on_recv_data(struct connection *conn) { open_local_endpoint(conn, 0); } - if (conn->endpoint_type == EP_PROXY && conn->endpoint.nc != NULL) { - proxy_from_client_to_target_host(conn); - } #ifndef MONGOOSE_NO_CGI if (conn->endpoint_type == EP_CGI && conn->endpoint.nc != NULL) { ns_forward(conn->ns_conn, conn->endpoint.nc); @@ -4736,18 +4780,18 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) { #ifndef MONGOOSE_NO_FILESYSTEM static void hexdump(struct ns_connection *nc, const char *path, int num_bytes, int is_sent) { - struct connection *mc = (struct connection *) nc->connection_data; const struct iobuf *io = is_sent ? &nc->send_iobuf : &nc->recv_iobuf; FILE *fp; - char *buf; + char *buf, src[60], dst[60]; int buf_size = num_bytes * 5 + 100; if (path != NULL && (fp = fopen(path, "a")) != NULL) { - fprintf(fp, "%lu %p %s:%d %s %s:%d %d\n", (unsigned long) time(NULL), - mc, mc->mg_conn.local_ip, mc->mg_conn.local_port, + ns_sock_to_str(nc->sock, src, sizeof(src), 3); + ns_sock_to_str(nc->sock, dst, sizeof(dst), 7); + fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) time(NULL), + nc->connection_data, src, is_sent == 0 ? "<-" : is_sent == 1 ? "->" : - is_sent == 2 ? "<A" : "C>", - mc->mg_conn.remote_ip, mc->mg_conn.remote_port, num_bytes); + is_sent == 2 ? "<A" : "C>", dst, num_bytes); if (num_bytes > 0 && (buf = (char *) malloc(buf_size)) != NULL) { ns_hexdump(io->buf + (is_sent ? 0 : io->len) - (is_sent ? 0 : num_bytes), num_bytes, buf, buf_size); @@ -4789,8 +4833,10 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) { break; case NS_CONNECT: - set_ips(nc, 1); - set_ips(nc, 0); + if (nc->connection_data != NULL) { + set_ips(nc, 1); + set_ips(nc, 0); + } #ifndef MONGOOSE_NO_FILESYSTEM hexdump(nc, server->config_options[HEXDUMP_FILE], 0, 3); #endif @@ -4825,16 +4871,6 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) { #ifndef MONGOOSE_NO_FILESYSTEM hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 1); #endif - if (conn != NULL && conn->mg_conn.connection_param != NULL && - conn->endpoint_type == EP_PROXY && - nc->send_iobuf.len <= (size_t) * (int * ) p) { - // All clear-text data has been sent to the client, switch to SSL -#ifdef NS_ENABLE_SSL - DBG(("%p %p: setting ssl", conn, conn->ns_conn)); - conn->ns_conn->ssl = (SSL *) conn->mg_conn.connection_param; - conn->mg_conn.connection_param = NULL; -#endif - } break; case NS_CLOSE: -- GitLab