session FEATURE expected hostname for TLS callhome
diff --git a/src/session_client.c b/src/session_client.c
index e0a58fa..223630d 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -1600,7 +1600,7 @@
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
int
-nc_client_ch_add_bind_listen(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
+nc_client_ch_add_bind_listen(const char *address, uint16_t port, const char *hostname, NC_TRANSPORT_IMPL ti)
{
int sock;
@@ -1625,20 +1625,16 @@
return -1;
}
- client_opts.ch_bind_ti = nc_realloc(client_opts.ch_bind_ti, client_opts.ch_bind_count * sizeof *client_opts.ch_bind_ti);
- if (!client_opts.ch_bind_ti) {
+ client_opts.ch_binds_aux = nc_realloc(client_opts.ch_binds_aux, client_opts.ch_bind_count * sizeof *client_opts.ch_binds_aux);
+ if (!client_opts.ch_binds_aux) {
ERRMEM;
close(sock);
return -1;
}
- client_opts.ch_bind_ti[client_opts.ch_bind_count - 1] = ti;
+ client_opts.ch_binds_aux[client_opts.ch_bind_count - 1].ti = ti;
+ client_opts.ch_binds_aux[client_opts.ch_bind_count - 1].hostname = hostname ? strdup(hostname) : NULL;
client_opts.ch_binds[client_opts.ch_bind_count - 1].address = strdup(address);
- if (!client_opts.ch_binds[client_opts.ch_bind_count - 1].address) {
- ERRMEM;
- close(sock);
- return -1;
- }
client_opts.ch_binds[client_opts.ch_bind_count - 1].port = port;
client_opts.ch_binds[client_opts.ch_bind_count - 1].sock = sock;
client_opts.ch_binds[client_opts.ch_bind_count - 1].pollin = 0;
@@ -1655,28 +1651,40 @@
if (!address && !port && !ti) {
for (i = 0; i < client_opts.ch_bind_count; ++i) {
close(client_opts.ch_binds[i].sock);
- free((char *)client_opts.ch_binds[i].address);
+ free(client_opts.ch_binds[i].address);
+
+ free(client_opts.ch_binds_aux[i].hostname);
ret = 0;
}
+ client_opts.ch_bind_count = 0;
+
free(client_opts.ch_binds);
client_opts.ch_binds = NULL;
- client_opts.ch_bind_count = 0;
+
+ free(client_opts.ch_binds_aux);
+ client_opts.ch_binds_aux = NULL;
} else {
for (i = 0; i < client_opts.ch_bind_count; ++i) {
if ((!address || !strcmp(client_opts.ch_binds[i].address, address)) &&
(!port || (client_opts.ch_binds[i].port == port)) &&
- (!ti || (client_opts.ch_bind_ti[i] == ti))) {
+ (!ti || (client_opts.ch_binds_aux[i].ti == ti))) {
close(client_opts.ch_binds[i].sock);
- free((char *)client_opts.ch_binds[i].address);
+ free(client_opts.ch_binds[i].address);
--client_opts.ch_bind_count;
if (!client_opts.ch_bind_count) {
free(client_opts.ch_binds);
client_opts.ch_binds = NULL;
+
+ free(client_opts.ch_binds_aux);
+ client_opts.ch_binds_aux = NULL;
} else if (i < client_opts.ch_bind_count) {
- memcpy(&client_opts.ch_binds[i], &client_opts.ch_binds[client_opts.ch_bind_count], sizeof *client_opts.ch_binds);
- client_opts.ch_bind_ti[i] = client_opts.ch_bind_ti[client_opts.ch_bind_count];
+ memcpy(&client_opts.ch_binds[i], &client_opts.ch_binds[client_opts.ch_bind_count],
+ sizeof *client_opts.ch_binds);
+
+ memcpy(&client_opts.ch_binds_aux[i], &client_opts.ch_binds_aux[client_opts.ch_bind_count],
+ sizeof *client_opts.ch_binds_aux);
}
ret = 0;
@@ -1703,20 +1711,20 @@
}
sock = nc_sock_accept_binds(client_opts.ch_binds, client_opts.ch_bind_count, timeout, &host, &port, &idx);
-
if (sock < 1) {
free(host);
return sock;
}
#ifdef NC_ENABLED_SSH
- if (client_opts.ch_bind_ti[idx] == NC_TI_LIBSSH) {
+ if (client_opts.ch_binds_aux[idx].ti == NC_TI_LIBSSH) {
*session = nc_accept_callhome_ssh_sock(sock, host, port, ctx, NC_TRANSPORT_TIMEOUT);
} else
#endif
#ifdef NC_ENABLED_TLS
- if (client_opts.ch_bind_ti[idx] == NC_TI_OPENSSL) {
- *session = nc_accept_callhome_tls_sock(sock, host, port, ctx, NC_TRANSPORT_TIMEOUT);
+ if (client_opts.ch_binds_aux[idx].ti == NC_TI_OPENSSL) {
+ *session = nc_accept_callhome_tls_sock(sock, host, port, ctx, NC_TRANSPORT_TIMEOUT,
+ client_opts.ch_binds_aux[idx].hostname);
} else
#endif
{
diff --git a/src/session_client.h b/src/session_client.h
index 2d87a76..39c9860 100644
--- a/src/session_client.h
+++ b/src/session_client.h
@@ -462,7 +462,7 @@
* If the caller needs to use specific TLS session properties, they are supposed to use ::nc_connect_libssl().
*
* @param[in] host Hostname or address (both Ipv4 and IPv6 are accepted) of the target server.
- * 'localhost' is used by default if NULL is specified.
+ * 'localhost' is used by default if NULL is specified. It is verified by TLS when connecting to it.
* @param[in] port Port number of the target server. Default value 6513 is used if 0 is specified.
* @param[in] ctx Optional custom context to use for the session. Disregarding whether set or not, any YANG modules
* not present and supported by the server are attempted to be loaded using \<get-schema\> (if supported) and/or by
diff --git a/src/session_client_ch.h b/src/session_client_ch.h
index 0ef9560..7b098b0 100644
--- a/src/session_client_ch.h
+++ b/src/session_client_ch.h
@@ -277,6 +277,16 @@
int nc_client_tls_ch_add_bind_listen(const char *address, uint16_t port);
/**
+ * @brief Add a new client bind and start listening on it for TLS Call Home connections coming from the specified hostname.
+ *
+ * @param[in] address IP address to bind to.
+ * @param[in] port Port to bind to.
+ * @param[in] hostname Expected server hostname, verified by TLS when connecting to it.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_tls_ch_add_bind_hostname_listen(const char *address, uint16_t port, const char *hostname);
+
+/**
* @brief Remove a TLS listening client bind.
*
* @param[in] address IP address the socket was bound to. NULL matches all.
diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c
index 54310a8..de0c1df 100644
--- a/src/session_client_ssh.c
+++ b/src/session_client_ssh.c
@@ -1146,7 +1146,7 @@
API int
nc_client_ssh_ch_add_bind_listen(const char *address, uint16_t port)
{
- return nc_client_ch_add_bind_listen(address, port, NC_TI_LIBSSH);
+ return nc_client_ch_add_bind_listen(address, port, NULL, NC_TI_LIBSSH);
}
API int
diff --git a/src/session_client_tls.c b/src/session_client_tls.c
index 43cfd09..04572a5 100644
--- a/src/session_client_tls.c
+++ b/src/session_client_tls.c
@@ -485,7 +485,13 @@
API int
nc_client_tls_ch_add_bind_listen(const char *address, uint16_t port)
{
- return nc_client_ch_add_bind_listen(address, port, NC_TI_OPENSSL);
+ return nc_client_ch_add_bind_listen(address, port, NULL, NC_TI_OPENSSL);
+}
+
+API int
+nc_client_tls_ch_add_bind_hostname_listen(const char *address, uint16_t port, const char *hostname)
+{
+ return nc_client_ch_add_bind_listen(address, port, hostname, NC_TI_OPENSSL);
}
API int
@@ -801,15 +807,15 @@
}
struct nc_session *
-nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout)
+nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout, const char *peername)
{
int ret;
SSL *tls = NULL;
struct nc_session *session = NULL;
struct timespec ts_timeout;
- /* create/update TLS structures without setting the peername */
- if (nc_client_tls_update_opts(&tls_ch_opts, NULL)) {
+ /* create/update TLS structures with explicit expected peername, if any set, the host is just the IP */
+ if (nc_client_tls_update_opts(&tls_ch_opts, peername)) {
goto cleanup;
}
diff --git a/src/session_p.h b/src/session_p.h
index d009af1..cade331 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -152,7 +152,10 @@
int sock;
int pollin;
} *ch_binds;
- NC_TRANSPORT_IMPL *ch_bind_ti;
+ struct {
+ NC_TRANSPORT_IMPL ti;
+ char *hostname;
+ } *ch_binds_aux;
uint16_t ch_bind_count;
};
@@ -745,10 +748,11 @@
*
* @param[in] address Address to bind to.
* @param[in] port Port to bind to.
+ * @param[in] hostname Expected server hostname, may be NULL.
* @param[in] ti Transport to use.
* @return 0 on success, -1 on error.
*/
-int nc_client_ch_add_bind_listen(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti);
+int nc_client_ch_add_bind_listen(const char *address, uint16_t port, const char *hostname, NC_TRANSPORT_IMPL ti);
/**
* @brief Remove a client Call Home bind, stop listening on it.
@@ -819,7 +823,8 @@
#ifdef NC_ENABLED_TLS
-struct nc_session *nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout);
+struct nc_session *nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx,
+ int timeout, const char *peername);
/**
* @brief Establish TLS transport on a socket.