Commit 25115a69 authored by Daniel O'Connell's avatar Daniel O'Connell

proxy support changes

parent 2436f9d6
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "net_skeleton.h" #include "net_skeleton.h"
#else #else
// net_skeleton start // net_skeleton start
// Copyright (c) 2014 Cesanta Software Limited // Copyright (c) 2014 Cesanta Software Limited
// All rights reserved // All rights reserved
// //
...@@ -39,7 +38,7 @@ ...@@ -39,7 +38,7 @@
#ifndef NS_SKELETON_HEADER_INCLUDED #ifndef NS_SKELETON_HEADER_INCLUDED
#define 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 ANSI WinAPI functions
#undef _UNICODE // Use multibyte encoding on Windows #undef _UNICODE // Use multibyte encoding on Windows
...@@ -72,7 +71,9 @@ ...@@ -72,7 +71,9 @@
#include <signal.h> #include <signal.h>
#ifdef _WIN32 #ifdef _WIN32
#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib") // Linking with winsock library #pragma comment(lib, "ws2_32.lib") // Linking with winsock library
#endif
#include <windows.h> #include <windows.h>
#include <process.h> #include <process.h>
#ifndef EINPROGRESS #ifndef EINPROGRESS
...@@ -91,6 +92,7 @@ ...@@ -91,6 +92,7 @@
#endif // MINGW #defines va_copy #endif // MINGW #defines va_copy
#define snprintf _snprintf #define snprintf _snprintf
#define vsnprintf _vsnprintf #define vsnprintf _vsnprintf
#define sleep(x) Sleep((x) * 1000)
#define to64(x) _atoi64(x) #define to64(x) _atoi64(x)
typedef int socklen_t; typedef int socklen_t;
typedef unsigned char uint8_t; typedef unsigned char uint8_t;
...@@ -883,6 +885,7 @@ int ns_server_poll(struct ns_server *server, int milli) { ...@@ -883,6 +885,7 @@ int ns_server_poll(struct ns_server *server, int milli) {
for (conn = server->active_connections; conn != NULL; conn = tmp_conn) { for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
tmp_conn = conn->next; tmp_conn = conn->next;
//DBG(("%p LOOP %p", conn, conn->ssl));
if (FD_ISSET(conn->sock, &read_set)) { if (FD_ISSET(conn->sock, &read_set)) {
conn->last_io_time = current_time; conn->last_io_time = current_time;
ns_read_from_socket(conn); ns_read_from_socket(conn);
...@@ -1052,7 +1055,6 @@ void ns_server_free(struct ns_server *s) { ...@@ -1052,7 +1055,6 @@ void ns_server_free(struct ns_server *s) {
s->ssl_ctx = s->client_ssl_ctx = NULL; s->ssl_ctx = s->client_ssl_ctx = NULL;
#endif #endif
} }
// net_skeleton end // net_skeleton end
#endif // NOEMBED_NET_SKELETON #endif // NOEMBED_NET_SKELETON
...@@ -1064,7 +1066,18 @@ void ns_server_free(struct ns_server *s) { ...@@ -1064,7 +1066,18 @@ void ns_server_free(struct ns_server *s) {
#ifndef S_ISDIR #ifndef S_ISDIR
#define S_ISDIR(x) ((x) & _S_IFDIR) #define S_ISDIR(x) ((x) & _S_IFDIR)
#endif #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 stat(x, y) mg_stat((x), (y))
#define fopen(x, y) mg_fopen((x), (y)) #define fopen(x, y) mg_fopen((x), (y))
#define open(x, y) mg_open((x), (y)) #define open(x, y) mg_open((x), (y))
...@@ -1072,7 +1085,6 @@ void ns_server_free(struct ns_server *s) { ...@@ -1072,7 +1085,6 @@ void ns_server_free(struct ns_server *s) {
#define popen(x, y) _popen((x), (y)) #define popen(x, y) _popen((x), (y))
#define pclose(x) _pclose(x) #define pclose(x) _pclose(x)
#define mkdir(x, y) _mkdir(x) #define mkdir(x, y) _mkdir(x)
#define to64(x) _atoi64(x)
#ifndef __func__ #ifndef __func__
#define STRX(x) #x #define STRX(x) #x
#define STR(x) STRX(x) #define STR(x) STRX(x)
...@@ -1624,7 +1636,7 @@ static int wait_until_ready(sock_t sock, int for_read) { ...@@ -1624,7 +1636,7 @@ static int wait_until_ready(sock_t sock, int for_read) {
} }
static void *push_to_stdin(void *arg) { static void *push_to_stdin(void *arg) {
struct threadparam *tp = arg; struct threadparam *tp = (struct threadparam *)arg;
int n, sent, stop = 0; int n, sent, stop = 0;
DWORD k; DWORD k;
char buf[IOBUF_SIZE]; char buf[IOBUF_SIZE];
...@@ -1644,7 +1656,7 @@ static void *push_to_stdin(void *arg) { ...@@ -1644,7 +1656,7 @@ static void *push_to_stdin(void *arg) {
} }
static void *pull_from_stdout(void *arg) { static void *pull_from_stdout(void *arg) {
struct threadparam *tp = arg; struct threadparam *tp = (struct threadparam *)arg;
int k, stop = 0; int k, stop = 0;
DWORD n, sent; DWORD n, sent;
char buf[IOBUF_SIZE]; char buf[IOBUF_SIZE];
...@@ -1666,7 +1678,7 @@ static void *pull_from_stdout(void *arg) { ...@@ -1666,7 +1678,7 @@ static void *pull_from_stdout(void *arg) {
static void spawn_stdio_thread(sock_t sock, HANDLE hPipe, static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
void *(*func)(void *)) { void *(*func)(void *)) {
struct threadparam *tp = malloc(sizeof(*tp)); struct threadparam *tp = (struct threadparam *)malloc(sizeof(*tp));
if (tp != NULL) { if (tp != NULL) {
tp->s = sock; tp->s = sock;
tp->hPipe = hPipe; tp->hPipe = hPipe;
...@@ -2410,7 +2422,7 @@ void mg_printf_data(struct mg_connection *c, const char *fmt, ...) { ...@@ -2410,7 +2422,7 @@ void mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
len = ns_avprintf(&buf, sizeof(mem), fmt, ap); len = ns_avprintf(&buf, sizeof(mem), fmt, ap);
va_end(ap); va_end(ap);
if (len > 0) { if (len >= 0) {
write_chunk((struct connection *) conn, buf, len); write_chunk((struct connection *) conn, buf, len);
} }
if (buf != mem && buf != NULL) { if (buf != mem && buf != NULL) {
...@@ -4004,13 +4016,37 @@ static int parse_url(const char *url, char *proto, size_t plen, ...@@ -4004,13 +4016,37 @@ static int parse_url(const char *url, char *proto, size_t plen,
return 0; 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) { static void proxify_connection(struct connection *conn) {
char proto[10], host[500], cert[500]; char proto[10], host[500], cert[500];
unsigned short port; unsigned short port = 80;
struct mg_connection *c = &conn->mg_conn; struct mg_connection *c = &conn->mg_conn;
struct ns_server *server = &conn->server->ns_server; struct ns_server *server = &conn->server->ns_server;
struct ns_connection *pc; struct ns_connection *pc;
int i, n, sent_close_header = 0; int n, use_ssl;
proto[0] = host[0] = cert[0] = '\0'; proto[0] = host[0] = cert[0] = '\0';
n = parse_url(c->uri, proto, sizeof(proto), host, sizeof(host), &port); n = parse_url(c->uri, proto, sizeof(proto), host, sizeof(host), &port);
...@@ -4031,21 +4067,27 @@ static void proxify_connection(struct connection *conn) { ...@@ -4031,21 +4067,27 @@ static void proxify_connection(struct connection *conn) {
} }
#endif #endif
use_ssl = port != 80 && cert[0] != '\0';
if (n > 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 // Interlink two connections
pc->flags |= MG_PROXY_CONN; pc->flags |= MG_PROXY_CONN;
conn->endpoint_type = EP_PROXY; conn->endpoint_type = EP_PROXY;
conn->endpoint.nc = pc; 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) { if (strcmp(c->request_method, "CONNECT") == 0) {
// For CONNECT request, reply with 200 OK. Tunnel is established. // For CONNECT request, reply with 200 OK. Tunnel is established.
mg_printf(c, "%s", "HTTP/1.1 200 OK\r\n\r\n"); 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 #ifdef NS_ENABLE_SSL
if (cert[0] != '\0') { if (use_ssl) {
SSL_CTX *ctx; SSL_CTX *ctx;
DBG(("%s", "Triggering MITM mode: terminating SSL connection"));
SSL_library_init(); SSL_library_init();
ctx = SSL_CTX_new(SSLv23_server_method()); ctx = SSL_CTX_new(SSLv23_server_method());
...@@ -4056,10 +4098,14 @@ static void proxify_connection(struct connection *conn) { ...@@ -4056,10 +4098,14 @@ static void proxify_connection(struct connection *conn) {
SSL_CTX_use_PrivateKey_file(ctx, cert, 1); SSL_CTX_use_PrivateKey_file(ctx, cert, 1);
SSL_CTX_use_certificate_chain_file(ctx, cert); SSL_CTX_use_certificate_chain_file(ctx, cert);
// When clear-text reply is pushed to client, // When clear-text reply is pushed to client, switch to SSL mode.
// we will switch to SSL mode. n = send(conn->ns_conn->sock, conn->ns_conn->send_iobuf.buf,
if ((c->connection_param = SSL_new(ctx)) != NULL) { conn->ns_conn->send_iobuf.len, 0);
SSL_set_fd((SSL *) c->connection_param, conn->ns_conn->sock); 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); SSL_CTX_free(ctx);
} }
...@@ -4067,24 +4113,8 @@ static void proxify_connection(struct connection *conn) { ...@@ -4067,24 +4113,8 @@ static void proxify_connection(struct connection *conn) {
#endif #endif
} else { } else {
// For other methods, forward the request to the target host. // 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->uri += n;
c->http_version); proxy_request(pc, c);
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);
} }
} else { } else {
conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY; conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
...@@ -4253,13 +4283,30 @@ static void try_parse(struct connection *conn) { ...@@ -4253,13 +4283,30 @@ static void try_parse(struct connection *conn) {
} }
} }
static void proxy_from_client_to_target_host(struct connection *conn) { 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); ns_forward(conn->ns_conn, conn->endpoint.nc);
}
} }
static void on_recv_data(struct connection *conn) { static void on_recv_data(struct connection *conn) {
struct iobuf *io = &conn->ns_conn->recv_iobuf; 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); try_parse(conn);
DBG(("%p %d %zu %d", conn, conn->request_len, io->len, conn->ns_conn->flags)); DBG(("%p %d %zu %d", conn, conn->request_len, io->len, conn->ns_conn->flags));
if (conn->request_len < 0 || if (conn->request_len < 0 ||
...@@ -4279,9 +4326,6 @@ static void on_recv_data(struct connection *conn) { ...@@ -4279,9 +4326,6 @@ static void on_recv_data(struct connection *conn) {
open_local_endpoint(conn, 0); 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 #ifndef MONGOOSE_NO_CGI
if (conn->endpoint_type == EP_CGI && conn->endpoint.nc != NULL) { if (conn->endpoint_type == EP_CGI && conn->endpoint.nc != NULL) {
ns_forward(conn->ns_conn, conn->endpoint.nc); ns_forward(conn->ns_conn, conn->endpoint.nc);
...@@ -4736,18 +4780,18 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) { ...@@ -4736,18 +4780,18 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) {
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
static void hexdump(struct ns_connection *nc, const char *path, static void hexdump(struct ns_connection *nc, const char *path,
int num_bytes, int is_sent) { 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; const struct iobuf *io = is_sent ? &nc->send_iobuf : &nc->recv_iobuf;
FILE *fp; FILE *fp;
char *buf; char *buf, src[60], dst[60];
int buf_size = num_bytes * 5 + 100; int buf_size = num_bytes * 5 + 100;
if (path != NULL && (fp = fopen(path, "a")) != NULL) { if (path != NULL && (fp = fopen(path, "a")) != NULL) {
fprintf(fp, "%lu %p %s:%d %s %s:%d %d\n", (unsigned long) time(NULL), ns_sock_to_str(nc->sock, src, sizeof(src), 3);
mc, mc->mg_conn.local_ip, mc->mg_conn.local_port, 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 == 0 ? "<-" : is_sent == 1 ? "->" :
is_sent == 2 ? "<A" : "C>", is_sent == 2 ? "<A" : "C>", dst, num_bytes);
mc->mg_conn.remote_ip, mc->mg_conn.remote_port, num_bytes);
if (num_bytes > 0 && (buf = (char *) malloc(buf_size)) != NULL) { if (num_bytes > 0 && (buf = (char *) malloc(buf_size)) != NULL) {
ns_hexdump(io->buf + (is_sent ? 0 : io->len) - (is_sent ? 0 : num_bytes), ns_hexdump(io->buf + (is_sent ? 0 : io->len) - (is_sent ? 0 : num_bytes),
num_bytes, buf, buf_size); num_bytes, buf, buf_size);
...@@ -4789,8 +4833,10 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) { ...@@ -4789,8 +4833,10 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
break; break;
case NS_CONNECT: case NS_CONNECT:
if (nc->connection_data != NULL) {
set_ips(nc, 1); set_ips(nc, 1);
set_ips(nc, 0); set_ips(nc, 0);
}
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
hexdump(nc, server->config_options[HEXDUMP_FILE], 0, 3); hexdump(nc, server->config_options[HEXDUMP_FILE], 0, 3);
#endif #endif
...@@ -4825,16 +4871,6 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) { ...@@ -4825,16 +4871,6 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 1); hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 1);
#endif #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; break;
case NS_CLOSE: case NS_CLOSE:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment