diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52ae4212..dcdc822c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -57,6 +57,10 @@ Expected: June 2021
Users may have to change how they access the system
+* Netconf message-id attribute changed from optional to mandatory
+ * Made NETCONF message handling more strict according to RFC 6241
+ * Set `CLICON_NETCONF_MESSAGE_ID_OPTIONAL` to true to accept omission of message-id attribute
+ * See also [need make sure message-id exist in rpc validate #240](https://github.com/clicon/clixon/issues/240)
* Changed config and install options for Restconf
* clixon_restconf daemon is installed in /usr/local/sbin (as clixon_backend), instead of /www-data
* `configure --with-wwwdir=
` remains but only applies to fcgi socket and log
@@ -64,11 +68,13 @@ Users may have to change how they access the system
* Restconf drop privileges user is defined by `CLICON_RESTCONF_USER`
* `configure --with-wwwuser=` is removed
* clixon_restconf drop of privileges is defined by `CLICON_RESTCONF_PRIVILEGES` option
-* New clixon-config@2020-05-20.yang revision
+* New clixon-config@2021-05-20.yang revision
* Added: `CLICON_RESTCONF_USER`
* Added: `CLICON_RESTCONF_PRIVILEGES`
* Added: `CLICON_RESTCONF_INSTALLDIR`
+ * Added: `CLICON_RESTCONF_STARTUP_DONTUPDATE`
* Added: `CLICON_RESTCONF_STARTUP_DONTUPDATE`
+ * Added: `CLICON_NETCONF_MESSAGE_ID_OPTIONAL`
* New clixon-restconf@2020-05-20.yang revision
* Added: restconf `log-destination`
* RESTCONF error replies have changed
@@ -110,7 +116,9 @@ Developers may need to change their code
### Corrected Bugs
-* Fixed: [ restconf patch method unable to chage value to empty string #229](https://github.com/clicon/clixon/issues/229)
+* Fixed: [need make sure message-id exist in rpc validate #240](https://github.com/clicon/clixon/issues/240)
+ * Netconf message-id attribute changed from optional to mandatory (see API changes)
+* Fixed: [restconf patch method unable to chage value to empty string #229](https://github.com/clicon/clixon/issues/229)
* Fixed: [restconf patch method adds redundant namespaces #235](https://github.com/clicon/clixon/issues/235)
* Fixed: Restconf HEAD did not work everywhere GET did, such as well-known and exact root.
* Fixed: [JSON parsing error for a specific input. #236](https://github.com/clicon/clixon/issues/236)
diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c
index 36494aff..9c10bd16 100644
--- a/apps/backend/backend_main.c
+++ b/apps/backend/backend_main.c
@@ -747,11 +747,6 @@ main(int argc,
clicon_configfile(h));
goto done;
}
-
- /* Treat unknown XML as anydata */
- if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
- xml_bind_yang_unknown_anydata(1);
-
/* Publish stream on pubsub channels.
* CLICON_STREAM_PUB should be set to URL to where streams are published
* and configure should be run with --enable-publish
diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c
index a78a128b..e965868f 100644
--- a/apps/cli/cli_main.c
+++ b/apps/cli/cli_main.c
@@ -635,11 +635,6 @@ main(int argc,
goto done;
/* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */
xml_nsctx_namespace_netconf_default(h);
-
- /* Treat unknwon XML as anydata */
- if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
- xml_bind_yang_unknown_anydata(1);
-
/* Create top-level and store as option */
if ((yspec = yspec_new()) == NULL)
goto done;
diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c
index 28947ea4..114f178b 100644
--- a/apps/cli/cli_show.c
+++ b/apps/cli/cli_show.c
@@ -495,8 +495,8 @@ cli_show_config1(clicon_handle h,
cli_xml2cli(xc, prefix, gt, cligen_output); /* cli syntax */
break;
case FORMAT_NETCONF:
- cligen_output(stdout, "\n",
- NETCONF_BASE_NAMESPACE);
+ cligen_output(stdout, "\n",
+ NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR);
xc = NULL; /* Dont print xt itself */
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
cli_xml2file(xc, 2, 1, cligen_output);
diff --git a/apps/restconf/restconf_main_fcgi.c b/apps/restconf/restconf_main_fcgi.c
index 162f10c8..88622b6a 100644
--- a/apps/restconf/restconf_main_fcgi.c
+++ b/apps/restconf/restconf_main_fcgi.c
@@ -375,10 +375,6 @@ main(int argc,
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
- /* Treat unknown XML as anydata */
- if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
- xml_bind_yang_unknown_anydata(1);
-
/* Initialize plugin module by creating a handle holding plugin and callback lists */
if (clixon_plugin_module_init(h) < 0)
goto done;
diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c
index 0a4532cb..ac89089a 100644
--- a/apps/restconf/restconf_main_native.c
+++ b/apps/restconf/restconf_main_native.c
@@ -1687,10 +1687,6 @@ restconf_clixon_init(clicon_handle h,
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
- /* Treat unknown XML as anydata */
- if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
- xml_bind_yang_unknown_anydata(1);
-
/* Load restconf plugins before yangs are loaded (eg extension callbacks) */
if ((dir = clicon_restconf_dir(h)) != NULL)
if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c
index 40d8fd99..10844869 100644
--- a/apps/restconf/restconf_methods.c
+++ b/apps/restconf/restconf_methods.c
@@ -513,11 +513,12 @@ api_data_write(clicon_handle h,
/* Create text buffer for transfer to backend */
if ((cbx = cbuf_new()) == NULL)
goto done;
- cprintf(cbx, "",
+ cprintf(cbx, "",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_BASE_PREFIX,
- NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
+ NETCONF_BASE_NAMESPACE, /* bind nc to netconf namespace */
+ NETCONF_MESSAGE_ID_ATTR);
cprintf(cbx, "",
+ cprintf(cbx, "",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_BASE_PREFIX,
- NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
+ NETCONF_BASE_NAMESPACE,
+ NETCONF_MESSAGE_ID_ATTR); /* bind nc to netconf namespace */
cprintf(cbx, "",
+ cprintf(cbx, "",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_BASE_PREFIX,
- NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
+ NETCONF_BASE_NAMESPACE,
+ NETCONF_MESSAGE_ID_ATTR); /* bind nc to netconf namespace */
cprintf(cbx, "
*/
if ((username = clicon_username_get(h)) != NULL){
- if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, "",
- NETCONF_BASE_NAMESPACE, username) < 0)
+ if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, "",
+ NETCONF_BASE_NAMESPACE, username, NETCONF_MESSAGE_ID_ATTR) < 0)
goto done;
}
else
- if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, "",
- NETCONF_BASE_NAMESPACE) < 0)
+ if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, "",
+ NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR) < 0)
goto done;
if (xml_rootchild(xtop, 0, &xtop) < 0)
goto done;
diff --git a/apps/restconf/restconf_stream_fcgi.c b/apps/restconf/restconf_stream_fcgi.c
index 680f8680..ddac456a 100644
--- a/apps/restconf/restconf_stream_fcgi.c
+++ b/apps/restconf/restconf_stream_fcgi.c
@@ -269,8 +269,8 @@ restconf_stream(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
- cprintf(cb, "%s",
- NETCONF_BASE_NAMESPACE, EVENT_RFC5277_NAMESPACE, name);
+ cprintf(cb, "%s",
+ NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR, EVENT_RFC5277_NAMESPACE, name);
/* Print all fields */
for (i=0; i"
+ cprintf(msg, ""
"<%slock><%s/>%slock>",
NETCONF_BASE_NAMESPACE,
+ NETCONF_MESSAGE_ID_ATTR,
lock?"":"un", db, lock?"":"un");
if (clicon_rpc1(sock, msg, msgret) < 0)
goto done;
@@ -422,6 +423,7 @@ clixon_client_get_xdata(int sock,
cprintf(msg, "<%s/>", db);
if (xpath && strlen(xpath)){
cprintf(msg, "<%s:filter %s:type=\"xpath\" xmlns=\"%s\" %s:select=\"%s\"",
diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c
index d9be082a..febf5b93 100644
--- a/lib/src/clixon_netconf_lib.c
+++ b/lib/src/clixon_netconf_lib.c
@@ -65,6 +65,7 @@
#include "clixon_xml.h"
#include "clixon_options.h"
#include "clixon_data.h"
+#include "clixon_xml_bind.h"
#include "clixon_xml_map.h"
#include "clixon_xml_io.h"
#include "clixon_xpath_ctx.h"
@@ -228,44 +229,82 @@ netconf_too_big(cbuf *cb,
goto done;
}
+/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
+ *
+ * An expected attribute is missing.
+ * @param[out] xret Error XML tree. Free with xml_free after use
+ * @param[in] type Error type: "rpc", "application" or "protocol"
+ * @param[in] attr bad-attribute and/or bad-element xml
+ * @param[in] message Error message (will be XML encoded)
+ */
+int
+netconf_missing_attribute_xml(cxobj **xret,
+ char *type,
+ char *attr,
+ char *message)
+{
+ int retval = -1;
+ cxobj *xerr = NULL;
+ char *encstr = NULL;
+ cxobj *xa;
+
+ if (*xret == NULL){
+ if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
+ goto done;
+ }
+ else if (xml_name_set(*xret, "rpc-reply") < 0)
+ goto done;
+ if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
+ goto done;
+ if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
+ goto done;
+ if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
+ goto done;
+ if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "%s"
+ "missing-attribute"
+ "%s"
+ "error", type, attr) < 0)
+ goto done;
+ if (message){
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
+ goto done;
+ if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "%s",
+ encstr) < 0)
+ goto done;
+ }
+ retval = 0;
+ done:
+ if (encstr)
+ free(encstr);
+ return retval;
+}
+
/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
*
* An expected attribute is missing.
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "rpc", "application" or "protocol"
- * @param[in] info bad-attribute or bad-element xml
- * @param[in] message Error message (will be XML encoded)
+ * @param[in] attr bad-attribute
+ * @param[in] message Error message (will be XML encoded) or NULL
*/
int
netconf_missing_attribute(cbuf *cb,
char *type,
- char *info,
+ char *attr,
char *message)
{
- int retval = -1;
- char *encstr = NULL;
+ int retval = -1;
+ cxobj *xret = NULL;
- if (cprintf(cb, ""
- "%s"
- "missing-attribute"
- "%s"
- "error",
- NETCONF_BASE_NAMESPACE, type, info) <0)
- goto err;
- if (message){
- if (xml_chardata_encode(&encstr, "%s", message) < 0)
- goto done;
- if (cprintf(cb, "%s", encstr) < 0)
- goto err;
- }
- if (cprintf(cb, "") <0)
- goto err;
+ if (netconf_missing_attribute_xml(&xret, type, attr, message) < 0)
+ goto done;
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
+ goto done;
retval = 0;
done:
+ if (xret)
+ xml_free(xret);
return retval;
- err:
- clicon_err(OE_XML, errno, "cprintf");
- goto done;
}
/*! Create Netconf bad-attribute error XML tree according to RFC 6241 App A
@@ -1429,6 +1468,16 @@ netconf_module_load(clicon_handle h)
/* Load restconf yang. Note this is also a part of clixon-config */
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
goto done;
+#if 1
+ /* XXX: Both the following settings are because clicon-handle is not part of all API
+ * functions
+ * Treat unknown XML as anydata */
+ if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
+ xml_bind_yang_unknown_anydata(1);
+ /* Make message-id attribute optional */
+ if (clicon_option_bool(h, "CLICON_NETCONF_MESSAGE_ID_OPTIONAL") == 1)
+ xml_bind_netconf_message_id_optional(1);
+#endif
retval = 0;
done:
return retval;
diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c
index fb22d5dc..c81a6ae7 100644
--- a/lib/src/clixon_proto_client.c
+++ b/lib/src/clixon_proto_client.c
@@ -451,6 +451,7 @@ clicon_rpc_get_config(clicon_handle h,
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
+ cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, "><%s/>", db);
if (xpath && strlen(xpath)){
cprintf(cb, "<%s:filter %s:type=\"xpath\" %s:select=\"%s\"",
@@ -541,6 +542,7 @@ clicon_rpc_edit_config(clicon_handle h,
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL)
cprintf(cb, " username=\"%s\"", username);
+ cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, "><%s/>", db);
cprintf(cb, "%s",
xml_operation2str(op));
@@ -595,10 +597,11 @@ clicon_rpc_copy_config(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- ""
+ ""
"<%s/><%s/>",
NETCONF_BASE_NAMESPACE,
username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
db1, db2)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
@@ -641,10 +644,12 @@ clicon_rpc_delete_config(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- ""
+ ""
"<%s/>none",
NETCONF_BASE_NAMESPACE,
- username?username:"", db)) == NULL)
+ username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
+ db)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@@ -682,10 +687,12 @@ clicon_rpc_lock(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- ""
+ ""
"<%s/>",
NETCONF_BASE_NAMESPACE,
- username?username:"", db)) == NULL)
+ username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
+ db)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@@ -723,10 +730,12 @@ clicon_rpc_unlock(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- ""
+ ""
"<%s/>",
NETCONF_BASE_NAMESPACE,
- username?username:"", db)) == NULL)
+ username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
+ db)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@@ -805,6 +814,7 @@ clicon_rpc_get(clicon_handle h,
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
+ cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, ">",
- NETCONF_BASE_NAMESPACE, username?username:"", 42)) == NULL)
+ "",
+ NETCONF_BASE_NAMESPACE, username?username:"",
+ NETCONF_MESSAGE_ID_ATTR)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@@ -932,9 +943,11 @@ clicon_rpc_kill_session(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(my_session_id,
- "%u",
+ "%u",
NETCONF_BASE_NAMESPACE,
- username?username:"", session_id)) == NULL)
+ username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
+ session_id)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@@ -972,9 +985,11 @@ clicon_rpc_validate(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- "<%s/>",
+ "<%s/>",
NETCONF_BASE_NAMESPACE,
- username?username:"", db)) == NULL)
+ username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
+ db)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@@ -1010,9 +1025,10 @@ clicon_rpc_commit(clicon_handle h)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- "",
+ "",
NETCONF_BASE_NAMESPACE,
- username?username:"")) == NULL)
+ username?username:"",
+ NETCONF_MESSAGE_ID_ATTR)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@@ -1048,9 +1064,10 @@ clicon_rpc_discard_changes(clicon_handle h)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- "",
+ "",
NETCONF_BASE_NAMESPACE,
- username?username:"")) == NULL)
+ username?username:"",
+ NETCONF_MESSAGE_ID_ATTR)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@@ -1094,12 +1111,13 @@ clicon_rpc_create_subscription(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- ""
+ ""
"%s"
""
"",
NETCONF_BASE_NAMESPACE,
username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
EVENT_RFC5277_NAMESPACE,
stream?stream:"", filter?filter:"")) == NULL)
goto done;
@@ -1139,9 +1157,10 @@ clicon_rpc_debug(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- "%d",
+ "%d",
NETCONF_BASE_NAMESPACE,
username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
CLIXON_LIB_NS,
level)) == NULL)
goto done;
@@ -1189,9 +1208,10 @@ clicon_rpc_restconf_debug(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
- "%d",
+ "%d",
NETCONF_BASE_NAMESPACE,
username?username:"",
+ NETCONF_MESSAGE_ID_ATTR,
CLIXON_RESTCONF_NS,
level)) == NULL)
goto done;
diff --git a/lib/src/clixon_xml_bind.c b/lib/src/clixon_xml_bind.c
index 35050cc5..7d38bff6 100644
--- a/lib/src/clixon_xml_bind.c
+++ b/lib/src/clixon_xml_bind.c
@@ -83,6 +83,7 @@
* Local variables
*/
static int _yang_unknown_anydata = 0;
+static int _netconf_message_id_optional = 0;
/*! Kludge to equate unknown XML with anydata
* The problem with this is that its global and should be bound to a handle
@@ -94,6 +95,16 @@ xml_bind_yang_unknown_anydata(int val)
return 0;
}
+/*! Kludge to set message_id_optional
+ * The problem with this is that its global and should be bound to a handle
+ */
+int
+xml_bind_netconf_message_id_optional(int val)
+{
+ _netconf_message_id_optional = val;
+ return 0;
+}
+
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
* May apply to other nodes?
*/
@@ -510,16 +521,16 @@ xml_bind_yang0(cxobj *xt,
* @retval -1 Error
* The
* @code
- * if (xml_bind_yang_rpc(h, x, NULL) < 0)
+ * if (xml_bind_yang_rpc(x, NULL) < 0)
* err;
* @endcode
* @see xml_bind_yang For other generic cases
* @see xml_bind_yang_rpc_reply
*/
int
-xml_bind_yang_rpc(cxobj *xrpc,
- yang_stmt *yspec,
- cxobj **xerr)
+xml_bind_yang_rpc(cxobj *xrpc,
+ yang_stmt *yspec,
+ cxobj **xerr)
{
int retval = -1;
yang_stmt *yrpc = NULL; /* yang node */
@@ -576,6 +587,17 @@ xml_bind_yang_rpc(cxobj *xrpc,
goto done;
goto fail;
}
+ if (_netconf_message_id_optional == 0){
+ /* RFC 6241 4.1:
+ * The element has a mandatory attribute "message-id"
+ */
+ if (xml_find_type(xrpc, NULL, "message-id", CX_ATTR) == NULL){
+ if (xerr &&
+ netconf_missing_attribute_xml(xerr, "rpc", "message-id", "Incoming rpc") < 0)
+ goto done;
+ goto fail;
+ }
+ }
x = NULL;
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
rpcname = xml_name(x);
diff --git a/test/test_c++.sh b/test/test_c++.sh
index 497058e3..c9be6f2a 100755
--- a/test/test_c++.sh
+++ b/test/test_c++.sh
@@ -154,7 +154,7 @@ new "wait backend"
wait_backend
new "Netconf runtime test"
-expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO0]]>]]>" '^042]]>]]>$'
+expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO0]]>]]>" "^042]]>]]>$"
if [ $BE -ne 0 ]; then
new "Kill backend"
diff --git a/test/test_client.sh b/test/test_client.sh
index 7a13092c..ed37410c 100755
--- a/test/test_client.sh
+++ b/test/test_client.sh
@@ -91,7 +91,7 @@ main(int argc,
/* Provide a clixon config-file, get a clixon handle */
if ((h = clixon_client_init("$cfg")) == NULL)
return -1;
- /* Make a conenction over netconf or ssh/netconf */
+ /* Make a connection over netconf or ssh/netconf */
if ((ch = clixon_client_connect(h, CLIXON_CLIENT_NETCONF)) == NULL)
return -1;
diff --git a/test/test_nacm_module_read.sh b/test/test_nacm_module_read.sh
index 660308c0..80f2bb1c 100755
--- a/test/test_nacm_module_read.sh
+++ b/test/test_nacm_module_read.sh
@@ -232,13 +232,13 @@ new "limit rpc ok"
expectpart "$(curl -u wilma:bar $CURLOPTS -X POST $RCPROTO://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' )" 0 "HTTP/$HVER 200" '{"clixon-example:output":{"x":"42","y":"42"}}'
new "limit rpc netconf ok"
-expecteof "$clixon_netconf -U wilma -qf $cfg" 0 "$DEFAULTHELLO0]]>]]>" '^042]]>]]>$'
+expecteof "$clixon_netconf -U wilma -qf $cfg" 0 "$DEFAULTHELLO0]]>]]>" "^042]]>]]>$"
new "guest rpc fail"
expectpart "$(curl -u guest:bar $CURLOPTS -X POST $RCPROTO://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' )" 0 "HTTP/$HVER 403" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}'
new "guest rpc netconf fail"
-expecteof "$clixon_netconf -U guest -qf $cfg" 0 "$DEFAULTHELLO0]]>]]>" '^applicationaccess-deniederroraccess denied]]>]]>$'
+expecteof "$clixon_netconf -U guest -qf $cfg" 0 "$DEFAULTHELLO0]]>]]>" "^applicationaccess-deniederroraccess denied]]>]]>$"
#------------------ Set read-default permit
diff --git a/test/test_netconf.sh b/test/test_netconf.sh
index dba65cf7..6339b0bc 100755
--- a/test/test_netconf.sh
+++ b/test/test_netconf.sh
@@ -26,6 +26,7 @@ cat < $cfg
/usr/local/lib/$APPNAME/backendexample_backend.so$/usr/local/lib/$APPNAME/netconf
+ false/usr/local/lib/$APPNAME/restconf/usr/local/lib/$APPNAME/cli$APPNAME
@@ -67,6 +68,9 @@ expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^protocolunknown-elementxxxerrorUnrecognized netconf operation]]>]]>$"
+new "Frame without message-id attribute"
+expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^rpcmissing-attributemessage-iderrorIncoming rpc]]>]]>$"
+
new "netconf rcv hello, disable RFC7895/ietf-yang-library"
expecteof "$clixon_netconf -f $cfg -o CLICON_MODULE_LIBRARY_RFC7895=0" 0 "$DEFAULTHELLO]]>]]>" "^urn:ietf:params:netconf:base:1.1urn:ietf:params:netconf:base:1.0urn:ietf:params:netconf:capability:candidate:1.0urn:ietf:params:netconf:capability:validate:1.1urn:ietf:params:netconf:capability:startup:1.0urn:ietf:params:netconf:capability:xpath:1.0urn:ietf:params:netconf:capability:notification:1.0[0-9]*]]>]]>]]>]]>$"
diff --git a/test/test_restconf.sh b/test/test_restconf.sh
index 99b227ec..91df06ca 100755
--- a/test/test_restconf.sh
+++ b/test/test_restconf.sh
@@ -393,7 +393,7 @@ function testrun()
new "restconf rpc using POST xml"
ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' $proto://$addr/restconf/operations/clixon-example:example)
- expect=''
+ expect=''
match=`echo $ret | grep --null -Eo "$expect"`
if [ -z "$match" ]; then
err "$expect" "$ret"
diff --git a/test/test_rpc.sh b/test/test_rpc.sh
index f0d61b17..9b8acd9c 100755
--- a/test/test_rpc.sh
+++ b/test/test_rpc.sh
@@ -89,10 +89,10 @@ new "restconf example rpc xml/json"
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+json' -d '0' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}'
new "restconf example rpc json/xml"
-expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' ''
+expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' ''
new "restconf example rpc xml/xml"
-expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '0' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' ''
+expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '0' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' ''
new "restconf example rpc xml in w json encoding (expect fail)"
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '0' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 "HTTP/$HVER 400" "rpcmalformed-messageerrorjson_parse: line 1: syntax error at or before: '<'"
diff --git a/yang/clixon/clixon-config@2021-05-20.yang b/yang/clixon/clixon-config@2021-05-20.yang
index 4a8cca7b..0e729594 100644
--- a/yang/clixon/clixon-config@2021-05-20.yang
+++ b/yang/clixon/clixon-config@2021-05-20.yang
@@ -50,6 +50,7 @@ module clixon-config {
CLICON_RESTCONF_PRIVILEGES
CLICON_RESTCONF_INSTALLDIR
CLICON_RESTCONF_STARTUP_DONTUPDATE
+ CLICON_NETCONF_MESSAGE_ID_OPTIONAL
Released in Clixon 5.2";
}
revision 2021-03-08 {
@@ -465,6 +466,16 @@ module clixon-config {
is returned, which conforms to the RFC.
Note this applies only to external NETCONF, not the internal (IPC) netconf";
}
+ leaf CLICON_NETCONF_MESSAGE_ID_OPTIONAL {
+ type boolean;
+ default false;
+ description
+ "This option relates to RFC 6241 Sec 4.1 Element
+ The element has a mandatory attribute 'message-id', which is a
+ string chosen by the sender of the RPC.
+ If true, an RPC can be sent without a message-id.
+ This applies to both external NETCONF and internal (IPC) netconf";
+ }
leaf CLICON_RESTCONF_DIR {
type string;
description