Commit 2238951c authored by Sergey Lyubka's avatar Sergey Lyubka

Integrated Dans net skeleton changes

parent f266dd2c
......@@ -203,10 +203,15 @@ struct ns_connection {
#define NSF_CONNECTING (1 << 3)
#define NSF_CLOSE_IMMEDIATELY (1 << 4)
#define NSF_ACCEPTED (1 << 5)
#define NSF_WANT_READ (1 << 6)
#define NSF_WANT_WRITE (1 << 7)
#define NSF_USER_1 (1 << 26)
#define NSF_USER_2 (1 << 27)
#define NSF_USER_3 (1 << 28)
#define NSF_USER_4 (1 << 29)
#define NSF_USER_5 (1 << 30)
#define NSF_USER_6 (1 << 31)
};
void ns_server_init(struct ns_server *, void *server_data, ns_callback_t);
......@@ -556,23 +561,8 @@ static sock_t ns_open_listening_socket(union socket_address *sa) {
return sock;
}
// Generating signed CA certificate:
// openssl genrsa -out ca.key 2048
// openssl req -new -x509 -key ca.key -out ca.crt -days 9999
// cat ca.key ca.crt > ca.pem
// echo 77 > ca.srl
// Generating server certificate:
// openssl genrsa -out server.key 2048
// openssl req -key server.key -new -out server.req -days 9999
// openssl x509 -req -in server.req -CA ca.pem -CAkey ca.pem -out server.crt
// cat server.key server.crt > server.pem
// Generating client certificate:
// openssl genrsa -out client.key 2048
// openssl req -new -key client.key -out client.req -days 9999
// openssl x509 -req -in client.req -CA ca.pem -CAkey ca.pem -out client.crt
// cat client.key client.crt > client.pem
// Certificate generation script is at
// https://github.com/cesanta/net_skeleton/blob/master/examples/gen_certs.sh
int ns_set_ssl_ca_cert(struct ns_server *server, const char *cert) {
#ifdef NS_ENABLE_SSL
STACK_OF(X509_NAME) *list = SSL_load_client_CA_file(cert);
......@@ -726,10 +716,13 @@ static void ns_read_from_socket(struct ns_connection *conn) {
if (ret == 0 && ok == 0 && conn->ssl != NULL) {
int res = SSL_connect(conn->ssl);
int ssl_err = SSL_get_error(conn->ssl, res);
DBG(("%p res %d %d", conn, res, ssl_err));
DBG(("%p %d wres %d %d", conn, conn->flags, res, ssl_err));
if (ssl_err == SSL_ERROR_WANT_READ) conn->flags |= NSF_WANT_READ;
if (ssl_err == SSL_ERROR_WANT_WRITE) conn->flags |= NSF_WANT_WRITE;
if (res == 1) {
conn->flags = NSF_SSL_HANDSHAKE_DONE;
} else if (res == 0 || ssl_err == 2 || ssl_err == 3) {
conn->flags |= NSF_SSL_HANDSHAKE_DONE;
} else if (ssl_err == SSL_ERROR_WANT_READ ||
ssl_err == SSL_ERROR_WANT_WRITE) {
return; // Call us again
} else {
ok = 1;
......@@ -752,10 +745,13 @@ static void ns_read_from_socket(struct ns_connection *conn) {
} else {
int res = SSL_accept(conn->ssl);
int ssl_err = SSL_get_error(conn->ssl, res);
DBG(("%p res %d %d", conn, res, ssl_err));
DBG(("%p %d rres %d %d", conn, conn->flags, res, ssl_err));
if (ssl_err == SSL_ERROR_WANT_READ) conn->flags |= NSF_WANT_READ;
if (ssl_err == SSL_ERROR_WANT_WRITE) conn->flags |= NSF_WANT_WRITE;
if (res == 1) {
conn->flags |= NSF_SSL_HANDSHAKE_DONE;
} else if (res == 0 || ssl_err == 2 || ssl_err == 3) {
} else if (ssl_err == SSL_ERROR_WANT_READ ||
ssl_err == SSL_ERROR_WANT_WRITE) {
return; // Call us again
} else {
conn->flags |= NSF_CLOSE_IMMEDIATELY;
......@@ -767,7 +763,8 @@ static void ns_read_from_socket(struct ns_connection *conn) {
{
n = recv(conn->sock, buf, sizeof(buf), 0);
}
DBG(("%p <- %d bytes", conn, n));
DBG(("%p %d <- %d bytes", conn, conn->flags, n));
if (ns_is_error(n)) {
conn->flags |= NSF_CLOSE_IMMEDIATELY;
......@@ -797,7 +794,7 @@ static void ns_write_to_socket(struct ns_connection *conn) {
#endif
{ n = send(conn->sock, io->buf, io->len, 0); }
DBG(("%p -> %d bytes", conn, n));
DBG(("%p %d -> %d bytes", conn, conn->flags, n));
ns_call(conn, NS_SEND, &n);
if (ns_is_error(n)) {
......@@ -843,13 +840,17 @@ int ns_server_poll(struct ns_server *server, int milli) {
for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
tmp_conn = conn->next;
ns_call(conn, NS_POLL, &current_time);
ns_add_to_set(conn->sock, &read_set, &max_fd);
if (conn->flags & NSF_CONNECTING) {
ns_add_to_set(conn->sock, &write_set, &max_fd);
if (!(conn->flags & NSF_WANT_WRITE)) {
//DBG(("%p read_set", conn));
ns_add_to_set(conn->sock, &read_set, &max_fd);
}
if (conn->send_iobuf.len > 0 && !(conn->flags & NSF_BUFFER_BUT_DONT_SEND)) {
if (((conn->flags & NSF_CONNECTING) && !(conn->flags & NSF_WANT_READ)) ||
(conn->send_iobuf.len > 0 && !(conn->flags & NSF_CONNECTING) &&
!(conn->flags & NSF_BUFFER_BUT_DONT_SEND))) {
//DBG(("%p write_set", conn));
ns_add_to_set(conn->sock, &write_set, &max_fd);
} else if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
}
if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
ns_close_conn(conn);
}
}
......@@ -1186,6 +1187,7 @@ enum {
#ifdef NS_ENABLE_SSL
SSL_CERTIFICATE,
SSL_CA_CERTIFICATE,
SSL_MITM_CERTS,
#endif
URL_REWRITES,
NUM_OPTIONS
......@@ -1227,6 +1229,7 @@ static const char *static_config_options[] = {
#ifdef NS_ENABLE_SSL
"ssl_certificate", NULL,
"ssl_ca_certificate", NULL,
"ssl_mitm_certs", NULL,
#endif
"url_rewrites", NULL,
NULL
......@@ -3996,19 +3999,39 @@ static int parse_url(const char *url, char *proto, size_t plen,
proto[0] = '\0';
return n;
}
return 0;
}
static void proxify_connection(struct connection *conn) {
char proto[10], host[500];
char proto[10], host[500], cert[500];
unsigned short port;
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;
proto[0] = host[0] = cert[0] = '\0';
n = parse_url(c->uri, proto, sizeof(proto), host, sizeof(host), &port);
if (n > 0 && (pc = ns_connect(server, host, port, 0, conn)) != NULL) {
#ifdef NS_ENABLE_SSL
// Find out whether we should be in the MITM mode
{
const char *certs = conn->server->config_options[SSL_MITM_CERTS];
int host_len = strlen(host);
struct vec a, b;
while ((certs = next_option(certs, &a, &b)) != NULL) {
if (a.len == host_len && mg_strncasecmp(a.ptr, host, a.len) == 0) {
snprintf(cert, sizeof(cert), "%.*s", b.len, b.ptr);
break;
}
}
}
#endif
if (n > 0 &&
(pc = ns_connect(server, host, port, cert[0] != '\0', conn)) != NULL) {
// Interlink two connections
pc->flags |= MG_PROXY_CONN;
conn->endpoint_type = EP_PROXY;
......@@ -4018,6 +4041,29 @@ static void proxify_connection(struct connection *conn) {
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");
#ifdef NS_ENABLE_SSL
if (cert[0] != '\0') {
SSL_CTX *ctx;
SSL_library_init();
ctx = SSL_CTX_new(SSLv23_server_method());
if (ctx == NULL) {
pc->flags |= NSF_CLOSE_IMMEDIATELY;
} else {
SSL_CTX_use_certificate_file(ctx, cert, 1);
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);
}
SSL_CTX_free(ctx);
}
}
#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,
......@@ -4194,7 +4240,7 @@ static void try_parse(struct connection *conn) {
// become invalid.
conn->request = (char *) malloc(conn->request_len);
memcpy(conn->request, io->buf, conn->request_len);
DBG(("%p [%.*s]", conn, conn->request_len, conn->request));
//DBG(("%p [%.*s]", conn, conn->request_len, conn->request));
iobuf_remove(io, conn->request_len);
conn->request_len = parse_http_message(conn->request, conn->request_len,
&conn->mg_conn);
......@@ -4359,6 +4405,7 @@ static void close_local_endpoint(struct connection *conn) {
case EP_CGI:
case EP_PROXY:
if (conn->endpoint.nc != NULL) {
DBG(("%p %p %p :-)", conn, conn->ns_conn, conn->endpoint.nc));
conn->endpoint.nc->flags |= NSF_CLOSE_IMMEDIATELY;
conn->endpoint.nc->connection_data = NULL;
}
......@@ -4374,16 +4421,19 @@ static void close_local_endpoint(struct connection *conn) {
#endif
// Gobble possible POST data sent to the URI handler
iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
iobuf_free(&conn->ns_conn->recv_iobuf);
free(conn->request);
free(conn->path_info);
conn->endpoint_type = EP_NONE;
conn->cl = conn->num_bytes_sent = conn->request_len = 0;
conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
MG_HEADERS_SENT | MG_LONG_RUNNING);
c->request_method = c->uri = c->http_version = c->query_string = NULL;
c->num_headers = c->status_code = c->is_websocket = c->content_len = 0;
free(conn->request); conn->request = NULL;
free(conn->path_info); conn->path_info = NULL;
conn->endpoint.nc = NULL;
c->request_method = c->uri = c->http_version = c->query_string = NULL;
conn->request = conn->path_info = NULL;
if (keep_alive) {
on_recv_data(conn); // Can call us recursively if pipelining is used
......@@ -4679,25 +4729,20 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) {
}
#ifndef MONGOOSE_NO_FILESYSTEM
static void print_hexdump_header(FILE *fp, struct ns_connection *nc,
int num_bytes, const char *marker) {
struct connection *mc = (struct connection *) nc->connection_data;
fprintf(fp, "%lu %s:%d %s %s:%d %d\n", (unsigned long) time(NULL),
mc->mg_conn.local_ip, mc->mg_conn.local_port, marker,
mc->mg_conn.remote_ip, mc->mg_conn.remote_port, num_bytes);
}
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;
int buf_size = num_bytes * 5 + 100;
if (path != NULL && (fp = fopen(path, "a")) != NULL) {
print_hexdump_header(fp, nc, num_bytes,
is_sent == 0 ? "<-" : is_sent == 1 ? "->" :
is_sent == 2 ? "<A" : "C>");
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,
is_sent == 0 ? "<-" : is_sent == 1 ? "->" :
is_sent == 2 ? "<A" : "C>",
mc->mg_conn.remote_ip, mc->mg_conn.remote_port, 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);
......@@ -4775,12 +4820,22 @@ 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:
nc->connection_data = NULL;
if ((nc->flags & MG_CGI_CONN) || (nc->flags & MG_PROXY_CONN)) {
DBG(("%p closing cgi/proxy conn", conn));
if (nc->flags & (MG_CGI_CONN | MG_PROXY_CONN)) {
DBG(("%p %p closing cgi/proxy conn", conn, nc));
if (conn && conn->ns_conn) {
conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len > 0 ?
......@@ -4788,7 +4843,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
conn->endpoint.nc = NULL;
}
} else if (conn != NULL) {
DBG(("%p %d closing", conn, conn->endpoint_type));
DBG(("%p %p %d closing", conn, nc, conn->endpoint_type));
if (conn->endpoint_type == EP_CLIENT && nc->recv_iobuf.len > 0) {
call_http_client_handler(conn);
......@@ -4796,6 +4851,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
call_user(conn, MG_CLOSE);
close_local_endpoint(conn);
conn->ns_conn = NULL;
free(conn);
}
break;
......
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