- Started nghttp2 work
- Added autoconf config options, temporary for nghttp2 development: `--disable-evhtp`and `--enable-nghttp2`. - Added special case for api-path:s beginning with //
This commit is contained in:
parent
c405a08ff8
commit
0ad577fa81
14 changed files with 634 additions and 291 deletions
|
|
@ -34,6 +34,8 @@ Expected: June 2021
|
||||||
|
|
||||||
### New features
|
### New features
|
||||||
|
|
||||||
|
* Started EXPERIMENTAL HTTP/2 work using nghttp2
|
||||||
|
* Added autoconf config options, temporary for nghttp2 development: `--disable-evhtp`and `--enable-nghttp2` enabling http/1 only / http/2 only linking
|
||||||
* YANG when statement in conjunction with grouping/uses/augment
|
* YANG when statement in conjunction with grouping/uses/augment
|
||||||
* Several cases were not implemented fully according to RFC 7950:
|
* Several cases were not implemented fully according to RFC 7950:
|
||||||
* Do not extend default values if when statements evaluate to false
|
* Do not extend default values if when statements evaluate to false
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,13 @@
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
/* evhtp */
|
/* evhtp */
|
||||||
#define EVHTP_DISABLE_REGEX
|
#define EVHTP_DISABLE_REGEX
|
||||||
#define EVHTP_DISABLE_EVTHR
|
#define EVHTP_DISABLE_EVTHR
|
||||||
|
|
||||||
#include <evhtp/evhtp.h>
|
#include <evhtp/evhtp.h>
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
|
|
||||||
/* cligen */
|
/* cligen */
|
||||||
#include <cligen/cligen.h>
|
#include <cligen/cligen.h>
|
||||||
|
|
@ -77,6 +79,7 @@ restconf_reply_header(void *req0,
|
||||||
const char *vfmt,
|
const char *vfmt,
|
||||||
...)
|
...)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
evhtp_request_t *req = (evhtp_request_t *)req0;
|
evhtp_request_t *req = (evhtp_request_t *)req0;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
size_t vlen;
|
size_t vlen;
|
||||||
|
|
@ -122,8 +125,12 @@ restconf_reply_header(void *req0,
|
||||||
if (value)
|
if (value)
|
||||||
free(value);
|
free(value);
|
||||||
return retval;
|
return retval;
|
||||||
|
#else /* HAVE_LIBEVHTP */
|
||||||
|
return 0;
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
/*! Send reply
|
/*! Send reply
|
||||||
* @see htp__create_reply_
|
* @see htp__create_reply_
|
||||||
*/
|
*/
|
||||||
|
|
@ -177,6 +184,7 @@ native_send_reply(restconf_conn_h *rc,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
|
|
||||||
/*! Send HTTP reply with potential message body
|
/*! Send HTTP reply with potential message body
|
||||||
* @param[in] req Evhtp http request handle
|
* @param[in] req Evhtp http request handle
|
||||||
|
|
@ -189,6 +197,7 @@ restconf_reply_send(void *req0,
|
||||||
int code,
|
int code,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
evhtp_request_t *req = (evhtp_request_t *)req0;
|
evhtp_request_t *req = (evhtp_request_t *)req0;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
const char *reason_phrase;
|
const char *reason_phrase;
|
||||||
|
|
@ -237,6 +246,9 @@ restconf_reply_send(void *req0,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
#else /* HAVE_LIBEVHTP */
|
||||||
|
return 0;
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! get input data
|
/*! get input data
|
||||||
|
|
@ -246,8 +258,10 @@ restconf_reply_send(void *req0,
|
||||||
cbuf *
|
cbuf *
|
||||||
restconf_get_indata(void *req0)
|
restconf_get_indata(void *req0)
|
||||||
{
|
{
|
||||||
evhtp_request_t *req = (evhtp_request_t *)req0;
|
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
|
evhtp_request_t *req = (evhtp_request_t *)req0;
|
||||||
|
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
|
|
||||||
|
|
@ -262,7 +276,9 @@ restconf_get_indata(void *req0)
|
||||||
/* Note the pullup may not be null-terminated */
|
/* Note the pullup may not be null-terminated */
|
||||||
cbuf_append_buf(cb, buf, len);
|
cbuf_append_buf(cb, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cb;
|
return cb;
|
||||||
|
#else /* HAVE_LIBEVHTP */
|
||||||
|
return cb;
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,14 @@ static const map_str2int http_media_map[] = {
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Mapping to http proto types */
|
||||||
|
static const map_str2int http_proto_map[] = {
|
||||||
|
{"http/1.0", HTTP_10},
|
||||||
|
{"http/1.1", HTTP_11},
|
||||||
|
{"http/2", HTTP_2},
|
||||||
|
{NULL, -1}
|
||||||
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
restconf_err2code(char *tag)
|
restconf_err2code(char *tag)
|
||||||
{
|
{
|
||||||
|
|
@ -234,6 +242,18 @@ restconf_media_int2str(restconf_media media)
|
||||||
return clicon_int2str(http_media_map, media);
|
return clicon_int2str(http_media_map, media);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
restconf_str2proto(char *str)
|
||||||
|
{
|
||||||
|
return clicon_str2int(http_proto_map, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
restconf_proto2str(int proto)
|
||||||
|
{
|
||||||
|
return clicon_int2str(http_proto_map, proto);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Return media_in from Content-Type, -1 if not found or unrecognized
|
/*! Return media_in from Content-Type, -1 if not found or unrecognized
|
||||||
* @note media-type syntax does not support parameters
|
* @note media-type syntax does not support parameters
|
||||||
* @see RFC7231 Sec 3.1.1.1 for media-type syntax type:
|
* @see RFC7231 Sec 3.1.1.1 for media-type syntax type:
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,14 @@ enum ietf_ds {
|
||||||
};
|
};
|
||||||
typedef enum ietf_ds ietf_ds_t;
|
typedef enum ietf_ds ietf_ds_t;
|
||||||
|
|
||||||
|
/* Just used in native */
|
||||||
|
enum restconf_http_proto{
|
||||||
|
HTTP_10,
|
||||||
|
HTTP_11,
|
||||||
|
HTTP_2
|
||||||
|
};
|
||||||
|
typedef enum restconf_http_proto restconf_http_proto;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
|
@ -75,6 +83,8 @@ int restconf_err2code(char *tag);
|
||||||
const char *restconf_code2reason(int code);
|
const char *restconf_code2reason(int code);
|
||||||
const restconf_media restconf_media_str2int(char *media);
|
const restconf_media restconf_media_str2int(char *media);
|
||||||
const char *restconf_media_int2str(restconf_media media);
|
const char *restconf_media_int2str(restconf_media media);
|
||||||
|
int restconf_str2proto(char *str);
|
||||||
|
const char *restconf_proto2str(int proto);
|
||||||
restconf_media restconf_content_type(clicon_handle h);
|
restconf_media restconf_content_type(clicon_handle h);
|
||||||
int get_user_cookie(char *cookiestr, char *attribute, char **val);
|
int get_user_cookie(char *cookiestr, char *attribute, char **val);
|
||||||
int restconf_terminate(clicon_handle h);
|
int restconf_terminate(clicon_handle h);
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,7 @@
|
||||||
/* clicon */
|
/* clicon */
|
||||||
#include <clixon/clixon.h>
|
#include <clixon/clixon.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
/* evhtp */
|
/* evhtp */
|
||||||
#include <event2/buffer.h> /* evbuffer */
|
#include <event2/buffer.h> /* evbuffer */
|
||||||
#define EVHTP_DISABLE_REGEX
|
#define EVHTP_DISABLE_REGEX
|
||||||
|
|
@ -158,6 +159,12 @@
|
||||||
|
|
||||||
#include <evhtp/evhtp.h>
|
#include <evhtp/evhtp.h>
|
||||||
#include <evhtp/sslutils.h> /* XXX inline this / use SSL directly */
|
#include <evhtp/sslutils.h> /* XXX inline this / use SSL directly */
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
|
/* nghttp2 */
|
||||||
|
#include <nghttp2/nghttp2.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* restconf */
|
/* restconf */
|
||||||
#include "restconf_lib.h" /* generic shared with plugins */
|
#include "restconf_lib.h" /* generic shared with plugins */
|
||||||
|
|
@ -336,6 +343,7 @@ openssl_cat_log_cb(void *handle,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
static char*
|
static char*
|
||||||
evhtp_method2str(enum htp_method m)
|
evhtp_method2str(enum htp_method m)
|
||||||
{
|
{
|
||||||
|
|
@ -399,17 +407,18 @@ evhtp_method2str(enum htp_method m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
print_header(evhtp_header_t *header,
|
evhtp_print_header(evhtp_header_t *header,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
clicon_debug(1, "%s %s %s", __FUNCTION__, header->key, header->val);
|
clicon_debug(1, "%s %s %s", __FUNCTION__, header->key, header->val);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
query_iterator(evhtp_header_t *hdr,
|
evhtp_query_iterator(evhtp_header_t *hdr,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
cvec *qvec = (cvec *)arg;
|
cvec *qvec = (cvec *)arg;
|
||||||
char *key;
|
char *key;
|
||||||
|
|
@ -436,8 +445,8 @@ query_iterator(evhtp_header_t *hdr,
|
||||||
* Example: Host -> HTTP_HOST
|
* Example: Host -> HTTP_HOST
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
convert_fcgi(evhtp_header_t *hdr,
|
evhtp_convert_fcgi(evhtp_header_t *hdr,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
clicon_handle h = (clicon_handle)arg;
|
clicon_handle h = (clicon_handle)arg;
|
||||||
|
|
@ -520,7 +529,7 @@ evhtp_params_set(clicon_handle h,
|
||||||
* that would mean double parsing,...
|
* that would mean double parsing,...
|
||||||
*/
|
*/
|
||||||
if (qvec && uri->query)
|
if (qvec && uri->query)
|
||||||
if (evhtp_kvs_for_each(uri->query, query_iterator, qvec) < 0){
|
if (evhtp_kvs_for_each(uri->query, evhtp_query_iterator, qvec) < 0){
|
||||||
clicon_err(OE_CFG, errno, "evhtp_kvs_for_each");
|
clicon_err(OE_CFG, errno, "evhtp_kvs_for_each");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -558,7 +567,7 @@ evhtp_params_set(clicon_handle h,
|
||||||
/* Translate all http headers by capitalizing, prepend w HTTP_ and - -> _
|
/* Translate all http headers by capitalizing, prepend w HTTP_ and - -> _
|
||||||
* Example: Host -> HTTP_HOST
|
* Example: Host -> HTTP_HOST
|
||||||
*/
|
*/
|
||||||
if (evhtp_headers_for_each(req->headers_in, convert_fcgi, h) < 0)
|
if (evhtp_headers_for_each(req->headers_in, evhtp_convert_fcgi, h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
|
|
@ -593,7 +602,6 @@ restconf_path_root(evhtp_request_t *req,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
evhtp_connection_t *conn;
|
|
||||||
int ret;
|
int ret;
|
||||||
cvec *qvec = NULL;
|
cvec *qvec = NULL;
|
||||||
|
|
||||||
|
|
@ -602,13 +610,9 @@ restconf_path_root(evhtp_request_t *req,
|
||||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((conn = req->conn) == NULL){
|
|
||||||
clicon_err(OE_RESTCONF, EINVAL, "req->conn is NULL");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* input debug */
|
/* input debug */
|
||||||
if (clicon_debug_get())
|
if (clicon_debug_get())
|
||||||
evhtp_headers_for_each(req->headers_in, print_header, h);
|
evhtp_headers_for_each(req->headers_in, evhtp_print_header, h);
|
||||||
|
|
||||||
/* get accepted connection */
|
/* get accepted connection */
|
||||||
/* Query vector, ie the ?a=x&b=y stuff */
|
/* Query vector, ie the ?a=x&b=y stuff */
|
||||||
|
|
@ -652,7 +656,6 @@ restconf_path_wellknown(evhtp_request_t *req,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
evhtp_connection_t *conn;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
clicon_debug(1, "------------");
|
clicon_debug(1, "------------");
|
||||||
|
|
@ -660,13 +663,9 @@ restconf_path_wellknown(evhtp_request_t *req,
|
||||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((conn = req->conn) == NULL){
|
|
||||||
clicon_err(OE_RESTCONF, EINVAL, "req->conn is NULL");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* input debug */
|
/* input debug */
|
||||||
if (clicon_debug_get())
|
if (clicon_debug_get())
|
||||||
evhtp_headers_for_each(req->headers_in, print_header, h);
|
evhtp_headers_for_each(req->headers_in, evhtp_print_header, h);
|
||||||
/* get accepted connection */
|
/* get accepted connection */
|
||||||
|
|
||||||
/* set fcgi-like paramaters (ignore query vector) */
|
/* set fcgi-like paramaters (ignore query vector) */
|
||||||
|
|
@ -688,6 +687,7 @@ restconf_path_wellknown(evhtp_request_t *req,
|
||||||
}
|
}
|
||||||
return; /* void */
|
return; /* void */
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
||||||
|
|
@ -720,8 +720,8 @@ init_openssl(void)
|
||||||
* used for the certificate chain verification.
|
* used for the certificate chain verification.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
restconf_verify_certs(int preverify_ok,
|
restconf_verify_certs(int preverify_ok,
|
||||||
evhtp_x509_store_ctx_t *store)
|
X509_STORE_CTX *store)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
X509 *err_cert;
|
X509 *err_cert;
|
||||||
|
|
@ -768,7 +768,8 @@ dump_alpn_proto_list(const unsigned char *in,
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
inp = (unsigned char*)in;
|
inp = (unsigned char*)in;
|
||||||
while ((len = *inp) != 0) {
|
while ((inp-in) < inlen) {
|
||||||
|
len = *inp;
|
||||||
inp++;
|
inp++;
|
||||||
if ((str = malloc(len+1)) == NULL){
|
if ((str = malloc(len+1)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
|
@ -798,23 +799,33 @@ alpn_select_proto_cb(SSL *ssl,
|
||||||
{
|
{
|
||||||
unsigned char *inp;
|
unsigned char *inp;
|
||||||
unsigned char len;
|
unsigned char len;
|
||||||
|
int pref = 0;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (clicon_debug_get())
|
if (clicon_debug_get())
|
||||||
dump_alpn_proto_list(in, inlen);
|
dump_alpn_proto_list(in, inlen);
|
||||||
/* select http/1.1 */
|
/* select http/1.1 */
|
||||||
inp = (unsigned char*)in;
|
inp = (unsigned char*)in;
|
||||||
while ((len = *inp) != 0) {
|
while ((inp-in) < inlen) {
|
||||||
|
len = *inp;
|
||||||
inp++;
|
inp++;
|
||||||
if (len == 8 && strncmp((char*)inp, "http/1.1", len) == 0)
|
if (pref < 10 && len == 8 && strncmp((char*)inp, "http/1.1", len) == 0){
|
||||||
// if (len == 2 && strncmp((char*)inp, "h2", len) == 0)
|
*outlen = len;
|
||||||
break;
|
*out = inp;
|
||||||
|
pref = 10;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
|
/* Higher pref than http/1.1 */
|
||||||
|
else if (pref < 20 && len == 2 && strncmp((char*)inp, "h2", len) == 0){
|
||||||
|
*outlen = len;
|
||||||
|
*out = inp;
|
||||||
|
pref = 20;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
inp += len;
|
inp += len;
|
||||||
}
|
}
|
||||||
if (len == 0)
|
if (pref == 0)
|
||||||
return SSL_TLSEXT_ERR_NOACK;
|
return SSL_TLSEXT_ERR_NOACK;
|
||||||
*outlen = len;
|
|
||||||
*out = inp;
|
|
||||||
return SSL_TLSEXT_ERR_OK;
|
return SSL_TLSEXT_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -912,13 +923,12 @@ restconf_ssl_context_configure(clixon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Free clixon/cbuf resources related to an evhtp connection
|
/*! Free clixon/cbuf resources related to an evhtp connection
|
||||||
|
* @param[in] rc restconf connection
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
restconf_conn_free(evhtp_connection_t *conn)
|
restconf_conn_free(restconf_conn_h *rc)
|
||||||
{
|
{
|
||||||
restconf_conn_h *rc;
|
if (rc != NULL){
|
||||||
|
|
||||||
if ((rc = conn->arg) != NULL){
|
|
||||||
if (rc->rc_outp_hdrs)
|
if (rc->rc_outp_hdrs)
|
||||||
cvec_free(rc->rc_outp_hdrs);
|
cvec_free(rc->rc_outp_hdrs);
|
||||||
if (rc->rc_outp_buf)
|
if (rc->rc_outp_buf)
|
||||||
|
|
@ -933,31 +943,33 @@ restconf_conn_free(evhtp_connection_t *conn)
|
||||||
* and always use this function, but it is difficult.
|
* and always use this function, but it is difficult.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
close_ssl_evhtp_socket(int s,
|
close_ssl_socket(restconf_conn_h *rc,
|
||||||
evhtp_connection_t *conn,
|
int shutdown)
|
||||||
int shutdown)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int ret;
|
int ret;
|
||||||
SSL *ssl;
|
#ifdef HAVE_LIBEVHTP
|
||||||
|
evhtp_connection_t *evconn;
|
||||||
|
|
||||||
ssl = conn->ssl;
|
evconn = (evhtp_connection_t *)rc->rc_arg;
|
||||||
clicon_debug(1, "%s conn-free (%p) 1", __FUNCTION__, conn);
|
clicon_debug(1, "%s evconn-free (%p) 1", __FUNCTION__, evconn);
|
||||||
restconf_conn_free(conn);
|
evhtp_connection_free(evconn); /* evhtp */
|
||||||
evhtp_connection_free(conn); /* evhtp */
|
#endif /* HAVE_LIBEVHTP */
|
||||||
if (ssl != NULL){
|
if (rc->rc_ssl != NULL){
|
||||||
if (shutdown && (ret = SSL_shutdown(ssl)) < 0){
|
if (shutdown && (ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
||||||
int e = SSL_get_error(ssl, ret);
|
int e = SSL_get_error(rc->rc_ssl, ret);
|
||||||
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
SSL_free(ssl);
|
SSL_free(rc->rc_ssl);
|
||||||
|
rc->rc_ssl = NULL;
|
||||||
}
|
}
|
||||||
if (close(s) < 0){
|
if (close(rc->rc_s) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "close");
|
clicon_err(OE_UNIX, errno, "close");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clixon_event_unreg_fd(s, restconf_connection);
|
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||||
|
restconf_conn_free(rc);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
|
|
@ -1023,85 +1035,89 @@ restconf_connection(int s,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
evhtp_connection_t *conn = NULL;
|
restconf_conn_h *rc = NULL;
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
char buf[BUFSIZ]; /* from stdio.h, typically 8K */
|
char buf[BUFSIZ]; /* from stdio.h, typically 8K */
|
||||||
clicon_handle h;
|
|
||||||
int readmore = 1;
|
int readmore = 1;
|
||||||
restconf_conn_h *rc;
|
#ifdef HAVE_LIBEVHTP
|
||||||
|
clicon_handle h;
|
||||||
|
evhtp_connection_t *evconn = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s %d", __FUNCTION__, s);
|
||||||
if ((conn = (evhtp_connection_t*)arg) == NULL){
|
if ((rc = (restconf_conn_h*)arg) == NULL){
|
||||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
h = (clicon_handle*)conn->htp->arg;
|
assert(s == rc->rc_s);
|
||||||
while (readmore) {
|
while (readmore) {
|
||||||
clicon_debug(1, "%s readmore", __FUNCTION__);
|
clicon_debug(1, "%s readmore", __FUNCTION__);
|
||||||
readmore = 0;
|
readmore = 0;
|
||||||
/* Example: curl -Ssik -u wilma:bar -X GET https://localhost/restconf/data/example:x */
|
/* Example: curl -Ssik -u wilma:bar -X GET https://localhost/restconf/data/example:x */
|
||||||
if (conn->ssl){
|
if (rc->rc_ssl){
|
||||||
/* Non-ssl gets n == 0 here!
|
/* Non-ssl gets n == 0 here!
|
||||||
curl -Ssik --key /var/tmp/./test_restconf_ssl_certs.sh/certs/limited.key --cert /var/tmp/./test_restconf_ssl_certs.sh/certs/limited.crt -X GET https://localhost/restconf/data/example:x
|
curl -Ssik --key /var/tmp/./test_restconf_ssl_certs.sh/certs/limited.key --cert /var/tmp/./test_restconf_ssl_certs.sh/certs/limited.crt -X GET https://localhost/restconf/data/example:x
|
||||||
*/
|
*/
|
||||||
if ((n = SSL_read(conn->ssl, buf, sizeof(buf))) < 0){
|
if ((n = SSL_read(rc->rc_ssl, buf, sizeof(buf))) < 0){
|
||||||
clicon_err(OE_XML, errno, "SSL_read");
|
clicon_err(OE_XML, errno, "SSL_read");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if ((n = read(conn->sock, buf, sizeof(buf))) < 0){ /* XXX atomicio ? */
|
if ((n = read(rc->rc_s, buf, sizeof(buf))) < 0){ /* XXX atomicio ? */
|
||||||
if (errno == ECONNRESET) {/* Connection reset by peer */
|
if (errno == ECONNRESET) {/* Connection reset by peer */
|
||||||
close(conn->sock);
|
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
|
||||||
restconf_conn_free(conn);
|
close(rc->rc_s);
|
||||||
clixon_event_unreg_fd(conn->sock, restconf_connection);
|
restconf_conn_free(rc);
|
||||||
|
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||||
goto ok; /* Close socket and ssl */
|
goto ok; /* Close socket and ssl */
|
||||||
}
|
}
|
||||||
clicon_err(OE_XML, errno, "read");
|
clicon_err(OE_XML, errno, "read");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clicon_debug(1, "%s read:%ld", __FUNCTION__, n);
|
||||||
if (n == 0){
|
if (n == 0){
|
||||||
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
|
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
|
||||||
if (close_ssl_evhtp_socket(s, conn, 1) < 0)
|
if (close_ssl_socket(rc, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
/* parse incoming packet
|
#ifdef HAVE_LIBEVHTP
|
||||||
|
h = rc->rc_h;
|
||||||
|
/* parse incoming packet using evhtp
|
||||||
* signature:
|
* signature:
|
||||||
*/
|
*/
|
||||||
if (connection_parse_nobev(buf, n, conn) < 0){
|
evconn = (evhtp_connection_t*)rc->rc_arg;
|
||||||
|
if (connection_parse_nobev(buf, n, evconn) < 0){
|
||||||
clicon_debug(1, "%s connection_parse error", __FUNCTION__);
|
clicon_debug(1, "%s connection_parse error", __FUNCTION__);
|
||||||
/* XXX To get more nuanced evhtp error check
|
/* XXX To get more nuanced evhtp error check
|
||||||
* htparser_get_error(conn->parser)
|
* htparser_get_error(conn->parser)
|
||||||
*/
|
*/
|
||||||
if (send_badrequest(h, s, conn->ssl, "application/yang-data+xml",
|
if (send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml",
|
||||||
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>The requested URL or a header is in some way badly formed</error-message></error></errors>") < 0)
|
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>The requested URL or a header is in some way badly formed</error-message></error></errors>") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
SSL_free(conn->ssl);
|
SSL_free(rc->rc_ssl);
|
||||||
if (close(s) < 0){
|
rc->rc_ssl = NULL;
|
||||||
|
evconn->ssl = NULL;
|
||||||
|
if (close(rc->rc_s) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "close");
|
clicon_err(OE_UNIX, errno, "close");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clixon_event_unreg_fd(s, restconf_connection);
|
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||||
conn->ssl = NULL;
|
clicon_debug(1, "%s evconn-free (%p) 2", __FUNCTION__, evconn);
|
||||||
clicon_debug(1, "%s conn-free (%p) 2", __FUNCTION__, conn);
|
restconf_conn_free(rc);
|
||||||
restconf_conn_free(conn);
|
evhtp_connection_free(evconn);
|
||||||
evhtp_connection_free(conn);
|
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s connection_parse OK", __FUNCTION__);
|
clicon_debug(1, "%s connection_parse OK", __FUNCTION__);
|
||||||
if (conn->bev != NULL){
|
if (evconn->bev != NULL){
|
||||||
struct evbuffer *ev;
|
struct evbuffer *ev;
|
||||||
size_t buflen0;
|
size_t buflen0;
|
||||||
size_t buflen1;
|
size_t buflen1;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
|
|
||||||
if ((rc = conn->arg) == NULL){
|
if ((ev = bufferevent_get_output(evconn->bev)) != NULL){
|
||||||
clicon_err(OE_RESTCONF, EFAULT, "Internal error: restconf-conn-h is NULL: shouldnt happen");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((ev = bufferevent_get_output(conn->bev)) != NULL){
|
|
||||||
buflen0 = evbuffer_get_length(ev);
|
buflen0 = evbuffer_get_length(ev);
|
||||||
buflen1 = buflen0 - rc->rc_bufferevent_output_offset;
|
buflen1 = buflen0 - rc->rc_bufferevent_output_offset;
|
||||||
if (buflen1 > 0){
|
if (buflen1 > 0){
|
||||||
|
|
@ -1126,17 +1142,19 @@ restconf_connection(int s,
|
||||||
if (cbuf_len(rc->rc_outp_buf) == 0)
|
if (cbuf_len(rc->rc_outp_buf) == 0)
|
||||||
readmore = 1;
|
readmore = 1;
|
||||||
else {
|
else {
|
||||||
if (buf_write(cbuf_get(rc->rc_outp_buf), cbuf_len(rc->rc_outp_buf), conn->sock, conn->ssl) < 0)
|
if (buf_write(cbuf_get(rc->rc_outp_buf), cbuf_len(rc->rc_outp_buf),
|
||||||
|
rc->rc_s, rc->rc_ssl) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cvec_reset(rc->rc_outp_hdrs); /* Can be done in native_send_reply */
|
cvec_reset(rc->rc_outp_hdrs); /* Can be done in native_send_reply */
|
||||||
cbuf_reset(rc->rc_outp_buf);
|
cbuf_reset(rc->rc_outp_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (send_badrequest(h, s, conn->ssl, "application/yang-data+xml",
|
if (send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml",
|
||||||
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>No evhtp output</error-message></error></errors>") < 0)
|
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>No evhtp output</error-message></error></errors>") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
} /* while readmore */
|
} /* while readmore */
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -1211,6 +1229,89 @@ restconf_checkcert_file(cxobj *xrestconf,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Check ALPN result
|
||||||
|
* @proto[out] proto
|
||||||
|
* @retval 1 OK with proto set
|
||||||
|
* @retval 0 Fail, ALPN null or not recognized
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ssl_alpn_check(clicon_handle h,
|
||||||
|
const unsigned char *alpn,
|
||||||
|
unsigned int alpnlen,
|
||||||
|
restconf_conn_h *rc,
|
||||||
|
restconf_http_proto *proto)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int ret;
|
||||||
|
cbuf *cberr = NULL;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
|
/* Alternatively, call restconf_str2proto but alpn is not a proper string */
|
||||||
|
if (alpn && alpnlen == 8 && memcmp("http/1.1", alpn, 8) == 0){
|
||||||
|
*proto = HTTP_11;
|
||||||
|
retval = 1; /* http/1.1 */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
|
else if (alpn && alpnlen == 2 && memcmp("h2", alpn, 2) == 0){
|
||||||
|
*proto = HTTP_2;
|
||||||
|
retval = 1; /* http/2 */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
if ((cberr = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (alpn != NULL){
|
||||||
|
cprintf(cberr, "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>ALPN: protocol not recognized: %s</error-message></error></errors>", alpn);
|
||||||
|
clicon_log(LOG_NOTICE, "Warning: %s", cbuf_get(cberr));
|
||||||
|
if (send_badrequest(h, rc->rc_s, rc->rc_ssl,
|
||||||
|
"application/yang-data+xml",
|
||||||
|
cbuf_get(cberr)) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/* XXX Sending badrequest here gives a segv in SSL_shutdown() later or a SIGPIPE here */
|
||||||
|
clicon_log(LOG_NOTICE, "Warning: ALPN: No protocol selected");
|
||||||
|
}
|
||||||
|
restconf_conn_free(rc);
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
|
{
|
||||||
|
evhtp_connection_t *evconn;
|
||||||
|
|
||||||
|
if ((evconn = (evhtp_connection_t *)rc->rc_arg) != NULL)
|
||||||
|
evhtp_connection_free(evconn); /* evhtp */
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
|
if (rc->rc_ssl){
|
||||||
|
/* nmap ssl-known-key SEGV at s->method->ssl_shutdown(s);
|
||||||
|
* OR OpenSSL error: : SSL_shutdown, err: SSL_ERROR_SYSCALL(5)
|
||||||
|
*/
|
||||||
|
if ((ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
||||||
|
int e = SSL_get_error(rc->rc_ssl, ret);
|
||||||
|
if (e == SSL_ERROR_SYSCALL){
|
||||||
|
clicon_log(LOG_NOTICE, "Warning: SSL_shutdown SSL_ERROR_SYSCALL");
|
||||||
|
/* Continue */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SSL_free(rc->rc_ssl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0; /* ALPN not OK */
|
||||||
|
done:
|
||||||
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
|
if (cberr)
|
||||||
|
cbuf_free(cberr);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Accept new socket client
|
/*! Accept new socket client
|
||||||
* @param[in] fd Socket (unix or ip)
|
* @param[in] fd Socket (unix or ip)
|
||||||
* @param[in] arg typecast clicon_handle
|
* @param[in] arg typecast clicon_handle
|
||||||
|
|
@ -1220,31 +1321,33 @@ static int
|
||||||
restconf_accept_client(int fd,
|
restconf_accept_client(int fd,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
restconf_socket *rsock = (restconf_socket *)arg;
|
restconf_socket *rsock;
|
||||||
restconf_native_handle *rh = NULL;
|
restconf_native_handle *rh = NULL;
|
||||||
restconf_conn_h *rc = NULL;
|
restconf_conn_h *rc = NULL;
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
int s;
|
int s;
|
||||||
struct sockaddr from = {0,};
|
struct sockaddr from = {0,};
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
SSL *ssl = NULL; /* structure for ssl connection */
|
int ret;
|
||||||
int ret;
|
int e;
|
||||||
evhtp_t *evhtp = NULL;
|
int er;
|
||||||
evhtp_connection_t *conn;
|
int readmore;
|
||||||
int e;
|
X509 *peercert;
|
||||||
int er;
|
const unsigned char *alpn = NULL;
|
||||||
int readmore;
|
unsigned int alpnlen = 0;
|
||||||
X509 *peercert;
|
restconf_http_proto proto = HTTP_11; /* Non-SSL negotiation NYI */
|
||||||
const unsigned char *alpn = NULL;
|
|
||||||
unsigned int alpnlen = 0;
|
|
||||||
|
|
||||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||||
if (rsock == NULL){
|
if ((rsock = (restconf_socket *)arg) == NULL){
|
||||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
clicon_debug(1, "%s type:%s addr:%s port:%hu", __FUNCTION__,
|
||||||
|
rsock->rs_addrtype,
|
||||||
|
rsock->rs_addrstr,
|
||||||
|
rsock->rs_port);
|
||||||
h = rsock->rs_h;
|
h = rsock->rs_h;
|
||||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
if ((rh = restconf_native_handle_get(h)) == NULL){
|
||||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||||
|
|
@ -1255,24 +1358,38 @@ restconf_accept_client(int fd,
|
||||||
clicon_err(OE_UNIX, errno, "accept");
|
clicon_err(OE_UNIX, errno, "accept");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
evhtp = rh->rh_evhtp;
|
/*
|
||||||
if ((conn = evhtp_connection_new_server(evhtp, s)) == NULL){
|
* Register callbacks for actual data socket
|
||||||
clicon_err(OE_UNIX, errno, "evhtp_connection_new_server");
|
*/
|
||||||
|
if ((rc = (restconf_conn_h*)malloc(sizeof(restconf_conn_h))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(rc, 0, sizeof(restconf_conn_h));
|
||||||
|
rc->rc_h = h;
|
||||||
|
rc->rc_s = s;
|
||||||
|
clicon_debug(1, "%s s:%d", __FUNCTION__, rc->rc_s);
|
||||||
|
if ((rc->rc_outp_hdrs = cvec_new(0)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((rc->rc_outp_buf = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s conn-new (%p)", __FUNCTION__, conn);
|
|
||||||
if (rsock->rs_ssl){
|
if (rsock->rs_ssl){
|
||||||
if ((ssl = SSL_new(rh->rh_ctx)) == NULL){
|
if ((rc->rc_ssl = SSL_new(rh->rh_ctx)) == NULL){
|
||||||
clicon_err(OE_SSL, 0, "SSL_new");
|
clicon_err(OE_SSL, 0, "SSL_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s SSL_new(%p)", __FUNCTION__, ssl);
|
clicon_debug(1, "%s SSL_new(%p)", __FUNCTION__, rc->rc_ssl);
|
||||||
/* CCL_CTX_set_verify already set, need not call SSL_set_verify again for this server
|
/* CCL_CTX_set_verify already set, need not call SSL_set_verify again for this server
|
||||||
*/
|
*/
|
||||||
/* X509_CHECK_FLAG_NO_WILDCARDS disables wildcard expansion */
|
/* X509_CHECK_FLAG_NO_WILDCARDS disables wildcard expansion */
|
||||||
SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_WILDCARDS);
|
SSL_set_hostflags(rc->rc_ssl, X509_CHECK_FLAG_NO_WILDCARDS);
|
||||||
#if 0
|
#if 0
|
||||||
/* Enable this if you want to restrict client certs to a specific set.
|
/* XXX This code is kept for the time being just for reference, it does not belong here.
|
||||||
|
* If you want to restrict client certs to a specific set.
|
||||||
* Otherwise this is done in restcon ca-auth callback and ultimately NACM
|
* Otherwise this is done in restcon ca-auth callback and ultimately NACM
|
||||||
* SSL_set1_host() sets the expected DNS hostname to name
|
* SSL_set1_host() sets the expected DNS hostname to name
|
||||||
C = SE
|
C = SE
|
||||||
|
|
@ -1282,17 +1399,16 @@ restconf_accept_client(int fd,
|
||||||
CN = ca <---
|
CN = ca <---
|
||||||
emailAddress = olof@hagsand.se
|
emailAddress = olof@hagsand.se
|
||||||
*/
|
*/
|
||||||
if (SSL_set1_host(ssl, "andy") != 1) { /* for peer cert */
|
if (SSL_set1_host(rc->rc_ssl, "andy") != 1) { /* for peer cert */
|
||||||
clicon_err(OE_SSL, 0, "SSL_set1_host");
|
clicon_err(OE_SSL, 0, "SSL_set1_host");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (SSL_add1_host(ssl, "olof") != 1) { /* for peer cert */
|
if (SSL_add1_host(rc->rc_ssl, "olof") != 1) { /* for peer cert */
|
||||||
clicon_err(OE_SSL, 0, "SSL_set1_host");
|
clicon_err(OE_SSL, 0, "SSL_set1_host");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
conn->ssl = ssl; /* evhtp */
|
if (SSL_set_fd(rc->rc_ssl, rc->rc_s) != 1){
|
||||||
if (SSL_set_fd(ssl, s) != 1){
|
|
||||||
clicon_err(OE_SSL, 0, "SSL_set_fd");
|
clicon_err(OE_SSL, 0, "SSL_set_fd");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1302,30 +1418,25 @@ restconf_accept_client(int fd,
|
||||||
/* 1: OK, -1 fatal, 0: TLS/SSL handshake was not successful
|
/* 1: OK, -1 fatal, 0: TLS/SSL handshake was not successful
|
||||||
* Both error cases: Call SSL_get_error() with the return value ret
|
* Both error cases: Call SSL_get_error() with the return value ret
|
||||||
*/
|
*/
|
||||||
if ((ret = SSL_accept(ssl)) != 1) {
|
if ((ret = SSL_accept(rc->rc_ssl)) != 1) {
|
||||||
clicon_debug(1, "%s SSL_accept() ret:%d errno:%d", __FUNCTION__, ret, er=errno);
|
clicon_debug(1, "%s SSL_accept() ret:%d errno:%d", __FUNCTION__, ret, er=errno);
|
||||||
e = SSL_get_error(ssl, ret);
|
e = SSL_get_error(rc->rc_ssl, ret);
|
||||||
switch (e){
|
switch (e){
|
||||||
case SSL_ERROR_SSL: /* 1 */
|
case SSL_ERROR_SSL: /* 1 */
|
||||||
clicon_debug(1, "%s SSL_ERROR_SSL (non-ssl message on ssl socket)", __FUNCTION__);
|
clicon_debug(1, "%s SSL_ERROR_SSL (non-ssl message on ssl socket)", __FUNCTION__);
|
||||||
#if 0
|
#if 1
|
||||||
/* XXX sending a bad request here may crash
|
if (send_badrequest(h, rc->rc_s, NULL, "application/yang-data+xml",
|
||||||
* eg when run nmap --script ssl*
|
|
||||||
*/
|
|
||||||
if (send_badrequest(h, s, NULL, "application/yang-data+xml",
|
|
||||||
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>The plain HTTP request was sent to HTTPS port</error-message></error></errors>") < 0)
|
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>The plain HTTP request was sent to HTTPS port</error-message></error></errors>") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
#endif
|
#endif
|
||||||
SSL_free(ssl);
|
SSL_free(rc->rc_ssl);
|
||||||
if (close(s) < 0){
|
rc->rc_ssl = NULL;
|
||||||
|
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||||
|
if (close(rc->rc_s) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "close");
|
clicon_err(OE_UNIX, errno, "close");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clixon_event_unreg_fd(s, restconf_connection);
|
restconf_conn_free(rc);
|
||||||
conn->ssl = NULL;
|
|
||||||
clicon_debug(1, "%s conn-free (%p) 3", __FUNCTION__, conn);
|
|
||||||
restconf_conn_free(conn);
|
|
||||||
evhtp_connection_free(conn); /* evhtp */
|
|
||||||
goto ok;
|
goto ok;
|
||||||
break;
|
break;
|
||||||
case SSL_ERROR_SYSCALL: /* 5 */
|
case SSL_ERROR_SYSCALL: /* 5 */
|
||||||
|
|
@ -1335,7 +1446,7 @@ restconf_accept_client(int fd,
|
||||||
operations should be performed on the connection and SSL_shutdown() must
|
operations should be performed on the connection and SSL_shutdown() must
|
||||||
not be called.*/
|
not be called.*/
|
||||||
clicon_debug(1, "%s SSL_accept() SSL_ERROR_SYSCALL %d", __FUNCTION__, er);
|
clicon_debug(1, "%s SSL_accept() SSL_ERROR_SYSCALL %d", __FUNCTION__, er);
|
||||||
if (close_ssl_evhtp_socket(s, conn, 0) < 0)
|
if (close_ssl_socket(rc, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1365,7 +1476,7 @@ restconf_accept_client(int fd,
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} /* SSL_accept */
|
||||||
} /* while(readmore) */
|
} /* while(readmore) */
|
||||||
/* For client-cert authentication, check if any certs are present,
|
/* For client-cert authentication, check if any certs are present,
|
||||||
* if not, send bad request
|
* if not, send bad request
|
||||||
|
|
@ -1373,53 +1484,43 @@ restconf_accept_client(int fd,
|
||||||
* but then SSL_accept fails.
|
* but then SSL_accept fails.
|
||||||
*/
|
*/
|
||||||
if (restconf_auth_type_get(h) == CLIXON_AUTH_CLIENT_CERTIFICATE){
|
if (restconf_auth_type_get(h) == CLIXON_AUTH_CLIENT_CERTIFICATE){
|
||||||
if ((peercert = SSL_get_peer_certificate(ssl)) != NULL){
|
if ((peercert = SSL_get_peer_certificate(rc->rc_ssl)) != NULL){
|
||||||
X509_free(peercert);
|
X509_free(peercert);
|
||||||
}
|
}
|
||||||
else { /* Get certificates (if available) */
|
else { /* Get certificates (if available) */
|
||||||
if (send_badrequest(h, s, ssl, "application/yang-data+xml", "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>Peer certificate required</error-message></error></errors>") < 0)
|
if (send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml",
|
||||||
|
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>Peer certificate required</error-message></error></errors>") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
restconf_conn_free(conn);
|
restconf_conn_free(rc);
|
||||||
evhtp_connection_free(conn); /* evhtp */
|
if (rc->rc_ssl){
|
||||||
if (ssl){
|
if ((ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
||||||
if ((ret = SSL_shutdown(ssl)) < 0){
|
int e = SSL_get_error(rc->rc_ssl, ret);
|
||||||
int e = SSL_get_error(ssl, ret);
|
|
||||||
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
SSL_free(ssl);
|
SSL_free(rc->rc_ssl);
|
||||||
|
rc->rc_ssl = NULL;
|
||||||
}
|
}
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Sets data and len to point to the client's requested protocol for this connection. */
|
/* Sets data and len to point to the client's requested protocol for this connection. */
|
||||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
SSL_get0_next_proto_negotiated(rc->rc_ssl, &alpn, &alpnlen);
|
||||||
if (alpn == NULL) {
|
if (alpn == NULL) {
|
||||||
/* Returns a pointer to the selected protocol in data with length len. */
|
/* Returns a pointer to the selected protocol in data with length len. */
|
||||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
SSL_get0_alpn_selected(rc->rc_ssl, &alpn, &alpnlen);
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s ALPN: %d %s", __FUNCTION__, alpnlen, alpn);
|
if ((ret = ssl_alpn_check(h, alpn, alpnlen, rc, &proto)) < 0)
|
||||||
if (alpn == NULL || alpnlen != 8 || memcmp("http/1.1", alpn, 8) != 0) {
|
goto done;
|
||||||
clicon_log(LOG_NOTICE, "------Warning1 Protocol http/1.1 not selected: %s", alpn);
|
if (ret == 0)
|
||||||
if (send_badrequest(h, s, ssl, "application/yang-data+xml", "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>Peer certificate required</error-message></error></errors>") < 0)
|
|
||||||
goto done;
|
|
||||||
restconf_conn_free(conn);
|
|
||||||
evhtp_connection_free(conn); /* evhtp */
|
|
||||||
if (ssl){
|
|
||||||
if ((ret = SSL_shutdown(ssl)) < 0){
|
|
||||||
int e = SSL_get_error(ssl, ret);
|
|
||||||
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
SSL_free(ssl);
|
|
||||||
}
|
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
clicon_debug(1, "%s proto:%s", __FUNCTION__, restconf_proto2str(proto));
|
||||||
/* Get the actual peer, XXX this maybe could be done in ca-auth client-cert code ?
|
/* Get the actual peer, XXX this maybe could be done in ca-auth client-cert code ?
|
||||||
* Note this _only_ works if SSL_set1_host() was set previously,...
|
* Note this _only_ works if SSL_set1_host() was set previously,...
|
||||||
*/
|
*/
|
||||||
if (SSL_get_verify_result(ssl) == X509_V_OK) { /* for peer cert */
|
if (SSL_get_verify_result(rc->rc_ssl) == X509_V_OK) { /* for peer cert */
|
||||||
const char *peername = SSL_get0_peername(ssl);
|
|
||||||
|
const char *peername = SSL_get0_peername(rc->rc_ssl);
|
||||||
|
|
||||||
if (peername != NULL) {
|
if (peername != NULL) {
|
||||||
/* Name checks were in scope and matched the peername */
|
/* Name checks were in scope and matched the peername */
|
||||||
|
|
@ -1428,27 +1529,33 @@ restconf_accept_client(int fd,
|
||||||
}
|
}
|
||||||
#if 0 /* debug */
|
#if 0 /* debug */
|
||||||
if (clicon_debug_get())
|
if (clicon_debug_get())
|
||||||
restconf_listcerts(ssl);
|
restconf_listcerts(rc->rc_ssl);
|
||||||
#endif
|
#endif
|
||||||
|
} /* if ssl */
|
||||||
|
rc->rc_proto = proto;
|
||||||
|
switch (rc->rc_proto){
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
|
case HTTP_10:
|
||||||
|
case HTTP_11:{
|
||||||
|
evhtp_connection_t *evconn;
|
||||||
|
/* Create evhtp-specific struct */
|
||||||
|
if ((evconn = evhtp_connection_new_server(rh->rh_evhtp, rc->rc_s)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "evhtp_connection_new_server");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Mutual pointers, from generic rc to evhtp specific and from evhtp conn to generic
|
||||||
|
*/
|
||||||
|
rc->rc_arg = evconn; /* Generic to specific */
|
||||||
|
evconn->arg = rc; /* Specific to generic */
|
||||||
|
evconn->ssl = rc->rc_ssl; /* evhtp */
|
||||||
}
|
}
|
||||||
/*
|
break;
|
||||||
* Register callbacks for actual data socket
|
#endif /* HAVE_LIBEVHTP */
|
||||||
*/
|
case HTTP_2:
|
||||||
if ((rc = (restconf_conn_h*)malloc(sizeof(restconf_conn_h))) == NULL){
|
default:
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
break;
|
||||||
goto done;
|
} /* switch proto */
|
||||||
}
|
if (clixon_event_reg_fd(rc->rc_s, restconf_connection, (void*)rc, "restconf client socket") < 0)
|
||||||
memset(rc, 0, sizeof(restconf_conn_h));
|
|
||||||
if ((rc->rc_outp_hdrs = cvec_new(0)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((rc->rc_outp_buf = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
conn->arg = rc;
|
|
||||||
if (clixon_event_reg_fd(s, restconf_connection, (void*)conn, "restconf client socket") < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -1463,7 +1570,7 @@ static int
|
||||||
restconf_native_terminate(clicon_handle h)
|
restconf_native_terminate(clicon_handle h)
|
||||||
{
|
{
|
||||||
restconf_native_handle *rh;
|
restconf_native_handle *rh;
|
||||||
restconf_socket *rsock;
|
restconf_socket *rsock;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((rh = restconf_native_handle_get(h)) != NULL){
|
if ((rh = restconf_native_handle_get(h)) != NULL){
|
||||||
|
|
@ -1471,15 +1578,22 @@ restconf_native_terminate(clicon_handle h)
|
||||||
clixon_event_unreg_fd(rsock->rs_ss, restconf_accept_client);
|
clixon_event_unreg_fd(rsock->rs_ss, restconf_accept_client);
|
||||||
close(rsock->rs_ss);
|
close(rsock->rs_ss);
|
||||||
DELQ(rsock, rh->rh_sockets, restconf_socket *);
|
DELQ(rsock, rh->rh_sockets, restconf_socket *);
|
||||||
|
if (rsock->rs_addrstr)
|
||||||
|
free(rsock->rs_addrstr);
|
||||||
|
if (rsock->rs_addrtype)
|
||||||
|
free(rsock->rs_addrtype);
|
||||||
free(rsock);
|
free(rsock);
|
||||||
}
|
}
|
||||||
if (rh->rh_ctx)
|
if (rh->rh_ctx)
|
||||||
SSL_CTX_free(rh->rh_ctx);
|
SSL_CTX_free(rh->rh_ctx);
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
if (rh->rh_evhtp){
|
if (rh->rh_evhtp){
|
||||||
if (rh->rh_evhtp->evbase)
|
if (rh->rh_evhtp->evbase)
|
||||||
event_base_free(rh->rh_evhtp->evbase);
|
event_base_free(rh->rh_evhtp->evbase);
|
||||||
evhtp_free(rh->rh_evhtp);
|
evhtp_free(rh->rh_evhtp);
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
|
|
||||||
free(rh);
|
free(rh);
|
||||||
}
|
}
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
|
|
@ -1596,6 +1710,7 @@ openssl_init_socket(clicon_handle h,
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Create per-socket openssl handle
|
* Create per-socket openssl handle
|
||||||
|
* See restconf_native_terminate for freeing
|
||||||
*/
|
*/
|
||||||
if ((rsock = malloc(sizeof *rsock)) == NULL){
|
if ((rsock = malloc(sizeof *rsock)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
|
@ -1605,6 +1720,15 @@ openssl_init_socket(clicon_handle h,
|
||||||
rsock->rs_h = h;
|
rsock->rs_h = h;
|
||||||
rsock->rs_ss = ss;
|
rsock->rs_ss = ss;
|
||||||
rsock->rs_ssl = ssl;
|
rsock->rs_ssl = ssl;
|
||||||
|
if ((rsock->rs_addrstr = strdup(address)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((rsock->rs_addrtype = strdup(addrtype)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
rsock->rs_port = port;
|
||||||
INSQ(rsock, rh->rh_sockets);
|
INSQ(rsock, rh->rh_sockets);
|
||||||
|
|
||||||
/* ss is a server socket that the clients connect to. The callback
|
/* ss is a server socket that the clients connect to. The callback
|
||||||
|
|
@ -1643,8 +1767,10 @@ restconf_openssl_init(clicon_handle h,
|
||||||
cxobj **vec = NULL;
|
cxobj **vec = NULL;
|
||||||
size_t veclen;
|
size_t veclen;
|
||||||
int i;
|
int i;
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
evhtp_t *evhtp = NULL;
|
evhtp_t *evhtp = NULL;
|
||||||
struct event_base *evbase = NULL;
|
struct event_base *evbase = NULL;
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
/* flag used for sanity of certs */
|
/* flag used for sanity of certs */
|
||||||
|
|
@ -1699,6 +1825,7 @@ restconf_openssl_init(clicon_handle h,
|
||||||
}
|
}
|
||||||
rh = restconf_native_handle_get(h);
|
rh = restconf_native_handle_get(h);
|
||||||
rh->rh_ctx = ctx;
|
rh->rh_ctx = ctx;
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
/* evhtp stuff */ /* XXX move this to global level */
|
/* evhtp stuff */ /* XXX move this to global level */
|
||||||
if ((evbase = event_base_new()) == NULL){
|
if ((evbase = event_base_new()) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "event_base_new");
|
clicon_err(OE_UNIX, errno, "event_base_new");
|
||||||
|
|
@ -1719,6 +1846,7 @@ restconf_openssl_init(clicon_handle h,
|
||||||
clicon_err(OE_EVENTS, errno, "evhtp_set_cb");
|
clicon_err(OE_EVENTS, errno, "evhtp_set_cb");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_LIBEVHTP */
|
||||||
/* get the list of socket config-data */
|
/* get the list of socket config-data */
|
||||||
if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0)
|
if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,10 @@ api_data_write(clicon_handle h,
|
||||||
cxobj *xfrom;
|
cxobj *xfrom;
|
||||||
cxobj *xac;
|
cxobj *xac;
|
||||||
|
|
||||||
xfrom = (api_path && strcmp(api_path,"/"))?xml_parent(xbot):xbot; // XXX xbot is /config has NULL parent
|
if (api_path && (strcmp(api_path, "/") != 0))
|
||||||
|
xfrom = xml_parent(xbot);
|
||||||
|
else
|
||||||
|
xfrom = xbot; // XXX xbot is /config has NULL parent
|
||||||
if (xml_copy_one(xfrom, xdata0) < 0)
|
if (xml_copy_one(xfrom, xdata0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
xa = NULL;
|
xa = NULL;
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,15 @@ extern "C" {
|
||||||
* Per connection request
|
* Per connection request
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// qelem_t rs_qelem; /* List header */
|
// qelem_t rs_qelem; /* List header */
|
||||||
cvec *rc_outp_hdrs; /* List of output headers */
|
cvec *rc_outp_hdrs; /* List of output headers */
|
||||||
cbuf *rc_outp_buf; /* Output buffer */
|
cbuf *rc_outp_buf; /* Output buffer */
|
||||||
size_t rc_bufferevent_output_offset; /* Kludge to drain libevent output buffer */
|
size_t rc_bufferevent_output_offset; /* Kludge to drain libevent output buffer */
|
||||||
|
restconf_http_proto rc_proto; /* HTTP protocol: http/1 or http/2 */
|
||||||
|
int rc_s; /* Connection socket */
|
||||||
|
clicon_handle rc_h; /* Clixon handle */
|
||||||
|
SSL *rc_ssl; /* Structure for SSL connection */
|
||||||
|
void *rc_arg; /* Specific connection pointer, eg evhtp conn struct */
|
||||||
} restconf_conn_h;
|
} restconf_conn_h;
|
||||||
|
|
||||||
/* Restconf request handle
|
/* Restconf request handle
|
||||||
|
|
@ -77,6 +82,10 @@ typedef struct {
|
||||||
clicon_handle rs_h; /* Clixon handle */
|
clicon_handle rs_h; /* Clixon handle */
|
||||||
int rs_ss; /* Server socket (ready for accept) */
|
int rs_ss; /* Server socket (ready for accept) */
|
||||||
int rs_ssl; /* 0: Not SSL socket, 1:SSL socket */
|
int rs_ssl; /* 0: Not SSL socket, 1:SSL socket */
|
||||||
|
char *rs_addrtype; /* Address type according to ietf-inet-types:
|
||||||
|
eg inet:ipv4-address or inet:ipv6-address */
|
||||||
|
char *rs_addrstr; /* Address as string, eg 127.0.0.1, ::1 */
|
||||||
|
uint16_t rs_port; /* Protocol port */
|
||||||
} restconf_socket;
|
} restconf_socket;
|
||||||
|
|
||||||
/* Restconf handle
|
/* Restconf handle
|
||||||
|
|
@ -84,8 +93,10 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SSL_CTX *rh_ctx; /* SSL context */
|
SSL_CTX *rh_ctx; /* SSL context */
|
||||||
evhtp_t *rh_evhtp; /* Evhtp struct */
|
|
||||||
restconf_socket *rh_sockets; /* List of restconf server (ready for accept) sockets */
|
restconf_socket *rh_sockets; /* List of restconf server (ready for accept) sockets */
|
||||||
|
#ifdef HAVE_LIBEVHTP
|
||||||
|
evhtp_t *rh_evhtp; /* Evhtp struct */
|
||||||
|
#endif
|
||||||
} restconf_native_handle;
|
} restconf_native_handle;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
166
configure
vendored
166
configure
vendored
|
|
@ -718,6 +718,8 @@ with_cligen
|
||||||
enable_optyangs
|
enable_optyangs
|
||||||
enable_publish
|
enable_publish
|
||||||
with_restconf
|
with_restconf
|
||||||
|
enable_evhtp
|
||||||
|
enable_nghttp2
|
||||||
with_configfile
|
with_configfile
|
||||||
with_libxml2
|
with_libxml2
|
||||||
with_yang_installdir
|
with_yang_installdir
|
||||||
|
|
@ -1365,6 +1367,10 @@ Optional Features:
|
||||||
in clixon install, default: no
|
in clixon install, default: no
|
||||||
--enable-publish Enable publish of notification streams using SSE and
|
--enable-publish Enable publish of notification streams using SSE and
|
||||||
curl
|
curl
|
||||||
|
--disable-evhtp Disable evhtp for native restconf http/1, default:
|
||||||
|
yes
|
||||||
|
--enable-nghttp2 Enable nghttp2 for native restconf http/2, default:
|
||||||
|
no
|
||||||
|
|
||||||
Optional Packages:
|
Optional Packages:
|
||||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||||
|
|
@ -3352,7 +3358,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
|
||||||
# Set to native or fcgi -> compile apps/restconf
|
# Set to native or fcgi -> compile apps/restconf
|
||||||
|
|
||||||
|
|
||||||
# Home dir for web user
|
# Home dir for web user, such as nginx fcgi sockets
|
||||||
wwwdir=/www-data
|
wwwdir=/www-data
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -5045,6 +5051,11 @@ fi
|
||||||
|
|
||||||
$as_echo "#define WITH_RESTCONF_FCGI 1" >>confdefs.h
|
$as_echo "#define WITH_RESTCONF_FCGI 1" >>confdefs.h
|
||||||
# For c-code that cant use strings
|
# For c-code that cant use strings
|
||||||
|
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define WWWDIR "$wwwdir"
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
elif test "x${with_restconf}" == xnative; then
|
elif test "x${with_restconf}" == xnative; then
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL_init_ssl in -lssl" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL_init_ssl in -lssl" >&5
|
||||||
$as_echo_n "checking for OPENSSL_init_ssl in -lssl... " >&6; }
|
$as_echo_n "checking for OPENSSL_init_ssl in -lssl... " >&6; }
|
||||||
|
|
@ -5140,7 +5151,42 @@ else
|
||||||
as_fn_error $? "libcrypto missing" "$LINENO" 5
|
as_fn_error $? "libcrypto missing" "$LINENO" 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for event_init in -levent" >&5
|
# Check if evhtp is enabled for http/1
|
||||||
|
# Check whether --enable-evhtp was given.
|
||||||
|
if test "${enable_evhtp+set}" = set; then :
|
||||||
|
enableval=$enable_evhtp;
|
||||||
|
if test "$enableval" = no; then
|
||||||
|
ac_enable_evhtp=no
|
||||||
|
else
|
||||||
|
ac_enable_evhtp=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
ac_enable_evhtp=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: checking evhtp is enabled: $ac_enable_evhtp" >&5
|
||||||
|
$as_echo "checking evhtp is enabled: $ac_enable_evhtp" >&6; }
|
||||||
|
if test "$ac_enable_evhtp" = "yes"; then
|
||||||
|
for ac_header in evhtp/evhtp.h
|
||||||
|
do :
|
||||||
|
ac_fn_c_check_header_compile "$LINENO" "evhtp/evhtp.h" "ac_cv_header_evhtp_evhtp_h" "$ac_includes_default
|
||||||
|
#define EVHTP_DISABLE_REGEX
|
||||||
|
#define EVHTP_DISABLE_EVTHR
|
||||||
|
|
||||||
|
"
|
||||||
|
if test "x$ac_cv_header_evhtp_evhtp_h" = xyes; then :
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define HAVE_EVHTP_EVHTP_H 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
else
|
||||||
|
as_fn_error $? "evhtp header missing. See https://github.com/clicon/libevhtp" "$LINENO" 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for event_init in -levent" >&5
|
||||||
$as_echo_n "checking for event_init in -levent... " >&6; }
|
$as_echo_n "checking for event_init in -levent... " >&6; }
|
||||||
if ${ac_cv_lib_event_event_init+:} false; then :
|
if ${ac_cv_lib_event_event_init+:} false; then :
|
||||||
$as_echo_n "(cached) " >&6
|
$as_echo_n "(cached) " >&6
|
||||||
|
|
@ -5187,25 +5233,7 @@ else
|
||||||
as_fn_error $? "libevent missing" "$LINENO" 5
|
as_fn_error $? "libevent missing" "$LINENO" 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for ac_header in evhtp/evhtp.h
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for evhtp_new in -levhtp" >&5
|
||||||
do :
|
|
||||||
ac_fn_c_check_header_compile "$LINENO" "evhtp/evhtp.h" "ac_cv_header_evhtp_evhtp_h" "$ac_includes_default
|
|
||||||
#define EVHTP_DISABLE_REGEX
|
|
||||||
#define EVHTP_DISABLE_EVTHR
|
|
||||||
|
|
||||||
"
|
|
||||||
if test "x$ac_cv_header_evhtp_evhtp_h" = xyes; then :
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
|
||||||
#define HAVE_EVHTP_EVHTP_H 1
|
|
||||||
_ACEOF
|
|
||||||
|
|
||||||
else
|
|
||||||
as_fn_error $? "evhtp header missing. See https://github.com/clicon/libevhtp" "$LINENO" 5
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for evhtp_new in -levhtp" >&5
|
|
||||||
$as_echo_n "checking for evhtp_new in -levhtp... " >&6; }
|
$as_echo_n "checking for evhtp_new in -levhtp... " >&6; }
|
||||||
if ${ac_cv_lib_evhtp_evhtp_new+:} false; then :
|
if ${ac_cv_lib_evhtp_evhtp_new+:} false; then :
|
||||||
$as_echo_n "(cached) " >&6
|
$as_echo_n "(cached) " >&6
|
||||||
|
|
@ -5252,6 +5280,87 @@ else
|
||||||
as_fn_error $? "libevhtp missing" "$LINENO" 5
|
as_fn_error $? "libevhtp missing" "$LINENO" 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if nghttp2 is enabled for http/2
|
||||||
|
# Check whether --enable-nghttp2 was given.
|
||||||
|
if test "${enable_nghttp2+set}" = set; then :
|
||||||
|
enableval=$enable_nghttp2;
|
||||||
|
if test "$enableval" = no; then
|
||||||
|
ac_enable_nghttp2=no
|
||||||
|
else
|
||||||
|
ac_enable_nghttp2=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
ac_enable_nghttp2=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: checking nghttp2 is enabled: $ac_enable_nghttp2" >&5
|
||||||
|
$as_echo "checking nghttp2 is enabled: $ac_enable_nghttp2" >&6; }
|
||||||
|
if test "$ac_enable_nghttp2" = "yes"; then
|
||||||
|
for ac_header in nghttp2/nghttp2.h
|
||||||
|
do :
|
||||||
|
ac_fn_c_check_header_mongrel "$LINENO" "nghttp2/nghttp2.h" "ac_cv_header_nghttp2_nghttp2_h" "$ac_includes_default"
|
||||||
|
if test "x$ac_cv_header_nghttp2_nghttp2_h" = xyes; then :
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define HAVE_NGHTTP2_NGHTTP2_H 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
else
|
||||||
|
as_fn_error $? "nghttp2 missing" "$LINENO" 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nghttp2_session_server_new in -lnghttp2" >&5
|
||||||
|
$as_echo_n "checking for nghttp2_session_server_new in -lnghttp2... " >&6; }
|
||||||
|
if ${ac_cv_lib_nghttp2_nghttp2_session_server_new+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
ac_check_lib_save_LIBS=$LIBS
|
||||||
|
LIBS="-lnghttp2 $LIBS"
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
/* Override any GCC internal prototype to avoid an error.
|
||||||
|
Use char because int might match the return type of a GCC
|
||||||
|
builtin and then its argument prototype would still apply. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
char nghttp2_session_server_new ();
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
return nghttp2_session_server_new ();
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_link "$LINENO"; then :
|
||||||
|
ac_cv_lib_nghttp2_nghttp2_session_server_new=yes
|
||||||
|
else
|
||||||
|
ac_cv_lib_nghttp2_nghttp2_session_server_new=no
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext \
|
||||||
|
conftest$ac_exeext conftest.$ac_ext
|
||||||
|
LIBS=$ac_check_lib_save_LIBS
|
||||||
|
fi
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nghttp2_nghttp2_session_server_new" >&5
|
||||||
|
$as_echo "$ac_cv_lib_nghttp2_nghttp2_session_server_new" >&6; }
|
||||||
|
if test "x$ac_cv_lib_nghttp2_nghttp2_session_server_new" = xyes; then :
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define HAVE_LIBNGHTTP2 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
LIBS="-lnghttp2 $LIBS"
|
||||||
|
|
||||||
|
else
|
||||||
|
as_fn_error $? "nghttp2 missing" "$LINENO" 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
$as_echo "#define WITH_RESTCONF_NATIVE 1" >>confdefs.h
|
$as_echo "#define WITH_RESTCONF_NATIVE 1" >>confdefs.h
|
||||||
# For c-code that cant use strings
|
# For c-code that cant use strings
|
||||||
|
|
@ -5290,21 +5399,6 @@ if test "${with_restconf+set}" = set; then :
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Common actions for all restconf packages
|
|
||||||
if test "x${with_restconf}" != "x"; then
|
|
||||||
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
|
||||||
#define WWWDIR "$wwwdir"
|
|
||||||
_ACEOF
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
|
||||||
#define WWWDIR ""
|
|
||||||
_ACEOF
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set default config file location
|
# Set default config file location
|
||||||
CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml
|
CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml
|
||||||
|
|
||||||
|
|
|
||||||
45
configure.ac
45
configure.ac
|
|
@ -218,15 +218,42 @@ if test "x${with_restconf}" == xfcgi; then
|
||||||
elif test "x${with_restconf}" == xnative; then
|
elif test "x${with_restconf}" == xnative; then
|
||||||
AC_CHECK_LIB(ssl, OPENSSL_init_ssl ,, AC_MSG_ERROR([libssl missing]))
|
AC_CHECK_LIB(ssl, OPENSSL_init_ssl ,, AC_MSG_ERROR([libssl missing]))
|
||||||
AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, , AC_MSG_ERROR([libcrypto missing]))
|
AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, , AC_MSG_ERROR([libcrypto missing]))
|
||||||
AC_CHECK_LIB(event, event_init,, AC_MSG_ERROR([libevent missing]))
|
# Check if evhtp is enabled for http/1
|
||||||
AC_CHECK_HEADERS(evhtp/evhtp.h,
|
AC_ARG_ENABLE(evhtp, AS_HELP_STRING([--disable-evhtp],[Disable evhtp for native restconf http/1, default: yes]),[
|
||||||
[],
|
if test "$enableval" = no; then
|
||||||
AC_MSG_ERROR([evhtp header missing. See https://github.com/clicon/libevhtp]),
|
ac_enable_evhtp=no
|
||||||
[AC_INCLUDES_DEFAULT[
|
else
|
||||||
#define EVHTP_DISABLE_REGEX
|
ac_enable_evhtp=yes
|
||||||
#define EVHTP_DISABLE_EVTHR
|
fi
|
||||||
]])
|
],
|
||||||
AC_CHECK_LIB(evhtp, evhtp_new,, AC_MSG_ERROR([libevhtp missing]),[-levent -lssl -lcrypto])
|
[ ac_enable_evhtp=yes])
|
||||||
|
AC_MSG_RESULT(checking evhtp is enabled: $ac_enable_evhtp)
|
||||||
|
if test "$ac_enable_evhtp" = "yes"; then
|
||||||
|
AC_CHECK_HEADERS(evhtp/evhtp.h,
|
||||||
|
[],
|
||||||
|
AC_MSG_ERROR([evhtp header missing. See https://github.com/clicon/libevhtp]),
|
||||||
|
[AC_INCLUDES_DEFAULT[
|
||||||
|
#define EVHTP_DISABLE_REGEX
|
||||||
|
#define EVHTP_DISABLE_EVTHR
|
||||||
|
]])
|
||||||
|
AC_CHECK_LIB(event, event_init,, AC_MSG_ERROR([libevent missing]))
|
||||||
|
AC_CHECK_LIB(evhtp, evhtp_new,, AC_MSG_ERROR([libevhtp missing]),[-levent -lssl -lcrypto])
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if nghttp2 is enabled for http/2
|
||||||
|
AC_ARG_ENABLE(nghttp2, AS_HELP_STRING([--enable-nghttp2],[Enable nghttp2 for native restconf http/2, default: no]),[
|
||||||
|
if test "$enableval" = no; then
|
||||||
|
ac_enable_nghttp2=no
|
||||||
|
else
|
||||||
|
ac_enable_nghttp2=yes
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[ ac_enable_nghttp2=no])
|
||||||
|
AC_MSG_RESULT(checking nghttp2 is enabled: $ac_enable_nghttp2)
|
||||||
|
if test "$ac_enable_nghttp2" = "yes"; then
|
||||||
|
AC_CHECK_HEADERS(nghttp2/nghttp2.h,[], AC_MSG_ERROR([nghttp2 missing]))
|
||||||
|
AC_CHECK_LIB(nghttp2, nghttp2_session_server_new,, AC_MSG_ERROR([nghttp2 missing]))
|
||||||
|
fi
|
||||||
AC_DEFINE(WITH_RESTCONF_NATIVE, 1, [Use native restconf mode]) # For c-code that cant use strings
|
AC_DEFINE(WITH_RESTCONF_NATIVE, 1, [Use native restconf mode]) # For c-code that cant use strings
|
||||||
elif test "x${with_restconf}" == xno; then
|
elif test "x${with_restconf}" == xno; then
|
||||||
# Cant get around "no" as an answer for --without-restconf that is reset here to undefined
|
# Cant get around "no" as an answer for --without-restconf that is reset here to undefined
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,9 @@
|
||||||
/* Define to 1 if you have the `m' library (-lm). */
|
/* Define to 1 if you have the `m' library (-lm). */
|
||||||
#undef HAVE_LIBM
|
#undef HAVE_LIBM
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `nghttp2' library (-lnghttp2). */
|
||||||
|
#undef HAVE_LIBNGHTTP2
|
||||||
|
|
||||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||||
#undef HAVE_LIBSOCKET
|
#undef HAVE_LIBSOCKET
|
||||||
|
|
||||||
|
|
@ -72,6 +75,9 @@
|
||||||
/* Define to 1 if you have the <memory.h> header file. */
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
#undef HAVE_MEMORY_H
|
#undef HAVE_MEMORY_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <nghttp2/nghttp2.h> header file. */
|
||||||
|
#undef HAVE_NGHTTP2_NGHTTP2_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `setns' function. */
|
/* Define to 1 if you have the `setns' function. */
|
||||||
#undef HAVE_SETNS
|
#undef HAVE_SETNS
|
||||||
|
|
||||||
|
|
@ -147,7 +153,7 @@
|
||||||
/* Use native restconf mode */
|
/* Use native restconf mode */
|
||||||
#undef WITH_RESTCONF_NATIVE
|
#undef WITH_RESTCONF_NATIVE
|
||||||
|
|
||||||
/* WWW dir for restconf daemon */
|
/* WWW dir for fcgi stuff / nginx */
|
||||||
#undef WWWDIR
|
#undef WWWDIR
|
||||||
|
|
||||||
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
||||||
|
|
|
||||||
|
|
@ -848,6 +848,14 @@ api_path2xpath(char *api_path,
|
||||||
clicon_err(OE_XML, EINVAL, "api_path is NULL");
|
clicon_err(OE_XML, EINVAL, "api_path is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* Special case: "//" is not handled proerly by uri_str2cvec
|
||||||
|
* and is an invalid api-path
|
||||||
|
*/
|
||||||
|
if (strlen(api_path)>1 && api_path[0] == '/' && api_path[1] == '/'){
|
||||||
|
if (xerr && netconf_invalid_value_xml(xerr, "application", "Invalid api-path beginning with //") < 0)
|
||||||
|
goto done;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
/* Split api-path into cligen variable vector,
|
/* Split api-path into cligen variable vector,
|
||||||
* dont decode since api_path2xpath_cvv takes uri encode as input */
|
* dont decode since api_path2xpath_cvv takes uri encode as input */
|
||||||
if (uri_str2cvec(api_path, '/', '=', 0, &cvv) < 0)
|
if (uri_str2cvec(api_path, '/', '=', 0, &cvv) < 0)
|
||||||
|
|
|
||||||
|
|
@ -1917,6 +1917,10 @@ xml_copy_one(cxobj *x0,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
|
if (x0 == NULL || x1 == NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "x0 or x1 is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
xml_type_set(x1, xml_type(x0));
|
xml_type_set(x1, xml_type(x0));
|
||||||
if ((s = xml_name(x0))) /* malloced string */
|
if ((s = xml_name(x0))) /* malloced string */
|
||||||
if ((xml_name_set(x1, s)) < 0)
|
if ((xml_name_set(x1, s)) < 0)
|
||||||
|
|
|
||||||
|
|
@ -195,9 +195,8 @@ function testrun()
|
||||||
expectpart "$(curl $CURLOPTS -X GET https://$addr:80/.well-known/host-meta 2>&1)" 35 #"wrong version number" # dependent on curl version
|
expectpart "$(curl $CURLOPTS -X GET https://$addr:80/.well-known/host-meta 2>&1)" 35 #"wrong version number" # dependent on curl version
|
||||||
else # see (1) http to https port in restconf_main_native.c
|
else # see (1) http to https port in restconf_main_native.c
|
||||||
new "Wrong proto=http on https port, expect bad request"
|
new "Wrong proto=http on https port, expect bad request"
|
||||||
# When run nmap --script ssl* I can crash restconf if try to return a bad request here
|
expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta)" 0 "HTTP/1.1 400 Bad Request"
|
||||||
# expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta)" 0 "HTTP/1.1 400 Bad Request"
|
# expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta 2>&1)" 56 "Connection reset by peer"
|
||||||
expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta 2>&1)" 56 "Connection reset by peer"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Exact match
|
# Exact match
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Restconf basic functionality also uri encoding using eth/0/0
|
# Restconf basic functionality also uri encoding using eth/0/0
|
||||||
# Note there are many variants: (1)fcgi/native, (2) http/https, (3) IPv4/IPv6, (4)local or backend-config
|
# NMAP ssl script testing.
|
||||||
# (1) fcgi/native
|
# The following tests are run:
|
||||||
# This is compile-time --with-restconf=fcgi or native, so either or
|
# - ssl-ccs-injection, but not deterministic, need to repeat (10 times) maybe this is wrong?
|
||||||
# - fcgi: Assume http server setup, such as nginx described in apps/restconf/README.md
|
# - ssl-cert-intaddr
|
||||||
# - native: test both local config and get config from backend
|
# - ssl-cert
|
||||||
# (2) http/https
|
# - ssl-date
|
||||||
# - fcgi: relies on nginx has https setup
|
# - ssl-dh-params
|
||||||
# - native: generate self-signed server certs
|
# - ssl-enum-ciphers
|
||||||
# (3) IPv4/IPv6 (only loopback 127.0.0.1 / ::1)
|
# - ssl-heartbleed
|
||||||
# - The tests runs through both
|
# - ssl-known-key
|
||||||
# - IPv6 by default disabled since docker does not support it out-of-the box
|
# - ssl-poodle
|
||||||
# (4) local/backend config. Native only
|
# - sslv2-drown
|
||||||
# - The tests runs through both (if compiled with native)
|
# - sslv2
|
||||||
# See also test_restconf_op.sh
|
|
||||||
# See test_restconf_rpc.sh for cases when CLICON_BACKEND_RESTCONF_PROCESS is set
|
|
||||||
|
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
@ -62,49 +60,22 @@ if [ "${WITH_RESTCONF}" = "native" ]; then
|
||||||
# Create server certs and CA
|
# Create server certs and CA
|
||||||
cacerts $cakey $cacert
|
cacerts $cakey $cacert
|
||||||
servercerts $cakey $cacert $srvkey $srvcert
|
servercerts $cakey $cacert $srvkey $srvcert
|
||||||
USEBACKEND=true
|
|
||||||
else
|
|
||||||
# Define default restconfig config: RESTCONFIG
|
|
||||||
RESTCONFIG=$(restconf_config none false)
|
|
||||||
USEBACKEND=false
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
|
# Create a single IPv4 https socket
|
||||||
state='{"clixon-example:state":{"op":\["41","42","43"\]}'
|
RESTCONFIG=$(cat <<EOF
|
||||||
|
<restconf>
|
||||||
if $IPv6; then
|
|
||||||
# For backend config, create 4 sockets, all combinations IPv4/IPv6 + http/https
|
|
||||||
RESTCONFIG1=$(cat <<EOF
|
|
||||||
<restconf xmlns="http://clicon.org/restconf">
|
|
||||||
<enable>true</enable>
|
<enable>true</enable>
|
||||||
<auth-type>none</auth-type>
|
<auth-type>none</auth-type>
|
||||||
<server-cert-path>$srvcert</server-cert-path>
|
<server-cert-path>$srvcert</server-cert-path>
|
||||||
<server-key-path>$srvkey</server-key-path>
|
<server-key-path>$srvkey</server-key-path>
|
||||||
<server-ca-cert-path>$cakey</server-ca-cert-path>
|
<server-ca-cert-path>$cakey</server-ca-cert-path>
|
||||||
<pretty>false</pretty>
|
<pretty>false</pretty>
|
||||||
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
|
|
||||||
<socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket>
|
|
||||||
<socket><namespace>default</namespace><address>::</address><port>80</port><ssl>false</ssl></socket>
|
|
||||||
<socket><namespace>default</namespace><address>::</address><port>443</port><ssl>true</ssl></socket>
|
|
||||||
</restconf>
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
else
|
|
||||||
# For backend config, create 2 sockets, all combinations IPv4 + http/https
|
|
||||||
RESTCONFIG1=$(cat <<EOF
|
|
||||||
<restconf xmlns="http://clicon.org/restconf">
|
|
||||||
<enable>true</enable>
|
|
||||||
<auth-type>none</auth-type>
|
|
||||||
<server-cert-path>$srvcert</server-cert-path>
|
|
||||||
<server-key-path>$srvkey</server-key-path>
|
|
||||||
<server-ca-cert-path>$cakey</server-ca-cert-path>
|
|
||||||
<pretty>false</pretty>
|
|
||||||
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
|
|
||||||
<socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket>
|
<socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket>
|
||||||
</restconf>
|
</restconf>
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
fi
|
|
||||||
|
|
||||||
# Clixon config
|
# Clixon config
|
||||||
cat <<EOF > $cfg
|
cat <<EOF > $cfg
|
||||||
|
|
@ -124,8 +95,8 @@ cat <<EOF > $cfg
|
||||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
|
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
|
||||||
<CLICON_BACKEND_RESTCONF_PROCESS>$USEBACKEND</CLICON_BACKEND_RESTCONF_PROCESS>
|
<CLICON_BACKEND_RESTCONF_PROCESS>false</CLICON_BACKEND_RESTCONF_PROCESS>
|
||||||
$RESTCONFIG <!-- only fcgi -->
|
$RESTCONFIG
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
@ -145,11 +116,11 @@ fi
|
||||||
new "wait backend"
|
new "wait backend"
|
||||||
wait_backend
|
wait_backend
|
||||||
|
|
||||||
new "netconf edit config"
|
#new "netconf edit config"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG1</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
#expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf commit"
|
#new "netconf commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
#expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
if [ $RC -ne 0 ]; then
|
||||||
new "kill old restconf daemon"
|
new "kill old restconf daemon"
|
||||||
|
|
@ -158,7 +129,7 @@ if [ $RC -ne 0 ]; then
|
||||||
new "start restconf daemon"
|
new "start restconf daemon"
|
||||||
# inline of start_restconf, cant make quotes to work
|
# inline of start_restconf, cant make quotes to work
|
||||||
echo "sudo -u $wwwstartuser -s $clixon_restconf $RCLOG -D $DBG -f $cfg -R <xml>"
|
echo "sudo -u $wwwstartuser -s $clixon_restconf $RCLOG -D $DBG -f $cfg -R <xml>"
|
||||||
sudo -u $wwwstartuser -s $clixon_restconf $RCLOG -D $DBG -f $cfg -R "$RESTCONFIG1" &
|
sudo -u $wwwstartuser -s $clixon_restconf $RCLOG -D $DBG -f $cfg &
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err1 "expected 0" "$?"
|
err1 "expected 0" "$?"
|
||||||
fi
|
fi
|
||||||
|
|
@ -167,10 +138,54 @@ fi
|
||||||
new "wait restconf"
|
new "wait restconf"
|
||||||
wait_restconf
|
wait_restconf
|
||||||
|
|
||||||
sleep 1 # Sometimes nmap test fails with no reply from server, _maybe_ this helps?
|
# Try 10 times, dont know why this is undeterministic?
|
||||||
new "nmap test"
|
let i=0;
|
||||||
|
new "nmap ssl-ccs-injection$i"
|
||||||
|
result=$(nmap --script ssl-ccs-injection -p 443 127.0.0.1)
|
||||||
|
# echo "result:$result"
|
||||||
|
while [[ "$result" = *"No reply from server"* ]]; do
|
||||||
|
if [ $i -ge 10 ]; then
|
||||||
|
err "ssl-ccs-injection"
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
let i++;
|
||||||
|
new "nmap ssl-ccs-injection$i"
|
||||||
|
result=$(nmap --script ssl-ccs-injection -p 443 127.0.0.1)
|
||||||
|
# echo "result:$result"
|
||||||
|
done
|
||||||
|
|
||||||
expectpart "$(nmap --script ssl* -p 443 127.0.0.1)" 0 "443/tcp open https" "least strength: A" "Nmap done: 1 IP address (1 host up) scanned in" --not-- "No reply from server" "TLSv1.0:" "TLSv1.1:"
|
new "nmap ssl-cert-intaddr"
|
||||||
|
expectpart "$(nmap --script ssl-cert-intaddr -p 443 127.0.0.1)" 0 "443/tcp open https"
|
||||||
|
|
||||||
|
new "nmap ssl-cert"
|
||||||
|
expectpart "$(nmap --script ssl-cert -p 443 127.0.0.1)" 0 "443/tcp open https" "| ssl-cert: Subject: commonName=www.clicon.org/organizationName=Clixon/countryName=SE"
|
||||||
|
|
||||||
|
new "nmap ssl-date"
|
||||||
|
expectpart "$(nmap --script ssl-date -p 443 127.0.0.1)" 0 "443/tcp open https"
|
||||||
|
|
||||||
|
new "nmap ssl-dh-params"
|
||||||
|
expectpart "$(nmap --script ssl-dh-params -p 443 127.0.0.1)" 0 "443/tcp open https"
|
||||||
|
|
||||||
|
new "nmap ssl-enum-ciphers"
|
||||||
|
expectpart "$(nmap --script ssl-enum-ciphers -p 443 127.0.0.1)" 0 "443/tcp open https" "least strength: A" "TLSv1.2" --not-- "No reply from server" "TLSv1.0:" "TLSv1.1:"
|
||||||
|
|
||||||
|
new "nmap ssl-heartbleed"
|
||||||
|
expectpart "$(nmap --script ssl-heartbleed -p 443 127.0.0.1)" 0 "443/tcp open https"
|
||||||
|
|
||||||
|
new "nmap ssl-known-key"
|
||||||
|
expectpart "$(nmap --script ssl-known-key -p 443 127.0.0.1)" 0 "443/tcp open https"
|
||||||
|
|
||||||
|
new "nmap ssl-poodle"
|
||||||
|
expectpart "$(nmap --script ssl-poodle -p 443 127.0.0.1)" 0 "443/tcp open https"
|
||||||
|
|
||||||
|
new "nmap sslv2-drown"
|
||||||
|
expectpart "$(nmap --script sslv2-drown -p 443 127.0.0.1)" 0 "443/tcp open https"
|
||||||
|
|
||||||
|
new "nmap sslv2"
|
||||||
|
expectpart "$(nmap --script sslv2 -p 443 127.0.0.1)" 0 "443/tcp open https"
|
||||||
|
|
||||||
|
new "restconf get. Just ensure restconf is alive"
|
||||||
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://127.0.0.1/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
if [ $RC -ne 0 ]; then
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
|
|
@ -192,8 +207,8 @@ fi
|
||||||
unset RCPROTO
|
unset RCPROTO
|
||||||
|
|
||||||
# Set by restconf_config
|
# Set by restconf_config
|
||||||
|
unset result
|
||||||
unset RESTCONFIG
|
unset RESTCONFIG
|
||||||
unset RESTCONFIG1
|
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue