mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-12 10:13:29 +00:00
proxy support changes
This commit is contained in:
+95
-59
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user