From 85e2945ec9109de35e7d968ea99492e69e508c09 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 30 Jun 2021 10:59:10 +0200 Subject: [PATCH] * 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 * Fixed: [need make sure message-id exist in rpc validate #240](https://github.com/clicon/clixon/issues/240) --- CHANGELOG.md | 12 ++- apps/backend/backend_main.c | 5 -- apps/cli/cli_main.c | 5 -- apps/cli/cli_show.c | 4 +- apps/restconf/restconf_main_fcgi.c | 4 - apps/restconf/restconf_main_native.c | 4 - apps/restconf/restconf_methods.c | 10 ++- apps/restconf/restconf_methods_post.c | 13 ++-- apps/restconf/restconf_stream_fcgi.c | 4 +- lib/clixon/clixon_netconf_lib.h | 5 ++ lib/clixon/clixon_xml_bind.h | 1 + lib/src/clixon_client.c | 4 +- lib/src/clixon_netconf_lib.c | 95 +++++++++++++++++------ lib/src/clixon_proto_client.c | 60 +++++++++----- lib/src/clixon_xml_bind.c | 30 ++++++- test/test_c++.sh | 2 +- test/test_client.sh | 2 +- test/test_nacm_module_read.sh | 4 +- test/test_netconf.sh | 4 + test/test_restconf.sh | 2 +- test/test_rpc.sh | 4 +- yang/clixon/clixon-config@2021-05-20.yang | 11 +++ 22 files changed, 196 insertions(+), 89 deletions(-) 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/>", 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/backend example_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='4242' + expect='4242' 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' '042' +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' '042' 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' '042' +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' '042' 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