From e1a9ad7f822d6520fa1e4c8476710a0df1649bd4 Mon Sep 17 00:00:00 2001 From: Marko Mikulicic Date: Thu, 10 Nov 2016 14:01:00 +0100 Subject: [PATCH] Overload `mg_bind` to bind to tunnel PUBLISHED_FROM=f554cc63dfea12455fe5e428c6ce5f3152774f8e --- docs/c-api/net.h/struct_mg_bind_opts.md | 7 +- examples/tun/tun.c | 11 +- mongoose.c | 156 +++++++++++++++++++----- mongoose.h | 79 +----------- 4 files changed, 135 insertions(+), 118 deletions(-) diff --git a/docs/c-api/net.h/struct_mg_bind_opts.md b/docs/c-api/net.h/struct_mg_bind_opts.md index 2012e3d7..18dfc3d4 100644 --- a/docs/c-api/net.h/struct_mg_bind_opts.md +++ b/docs/c-api/net.h/struct_mg_bind_opts.md @@ -10,11 +10,14 @@ signature: | struct mg_iface *iface; /* Interface instance */ #if MG_ENABLE_SSL /* SSL settings. */ - const char *ssl_cert; /* Server certificate to present to clients */ + const char *ssl_cert; /* Server certificate to present to clients + * Or client certificate to present to tunnel + * dispatcher. */ const char *ssl_key; /* Private key corresponding to the certificate. If ssl_cert is set but ssl_key is not, ssl_cert is used. */ - const char *ssl_ca_cert; /* Verify client certificates with this CA bundle */ + const char *ssl_ca_cert; /* CA bundle used to verify client certificates or + * tunnel dispatchers. */ #endif }; --- diff --git a/examples/tun/tun.c b/examples/tun/tun.c index 700f59bc..aa9f5350 100644 --- a/examples/tun/tun.c +++ b/examples/tun/tun.c @@ -1,9 +1,7 @@ #include "mongoose.h" static const char *s_local_port = ":8001"; -static const char *s_dispatcher = "ws://localhost:8000"; -static const char *s_user = "foo"; -static const char *s_pass = "bar"; +static const char *s_dispatcher = "ws://foo:bar@localhost:8000"; void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { struct http_message *hm = (struct http_message *) ev_data; @@ -41,15 +39,10 @@ int main(int argc, char **argv) { s_local_port = argv[++i]; } else if (strcmp(argv[i], "-d") == 0) { s_dispatcher = argv[++i]; - } else if (strcmp(argv[i], "-u") == 0) { - s_user = argv[++i]; - } else if (strcmp(argv[i], "-p") == 0) { - s_pass = argv[++i]; } } - if ((nc = mg_tuna_bind(&mgr, ev_handler, s_dispatcher, s_user, s_pass)) == - NULL) { + if ((nc = mg_bind(&mgr, s_dispatcher, ev_handler)) == NULL) { fprintf(stderr, "Cannot create tunneled listening socket on [%s]\n", s_dispatcher); exit(EXIT_FAILURE); diff --git a/mongoose.c b/mongoose.c index 8b1e7ba1..095e5a3f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1796,6 +1796,87 @@ int64_t cs_to64(const char *s) { #endif /* EXCLUDE_COMMON */ #ifdef MG_MODULE_LINES +#line 1 "mongoose/src/tun.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_MONGOOSE_SRC_TUN_H_ +#define CS_MONGOOSE_SRC_TUN_H_ + +#if MG_ENABLE_TUN + +/* Amalgamated: #include "mongoose/src/net.h" */ +/* Amalgamated: #include "common/mg_str.h" */ + +#ifndef MG_TUN_RECONNECT_INTERVAL +#define MG_TUN_RECONNECT_INTERVAL 1 +#endif + +#define MG_TUN_DATA_FRAME 0x0 +#define MG_TUN_F_END_STREAM 0x1 + +/* + * MG TUN frame format is loosely based on HTTP/2. + * However since the communication happens via WebSocket + * there is no need to encode the frame length, since that's + * solved by WebSocket framing. + * + * TODO(mkm): Detailed description of the protocol. + */ +struct mg_tun_frame { + uint8_t type; + uint8_t flags; + uint32_t stream_id; /* opaque stream identifier */ + struct mg_str body; +}; + +struct mg_tun_ssl_opts { +#if MG_ENABLE_SSL + const char *ssl_cert; + const char *ssl_key; + const char *ssl_ca_cert; +#else + int dummy; /* some compilers don't like empty structs */ +#endif +}; + +struct mg_tun_client { + struct mg_mgr *mgr; + struct mg_iface *iface; + const char *disp_url; + struct mg_tun_ssl_opts ssl; + + uint32_t last_stream_id; /* stream id of most recently accepted connection */ + + struct mg_connection *disp; + struct mg_connection *listener; +}; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr, + const char *dispatcher, + mg_event_handler_t handler, + struct mg_bind_opts opts); + +int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame); + +void mg_tun_send_frame(struct mg_connection *ws, uint32_t stream_id, + uint8_t type, uint8_t flags, struct mg_str msg); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MG_ENABLE_TUN */ + +#endif /* CS_MONGOOSE_SRC_TUN_H_ */ +#ifdef MG_MODULE_LINES #line 1 "mongoose/src/net.c" #endif /* @@ -1821,6 +1902,7 @@ int64_t cs_to64(const char *s) { /* Amalgamated: #include "mongoose/src/internal.h" */ /* Amalgamated: #include "mongoose/src/resolv.h" */ /* Amalgamated: #include "mongoose/src/util.h" */ +/* Amalgamated: #include "mongoose/src/tun.h" */ #define MG_MAX_HOST_LEN 200 @@ -2797,6 +2879,13 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts); +#if MG_ENABLE_TUN + if (mg_strncmp(mg_mk_str(address), mg_mk_str("ws://"), 5) == 0 || + mg_strncmp(mg_mk_str(address), mg_mk_str("wss://"), 6) == 0) { + return mg_tun_bind_opt(mgr, address, callback, opts); + } +#endif + if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) { MG_SET_PTRPTR(opts.error_string, "cannot parse address"); return NULL; @@ -10676,13 +10765,12 @@ static void mg_tun_reconnect(struct mg_tun_client *client); static void mg_tun_init_client(struct mg_tun_client *client, struct mg_mgr *mgr, struct mg_iface *iface, const char *dispatcher, - const char *user, const char *pass) { + struct mg_tun_ssl_opts ssl) { client->mgr = mgr; client->iface = iface; client->disp_url = dispatcher; - client->user = user; - client->pass = pass; client->last_stream_id = 0; + client->ssl = ssl; client->disp = NULL; /* will be set by mg_tun_reconnect */ client->listener = NULL; /* will be set by mg_do_bind */ @@ -10787,24 +10875,23 @@ static void mg_tun_client_handler(struct mg_connection *nc, int ev, static void mg_tun_do_reconnect(struct mg_tun_client *client) { struct mg_connection *dc; - struct mbuf headers; - mbuf_init(&headers, 0); - + struct mg_connect_opts opts; + memset(&opts, 0, sizeof(opts)); +#if MG_ENABLE_SSL + opts.ssl_cert = client->ssl.ssl_cert; + opts.ssl_key = client->ssl.ssl_key; + opts.ssl_ca_cert = client->ssl.ssl_ca_cert; +#endif /* HTTP/Websocket listener */ - mg_basic_auth_header(client->user, client->pass, &headers); - mbuf_append(&headers, "", 1); /* nul terminate */ - if ((dc = mg_connect_ws(client->mgr, mg_tun_client_handler, client->disp_url, - "mg_tun", headers.buf)) == NULL) { + if ((dc = mg_connect_ws_opt(client->mgr, mg_tun_client_handler, opts, + client->disp_url, "mg_tun", NULL)) == NULL) { LOG(LL_ERROR, ("Cannot connect to WS server on addr [%s]\n", client->disp_url)); - goto clean; + return; } client->disp = dc; dc->user_data = client; - -clean: - mbuf_free(&headers); } void mg_tun_reconnect_ev_handler(struct mg_connection *nc, int ev, @@ -10829,8 +10916,7 @@ static void mg_tun_reconnect(struct mg_tun_client *client) { static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr, const char *dispatcher, - const char *user, - const char *pass) { + struct mg_tun_ssl_opts ssl) { struct mg_tun_client *client = NULL; struct mg_iface *iface = mg_find_iface(mgr, &mg_tun_iface_vtable, NULL); if (iface == NULL) { @@ -10840,39 +10926,43 @@ static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr, } client = (struct mg_tun_client *) MG_MALLOC(sizeof(*client)); - mg_tun_init_client(client, mgr, iface, dispatcher, user, pass); + mg_tun_init_client(client, mgr, iface, dispatcher, ssl); iface->data = client; mg_tun_do_reconnect(client); return client; } -static struct mg_connection *mg_tuna_do_bind(struct mg_tun_client *client, - mg_event_handler_t handler) { +static struct mg_connection *mg_tun_do_bind(struct mg_tun_client *client, + mg_event_handler_t handler, + struct mg_bind_opts opts) { struct mg_connection *lc; - struct mg_bind_opts opts; - const char *err; - memset(&opts, 0, sizeof(opts)); opts.iface = client->iface; - opts.error_string = &err; lc = mg_bind_opt(client->mgr, ":1234" /* dummy port */, handler, opts); - if (lc == NULL) { - LOG(LL_ERROR, ("Cannot bind: %s", err)); - } client->listener = lc; return lc; } -struct mg_connection *mg_tuna_bind(struct mg_mgr *mgr, - mg_event_handler_t handler, - const char *dispatcher, const char *user, - const char *pass) { - struct mg_tun_client *client = - mg_tun_create_client(mgr, dispatcher, user, pass); +struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr, + const char *dispatcher, + mg_event_handler_t handler, + struct mg_bind_opts opts) { +#if MG_ENABLE_SSL + struct mg_tun_ssl_opts ssl = {opts.ssl_cert, opts.ssl_key, opts.ssl_ca_cert}; +#else + struct mg_tun_ssl_opts ssl = {0}; +#endif + struct mg_tun_client *client = mg_tun_create_client(mgr, dispatcher, ssl); if (client == NULL) { return NULL; } - return mg_tuna_do_bind(client, handler); +#if MG_ENABLE_SSL + /* these options don't make sense in the local mouth of the tunnel */ + opts.ssl_cert = NULL; + opts.ssl_key = NULL; + opts.ssl_ca_cert = NULL; +#endif + return mg_tun_do_bind(client, handler, opts); } int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame) { diff --git a/mongoose.h b/mongoose.h index db683c21..edb0216c 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3221,11 +3221,14 @@ struct mg_bind_opts { struct mg_iface *iface; /* Interface instance */ #if MG_ENABLE_SSL /* SSL settings. */ - const char *ssl_cert; /* Server certificate to present to clients */ + const char *ssl_cert; /* Server certificate to present to clients + * Or client certificate to present to tunnel + * dispatcher. */ const char *ssl_key; /* Private key corresponding to the certificate. If ssl_cert is set but ssl_key is not, ssl_cert is used. */ - const char *ssl_ca_cert; /* Verify client certificates with this CA bundle */ + const char *ssl_ca_cert; /* CA bundle used to verify client certificates or + * tunnel dispatchers. */ #endif }; @@ -5540,75 +5543,3 @@ uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io); #endif /* MG_ENABLE_COAP */ #endif /* CS_MONGOOSE_SRC_COAP_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/tun.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_MONGOOSE_SRC_TUN_H_ -#define CS_MONGOOSE_SRC_TUN_H_ - -#if MG_ENABLE_TUN - -/* Amalgamated: #include "mongoose/src/net.h" */ -/* Amalgamated: #include "common/mg_str.h" */ - -#ifndef MG_TUN_RECONNECT_INTERVAL -#define MG_TUN_RECONNECT_INTERVAL 1 -#endif - -#define MG_TUN_DATA_FRAME 0x0 -#define MG_TUN_F_END_STREAM 0x1 - -/* - * MG TUN frame format is loosely based on HTTP/2. - * However since the communication happens via WebSocket - * there is no need to encode the frame length, since that's - * solved by WebSocket framing. - * - * TODO(mkm): Detailed description of the protocol. - */ -struct mg_tun_frame { - uint8_t type; - uint8_t flags; - uint32_t stream_id; /* opaque stream identifier */ - struct mg_str body; -}; - -struct mg_tun_client { - struct mg_mgr *mgr; - struct mg_iface *iface; - const char *disp_url; - const char *user; - const char *pass; - - uint32_t last_stream_id; /* stream id of most recently accepted connection */ - - struct mg_connection *disp; - struct mg_connection *listener; -}; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -struct mg_connection *mg_tuna_bind(struct mg_mgr *mgr, - mg_event_handler_t handler, - const char *dispatcher, const char *user, - const char *pass); - -int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame); - -void mg_tun_send_frame(struct mg_connection *ws, uint32_t stream_id, - uint8_t type, uint8_t flags, struct mg_str msg); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* MG_ENABLE_TUN */ - -#endif /* CS_MONGOOSE_SRC_TUN_H_ */