* Fixed: [CLIXON is not waiting for the hello message #184](https://github.com/clicon/clixon/issues/184)
* Hello message semantics has been made stricter according to RFC 6241 Sec 8.1, for example: * A client MUST send a <hello> element. * Each peer MUST send at least the base NETCONF capability, "urn:ietf:params:netconf:base:1.1" (or 1.0 for RFC 4741) * The netconf client will terminate (close the socket) if the client does not comply * You can set `CLICON_NETCONF_HELLO_OPTIONAL` to true to use the old behavior of essentially ignoring hellos. * New clixon-config@2020-03-08.yang revision * Added: `CLICON_NETCONF_HELLO_OPTIONAL` * The base capability has been changed to "urn:ietf:params:netconf:base:1.1" following RFC6241.
This commit is contained in:
parent
608f298ed9
commit
5692072d36
81 changed files with 1189 additions and 1351 deletions
|
|
@ -195,6 +195,40 @@ clixon_client_lock(int sock,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Internal function to construct the encoding and hello message
|
||||
*
|
||||
* @param[in] sock Socket
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||
* @param[in] xpath XPath
|
||||
* @param[out] xdata XML data tree (may or may not include the intended data)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
clixon_client_hello(int sock)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *msg = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((msg = cbuf_new()) == NULL){
|
||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(msg, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
cprintf(msg, "<hello xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
|
||||
cprintf(msg, "<capabilities><capability>%s</capability></capabilities>", NETCONF_BASE_CAPABILITY_1_1);
|
||||
cprintf(msg, "</hello>");
|
||||
if (clicon_msg_send1(sock, msg) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (msg)
|
||||
cbuf_free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Connect client to clixon backend according to config and return a socket
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] socktype Type of socket, internal/external/netconf/ssh
|
||||
|
|
@ -260,6 +294,9 @@ clixon_client_connect(clicon_handle h,
|
|||
if (clixon_proc_socket(argv, &cch->cch_pid, &cch->cch_socket) < 0){
|
||||
goto err;
|
||||
}
|
||||
/* Start with encoding and hello message */
|
||||
if (clixon_client_hello(cch->cch_socket) < 0)
|
||||
goto err;
|
||||
break;
|
||||
case CLIXON_CLIENT_SSH:
|
||||
break;
|
||||
|
|
@ -349,6 +386,7 @@ clixon_xml_bottom(cxobj *xtop,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Internal function to construct a get-config and query a value from the backend
|
||||
*
|
||||
* @param[in] sock Socket
|
||||
|
|
|
|||
|
|
@ -1541,7 +1541,13 @@ netconf_hello_server(clicon_handle h,
|
|||
|
||||
cprintf(cb, "<hello xmlns=\"%s\" message-id=\"%u\">", NETCONF_BASE_NAMESPACE, 42);
|
||||
cprintf(cb, "<capabilities>");
|
||||
cprintf(cb, "<capability>urn:ietf:params:netconf:base:1.0</capability>");
|
||||
/* Each peer MUST send at least the base NETCONF capability, "urn:ietf:params:netconf:base:1.1"
|
||||
* RFC 6241 Sec 8.1
|
||||
*/
|
||||
cprintf(cb, "<capability>%s</capability>", NETCONF_BASE_CAPABILITY_1_1);
|
||||
/* A peer MAY include capabilities for previous NETCONF versions, to indicate
|
||||
that it supports multiple protocol versions. */
|
||||
cprintf(cb, "<capability>%s</capability>", NETCONF_BASE_CAPABILITY_1_0);
|
||||
/* Check if RFC7895 loaded and revision found */
|
||||
if ((ietf_yang_library_revision = yang_modules_revision(h)) != NULL){
|
||||
if (xml_chardata_encode(&encstr, "urn:ietf:params:netconf:capability:yang-library:1.0?revision=%s&module-set-id=%s",
|
||||
|
|
@ -1575,7 +1581,7 @@ netconf_hello_req(clicon_handle h,
|
|||
|
||||
cprintf(cb, "<hello xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
|
||||
cprintf(cb, "<capabilities>");
|
||||
cprintf(cb, "<capability>urn:ietf:params:netconf:base:1.0</capability>");
|
||||
cprintf(cb, "<capability>%s</capability>", NETCONF_BASE_CAPABILITY_1_1);
|
||||
cprintf(cb, "</capabilities>");
|
||||
cprintf(cb, "</hello>");
|
||||
cprintf(cb, "]]>]]>");
|
||||
|
|
|
|||
|
|
@ -1187,9 +1187,10 @@ clicon_hello_req(clicon_handle h,
|
|||
int ret;
|
||||
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(0, "<hello username=\"%s\" xmlns=\"%s\" message-id=\"42\"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability></capabilities></hello>",
|
||||
if ((msg = clicon_msg_encode(0, "<hello username=\"%s\" xmlns=\"%s\" message-id=\"42\"><capabilities><capability>%s</capability></capabilities></hello>",
|
||||
username?username:"",
|
||||
NETCONF_BASE_NAMESPACE)) == NULL)
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
NETCONF_BASE_CAPABILITY_1_1)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -543,8 +543,38 @@ xml_bind_yang_rpc(cxobj *xrpc,
|
|||
cxobj *xc;
|
||||
|
||||
opname = xml_name(xrpc);
|
||||
if ((strcmp(opname, "hello")) == 0) /* Hello: dont bind, dont appear in any yang spec */
|
||||
if ((strcmp(opname, "hello")) == 0){
|
||||
/* Hello: dont bind, dont appear in any yang spec, just ensure there is nothing apart from
|
||||
* session-id or capabilities/capability tags
|
||||
* If erro, just log, drop and close, rpc-error should not be sent since it is not rpc
|
||||
*/
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
|
||||
name = xml_name(x);
|
||||
if (strcmp(name, "session-id") == 0)
|
||||
continue;
|
||||
else if (strcmp(name, "capabilities") == 0){
|
||||
xc = NULL;
|
||||
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(xc), "capability") != 0){
|
||||
if (xerr &&
|
||||
netconf_unknown_element_xml(xerr, "protocol", xml_name(xc),
|
||||
"Unrecognized hello/capabilities element") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (xerr &&
|
||||
netconf_unknown_element_xml(xerr, "protocol", name, "Unrecognized hello element") < 0)
|
||||
goto done;
|
||||
clicon_err(OE_XML, EFAULT, "Unrecognized hello element: %s", name);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
goto ok;
|
||||
}
|
||||
else if ((strcmp(opname, "notification")) == 0)
|
||||
goto ok;
|
||||
else if ((strcmp(opname, "rpc")) == 0)
|
||||
|
|
|
|||
|
|
@ -690,7 +690,7 @@ clixon_xml_parse_file(FILE *fp,
|
|||
* @param[in,out] xt Pointer to XML parse tree. If empty will be created.
|
||||
* @param[out] xerr Reason for failure (yang assignment not made) if retval = 0
|
||||
* @retval 1 Parse OK and all yang assignment made
|
||||
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||
* @retval 0 Parse OK but yang assigment not made (or only partial), xerr is set
|
||||
* @retval -1 Error with clicon_err called. Includes parse error
|
||||
*
|
||||
* @code
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_netconf_lib.h"
|
||||
#include "clixon_xml_nsctx.h"
|
||||
|
||||
/* Undefine if you want to ensure strict namespace assignment on all netconf
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ xml_parse_version(clixon_xml_yacc *xy,
|
|||
char *ver)
|
||||
{
|
||||
if(strcmp(ver, "1.0")){
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "Wrong XML version %s expected 1.0", ver);
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "Unsupported XML version: %s expected 1.0", ver);
|
||||
free(ver);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -179,6 +179,31 @@ xml_parse_version(clixon_xml_yacc *xy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Parse XML encoding
|
||||
* From under Encoding Declaration:
|
||||
* In an encoding declaration, the values UTF-8, UTF-16, ISO-10646-UCS-2, and ISO-10646-UCS-4
|
||||
* SHOULD be used for the various encodings and transformations of Unicode / ISO/IEC 10646, the
|
||||
* values ISO-8859-1, ISO-8859-2, ... ISO-8859- n (where n is the part number) SHOULD be used for
|
||||
* the parts of ISO 8859, and the values ISO-2022-JP, Shift_JIS, and EUC-JP " SHOULD be used for
|
||||
* the various encoded forms of JIS X-0208-1997.
|
||||
* [UTF-8 is default]
|
||||
* Note that since ASCII is a subset of UTF-8, ordinary ASCII entities do not strictly need an
|
||||
* encoding declaration.
|
||||
*
|
||||
* Clixon supports only UTF-8 (or no declaration)
|
||||
*/
|
||||
static int
|
||||
xml_parse_encoding(clixon_xml_yacc *xy,
|
||||
char *enc)
|
||||
{
|
||||
if(strcmp(enc, "UTF-8")){
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "Unsupported XML encoding: %s expected UTF-8", enc);
|
||||
free(enc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Parse Qualified name -> (Un)PrefixedName
|
||||
*
|
||||
* This is where all (parsed) xml elements are created
|
||||
|
|
@ -358,6 +383,7 @@ misc : comment { _PARSE_DEBUG("misc->comment"); }
|
|||
| WHITESPACE { _PARSE_DEBUG("misc->white space"); }
|
||||
;
|
||||
|
||||
/* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'*/
|
||||
xmldcl : BXMLDCL verinfo encodingdecl sddecl EQMARK
|
||||
{ _PARSE_DEBUG("xmldcl->verinfo encodingdecl? sddecl?"); }
|
||||
;
|
||||
|
|
@ -370,8 +396,12 @@ verinfo : VER '=' '\"' STRING '\"'
|
|||
_PARSE_DEBUG("verinfo->version='STRING'");}
|
||||
;
|
||||
|
||||
encodingdecl : ENC '=' '\"' STRING '\"' {if ($4)free($4);}
|
||||
| ENC '=' '\'' STRING '\'' {if ($4)free($4);}
|
||||
encodingdecl : ENC '=' '\"' STRING '\"'
|
||||
{ if (xml_parse_encoding(_XY, $4) <0) YYABORT; if ($4)free($4);
|
||||
_PARSE_DEBUG("encodingdecl-> encoding = \" STRING \"");}
|
||||
| ENC '=' '\'' STRING '\''
|
||||
{ if (xml_parse_encoding(_XY, $4) <0) YYABORT; if ($4)free($4);
|
||||
_PARSE_DEBUG("encodingdecl-> encoding = ' STRING '");}
|
||||
|
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -182,19 +182,22 @@ nodetest_eval_node_localonly(cxobj *x,
|
|||
xpath_tree *xs,
|
||||
cvec *nsc)
|
||||
{
|
||||
int retval = -1;
|
||||
int retval = -1;
|
||||
char *name1 = xml_name(x);
|
||||
char *name2 = NULL;
|
||||
|
||||
/* Namespaces is s0, name is s1 */
|
||||
if (strcmp(xs->xs_s1, "*")==0)
|
||||
return 1;
|
||||
name2 = xs->xs_s1;
|
||||
/* Before going into namespaces, check name equality and filter out noteq */
|
||||
if (strcmp(name1, name2) != 0){
|
||||
retval = 0; /* no match */
|
||||
if (strcmp(xs->xs_s1, "*")==0){
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
name2 = xs->xs_s1;
|
||||
/* Before going into namespaces, check name equality and filter out noteq */
|
||||
if (strcmp(name1, name2) == 0){
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
retval = 0; /* no match */
|
||||
done: /* retval set in preceding statement */
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue