mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
patches/libnetconf2: silence netopeer2-server warnings in log
Fixes #1446 Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+217
@@ -0,0 +1,217 @@
|
||||
From dfa37a99b335b99e89df1be87b240123178cf1f0 Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Wiberg <troglobit@gmail.com>
|
||||
Date: Thu, 19 Mar 2026 15:15:52 +0100
|
||||
Subject: [PATCH 1/2] server_config: use YANG identity derivation for key
|
||||
formats
|
||||
Organization: Wires
|
||||
|
||||
Replace plain string comparison of public/private key format identities
|
||||
with proper derived-from-or-self() semantics. This allows vendor-extended
|
||||
identities (e.g. an identity with base ct:subject-public-key-info-format)
|
||||
to be silently mapped to the correct internal type without any warning.
|
||||
|
||||
Also silence the spurious warning for symmetric-keys: the feature is
|
||||
intentionally disabled for NETCONF, but a shared keystore may legitimately
|
||||
contain symmetric keys used by other applications, e.g, Wi-Fi passphrases,
|
||||
WireGuard PSKs, etc.
|
||||
|
||||
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
||||
---
|
||||
src/server_config.c | 131 ++++++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 107 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/src/server_config.c b/src/server_config.c
|
||||
index 9f85655..54c470c 100644
|
||||
--- a/src/server_config.c
|
||||
+++ b/src/server_config.c
|
||||
@@ -110,6 +110,64 @@ nc_lyd_find_child(const struct lyd_node *node, const char *child, int fail_if_no
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * @brief Recursively check if @p ident is in the derived tree of @p base.
|
||||
+ *
|
||||
+ * @param[in] base Base identity to search from.
|
||||
+ * @param[in] ident Identity to find.
|
||||
+ * @return 1 if @p ident is @p base or derived from it, 0 otherwise.
|
||||
+ */
|
||||
+static int
|
||||
+nc_ident_derived_or_self(const struct lysc_ident *base, const struct lysc_ident *ident)
|
||||
+{
|
||||
+ LY_ARRAY_COUNT_TYPE i;
|
||||
+
|
||||
+ if (base == ident)
|
||||
+ return 1;
|
||||
+
|
||||
+ LY_ARRAY_FOR(base->derived, i) {
|
||||
+ if (nc_ident_derived_or_self(base->derived[i], ident))
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * @brief Check if a YANG identity derives from (or is) a named identity in a given module.
|
||||
+ *
|
||||
+ * Implements YANG derived-from-or-self() semantics so that vendor-extended
|
||||
+ * format identities (e.g. an identity with base ct:subject-public-key-info-format)
|
||||
+ * are treated the same as their standard base.
|
||||
+ *
|
||||
+ * @param[in] ctx libyang context used to look up the base module.
|
||||
+ * @param[in] ident Identity value from the data node.
|
||||
+ * @param[in] base_mod Name of the module that defines the base identity.
|
||||
+ * @param[in] base_name Name of the base identity.
|
||||
+ * @return 1 if @p ident is or derives from the named base, 0 otherwise.
|
||||
+ */
|
||||
+static int
|
||||
+nc_ident_is_derived_from(const struct ly_ctx *ctx, const struct lysc_ident *ident,
|
||||
+ const char *base_mod, const char *base_name)
|
||||
+{
|
||||
+ const struct lysc_ident *base;
|
||||
+ const struct lys_module *mod;
|
||||
+ LY_ARRAY_COUNT_TYPE i;
|
||||
+
|
||||
+ mod = ly_ctx_get_module_implemented(ctx, base_mod);
|
||||
+ if (!mod)
|
||||
+ return 0;
|
||||
+
|
||||
+ LY_ARRAY_FOR(mod->identities, i) {
|
||||
+ if (!strcmp(mod->identities[i].name, base_name)) {
|
||||
+ base = &mod->identities[i];
|
||||
+ return nc_ident_derived_or_self(base, ident);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
@@ -746,23 +804,32 @@ static int
|
||||
config_pubkey_format(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key *pubkey)
|
||||
{
|
||||
enum nc_operation op;
|
||||
- const char *format;
|
||||
+ const struct lysc_ident *ident;
|
||||
|
||||
NC_NODE_GET_OP(node, parent_op, &op);
|
||||
|
||||
if (op == NC_OP_DELETE) {
|
||||
pubkey->type = NC_PUBKEY_FORMAT_UNKNOWN;
|
||||
} else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
- format = ((struct lyd_node_term *)node)->value.ident->name;
|
||||
- assert(format);
|
||||
- if (!strcmp(format, "ssh-public-key-format")) {
|
||||
+ ident = ((struct lyd_node_term *)node)->value.ident;
|
||||
+ assert(ident);
|
||||
+
|
||||
+ /*
|
||||
+ * Use derived-from-or-self semantics so that vendor-extended identities
|
||||
+ * (e.g. an identity with base ct:ssh-public-key-format) are correctly
|
||||
+ * mapped without requiring explicit registration in libnetconf2.
|
||||
+ */
|
||||
+ if (nc_ident_is_derived_from(LYD_CTX(node), ident, "ietf-crypto-types", "ssh-public-key-format")) {
|
||||
pubkey->type = NC_PUBKEY_FORMAT_SSH;
|
||||
- } else if (!strcmp(format, "subject-public-key-info-format")) {
|
||||
+ } else if (nc_ident_is_derived_from(LYD_CTX(node), ident, "ietf-crypto-types", "subject-public-key-info-format")) {
|
||||
pubkey->type = NC_PUBKEY_FORMAT_X509;
|
||||
} else {
|
||||
- /* do not fail, the key may still be usable, or it may have come from a keystore/truststore
|
||||
- * and have a different purpose other than NETCONF */
|
||||
- WRN(NULL, "Public key format \"%s\" not supported. The key may not be usable.", format);
|
||||
+ /*
|
||||
+ * The key format is not one used by NETCONF - it may be present in the
|
||||
+ * keystore for other purposes (e.g. TLS, WireGuard, Wi-Fi). Do not
|
||||
+ * fail; just mark it unusable for NETCONF and continue.
|
||||
+ */
|
||||
+ VRB(NULL, "Public key format \"%s\" not used by NETCONF, ignoring.", ident->name);
|
||||
pubkey->type = NC_PUBKEY_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -792,29 +859,35 @@ config_pubkey_data(const struct lyd_node *node, enum nc_operation parent_op, str
|
||||
static int
|
||||
config_privkey_format(const struct lyd_node *node, enum nc_operation parent_op, struct nc_private_key *privkey)
|
||||
{
|
||||
+ const struct lysc_ident *ident;
|
||||
enum nc_operation op;
|
||||
- const char *format;
|
||||
|
||||
NC_NODE_GET_OP(node, parent_op, &op);
|
||||
|
||||
if (op == NC_OP_DELETE) {
|
||||
privkey->type = NC_PRIVKEY_FORMAT_UNKNOWN;
|
||||
} else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
- format = ((struct lyd_node_term *)node)->value.ident->name;
|
||||
- assert(format);
|
||||
-
|
||||
- if (!strcmp(format, "rsa-private-key-format")) {
|
||||
+ ident = ((struct lyd_node_term *)node)->value.ident;
|
||||
+ assert(ident);
|
||||
+ /*
|
||||
+ * Use derived-from-or-self semantics so that vendor-extended identities
|
||||
+ * are correctly mapped without requiring explicit registration here.
|
||||
+ */
|
||||
+ if (nc_ident_is_derived_from(LYD_CTX(node), ident, "ietf-crypto-types", "rsa-private-key-format")) {
|
||||
privkey->type = NC_PRIVKEY_FORMAT_RSA;
|
||||
- } else if (!strcmp(format, "ec-private-key-format")) {
|
||||
+ } else if (nc_ident_is_derived_from(LYD_CTX(node), ident, "ietf-crypto-types", "ec-private-key-format")) {
|
||||
privkey->type = NC_PRIVKEY_FORMAT_EC;
|
||||
- } else if (!strcmp(format, "private-key-info-format")) {
|
||||
+ } else if (nc_ident_is_derived_from(LYD_CTX(node), ident, "ietf-crypto-types", "private-key-info-format")) {
|
||||
privkey->type = NC_PRIVKEY_FORMAT_X509;
|
||||
- } else if (!strcmp(format, "openssh-private-key-format")) {
|
||||
+ } else if (nc_ident_is_derived_from(LYD_CTX(node), ident, "ietf-crypto-types", "openssh-private-key-format")) {
|
||||
privkey->type = NC_PRIVKEY_FORMAT_OPENSSH;
|
||||
} else {
|
||||
- /* do not fail, the key may still be usable, or it may have come from a keystore/truststore
|
||||
- * and have a different purpose other than NETCONF */
|
||||
- WRN(NULL, "Private key format \"%s\" not supported. The key may not be usable.", format);
|
||||
+ /*
|
||||
+ * The key format is not one used by NETCONF - it may be present in the
|
||||
+ * keystore for other purposes. Do not fail; just mark it unusable for
|
||||
+ * NETCONF and continue.
|
||||
+ */
|
||||
+ VRB(NULL, "Private key format \"%s\" not used by NETCONF, ignoring.", ident->name);
|
||||
privkey->type = NC_PRIVKEY_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -4223,9 +4296,14 @@ config_asymmetric_key(const struct lyd_node *node, enum nc_operation parent_op,
|
||||
NC_CHECK_RET(config_encrypted_privkey_data(encrypted, op));
|
||||
}
|
||||
|
||||
- /* config asymmetric key certificates */
|
||||
- NC_CHECK_RET(nc_lyd_find_child(node, "certificates", 1, &n));
|
||||
- NC_CHECK_RET(config_asymmetric_key_certs(n, op, entry));
|
||||
+ /*
|
||||
+ * config asymmetric key certificates (optional: keys shared with other
|
||||
+ * applications may legitimately have no certificates node)
|
||||
+ */
|
||||
+ NC_CHECK_RET(nc_lyd_find_child(node, "certificates", 0, &n));
|
||||
+ if (n) {
|
||||
+ NC_CHECK_RET(config_asymmetric_key_certs(n, op, entry));
|
||||
+ }
|
||||
|
||||
/* config generate csr */
|
||||
NC_CHECK_RET(nc_lyd_find_child(node, "generate-csr", 0, &n));
|
||||
@@ -4261,9 +4339,14 @@ config_asymmetric_keys(const struct lyd_node *node, enum nc_operation parent_op,
|
||||
}
|
||||
|
||||
static int
|
||||
-config_symmetric_keys(const struct lyd_node *node, enum nc_operation UNUSED(parent_op))
|
||||
+config_symmetric_keys(const struct lyd_node *UNUSED(node), enum nc_operation UNUSED(parent_op))
|
||||
{
|
||||
- CONFIG_LOG_UNSUPPORTED(node);
|
||||
+ /*
|
||||
+ * Symmetric keys are not supported for NETCONF. They may legitimately
|
||||
+ * be present in a shared keystore used by other applications, e.g.,
|
||||
+ * Wi-Fi passphrases, WireGuard PSKs. Silently ignore them rather than
|
||||
+ * emitting a warning that would confuse operators.
|
||||
+ */
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.43.0
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
From 7988dc8bb8b5dfd3ef1c783164f067a05dd5861b Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Wiberg <troglobit@gmail.com>
|
||||
Date: Thu, 19 Mar 2026 16:38:33 +0100
|
||||
Subject: [PATCH 2/2] session: silence spurious errors on client disconnect
|
||||
Organization: Wires
|
||||
|
||||
When a client drops the TCP connection, ssh_channel_poll_timeout()
|
||||
returns SSH_ERROR with "Socket error: disconnected". This is normal
|
||||
and should not be logged as an error.
|
||||
|
||||
Use ssh_is_connected() to distinguish a peer disconnect from a real
|
||||
channel error. On disconnect, set the termination reason to DROPPED
|
||||
and omit the SESSION_ERROR flag so no ERR message is emitted. Real
|
||||
channel errors retain the existing ERR log and TERM_OTHER reason.
|
||||
|
||||
SSH_EOF (clean channel close by the peer) is treated the same way:
|
||||
downgraded from ERR to VRB, since it too is an expected condition.
|
||||
|
||||
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
||||
---
|
||||
src/io.c | 11 ++++++++---
|
||||
src/session_server.c | 16 +++++++++++-----
|
||||
2 files changed, 19 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/io.c b/src/io.c
|
||||
index b9837c6..9d55a0f 100644
|
||||
--- a/src/io.c
|
||||
+++ b/src/io.c
|
||||
@@ -376,12 +376,17 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
||||
/* EINTR is handled, it resumes waiting */
|
||||
ret = ssh_channel_poll_timeout(session->ti.libssh.channel, io_timeout, 0);
|
||||
if (ret == SSH_ERROR) {
|
||||
- ERR(session, "SSH channel poll error (%s).", ssh_get_error(session->ti.libssh.session));
|
||||
+ if (!ssh_is_connected(session->ti.libssh.session)) {
|
||||
+ VRB(session, "SSH session disconnected.");
|
||||
+ session->term_reason = NC_SESSION_TERM_DROPPED;
|
||||
+ } else {
|
||||
+ ERR(session, "SSH channel poll error (%s).", ssh_get_error(session->ti.libssh.session));
|
||||
+ session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
+ }
|
||||
session->status = NC_STATUS_INVALID;
|
||||
- session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
return -1;
|
||||
} else if (ret == SSH_EOF) {
|
||||
- ERR(session, "SSH channel unexpected EOF.");
|
||||
+ VRB(session, "SSH channel closed by the other side.");
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_DROPPED;
|
||||
return -1;
|
||||
diff --git a/src/session_server.c b/src/session_server.c
|
||||
index 929f8bf..710d66c 100644
|
||||
--- a/src/session_server.c
|
||||
+++ b/src/session_server.c
|
||||
@@ -2097,15 +2097,21 @@ nc_ps_poll_session_io(struct nc_session *session, int io_timeout, time_t now_mon
|
||||
|
||||
r = ssh_channel_poll_timeout(session->ti.libssh.channel, 0, 0);
|
||||
if (r == SSH_EOF) {
|
||||
- sprintf(msg, "SSH channel unexpected EOF");
|
||||
+ sprintf(msg, "SSH channel closed by the other side");
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_DROPPED;
|
||||
- ret = NC_PSPOLL_SESSION_TERM | NC_PSPOLL_SESSION_ERROR;
|
||||
+ ret = NC_PSPOLL_SESSION_TERM;
|
||||
} else if (r == SSH_ERROR) {
|
||||
- sprintf(msg, "SSH channel poll error (%s)", ssh_get_error(session->ti.libssh.session));
|
||||
+ if (!ssh_is_connected(session->ti.libssh.session)) {
|
||||
+ sprintf(msg, "SSH session disconnected");
|
||||
+ session->term_reason = NC_SESSION_TERM_DROPPED;
|
||||
+ ret = NC_PSPOLL_SESSION_TERM;
|
||||
+ } else {
|
||||
+ sprintf(msg, "SSH channel poll error (%s)", ssh_get_error(session->ti.libssh.session));
|
||||
+ session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
+ ret = NC_PSPOLL_SESSION_TERM | NC_PSPOLL_SESSION_ERROR;
|
||||
+ }
|
||||
session->status = NC_STATUS_INVALID;
|
||||
- session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
- ret = NC_PSPOLL_SESSION_TERM | NC_PSPOLL_SESSION_ERROR;
|
||||
} else if (!r) {
|
||||
/* no application data received */
|
||||
ret = NC_PSPOLL_TIMEOUT;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
diff --git a/src/server_config.c b/src/server_config.c
|
||||
index 48d362e..dc9f59d 100644
|
||||
--- a/src/server_config.c
|
||||
+++ b/src/server_config.c
|
||||
@@ -4151,6 +4151,8 @@ config_asymmetric_key_certs(const struct lyd_node *node, enum nc_operation paren
|
||||
struct lyd_node *n;
|
||||
enum nc_operation op;
|
||||
|
||||
+ if (!node)
|
||||
+ return 0;
|
||||
NC_NODE_GET_OP(node, parent_op, &op);
|
||||
|
||||
/* configure all certificates */
|
||||
@@ -4225,7 +4227,7 @@ config_asymmetric_key(const struct lyd_node *node, enum nc_operation parent_op,
|
||||
}
|
||||
|
||||
/* config asymmetric key certificates */
|
||||
- NC_CHECK_RET(nc_lyd_find_child(node, "certificates", 1, &n));
|
||||
+ NC_CHECK_RET(nc_lyd_find_child(node, "certificates", 0, &n));
|
||||
NC_CHECK_RET(config_asymmetric_key_certs(n, op, entry));
|
||||
|
||||
/* config generate csr */
|
||||
Reference in New Issue
Block a user