- Pagination: enabled LIST_PAGINATION and remobved constant

- Changed logic on how to find clixon_restconf in pseudo plugin
- Removed ==== in constants to avoid conflict with git merge
- Remove assert
- Added fuzzing for netconf
This commit is contained in:
Olof hagsand 2021-09-23 13:22:40 +02:00
parent 47141089c2
commit b70e22096e
28 changed files with 114 additions and 155 deletions

View file

@ -57,7 +57,6 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
/* cligen */
@ -394,7 +393,10 @@ from_client_edit_config(clicon_handle h,
goto ok;
}
}
assert(cbuf_len(cbret) == 0);
if (cbuf_len(cbret) != 0){
clicon_err(OE_NETCONF, EINVAL, "Internal error: cbret is not empty");
goto done;
}
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok", NETCONF_BASE_NAMESPACE);
if (clicon_data_get(h, "objectexisted", &val) == 0)
cprintf(cbret, " objectexisted=\"%s\"", val);
@ -1367,7 +1369,10 @@ from_client(int s,
int eof = 0;
clicon_debug(1, "%s", __FUNCTION__);
// assert(s == ce->ce_s);
if (s != ce->ce_s){
clicon_err(OE_NETCONF, EINVAL, "Internal error: s != ce->ce_s");
goto done;
}
if (clicon_msg_rcv(ce->ce_s, &msg, &eof) < 0)
goto done;
if (eof)

View file

@ -389,8 +389,6 @@ get_nacm_and_reply(clicon_handle h,
return retval;
}
#ifdef LIST_PAGINATION
/*! Help function for parsing restconf query parameter and setting netconf attribute
*
* If not "unbounded", parse and set a numeric value
@ -652,7 +650,6 @@ get_list_pagination(clicon_handle h,
xml_free(xret);
return retval;
}
#endif /* LIST_PAGINATION */
/*! Common get/get-config code for retrieving configuration and state information.
*
@ -692,11 +689,9 @@ get_common(clicon_handle h,
cbuf *cbmsg = NULL; /* For error msg */
char *xpath0;
cbuf *cbreason = NULL;
#ifdef LIST_PAGINATION
int list_pagination = 0;
char *valstr;
cxobj *x;
#endif /* LIST_PAGINATION */
clicon_debug(1, "%s", __FUNCTION__);
username = clicon_username_get(h);
@ -736,7 +731,6 @@ get_common(clicon_handle h,
goto ok;
}
}
#ifdef LIST_PAGINATION
/* Check if list pagination */
if ((x = xml_find_type(xe, NULL, "list-pagination", CX_ELMNT)) != NULL &&
(valstr = xml_body(x)) != NULL &&
@ -752,7 +746,6 @@ get_common(clicon_handle h,
goto done;
goto ok;
}
#endif /* LIST_PAGINATION */
/* Read configuration */
switch (content){
case CONTENT_CONFIG: /* config data only */

View file

@ -246,9 +246,11 @@ restconf_pseudo_process_control(clicon_handle h)
int i;
int nr;
cbuf *cb = NULL;
char *dir = NULL;
char *dir0 = NULL;
char *dir1 = NULL;
char *pgm;
struct stat fstat;
int found = 0;
nr = 10;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
@ -265,19 +267,32 @@ restconf_pseudo_process_control(clicon_handle h)
* If not, use the Makefile
* Use PATH?
*/
if ((dir = clicon_option_str(h, "CLICON_RESTCONF_INSTALLDIR")) == NULL){
if ((dir = CLIXON_CONFIG_SBINDIR) == NULL){
clicon_err(OE_RESTCONF, EINVAL, "Both option CLICON_RESTCONF_INSTALLDIR and makefile constant CLIXON_CONFIG_SBINDIR are NULL which make sit not possible to know where clixon_restconf is installed(shouldnt happen)");
goto done;
if ((dir0 = clicon_option_str(h, "CLICON_RESTCONF_INSTALLDIR")) != NULL){
cprintf(cb, "%s/clixon_restconf", dir0);
pgm = cbuf_get(cb);
if (stat(pgm, &fstat) == 0){ /* Sanity check: program exists */
clicon_debug(1, "Found %s", pgm);
found++;
}
else
clicon_debug(1, "Not found: %s", pgm);
}
cprintf(cb, "%s/clixon_restconf", dir);
pgm = cbuf_get(cb);
/* Sanity check: program exists */
if (stat(pgm, &fstat) < 0) {
clicon_err(OE_FATAL, errno, "%s, you may have set CLICON_BACKEND_RESTCONF_PROCESS but clixon_restconf is not found in %s. Try overriding with CLICON_RESTCONF_INSTALLDIR",
pgm,
CLIXON_CONFIG_SBINDIR);
if (!found &&
(dir1 = CLIXON_CONFIG_SBINDIR) != NULL){
cbuf_reset(cb);
cprintf(cb, "%s/clixon_restconf", dir1);
pgm = cbuf_get(cb);
clicon_debug(1, "Looking for %s", pgm);
if (stat(pgm, &fstat) == 0){ /* Sanity check: program exists */
clicon_debug(1, "Found %s", pgm);
found++;
}
else
clicon_debug(1, "Not found: %s", pgm);
}
if (!found){
clicon_err(OE_RESTCONF, 0, "clixon_restconf not found in neither CLICON_RESTCONF_INSTALLDIR(%s) nor CLIXON_CONFIG_SBINDIR(%s). Try overriding with CLICON_RESTCONF_INSTALLDIR",
dir0, dir1);
goto done;
}
argv[i++] = pgm;

View file

@ -39,6 +39,33 @@
* | | ------------> | cli |
* | list{key A;}| | syntax |
* +-------------+ +-------------+
* YANG generate CLI
This is an example yang module:
module m {
container x {
namespace "urn:example:m";
prefix m;
list m1 {
key "a";
leaf a {
type string;
}
leaf b {
type string;
}
}
}
}
You can see which CLISPEC it generates via clixon_cli -D 2:
x,cli_set("/example:x");{
m1 a (<a:string>|<a:string expand_dbvar("candidate","/example:x/m1=%s/a")>),overwrite_me("/example:x/m1=%s/");
{
b (<b:string>|<b:string expand_dbvar("candidate","/example:x/m1=%s/b")>),overwrite_me("/example:x/m1=%s/b");
}
}
*/
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
@ -69,36 +96,6 @@
/* variable expand function */
#define GENERATE_EXPAND_XMLDB "expand_dbvar"
/*=====================================================================
* YANG generate CLI
*=====================================================================*/
/*
This is an example yang module:
module m {
container x {
namespace "urn:example:m";
prefix m;
list m1 {
key "a";
leaf a {
type string;
}
leaf b {
type string;
}
}
}
}
You can see which CLISPEC it generates via clixon_cli -D 2:
x,cli_set("/example:x");{
m1 a (<a:string>|<a:string expand_dbvar("candidate","/example:x/m1=%s/a")>),overwrite_me("/example:x/m1=%s/");
{
b (<b:string>|<b:string expand_dbvar("candidate","/example:x/m1=%s/b")>),overwrite_me("/example:x/m1=%s/b");
}
}
*/
/*! Create cligen variable expand entry with xmlkey format string as argument
* @param[in] h clicon handle
* @param[in] ys yang_stmt of the node at hand

View file

@ -891,8 +891,6 @@ cli_show_options(clicon_handle h,
return retval;
}
#ifdef LIST_PAGINATION
/*! Show pagination
* @param[in] h Clicon handle
* @param[in] cvv Vector of cli string and instantiated variables
@ -1016,11 +1014,3 @@ cli_pagination(clicon_handle h,
cbuf_free(cb);
return retval;
}
#else
int
cli_pagination(clicon_handle h, cvec *cvv, cvec *argv)
{
fprintf(stderr, "Not yet implemented\n");
return 0;
}
#endif /* LIST_PAGINATION */

View file

@ -300,7 +300,6 @@ api_data_get2(clicon_handle h,
return retval;
}
#ifdef LIST_PAGINATION
/*! GET Collection
* According to restconf collection draft. Lists, work in progress
* @param[in] h Clixon handle
@ -566,7 +565,6 @@ api_data_collection(clicon_handle h,
free(xvec);
return retval;
}
#endif /* LIST_PAGINATION */
/*! REST HEAD method
* @param[in] h Clixon handle
@ -644,13 +642,8 @@ api_data_get(clicon_handle h,
break;
case YANG_COLLECTION_XML:
case YANG_COLLECTION_JSON:
#ifdef LIST_PAGINATION
if (api_data_collection(h, req, api_path, pcvec, pi, qvec, pretty, media_out) < 0)
goto done;
#else
if (restconf_notimplemented(h, req, pretty, media_out) < 0)
goto done;
#endif
break;
default:
break;

View file

@ -266,7 +266,7 @@ restconf_connection_sanity(clicon_handle h,
if (rc->rc_ssl == NULL &&
rc->rc_proto == HTTP_2 &&
clicon_option_bool(h, "CLICON_RESTCONF_HTTP2_PLAIN") == 0){
if (netconf_invalid_value_xml(&xerr, "protocol", "Plain HTTP/2 is disabled") < 0)
if (netconf_invalid_value_xml(&xerr, "protocol", "Only HTTP/2 with TLS is enabled, plain http/2 is disabled") < 0)
goto done;
if ((media_str = restconf_param_get(h, "HTTP_ACCEPT")) == NULL){
media_out = YANG_DATA_JSON;

View file

@ -104,6 +104,8 @@ Notes:
Use `/* */`. Use `//` only for temporal comments.
Do not use "======", ">>>>>" or "<<<<<<" in comments since git merge conflict uses that.
## How to work in git
Clixon uses semantic versioning (https://semver.org).

View file

@ -1,7 +1,7 @@
#!/bin/sh
# Kill all controller containers (optionally do `make clean`)
sudo docker kill clixon-system
sudo docker kill clixon-system 2> /dev/null # ignore errors

View file

@ -2,8 +2,6 @@
Clixon can be fuzzed with [american fuzzy lop](https://github.com/google/AFL/releases) but not without pain.
So far the backend and cli can be fuzzed.
Some issues are as follows:
- Static linking. Fuzzing requires static linking. You can statically link clixon using: `LINKAGE=static ./configure` but that does not work with Clixon plugins (at least yet). Therefore fuzzing has been made with no plugins using the hello example only.
- Multiple processes. Only the backend can run stand-alone, cli/netconf/restconf requires a backend. When you fuzz eg clixon_cli, the backend must be running and it will be slow due to IPC. Possibly one could link them together and run as a monolith by making a threaded image.

View file

@ -1 +1 @@
set hello world
set table parameter a value 42

View file

@ -1 +1,2 @@
validate
commit

View file

@ -1 +1 @@
<rpc><edit-config><target><candidate/></target><config><hello xmlns="urn:example:hello"><world/></hello></config></edit-config></rpc>]]>]]>
<rpc message-id="42" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><table xmlns="urn:example:clixon"><parameter><name>a</name></parameter></table></config></edit-config></rpc>]]>]]>

View file

@ -1 +1 @@
<rpc><commit/></rpc>]]>]]>
<rpc message-id="99" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">><commit/></rpc>]]>]]>

View file

@ -1 +1 @@
<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>
<rpc message-id="238" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">><get-config><source><running/></source></get-config></rpc>]]>]]>

View file

@ -49,4 +49,4 @@ test ! -d output || rm -rf output
test -d output || mkdir output
# Run script
afl-fuzz -i input -o output -m $MEGS -- clixon_netconf -f $cfg
afl-fuzz -i input -o output -m $MEGS -x xml.dict -- clixon_netconf -qf $cfg -o CLICON_NETCONF_HELLO_OPTIONAL=true

View file

@ -12,11 +12,8 @@ attr_generic=" a=\"1\""
attr_href=" href=\"1\""
attr_standalone=" standalone=\"no\""
attr_version=" version=\"1\""
attr_xml_base=" xml:base=\"1\""
attr_xml_id=" xml:id=\"1\""
attr_xml_lang=" xml:lang=\"1\""
attr_xml_space=" xml:space=\"1\""
attr_xmlns=" xmlns=\"1\""
attr_xmlns=" xmlns:ns=\"1\""
entity_builtin="&lt;"
entity_decimal="&#1;"
@ -26,30 +23,13 @@ entity_hex="&#x1;"
string_any="ANY"
string_brackets="[]"
string_cdata="CDATA"
string_col_fallback=":fallback"
string_col_generic=":a"
string_col_include=":include"
string_dashes="--"
string_empty="EMPTY"
string_empty_dblquotes="\"\""
string_empty_quotes="''"
string_entities="ENTITIES"
string_entity="ENTITY"
string_fixed="#FIXED"
string_id="ID"
string_idref="IDREF"
string_idrefs="IDREFS"
string_implied="#IMPLIED"
string_nmtoken="NMTOKEN"
string_nmtokens="NMTOKENS"
string_notation="NOTATION"
string_parentheses="()"
string_pcdata="#PCDATA"
string_percent="%a"
string_public="PUBLIC"
string_required="#REQUIRED"
string_schema=":schema"
string_system="SYSTEM"
string_ucs4="UCS-4"
string_utf16="UTF-16"
string_utf8="UTF-8"
@ -59,11 +39,6 @@ tag_attlist="<!ATTLIST"
tag_cdata="<![CDATA["
tag_close="</a>"
tag_doctype="<!DOCTYPE"
tag_element="<!ELEMENT"
tag_entity="<!ENTITY"
tag_ignore="<![IGNORE["
tag_include="<![INCLUDE["
tag_notation="<!NOTATION"
tag_open="<a>"
tag_open_close="<a />"
tag_open_exclamation="<!"

View file

@ -118,13 +118,6 @@
*/
#undef YANG_PATCH
/*! Enable list pagination drafts
* draft-wwlh-netconf-list-pagination-00,
* draft-wwlh-netconf-list-pagination-nc-01
* draft-wwlh-netconf-list-pagination-rc-01
*/
#define LIST_PAGINATION
/*! Enable "remaining" attribute (sub-feature of list pagination)
* As defined in draft-wwlh-netconf-list-pagination-00 using Yang metadata value [RFC7952]
*/

View file

@ -33,7 +33,6 @@
***** END LICENSE BLOCK *****
* CALLING ORDER OF YANG PARSE FILES
* =================================
* yang_spec_parse_module
* | |
* v v v

View file

@ -923,12 +923,9 @@ xml2json1_cbuf(cbuf *cb,
--commas;
}
}
#ifdef LIST_PAGINATION /* identify md:annotations as RFC 7952 Sec 5.2.1*/
if (metacbc){
cprintf(cb, "%s", cbuf_get(metacbc));
}
#endif
#if 0 /* identify md:annotations as RFC 7952 Sec 5.2.1*/
for (i=0; i<xml_child_nr(x); i++){

View file

@ -1530,27 +1530,12 @@ netconf_module_load(clicon_handle h)
if (clicon_option_bool(h, "CLICON_NETCONF_MESSAGE_ID_OPTIONAL") == 1)
xml_bind_netconf_message_id_optional(1);
#endif
#ifdef LIST_PAGINATION
/* Load clixon netconf list pagination */
if (yang_spec_parse_module(h, "clixon-netconf-list-pagination", NULL, yspec)< 0)
goto done;
/* Load restconf list pagination */
if (yang_spec_parse_module(h, "ietf-restconf-list-pagination", NULL, yspec)< 0)
goto done;
#if 0
/* XXX Clixon test harness problem: when loading ietf-list-pagination, it loads
* ietf-system-capabilities which in turn loads ietf-netconf-acm. As this is a
* system module (always loaded) it means all test-cases
*/
/* Load list pagination */
if (yang_spec_parse_module(h, "ietf-list-pagination", NULL, yspec)< 0)
goto done;
#endif
#ifdef LIST_PAGINATION
#endif
#endif
retval = 0;
done:
return retval;

View file

@ -878,7 +878,6 @@ clicon_rpc_get(clicon_handle h,
return retval;
}
#ifdef LIST_PAGINATION
/*! Get database configuration and state data collection
* @param[in] h Clicon handle
* @param[in] xpath To identify a list/leaf-list
@ -1014,7 +1013,6 @@ clicon_rpc_get_pageable_list(clicon_handle h,
free(msg);
return retval;
}
#endif /* LIST_PAGINATION */
/*! Send a close a netconf user session. Socket is also closed if still open
*

View file

@ -37,7 +37,6 @@
* @see https://tools.ietf.org/html/rfc7950 YANG 1.1
*
* CALLING ORDER OF YANG PARSE FILES
* =================================
* yang_spec_parse_module
* | |
* v v v

View file

@ -14,6 +14,11 @@
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
if ! ${HAVE_LIBEVHTP}; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi
APPNAME=example
# Common NACM scripts
@ -28,11 +33,6 @@ fyang=$dir/myexample.yang
# No ssl
if ! ${HAVE_LIBEVHTP}; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi
RCPROTO=http
HVER=1.1

View file

@ -23,6 +23,11 @@
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
if ! ${HAVE_LIBEVHTP}; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi
APPNAME=example
cfg=$dir/conf.xml
@ -31,11 +36,6 @@ fyang2=$dir/augment.yang
fxml=$dir/initial.xml
fstate=$dir/state.xml
if ! ${HAVE_LIBEVHTP}; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi
RCPROTO=http # Force to http due to netcat
HVER=1.1

View file

@ -14,6 +14,11 @@
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
if ! ${HAVE_LIBEVHTP}; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi
APPNAME=example
cfg=$dir/conf.xml
@ -24,11 +29,6 @@ RESTCONFDBG=$DBG
RCPROTO=http # no ssl here
HVER=1.1
if ! ${HAVE_LIBEVHTP}; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi
# log-destination in restconf xml: syslog or file
: ${LOGDST:=syslog}
# Set daemon command-line to -f
@ -495,6 +495,7 @@ new "endtest"
endtest
# Set by restconf_config
unset HVER
unset LOGDST
unset LOGDST_CMD
unset pid

View file

@ -25,6 +25,11 @@
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
if ! ${HAVE_LIBEVHTP}; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi
APPNAME=example
cfg=$dir/conf.xml
@ -34,10 +39,6 @@ startupdb=$dir/startup_db
RESTCONFDBG=$DBG
RCPROTO=http # no ssl here
HVER=1.1
if ! ${HAVE_LIBEVHTP}; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi
INVALIDADDR=251.1.1.1 # used by fourth usecase as invalid
@ -477,6 +478,7 @@ unset RESTCONFIG1
unset RESTCONFIG2
unset RESTCONFDBG
unset RCPROTO
unset HVER
rm -rf $dir

View file

@ -296,7 +296,23 @@ EOF
expectpart "$(curl $CURLOPTS --key $certdir/limited.key --cert $certdir/limited.crt -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" 0 "HTTP/$HVER 400" "<error-message>HTTP cert verification failed, unknown ca"
new "too weak cert (sign w md5)"
expectpart "$(curl $CURLOPTS --key $certdir/mymd5.key --cert $certdir/mymd5.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" "35 58" # "md too weak"
# Either curl error or error return ret=$(curl $CURLOPTS --key $certdir/mymd5.key --cert $certdir/mymd5.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2> /dev/null)
r=$?
if [ $r = 0 ]; then
# Check return value
match=$(echo "$ret" | grep --null -o "HTTP/$HVER 400")
r1=$?
if [ $r1 != 0 ]; then
err "HTTP/$HVER 400" "$match"
fi
match=$(echo "$ret" | grep --null -o "HTTP cert verification failed")
r1=$?
if [ $r1 != 0 ]; then
err "HTTP cert verification failed" "$match"
fi
elif [ $r != 35 -a $r != 58 ]; then
err "35 58" "$r"
fi
new "Random cert"
expectpart "$(curl $CURLOPTS --key $certdir/random.key --cert $certdir/random.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" 0 "HTTP/$HVER 400" "HTTP cert verification failed"