* Fixed: [namespace prefix nc is not supported](https://github.com/clicon/clixon/issues/143)

* Added more sanity checks on incoming top-level rpc and hello messages, including verifying top-level namespace
This commit is contained in:
Olof hagsand 2020-10-17 18:04:46 +02:00
parent 46bee9e358
commit a77cd27abb
8 changed files with 280 additions and 110 deletions

View file

@ -63,6 +63,7 @@ Users may have to change how they access the system
### Minor changes ### Minor changes
* Added more sanity checks on incoming top-level rpc and hello messages, including verifying top-level namespace
* Added inline state field to clixon-example.yang * Added inline state field to clixon-example.yang
* Added stricter check on schema-node identifier checking, such as for augments. * Added stricter check on schema-node identifier checking, such as for augments.
* These checks are now made at YANG loading time * These checks are now made at YANG loading time
@ -70,7 +71,8 @@ Users may have to change how they access the system
### Corrected Bugs ### Corrected Bugs
* Fixed [Crash seen with startup mode as running with the XML_DB format being set to JSON. [clixon : 4.7.0] #138](https://github.com/clicon/clixon/issues/138) * Fixed: [namespace prefix nc is not supported](https://github.com/clicon/clixon/issues/143)
* Fixed: [Crash seen with startup mode as running with the XML_DB format being set to JSON. [clixon : 4.7.0] #138](https://github.com/clicon/clixon/issues/138)
* Fixed: Performance enhancement of unique list check (of duplicate keys) * Fixed: Performance enhancement of unique list check (of duplicate keys)
* Fixed: Validate/commit error with false positive yang choice changes detected in validation found in ietf-ipfix-psamp.yang. * Fixed: Validate/commit error with false positive yang choice changes detected in validation found in ietf-ipfix-psamp.yang.
* Fixed: Accepted added subtrees containing lists with duplicate keys. * Fixed: Accepted added subtrees containing lists with duplicate keys.

View file

@ -1594,6 +1594,9 @@ from_client_msg(clicon_handle h,
cxobj *xret = NULL; cxobj *xret = NULL;
uint32_t id; uint32_t id;
enum nacm_credentials_t creds; enum nacm_credentials_t creds;
char *rpcname;
char *rpcprefix;
char *namespace;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
yspec = clicon_dbspec_yang(h); yspec = clicon_dbspec_yang(h);
@ -1615,18 +1618,47 @@ from_client_msg(clicon_handle h,
goto done; goto done;
goto reply; goto reply;
} }
if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){ /* Check for empty frame (no mesaages), return empty message, not clear from RFC what to do */
if ((x = xpath_first(xt, NULL, "/hello")) != NULL){ if (xml_child_nr_type(xt, CX_ELMNT) == 0){
if ((ret = from_client_hello(h, x, ce, cbret)) <0) if (netconf_malformed_message(cbret, "Empty message in netconf rpc frame")< 0)
goto done; goto done;
goto reply; goto reply;
} }
else{ /* Check for multi-messages in frame */
if (netconf_malformed_message(cbret, "rpc keyword expected")< 0) if (xml_child_nr_type(xt, CX_ELMNT) != 1){
if (netconf_malformed_message(cbret, "More than one message in netconf rpc frame")< 0)
goto done;
goto reply;
}
if ((x = xml_child_i_type(xt, 0, CX_ELMNT)) == NULL){ /* Shouldnt happen */
clicon_err(OE_XML, EFAULT, "No xml req (shouldnt happen)");
goto done;
}
rpcname = xml_name(x);
rpcprefix = xml_prefix(x);
if (0) { /* XXX notyet (4.8) restconf seems not to produce right namespace */
if (xml2ns(x, rpcprefix, &namespace) < 0)
goto done;
/* Only accept resolved NETCONF base namespace */
if (namespace == NULL || strcmp(namespace, NETCONF_BASE_NAMESPACE) != 0){
if (netconf_unknown_namespace(cbret, "protocol", rpcprefix, "No appropriate namespace associated with prefix")< 0)
goto done; goto done;
goto reply; goto reply;
} }
} }
if (strcmp(rpcname, "rpc") == 0){
; /* continue below */
}
else if (strcmp(rpcname, "hello") == 0){
if ((ret = from_client_hello(h, x, ce, cbret)) <0)
goto done;
goto reply;
}
else{
if (netconf_unknown_element(cbret, "protocol", rpcname, "Unrecognized netconf operation")< 0)
goto done;
goto reply;
}
ce->ce_id = id; ce->ce_id = id;
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0) if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
goto done; goto done;

View file

@ -79,7 +79,8 @@
static int ignore_packet_errors = 1; static int ignore_packet_errors = 1;
static int static int
netconf_hello(cxobj *xn) netconf_hello(clicon_handle h,
cxobj *xn)
{ {
#ifdef nyi #ifdef nyi
cxobj *x; cxobj *x;
@ -93,125 +94,230 @@ netconf_hello(cxobj *xn)
return 0; return 0;
} }
/*! Process incoming Netconf RPC netconf message
* @param[in] h Clicon handle
* @param[in] xreq XML tree containing netconf RPC message
* @param[in] yspec YANG spec
* @retval 0 OK
* @retval -1 Error
*/
int int
netconf_hello_dispatch(cxobj *xn) netconf_rpc_message(clicon_handle h,
cxobj *xrpc,
yang_stmt *yspec)
{ {
cxobj *xp; int retval = -1;
int retval = -1; cxobj *xret = NULL; /* Return (out) */
int ret;
cbuf *cbret = NULL;
cxobj *xc;
cxobj *xa;
cxobj *xa2;
if ((xp = xpath_first(xn, NULL, "//hello")) != NULL) if ((ret = xml_bind_yang_rpc(xrpc, yspec, &xret)) < 0)
retval = netconf_hello(xp); goto done;
if (ret > 0 &&
(ret = xml_yang_validate_rpc(h, xrpc, &xret)) < 0)
goto done;
if (ret == 0){
if ((cbret = cbuf_new()) == NULL){
clicon_err(LOG_ERR, errno, "cbuf_new");
goto done;
}
clicon_xml2cbuf(cbret, xret, 0, 0, -1);
netconf_output_encap(1, cbret, "rpc-error");
goto ok;
}
if (netconf_rpc_dispatch(h, xrpc, &xret) < 0){
goto done;
}
else{ /* there is a return message in xret */
if (xret == NULL){
if ((cbret = cbuf_new()) == NULL){
clicon_err(LOG_ERR, errno, "cbuf_new");
goto done;
}
if (netconf_operation_failed(cbret, "rpc", "Internal error: no xml return")< 0)
goto done;
netconf_output_encap(1, cbret, "rpc-error");
goto done;
}
if ((xc = xml_child_i(xret, 0))!=NULL){
xa=NULL;
/* Copy message-id attribute from incoming to reply.
* RFC 6241:
* If additional attributes are present in an <rpc> element, a NETCONF
* peer MUST return them unmodified in the <rpc-reply> element. This
* includes any "xmlns" attributes.
*/
while ((xa = xml_child_each(xrpc, xa, CX_ATTR)) != NULL){
/* If attribute already exists, dont copy it */
if (xml_find_type(xc, NULL, xml_name(xa), CX_ATTR) != NULL)
continue;
if ((xa2 = xml_dup(xa)) ==NULL)
goto done;
if (xml_addsub(xc, xa2) < 0)
goto done;
}
if ((cbret = cbuf_new()) == NULL){
clicon_err(LOG_ERR, errno, "cbuf_new");
goto done;
}
clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0, -1);
if (netconf_output_encap(1, cbret, "rpc-reply") < 0){
cbuf_free(cbret);
goto done;
}
}
}
ok:
retval = 0;
done:
if (cbret)
cbuf_free(cbret);
if (xret)
xml_free(xret);
return retval; return retval;
} }
/*! Process incoming packet /*! Process incoming a single netconf message parsed as XML
* @param[in] h Clicon handle * Identify what netconf message it is
* @param[in] cb Packet buffer * @param[in] h Clicon handle
* @param[in] xreq XML tree containing netconf
* @param[in] yspec YANG spec
* @retval 0 OK
* @retval -1 Error
*/ */
static int static int
netconf_input_packet(clicon_handle h, netconf_input_packet(clicon_handle h,
cbuf *cb) cxobj *xreq,
yang_stmt *yspec)
{ {
int retval = -1; int retval = -1;
char *str;
char *str0;
cxobj *xreq = NULL; /* Request (in) */
int isrpc = 0; /* either hello or rpc */
cbuf *cbret = NULL; cbuf *cbret = NULL;
char *rpcname;
char *rpcprefix;
char *namespace = NULL;
clicon_debug(1, "%s", __FUNCTION__);
rpcname = xml_name(xreq);
rpcprefix = xml_prefix(xreq);
if (xml2ns(xreq, rpcprefix, &namespace) < 0)
goto done;
/* Only accept resolved NETCONF base namespace */
if (namespace == NULL || strcmp(namespace, NETCONF_BASE_NAMESPACE) != 0){
if ((cbret = cbuf_new()) == NULL){
clicon_err(LOG_ERR, errno, "cbuf_new");
goto done;
}
if (netconf_unknown_namespace(cbret, "protocol", rpcprefix, "No appropriate namespace associated with prefix")< 0)
goto done;
netconf_output_encap(1, cbret, "rpc-error");
}
if (strcmp(rpcname, "rpc") == 0){
if (netconf_rpc_message(h, xreq, yspec) < 0)
goto done;
}
else if (strcmp(rpcname, "hello") == 0){
if (netconf_hello(h, xreq) < 0)
goto done;
}
else{
if ((cbret = cbuf_new()) == NULL){
clicon_err(LOG_ERR, errno, "cbuf_new");
goto done;
}
if (netconf_unknown_element(cbret, "protocol", rpcname, "Unrecognized netconf operation")< 0)
goto done;
netconf_output_encap(1, cbret, "rpc-error");
}
retval = 0;
done:
if (cbret)
cbuf_free(cbret);
return retval;
}
/*! Process incoming frame, ie a char message framed by ]]>]]>
* Parse string to xml, check only one netconf message within a frame
* @param[in] h Clicon handle
* @param[in] cb Packet buffer
* @retval 0 OK
* @retval -1 Fatal error
*/
static int
netconf_input_frame(clicon_handle h,
cbuf *cb)
{
int retval = -1;
char *str = NULL;
cxobj *xtop = NULL; /* Request (in) */
cxobj *xreq = NULL;
cxobj *xret = NULL; /* Return (out) */ cxobj *xret = NULL; /* Return (out) */
cxobj *xrpc; cbuf *cbret = NULL;
cxobj *xc;
yang_stmt *yspec; yang_stmt *yspec;
int ret; int ret;
cxobj *xa;
cxobj *xa2;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
clicon_debug(2, "%s: \"%s\"", __FUNCTION__, cbuf_get(cb)); clicon_debug(2, "%s: \"%s\"", __FUNCTION__, cbuf_get(cb));
if ((cbret = cbuf_new()) == NULL){ yspec = clicon_dbspec_yang(h);
clicon_err(LOG_ERR, errno, "cbuf_new"); if ((str = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done; goto done;
} }
yspec = clicon_dbspec_yang(h);
if ((str0 = strdup(cbuf_get(cb))) == NULL){
clicon_log(LOG_ERR, "%s: strdup: %s", __FUNCTION__, strerror(errno));
return -1;
}
str = str0;
/* Parse incoming XML message */ /* Parse incoming XML message */
if (clixon_xml_parse_string(str, YB_MODULE, yspec, &xreq, NULL) < 0){ if ((ret = clixon_xml_parse_string(str, YB_RPC, yspec, &xtop, &xret)) < 0){
free(str0); if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
if (netconf_operation_failed(cbret, "rpc", clicon_err_reason)< 0) if (netconf_operation_failed(cbret, "rpc", clicon_err_reason)< 0)
goto done; goto done;
netconf_output_encap(1, cbret, "rpc-error"); /* XXX */
goto ok;
}
if (ret == 0){
if ((cbret = cbuf_new()) == NULL){
clicon_err(LOG_ERR, errno, "cbuf_new");
goto done;
}
clicon_xml2cbuf(cbret, xret, 0, 0, -1);
netconf_output_encap(1, cbret, "rpc-error"); netconf_output_encap(1, cbret, "rpc-error");
goto ok;
}
/* Check for empty frame (no mesaages), return empty message, not clear from RFC what to do */
if (xml_child_nr_type(xtop, CX_ELMNT) == 0){
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
netconf_output_encap(1, cbret, "rpc-error");
goto ok;
}
/* Check for multi-messages in frame */
if (xml_child_nr_type(xtop, CX_ELMNT) != 1){
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
if (netconf_malformed_message(cbret, "More than one message in netconf rpc frame")< 0)
goto done;
netconf_output_encap(1, cbret, "rpc-error");
goto ok;
}
if ((xreq = xml_child_i_type(xtop, 0, CX_ELMNT)) == NULL){ /* Shouldnt happen */
clicon_err(OE_XML, EFAULT, "No xml req (shouldnt happen)");
goto done; goto done;
} }
free(str0); if (netconf_input_packet(h, xreq, yspec) < 0)
if ((xrpc=xpath_first(xreq, NULL, "//rpc")) != NULL){ goto done;
isrpc++;
if ((ret = xml_bind_yang_rpc(xrpc, yspec, &xret)) < 0)
goto done;
if (ret > 0 &&
(ret = xml_yang_validate_rpc(h, xrpc, &xret)) < 0)
goto done;
if (ret == 0){
clicon_xml2cbuf(cbret, xret, 0, 0, -1);
netconf_output_encap(1, cbret, "rpc-error");
goto ok;
}
}
else
if (xpath_first(xreq, NULL, "//hello") != NULL)
;
else{
clicon_log(LOG_WARNING, "Invalid netconf msg: neither rpc or hello: dropped");
goto done;
}
if (!isrpc){ /* hello */
if (netconf_hello_dispatch(xreq) < 0)
goto done;
}
else /* rpc */
if (netconf_rpc_dispatch(h, xrpc, &xret) < 0){
goto done;
}
else{ /* there is a return message in xret */
if (xret == NULL){
if (netconf_operation_failed(cbret, "rpc", "Internal error: no xml return")< 0)
goto done;
netconf_output_encap(1, cbret, "rpc-error");
goto done;
}
if ((xc = xml_child_i(xret, 0))!=NULL){
xa=NULL;
/* Copy message-id attribute from incoming to reply.
* RFC 6241:
* If additional attributes are present in an <rpc> element, a NETCONF
* peer MUST return them unmodified in the <rpc-reply> element. This
* includes any "xmlns" attributes.
*/
while ((xa = xml_child_each(xrpc, xa, CX_ATTR)) != NULL){
/* If attribute already exists, dont copy it */
if (xml_find_type(xc, NULL, xml_name(xa), CX_ATTR) != NULL)
continue;
if ((xa2 = xml_dup(xa)) ==NULL)
goto done;
if (xml_addsub(xc, xa2) < 0)
goto done;
}
clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0, -1);
if (netconf_output_encap(1, cbret, "rpc-reply") < 0){
cbuf_free(cbret);
goto done;
}
}
}
ok: ok:
retval = 0; retval = 0;
done: done:
if (xreq) if (str)
xml_free(xreq); free(str);
if (xtop)
xml_free(xtop);
if (xret) if (xret)
xml_free(xret); xml_free(xret);
if (cbret) if (cbret)
@ -269,7 +375,7 @@ netconf_input_cb(int s,
/* OK, we have an xml string from a client */ /* OK, we have an xml string from a client */
/* Remove trailer */ /* Remove trailer */
*(((char*)cbuf_get(cb)) + cbuf_len(cb) - strlen("]]>]]>")) = '\0'; *(((char*)cbuf_get(cb)) + cbuf_len(cb) - strlen("]]>]]>")) = '\0';
if (netconf_input_packet(h, cb) < 0 && if (netconf_input_frame(h, cb) < 0 &&
!ignore_packet_errors) // default is to ignore errors !ignore_packet_errors) // default is to ignore errors
goto done; goto done;
if (cc_closed) if (cc_closed)

View file

@ -461,7 +461,7 @@ _xml_parse(const char *str,
clicon_debug(2, "%s", __FUNCTION__); clicon_debug(2, "%s", __FUNCTION__);
if (strlen(str) == 0) if (strlen(str) == 0)
return 0; /* OK */ return 1; /* OK */
if (xt == NULL){ if (xt == NULL){
clicon_err(OE_XML, errno, "Unexpected NULL XML"); clicon_err(OE_XML, errno, "Unexpected NULL XML");
return -1; return -1;

View file

@ -433,7 +433,7 @@ expectpart(){
# Pipe stdin to command # Pipe stdin to command
# Arguments: # Arguments:
# - Command # - Command
# - expected command return value (0 if OK) # - expected command return value (0 if OK) XXX SHOULD SWITCH w next
# - stdin input # - stdin input
# - expected stdout outcome # - expected stdout outcome
# Use this if you want regex eg ^foo$ # Use this if you want regex eg ^foo$

View file

@ -222,7 +222,7 @@ if [ $BE -ne 0 ]; then
err err
fi fi
new "start backend" new "start backend"
start_backend -s running -f $cfg start_backend -s init -f $cfg
fi fi
new "waiting" new "waiting"

View file

@ -49,12 +49,40 @@ if [ $BE -ne 0 ]; then
wait_backend wait_backend
fi fi
new "netconf hello" # Framing. with -q to inhibit rcv hello
expecteof "$clixon_netconf -f $cfg" 0 "<rpc $DEFAULTNS message-id=\"101\"><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=2016-06-21&amp;module-set-id=42</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]><rpc-reply $DEFAULTNS message-id=\"101\"><data/></rpc-reply>]]>]]>$" new "Empty frame"
expecteof "$clixon_netconf -qf $cfg" 0 ']]>]]>' ']]>]]>'
new "netconf hello, disable RFC7895/ietf-yang-library" if [ $valgrindtest -eq 0 ]; then # Some leakage in lex / error handling difficult to catch
new "Frame invalid non-xml"
expecteof "$clixon_netconf -qf $cfg" 0 "This is not XML]]>]]>" '<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>rpc</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>xml_parse: line 0: syntax error: at or before: This</error-message></rpc-error></rpc-reply>]]>]]>' 2> /dev/null
fi
new "Frame with two messages"
expecteof "$clixon_netconf -qf $cfg" 0 "<hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability></capabilities></hello><rpc $DEFAULTNS message-id=\"101\"><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>rpc</error-type><error-tag>malformed-message</error-tag><error-severity>error</error-severity><error-message>More than one message in netconf rpc frame</error-message></rpc-error></rpc-reply>]]>]]>'
new "Frame with unknown message"
expecteof "$clixon_netconf -qf $cfg" 0 "<xxx $DEFAULTNS></xxx>]]>]]>" '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>protocol</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>xxx</bad-element></error-info><error-severity>error</error-severity><error-message>Unrecognized netconf operation</error-message></rpc-error></rpc-reply>]]>]]>$'
# Hello
new "Netconf snd hello with xmldecl"
expecteof "$clixon_netconf -qf $cfg" 0 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability></capabilities></hello>]]>]]>" '^$'
new "Netconf snd hello with wrong prefix"
expecteof "$clixon_netconf -qf $cfg" 0 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><xx:hello xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><nc:capabilities><nc:capability>urn:ietf:params:netconf:base:1.0</nc:capability></nc:capabilities></xx:hello>]]>]]>" '<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>protocol</error-type><error-tag>unknown-namespace</error-tag><error-info><bad-namespace>xx</bad-namespace></error-info><error-severity>error</error-severity><error-message>No appropriate namespace associated with prefix</error-message></rpc-error></rpc-reply>]]>]]>'
new "Netconf snd hello with prefix"
expecteof "$clixon_netconf -qf $cfg" 0 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><nc:hello xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><nc:capabilities><nc:capability>urn:ietf:params:netconf:base:1.0</nc:capability></nc:capabilities></nc:hello>]]>]]>" '^$'
new "netconf snd + rcv hello"
expecteof "$clixon_netconf -f $cfg" 0 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability></capabilities></hello>]]>]]>" "^<hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=2016-06-21&amp;module-set-id=42</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]>$"
new "netconf rcv hello, disable RFC7895/ietf-yang-library"
expecteof "$clixon_netconf -f $cfg -o CLICON_MODULE_LIBRARY_RFC7895=0" 0 "<rpc $DEFAULTNS message-id=\"101\"><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]><rpc-reply $DEFAULTNS message-id=\"101\"><data/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -f $cfg -o CLICON_MODULE_LIBRARY_RFC7895=0" 0 "<rpc $DEFAULTNS message-id=\"101\"><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]><rpc-reply $DEFAULTNS message-id=\"101\"><data/></rpc-reply>]]>]]>$"
new "netconf get-config prefix"
expecteof "$clixon_netconf -qf $cfg" 0 "<nc:rpc xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"101\"><nc:get-config><nc:source><nc:candidate/></nc:source></nc:get-config></nc:rpc>]]>]]>" "^<rpc-reply $DEFAULTNS xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"101\"><data/></rpc-reply>]]>]]>$"
new "netconf get-config double quotes" new "netconf get-config double quotes"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS message-id=\"101\"><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS message-id=\"101\"><data/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS message-id=\"101\"><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS message-id=\"101\"><data/></rpc-reply>]]>]]>$"

View file

@ -179,6 +179,8 @@ EOF
) )
expecteof "$clixon_util_xml -o" 0 "$XML" '^<bk:book xmlns:bk="urn:loc.gov:books" xmlns:isbn="urn:ISBN:0-395-36341-6"><bk:title>Cheaper by the Dozen</bk:title><isbn:number>1568491379</isbn:number></bk:book>$' expecteof "$clixon_util_xml -o" 0 "$XML" '^<bk:book xmlns:bk="urn:loc.gov:books" xmlns:isbn="urn:ISBN:0-395-36341-6"><bk:title>Cheaper by the Dozen</bk:title><isbn:number>1568491379</isbn:number></bk:book>$'
endtest
rm -rf $dir rm -rf $dir
# unset conditional parameters # unset conditional parameters