diff --git a/inc_internal/edge_protocol.h b/inc_internal/edge_protocol.h index eec76112..4ffea3bb 100644 --- a/inc_internal/edge_protocol.h +++ b/inc_internal/edge_protocol.h @@ -18,6 +18,8 @@ limitations under the License. #ifndef ZITI_SDK_EDGE_PROTOCOL_H #define ZITI_SDK_EDGE_PROTOCOL_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -42,6 +44,11 @@ enum content_type { ContentTypeStateSessionEnded = 60792, ContentTypeProbe = 60793, ContentTypeUpdateBind = 60794, + ContentTypeHealthEvent = 60795, + ContentTypeTraceRoute = 60796, + ContentTypeTraceRouteResponse = 60797, + ContentTypeConnInspectRequest = 60798, + ContentTypeConnInspectResponse = 60799, }; enum header_id { @@ -86,6 +93,14 @@ enum header_id { ConnectionMarkerHeader = 1025, }; +typedef uint8_t connection_type_t; +enum connection_type { + ConnTypeInvalid, + ConnTypeDial = 1, + ConnTypeBind = 2, + ConnTypeUnknown = 3, +}; + enum crypto_method { CryptoMethodLibsodium = 0, CryptoMethodAES256GCM = 1, diff --git a/inc_internal/message.h b/inc_internal/message.h index ccb83b8d..c540ab35 100644 --- a/inc_internal/message.h +++ b/inc_internal/message.h @@ -16,6 +16,7 @@ #define ZITI_SDK_MESSAGE_H #include "pool.h" +#include "edge_protocol.h" #include #include @@ -101,6 +102,7 @@ message *message_new(pool_t *pool, uint32_t content, const hdr_t *headers, int n void message_set_seq(message *m, uint32_t *seq); +message* new_inspect_result(uint32_t req_seq, uint32_t conn_id, connection_type_t type, const char *msg, size_t msglen); #ifdef __cplusplus }; diff --git a/library/bind.c b/library/bind.c index 6c3ac56b..54c1489d 100644 --- a/library/bind.c +++ b/library/bind.c @@ -215,6 +215,7 @@ static void session_cb(ziti_net_session *session, const ziti_error *err, void *c static void get_service_cb(ziti_context ztx, ziti_service *service, int status, void *ctx) { struct ziti_conn *conn = ctx; if (status == ZITI_OK) { + conn->encrypted = service->encryption; if (ziti_service_has_permission(service, ziti_session_types.Bind)) { ziti_ctrl_create_session(&ztx->controller, service->id, ziti_session_types.Bind, session_cb, conn); } else { @@ -295,6 +296,23 @@ static int dispose(ziti_connection server) { return 1; } +#define BOOL_STR(v) ((v) ? "Y" : "N") + +static void process_inspect(struct binding_s *b, message *msg) { + struct ziti_conn *conn = b->conn; + char conn_info[256]; + char listener_id[sodium_base64_ENCODED_LEN(sizeof(conn->server.listener_id), sodium_base64_VARIANT_URLSAFE)]; + sodium_bin2base64(listener_id, sizeof(listener_id), conn->server.listener_id, sizeof(conn->server.listener_id), sodium_base64_VARIANT_URLSAFE); + size_t ci_len = snprintf(conn_info, sizeof(conn_info), + "id[%d] serviceName[%s] listenerId[%s] " + "closed[%s] encrypted[%s]", + conn->conn_id, conn->service, listener_id, + BOOL_STR(conn->close), BOOL_STR(conn->encrypted)); + CONN_LOG(DEBUG, "processing inspect: %.*s", (int)ci_len, conn_info); + message *reply = new_inspect_result(msg->header.seq, conn->conn_id, ConnTypeBind, conn_info, ci_len); + ziti_channel_send_message(b->ch, reply, NULL); +} + static void process_dial(struct binding_s *b, message *msg) { struct ziti_conn *conn = b->conn; @@ -320,7 +338,7 @@ static void process_dial(struct binding_s *b, message *msg) { } client->start = uv_now(conn->ziti_ctx->loop); - if (peer_key_sent) { + if (conn->encrypted) { client->encrypted = true; if (init_crypto(&client->key_ex, &b->key_pair, peer_key, true) != 0) { reject_dial_request(0, b->ch, msg->header.seq, "failed to establish crypto"); @@ -371,6 +389,9 @@ static void on_message(struct binding_s *b, message *msg, int code) { case ContentTypeDial: process_dial(b, msg); break; + case ContentTypeConnInspectRequest: + process_inspect(b, msg); + break; default: ZITI_LOG(ERROR, "unexpected msg[%X] for bound conn[%d]", msg->header.content, conn->conn_id); } @@ -405,6 +426,7 @@ void start_binding(struct binding_s *b, ziti_channel_t *ch) { b->ch = ch; + uint8_t true_val = 1; int32_t conn_id = htole32(conn->conn_id); int32_t msg_seq = htole32(0); @@ -419,16 +441,21 @@ void start_binding(struct binding_s *b, ziti_channel_t *ch) { .length = sizeof(msg_seq), .value = (uint8_t *) &msg_seq }, - { - .header_id = PublicKeyHeader, - .length = sizeof(b->key_pair.pk), - .value = b->key_pair.pk, - }, { .header_id = ListenerId, .length = sizeof(b->conn->server.listener_id), .value = (uint8_t*)b->conn->server.listener_id, }, + { + .header_id = SupportsInspectHeader, + .length = 1, + .value = &true_val, + }, + { + .header_id = PublicKeyHeader, + .length = sizeof(b->key_pair.pk), + .value = b->key_pair.pk, + }, // blank hdr_t's to be filled in if needed by options { .header_id = -1, @@ -447,6 +474,10 @@ void start_binding(struct binding_s *b, ziti_channel_t *ch) { } }; int nheaders = 4; + if (conn->encrypted) { + nheaders++; + } + if (conn->server.identity != NULL) { headers[nheaders].header_id = TerminatorIdentityHeader; headers[nheaders].value = (uint8_t *) conn->server.identity; diff --git a/library/channel.c b/library/channel.c index c1cbb906..e5878deb 100644 --- a/library/channel.c +++ b/library/channel.c @@ -465,6 +465,7 @@ static bool is_edge(uint32_t content) { case ContentTypeDialFailed: case ContentTypeBind: case ContentTypeUnbind: + case ContentTypeConnInspectRequest: return true; default: return false; @@ -517,8 +518,12 @@ static void dispatch_message(ziti_channel_t *ch, message *m) { if (conn) { conn->receive(conn->receiver, m, ZITI_OK); } else { - // close confirmation is OK if connection is gone already - if (ct != ContentTypeStateClosed) { + if (ct == ContentTypeConnInspectRequest) { + char msg[128]; + size_t len = snprintf(msg, sizeof(msg), "invalid conn id [%d]", conn_id); + message *reply = new_inspect_result(m->header.seq, conn_id, ConnTypeInvalid, msg, len); + ziti_channel_send_message(ch, reply, NULL); + } else if (ct != ContentTypeStateClosed) { // close confirmation is OK if connection is gone already CH_LOG(WARN, "received message without conn_id or for unknown connection ct[%04X] conn_id[%d]", ct, conn_id); } @@ -693,15 +698,21 @@ static void hello_reply_cb(void *ctx, message *msg, int err) { } static void send_hello(ziti_channel_t *ch, ziti_api_session *session) { + uint8_t true_val; hdr_t headers[] = { { .header_id = SessionTokenHeader, .length = strlen(session->token), .value = (uint8_t *)session->token - } + }, + { + .header_id = SupportsInspectHeader, + .length = sizeof(true_val), + .value = &true_val, + }, }; ch->latency = uv_now(ch->loop); - ziti_channel_send_for_reply(ch, ContentTypeHelloType, headers, 1, ch->token, strlen(ch->token), hello_reply_cb, ch); + ziti_channel_send_for_reply(ch, ContentTypeHelloType, headers, 2, ch->token, strlen(ch->token), hello_reply_cb, ch); } diff --git a/library/connect.c b/library/connect.c index 72c23a36..acdc42da 100644 --- a/library/connect.c +++ b/library/connect.c @@ -23,6 +23,8 @@ static const char *INVALID_SESSION = "Invalid Session"; static const int MAX_CONNECT_RETRY = 3; +#define BOOL_STR(v) ((v) ? "Y" : "N") + #define CONN_LOG(lvl, fmt, ...) ZITI_LOG(lvl, "conn[%u.%u/%.*s/%s] " fmt, \ conn->ziti_ctx->id, conn->conn_id, (int)sizeof(conn->marker), conn->marker, conn_state_str[conn->state], ##__VA_ARGS__) @@ -1238,6 +1240,19 @@ static void queue_edge_message(struct ziti_conn *conn, message *msg, int code) { return; } + if (msg->header.content == ContentTypeConnInspectRequest) { + char conn_info[256]; + size_t ci_len = snprintf(conn_info, sizeof(conn_info), + "id[%d/%s] serviceName[%s] closed[%s] encrypted[%s] " + "recvFIN[%s] sentFIN[%s]", + conn->conn_id, conn->marker, conn->service, BOOL_STR(conn->close), BOOL_STR(conn->encrypted), + BOOL_STR(conn->fin_recv), BOOL_STR(conn->fin_sent)); + message *reply = new_inspect_result(msg->header.seq, conn->conn_id, ConnTypeDial, conn_info, ci_len); + ziti_channel_send_message(conn->channel, reply, NULL); + pool_return_obj(msg); + return; + } + TAILQ_INSERT_TAIL(&conn->in_q, msg, _next); flush_connection(conn); } diff --git a/library/message.c b/library/message.c index a8974906..f58630f9 100644 --- a/library/message.c +++ b/library/message.c @@ -237,3 +237,29 @@ void message_set_seq(message *m, uint32_t *seq) { } header_to_buffer(&m->header, m->msgbufp); } + + +message* new_inspect_result(uint32_t req_seq, uint32_t conn_id, connection_type_t type, const char *msg, size_t msglen) { + const hdr_t hdrs[] = { + { + .header_id = ConnIdHeader, + .length = sizeof(conn_id), + .value = (uint8_t *) &conn_id, + }, + { + .header_id = ConnTypeHeader, + .length = sizeof(type), + .value = &type, + }, + { + .header_id = ReplyForHeader, + .length = sizeof(req_seq), + .value = (uint8_t *) &(req_seq), + } + }; + message *reply = message_new(NULL, ContentTypeConnInspectResponse, hdrs, 3, msglen); + if (msglen > 0) { + strncpy((char *) reply->body, msg, msglen); + } + return reply; +} diff --git a/tests/integ/CMakeLists.txt b/tests/integ/CMakeLists.txt index 7458ffbe..382dcbc5 100644 --- a/tests/integ/CMakeLists.txt +++ b/tests/integ/CMakeLists.txt @@ -22,7 +22,7 @@ else () set_property(TARGET integ-tests PROPERTY CXX_STANDARD 14) endif () -set(ZITI_CLI_VER "v0.31.0" CACHE STRING "ziti version for integration tests") +set(ZITI_CLI_VER "v0.31.4" CACHE STRING "ziti version for integration tests") add_custom_target(ziti-cli ALL COMMAND ${CMAKE_COMMAND} -E env GOBIN=${CMAKE_CURRENT_BINARY_DIR} ${GOLANG_EXE} install github.com/openziti/ziti/ziti@${ZITI_CLI_VER}