- 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
|
||||
|
||||
* 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
|
||||
* Several cases were not implemented fully according to RFC 7950:
|
||||
* Do not extend default values if when statements evaluate to false
|
||||
|
|
|
|||
|
|
@ -49,11 +49,13 @@
|
|||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
/* evhtp */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
|
||||
#include <evhtp/evhtp.h>
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
@ -77,6 +79,7 @@ restconf_reply_header(void *req0,
|
|||
const char *vfmt,
|
||||
...)
|
||||
{
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
evhtp_request_t *req = (evhtp_request_t *)req0;
|
||||
int retval = -1;
|
||||
size_t vlen;
|
||||
|
|
@ -122,8 +125,12 @@ restconf_reply_header(void *req0,
|
|||
if (value)
|
||||
free(value);
|
||||
return retval;
|
||||
#else /* HAVE_LIBEVHTP */
|
||||
return 0;
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
/*! Send reply
|
||||
* @see htp__create_reply_
|
||||
*/
|
||||
|
|
@ -177,6 +184,7 @@ native_send_reply(restconf_conn_h *rc,
|
|||
done:
|
||||
return retval;
|
||||
}
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
/*! Send HTTP reply with potential message body
|
||||
* @param[in] req Evhtp http request handle
|
||||
|
|
@ -189,6 +197,7 @@ restconf_reply_send(void *req0,
|
|||
int code,
|
||||
cbuf *cb)
|
||||
{
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
evhtp_request_t *req = (evhtp_request_t *)req0;
|
||||
int retval = -1;
|
||||
const char *reason_phrase;
|
||||
|
|
@ -237,6 +246,9 @@ restconf_reply_send(void *req0,
|
|||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
#else /* HAVE_LIBEVHTP */
|
||||
return 0;
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
}
|
||||
|
||||
/*! get input data
|
||||
|
|
@ -246,8 +258,10 @@ restconf_reply_send(void *req0,
|
|||
cbuf *
|
||||
restconf_get_indata(void *req0)
|
||||
{
|
||||
evhtp_request_t *req = (evhtp_request_t *)req0;
|
||||
cbuf *cb = NULL;
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
evhtp_request_t *req = (evhtp_request_t *)req0;
|
||||
|
||||
size_t len;
|
||||
unsigned char *buf;
|
||||
|
||||
|
|
@ -262,7 +276,9 @@ restconf_get_indata(void *req0)
|
|||
/* Note the pullup may not be null-terminated */
|
||||
cbuf_append_buf(cb, buf, len);
|
||||
}
|
||||
|
||||
return cb;
|
||||
#else /* HAVE_LIBEVHTP */
|
||||
return cb;
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -210,6 +210,14 @@ static const map_str2int http_media_map[] = {
|
|||
{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
|
||||
restconf_err2code(char *tag)
|
||||
{
|
||||
|
|
@ -234,6 +242,18 @@ restconf_media_int2str(restconf_media 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
|
||||
* @note media-type syntax does not support parameters
|
||||
* @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;
|
||||
|
||||
/* Just used in native */
|
||||
enum restconf_http_proto{
|
||||
HTTP_10,
|
||||
HTTP_11,
|
||||
HTTP_2
|
||||
};
|
||||
typedef enum restconf_http_proto restconf_http_proto;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
|
|
@ -75,6 +83,8 @@ int restconf_err2code(char *tag);
|
|||
const char *restconf_code2reason(int code);
|
||||
const restconf_media restconf_media_str2int(char *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);
|
||||
int get_user_cookie(char *cookiestr, char *attribute, char **val);
|
||||
int restconf_terminate(clicon_handle h);
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@
|
|||
/* clicon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
/* evhtp */
|
||||
#include <event2/buffer.h> /* evbuffer */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
|
|
@ -158,6 +159,12 @@
|
|||
|
||||
#include <evhtp/evhtp.h>
|
||||
#include <evhtp/sslutils.h> /* XXX inline this / use SSL directly */
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
/* nghttp2 */
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
||||
/* restconf */
|
||||
#include "restconf_lib.h" /* generic shared with plugins */
|
||||
|
|
@ -336,6 +343,7 @@ openssl_cat_log_cb(void *handle,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
static char*
|
||||
evhtp_method2str(enum htp_method m)
|
||||
{
|
||||
|
|
@ -399,8 +407,9 @@ evhtp_method2str(enum htp_method m)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
print_header(evhtp_header_t *header,
|
||||
evhtp_print_header(evhtp_header_t *header,
|
||||
void *arg)
|
||||
{
|
||||
clicon_debug(1, "%s %s %s", __FUNCTION__, header->key, header->val);
|
||||
|
|
@ -408,7 +417,7 @@ print_header(evhtp_header_t *header,
|
|||
}
|
||||
|
||||
static int
|
||||
query_iterator(evhtp_header_t *hdr,
|
||||
evhtp_query_iterator(evhtp_header_t *hdr,
|
||||
void *arg)
|
||||
{
|
||||
cvec *qvec = (cvec *)arg;
|
||||
|
|
@ -436,7 +445,7 @@ query_iterator(evhtp_header_t *hdr,
|
|||
* Example: Host -> HTTP_HOST
|
||||
*/
|
||||
static int
|
||||
convert_fcgi(evhtp_header_t *hdr,
|
||||
evhtp_convert_fcgi(evhtp_header_t *hdr,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -520,7 +529,7 @@ evhtp_params_set(clicon_handle h,
|
|||
* that would mean double parsing,...
|
||||
*/
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -558,7 +567,7 @@ evhtp_params_set(clicon_handle h,
|
|||
/* Translate all http headers by capitalizing, prepend w HTTP_ and - -> _
|
||||
* 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;
|
||||
retval = 1;
|
||||
done:
|
||||
|
|
@ -593,7 +602,6 @@ restconf_path_root(evhtp_request_t *req,
|
|||
{
|
||||
int retval = -1;
|
||||
clicon_handle h;
|
||||
evhtp_connection_t *conn;
|
||||
int ret;
|
||||
cvec *qvec = NULL;
|
||||
|
||||
|
|
@ -602,13 +610,9 @@ restconf_path_root(evhtp_request_t *req,
|
|||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((conn = req->conn) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "req->conn is NULL");
|
||||
goto done;
|
||||
}
|
||||
/* input debug */
|
||||
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 */
|
||||
/* Query vector, ie the ?a=x&b=y stuff */
|
||||
|
|
@ -652,7 +656,6 @@ restconf_path_wellknown(evhtp_request_t *req,
|
|||
{
|
||||
int retval = -1;
|
||||
clicon_handle h;
|
||||
evhtp_connection_t *conn;
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "------------");
|
||||
|
|
@ -660,13 +663,9 @@ restconf_path_wellknown(evhtp_request_t *req,
|
|||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((conn = req->conn) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "req->conn is NULL");
|
||||
goto done;
|
||||
}
|
||||
/* input debug */
|
||||
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 */
|
||||
|
||||
/* set fcgi-like paramaters (ignore query vector) */
|
||||
|
|
@ -688,6 +687,7 @@ restconf_path_wellknown(evhtp_request_t *req,
|
|||
}
|
||||
return; /* void */
|
||||
}
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
/*
|
||||
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
||||
|
|
@ -721,7 +721,7 @@ init_openssl(void)
|
|||
*/
|
||||
static int
|
||||
restconf_verify_certs(int preverify_ok,
|
||||
evhtp_x509_store_ctx_t *store)
|
||||
X509_STORE_CTX *store)
|
||||
{
|
||||
char buf[256];
|
||||
X509 *err_cert;
|
||||
|
|
@ -768,7 +768,8 @@ dump_alpn_proto_list(const unsigned char *in,
|
|||
char *str;
|
||||
|
||||
inp = (unsigned char*)in;
|
||||
while ((len = *inp) != 0) {
|
||||
while ((inp-in) < inlen) {
|
||||
len = *inp;
|
||||
inp++;
|
||||
if ((str = malloc(len+1)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
|
|
@ -798,23 +799,33 @@ alpn_select_proto_cb(SSL *ssl,
|
|||
{
|
||||
unsigned char *inp;
|
||||
unsigned char len;
|
||||
int pref = 0;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (clicon_debug_get())
|
||||
dump_alpn_proto_list(in, inlen);
|
||||
/* select http/1.1 */
|
||||
inp = (unsigned char*)in;
|
||||
while ((len = *inp) != 0) {
|
||||
while ((inp-in) < inlen) {
|
||||
len = *inp;
|
||||
inp++;
|
||||
if (len == 8 && strncmp((char*)inp, "http/1.1", len) == 0)
|
||||
// if (len == 2 && strncmp((char*)inp, "h2", len) == 0)
|
||||
break;
|
||||
inp += len;
|
||||
}
|
||||
if (len == 0)
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
if (pref < 10 && len == 8 && strncmp((char*)inp, "http/1.1", len) == 0){
|
||||
*outlen = len;
|
||||
*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;
|
||||
}
|
||||
if (pref == 0)
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
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
|
||||
* @param[in] rc restconf connection
|
||||
*/
|
||||
static int
|
||||
restconf_conn_free(evhtp_connection_t *conn)
|
||||
restconf_conn_free(restconf_conn_h *rc)
|
||||
{
|
||||
restconf_conn_h *rc;
|
||||
|
||||
if ((rc = conn->arg) != NULL){
|
||||
if (rc != NULL){
|
||||
if (rc->rc_outp_hdrs)
|
||||
cvec_free(rc->rc_outp_hdrs);
|
||||
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.
|
||||
*/
|
||||
static int
|
||||
close_ssl_evhtp_socket(int s,
|
||||
evhtp_connection_t *conn,
|
||||
close_ssl_socket(restconf_conn_h *rc,
|
||||
int shutdown)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
SSL *ssl;
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
evhtp_connection_t *evconn;
|
||||
|
||||
ssl = conn->ssl;
|
||||
clicon_debug(1, "%s conn-free (%p) 1", __FUNCTION__, conn);
|
||||
restconf_conn_free(conn);
|
||||
evhtp_connection_free(conn); /* evhtp */
|
||||
if (ssl != NULL){
|
||||
if (shutdown && (ret = SSL_shutdown(ssl)) < 0){
|
||||
int e = SSL_get_error(ssl, ret);
|
||||
evconn = (evhtp_connection_t *)rc->rc_arg;
|
||||
clicon_debug(1, "%s evconn-free (%p) 1", __FUNCTION__, evconn);
|
||||
evhtp_connection_free(evconn); /* evhtp */
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
if (rc->rc_ssl != NULL){
|
||||
if (shutdown && (ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
||||
int e = SSL_get_error(rc->rc_ssl, ret);
|
||||
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
clixon_event_unreg_fd(s, restconf_connection);
|
||||
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||
restconf_conn_free(rc);
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
|
|
@ -1023,85 +1035,89 @@ restconf_connection(int s,
|
|||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
evhtp_connection_t *conn = NULL;
|
||||
restconf_conn_h *rc = NULL;
|
||||
ssize_t n;
|
||||
char buf[BUFSIZ]; /* from stdio.h, typically 8K */
|
||||
clicon_handle h;
|
||||
int readmore = 1;
|
||||
restconf_conn_h *rc;
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
clicon_handle h;
|
||||
evhtp_connection_t *evconn = NULL;
|
||||
#endif
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((conn = (evhtp_connection_t*)arg) == NULL){
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, s);
|
||||
if ((rc = (restconf_conn_h*)arg) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||
goto done;
|
||||
}
|
||||
h = (clicon_handle*)conn->htp->arg;
|
||||
assert(s == rc->rc_s);
|
||||
while (readmore) {
|
||||
clicon_debug(1, "%s readmore", __FUNCTION__);
|
||||
readmore = 0;
|
||||
/* 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!
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
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 */
|
||||
close(conn->sock);
|
||||
restconf_conn_free(conn);
|
||||
clixon_event_unreg_fd(conn->sock, restconf_connection);
|
||||
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
|
||||
close(rc->rc_s);
|
||||
restconf_conn_free(rc);
|
||||
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||
goto ok; /* Close socket and ssl */
|
||||
}
|
||||
clicon_err(OE_XML, errno, "read");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
clicon_debug(1, "%s read:%ld", __FUNCTION__, n);
|
||||
if (n == 0){
|
||||
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 ok;
|
||||
}
|
||||
/* parse incoming packet
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
h = rc->rc_h;
|
||||
/* parse incoming packet using evhtp
|
||||
* 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__);
|
||||
/* XXX To get more nuanced evhtp error check
|
||||
* 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)
|
||||
goto done;
|
||||
SSL_free(conn->ssl);
|
||||
if (close(s) < 0){
|
||||
SSL_free(rc->rc_ssl);
|
||||
rc->rc_ssl = NULL;
|
||||
evconn->ssl = NULL;
|
||||
if (close(rc->rc_s) < 0){
|
||||
clicon_err(OE_UNIX, errno, "close");
|
||||
goto done;
|
||||
}
|
||||
clixon_event_unreg_fd(s, restconf_connection);
|
||||
conn->ssl = NULL;
|
||||
clicon_debug(1, "%s conn-free (%p) 2", __FUNCTION__, conn);
|
||||
restconf_conn_free(conn);
|
||||
evhtp_connection_free(conn);
|
||||
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||
clicon_debug(1, "%s evconn-free (%p) 2", __FUNCTION__, evconn);
|
||||
restconf_conn_free(rc);
|
||||
evhtp_connection_free(evconn);
|
||||
goto ok;
|
||||
}
|
||||
clicon_debug(1, "%s connection_parse OK", __FUNCTION__);
|
||||
if (conn->bev != NULL){
|
||||
if (evconn->bev != NULL){
|
||||
struct evbuffer *ev;
|
||||
size_t buflen0;
|
||||
size_t buflen1;
|
||||
char *buf = NULL;
|
||||
|
||||
if ((rc = conn->arg) == 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){
|
||||
if ((ev = bufferevent_get_output(evconn->bev)) != NULL){
|
||||
buflen0 = evbuffer_get_length(ev);
|
||||
buflen1 = buflen0 - rc->rc_bufferevent_output_offset;
|
||||
if (buflen1 > 0){
|
||||
|
|
@ -1126,17 +1142,19 @@ restconf_connection(int s,
|
|||
if (cbuf_len(rc->rc_outp_buf) == 0)
|
||||
readmore = 1;
|
||||
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;
|
||||
cvec_reset(rc->rc_outp_hdrs); /* Can be done in native_send_reply */
|
||||
cbuf_reset(rc->rc_outp_buf);
|
||||
}
|
||||
}
|
||||
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)
|
||||
goto done;
|
||||
}
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
} /* while readmore */
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
@ -1211,6 +1229,89 @@ restconf_checkcert_file(cxobj *xrestconf,
|
|||
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
|
||||
* @param[in] fd Socket (unix or ip)
|
||||
* @param[in] arg typecast clicon_handle
|
||||
|
|
@ -1221,7 +1322,7 @@ restconf_accept_client(int fd,
|
|||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
restconf_socket *rsock = (restconf_socket *)arg;
|
||||
restconf_socket *rsock;
|
||||
restconf_native_handle *rh = NULL;
|
||||
restconf_conn_h *rc = NULL;
|
||||
clicon_handle h;
|
||||
|
|
@ -1229,22 +1330,24 @@ restconf_accept_client(int fd,
|
|||
struct sockaddr from = {0,};
|
||||
socklen_t len;
|
||||
char *name = NULL;
|
||||
SSL *ssl = NULL; /* structure for ssl connection */
|
||||
int ret;
|
||||
evhtp_t *evhtp = NULL;
|
||||
evhtp_connection_t *conn;
|
||||
int e;
|
||||
int er;
|
||||
int readmore;
|
||||
X509 *peercert;
|
||||
const unsigned char *alpn = NULL;
|
||||
unsigned int alpnlen = 0;
|
||||
restconf_http_proto proto = HTTP_11; /* Non-SSL negotiation NYI */
|
||||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||
if (rsock == NULL){
|
||||
if ((rsock = (restconf_socket *)arg) == NULL){
|
||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||
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;
|
||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||
|
|
@ -1255,24 +1358,38 @@ restconf_accept_client(int fd,
|
|||
clicon_err(OE_UNIX, errno, "accept");
|
||||
goto done;
|
||||
}
|
||||
evhtp = rh->rh_evhtp;
|
||||
if ((conn = evhtp_connection_new_server(evhtp, s)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "evhtp_connection_new_server");
|
||||
/*
|
||||
* Register callbacks for actual data socket
|
||||
*/
|
||||
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;
|
||||
}
|
||||
clicon_debug(1, "%s conn-new (%p)", __FUNCTION__, conn);
|
||||
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");
|
||||
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
|
||||
*/
|
||||
/* 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
|
||||
/* 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
|
||||
* SSL_set1_host() sets the expected DNS hostname to name
|
||||
C = SE
|
||||
|
|
@ -1282,17 +1399,16 @@ restconf_accept_client(int fd,
|
|||
CN = ca <---
|
||||
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");
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
conn->ssl = ssl; /* evhtp */
|
||||
if (SSL_set_fd(ssl, s) != 1){
|
||||
if (SSL_set_fd(rc->rc_ssl, rc->rc_s) != 1){
|
||||
clicon_err(OE_SSL, 0, "SSL_set_fd");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1302,30 +1418,25 @@ restconf_accept_client(int fd,
|
|||
/* 1: OK, -1 fatal, 0: TLS/SSL handshake was not successful
|
||||
* 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);
|
||||
e = SSL_get_error(ssl, ret);
|
||||
e = SSL_get_error(rc->rc_ssl, ret);
|
||||
switch (e){
|
||||
case SSL_ERROR_SSL: /* 1 */
|
||||
clicon_debug(1, "%s SSL_ERROR_SSL (non-ssl message on ssl socket)", __FUNCTION__);
|
||||
#if 0
|
||||
/* XXX sending a bad request here may crash
|
||||
* eg when run nmap --script ssl*
|
||||
*/
|
||||
if (send_badrequest(h, s, NULL, "application/yang-data+xml",
|
||||
#if 1
|
||||
if (send_badrequest(h, rc->rc_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)
|
||||
goto done;
|
||||
#endif
|
||||
SSL_free(ssl);
|
||||
if (close(s) < 0){
|
||||
SSL_free(rc->rc_ssl);
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
clixon_event_unreg_fd(s, restconf_connection);
|
||||
conn->ssl = NULL;
|
||||
clicon_debug(1, "%s conn-free (%p) 3", __FUNCTION__, conn);
|
||||
restconf_conn_free(conn);
|
||||
evhtp_connection_free(conn); /* evhtp */
|
||||
restconf_conn_free(rc);
|
||||
goto ok;
|
||||
break;
|
||||
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
|
||||
not be called.*/
|
||||
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 ok;
|
||||
break;
|
||||
|
|
@ -1365,7 +1476,7 @@ restconf_accept_client(int fd,
|
|||
goto done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* SSL_accept */
|
||||
} /* while(readmore) */
|
||||
/* For client-cert authentication, check if any certs are present,
|
||||
* if not, send bad request
|
||||
|
|
@ -1373,53 +1484,43 @@ restconf_accept_client(int fd,
|
|||
* but then SSL_accept fails.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
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;
|
||||
restconf_conn_free(conn);
|
||||
evhtp_connection_free(conn); /* evhtp */
|
||||
if (ssl){
|
||||
if ((ret = SSL_shutdown(ssl)) < 0){
|
||||
int e = SSL_get_error(ssl, ret);
|
||||
restconf_conn_free(rc);
|
||||
if (rc->rc_ssl){
|
||||
if ((ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
||||
int e = SSL_get_error(rc->rc_ssl, ret);
|
||||
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
||||
goto done;
|
||||
}
|
||||
SSL_free(ssl);
|
||||
SSL_free(rc->rc_ssl);
|
||||
rc->rc_ssl = NULL;
|
||||
}
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
/* 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) {
|
||||
/* 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 (alpn == NULL || alpnlen != 8 || memcmp("http/1.1", alpn, 8) != 0) {
|
||||
clicon_log(LOG_NOTICE, "------Warning1 Protocol http/1.1 not selected: %s", alpn);
|
||||
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 ((ret = ssl_alpn_check(h, alpn, alpnlen, rc, &proto)) < 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);
|
||||
}
|
||||
if (ret == 0)
|
||||
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 ?
|
||||
* Note this _only_ works if SSL_set1_host() was set previously,...
|
||||
*/
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK) { /* for peer cert */
|
||||
const char *peername = SSL_get0_peername(ssl);
|
||||
if (SSL_get_verify_result(rc->rc_ssl) == X509_V_OK) { /* for peer cert */
|
||||
|
||||
const char *peername = SSL_get0_peername(rc->rc_ssl);
|
||||
|
||||
if (peername != NULL) {
|
||||
/* Name checks were in scope and matched the peername */
|
||||
|
|
@ -1428,27 +1529,33 @@ restconf_accept_client(int fd,
|
|||
}
|
||||
#if 0 /* debug */
|
||||
if (clicon_debug_get())
|
||||
restconf_listcerts(ssl);
|
||||
restconf_listcerts(rc->rc_ssl);
|
||||
#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;
|
||||
}
|
||||
/*
|
||||
* Register callbacks for actual data socket
|
||||
/* Mutual pointers, from generic rc to evhtp specific and from evhtp conn to generic
|
||||
*/
|
||||
if ((rc = (restconf_conn_h*)malloc(sizeof(restconf_conn_h))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
rc->rc_arg = evconn; /* Generic to specific */
|
||||
evconn->arg = rc; /* Specific to generic */
|
||||
evconn->ssl = rc->rc_ssl; /* evhtp */
|
||||
}
|
||||
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)
|
||||
break;
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
case HTTP_2:
|
||||
default:
|
||||
break;
|
||||
} /* switch proto */
|
||||
if (clixon_event_reg_fd(rc->rc_s, restconf_connection, (void*)rc, "restconf client socket") < 0)
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
@ -1471,15 +1578,22 @@ restconf_native_terminate(clicon_handle h)
|
|||
clixon_event_unreg_fd(rsock->rs_ss, restconf_accept_client);
|
||||
close(rsock->rs_ss);
|
||||
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);
|
||||
}
|
||||
if (rh->rh_ctx)
|
||||
SSL_CTX_free(rh->rh_ctx);
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
if (rh->rh_evhtp){
|
||||
if (rh->rh_evhtp->evbase)
|
||||
event_base_free(rh->rh_evhtp->evbase);
|
||||
evhtp_free(rh->rh_evhtp);
|
||||
}
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
free(rh);
|
||||
}
|
||||
EVP_cleanup();
|
||||
|
|
@ -1596,6 +1710,7 @@ openssl_init_socket(clicon_handle h,
|
|||
}
|
||||
/*
|
||||
* Create per-socket openssl handle
|
||||
* See restconf_native_terminate for freeing
|
||||
*/
|
||||
if ((rsock = malloc(sizeof *rsock)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
|
|
@ -1605,6 +1720,15 @@ openssl_init_socket(clicon_handle h,
|
|||
rsock->rs_h = h;
|
||||
rsock->rs_ss = ss;
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
size_t veclen;
|
||||
int i;
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
evhtp_t *evhtp = NULL;
|
||||
struct event_base *evbase = NULL;
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
/* flag used for sanity of certs */
|
||||
|
|
@ -1699,6 +1825,7 @@ restconf_openssl_init(clicon_handle h,
|
|||
}
|
||||
rh = restconf_native_handle_get(h);
|
||||
rh->rh_ctx = ctx;
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
/* evhtp stuff */ /* XXX move this to global level */
|
||||
if ((evbase = event_base_new()) == NULL){
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
/* get the list of socket config-data */
|
||||
if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -287,7 +287,10 @@ api_data_write(clicon_handle h,
|
|||
cxobj *xfrom;
|
||||
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)
|
||||
goto done;
|
||||
xa = NULL;
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ typedef struct {
|
|||
cvec *rc_outp_hdrs; /* List of output headers */
|
||||
cbuf *rc_outp_buf; /* 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 request handle
|
||||
|
|
@ -77,6 +82,10 @@ typedef struct {
|
|||
clicon_handle rs_h; /* Clixon handle */
|
||||
int rs_ss; /* Server socket (ready for accept) */
|
||||
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 handle
|
||||
|
|
@ -84,8 +93,10 @@ typedef struct {
|
|||
*/
|
||||
typedef struct {
|
||||
SSL_CTX *rh_ctx; /* SSL context */
|
||||
evhtp_t *rh_evhtp; /* Evhtp struct */
|
||||
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;
|
||||
|
||||
/*
|
||||
|
|
|
|||
162
configure
vendored
162
configure
vendored
|
|
@ -718,6 +718,8 @@ with_cligen
|
|||
enable_optyangs
|
||||
enable_publish
|
||||
with_restconf
|
||||
enable_evhtp
|
||||
enable_nghttp2
|
||||
with_configfile
|
||||
with_libxml2
|
||||
with_yang_installdir
|
||||
|
|
@ -1365,6 +1367,10 @@ Optional Features:
|
|||
in clixon install, default: no
|
||||
--enable-publish Enable publish of notification streams using SSE and
|
||||
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:
|
||||
--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
|
||||
|
||||
|
||||
# Home dir for web user
|
||||
# Home dir for web user, such as nginx fcgi sockets
|
||||
wwwdir=/www-data
|
||||
|
||||
|
||||
|
|
@ -5045,6 +5051,11 @@ fi
|
|||
|
||||
$as_echo "#define WITH_RESTCONF_FCGI 1" >>confdefs.h
|
||||
# For c-code that cant use strings
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define WWWDIR "$wwwdir"
|
||||
_ACEOF
|
||||
|
||||
elif test "x${with_restconf}" == xnative; then
|
||||
{ $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; }
|
||||
|
|
@ -5140,6 +5151,41 @@ else
|
|||
as_fn_error $? "libcrypto missing" "$LINENO" 5
|
||||
fi
|
||||
|
||||
# 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; }
|
||||
if ${ac_cv_lib_event_event_init+:} false; then :
|
||||
|
|
@ -5187,24 +5233,6 @@ else
|
|||
as_fn_error $? "libevent missing" "$LINENO" 5
|
||||
fi
|
||||
|
||||
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 evhtp_new in -levhtp" >&5
|
||||
$as_echo_n "checking for evhtp_new in -levhtp... " >&6; }
|
||||
if ${ac_cv_lib_evhtp_evhtp_new+:} false; then :
|
||||
|
|
@ -5252,6 +5280,87 @@ else
|
|||
as_fn_error $? "libevhtp missing" "$LINENO" 5
|
||||
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
|
||||
# For c-code that cant use strings
|
||||
|
|
@ -5290,21 +5399,6 @@ if test "${with_restconf+set}" = set; then :
|
|||
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
|
||||
CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml
|
||||
|
||||
|
|
|
|||
29
configure.ac
29
configure.ac
|
|
@ -218,7 +218,17 @@ if test "x${with_restconf}" == xfcgi; then
|
|||
elif test "x${with_restconf}" == xnative; then
|
||||
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(event, event_init,, AC_MSG_ERROR([libevent missing]))
|
||||
# Check if evhtp is enabled for http/1
|
||||
AC_ARG_ENABLE(evhtp, AS_HELP_STRING([--disable-evhtp],[Disable evhtp for native restconf http/1, default: yes]),[
|
||||
if test "$enableval" = no; then
|
||||
ac_enable_evhtp=no
|
||||
else
|
||||
ac_enable_evhtp=yes
|
||||
fi
|
||||
],
|
||||
[ 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]),
|
||||
|
|
@ -226,7 +236,24 @@ elif test "x${with_restconf}" == xnative; then
|
|||
#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
|
||||
elif test "x${with_restconf}" == xno; then
|
||||
# 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). */
|
||||
#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). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
|
|
@ -72,6 +75,9 @@
|
|||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#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. */
|
||||
#undef HAVE_SETNS
|
||||
|
||||
|
|
@ -147,7 +153,7 @@
|
|||
/* Use native restconf mode */
|
||||
#undef WITH_RESTCONF_NATIVE
|
||||
|
||||
/* WWW dir for restconf daemon */
|
||||
/* WWW dir for fcgi stuff / nginx */
|
||||
#undef WWWDIR
|
||||
|
||||
/* 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");
|
||||
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,
|
||||
* dont decode since api_path2xpath_cvv takes uri encode as input */
|
||||
if (uri_str2cvec(api_path, '/', '=', 0, &cvv) < 0)
|
||||
|
|
|
|||
|
|
@ -1917,6 +1917,10 @@ xml_copy_one(cxobj *x0,
|
|||
int retval = -1;
|
||||
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));
|
||||
if ((s = xml_name(x0))) /* malloced string */
|
||||
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
|
||||
else # see (1) http to https port in restconf_main_native.c
|
||||
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 2>&1)" 56 "Connection reset by peer"
|
||||
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"
|
||||
fi
|
||||
|
||||
# Exact match
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
# 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
|
||||
# (1) fcgi/native
|
||||
# This is compile-time --with-restconf=fcgi or native, so either or
|
||||
# - fcgi: Assume http server setup, such as nginx described in apps/restconf/README.md
|
||||
# - native: test both local config and get config from backend
|
||||
# (2) http/https
|
||||
# - fcgi: relies on nginx has https setup
|
||||
# - native: generate self-signed server certs
|
||||
# (3) IPv4/IPv6 (only loopback 127.0.0.1 / ::1)
|
||||
# - The tests runs through both
|
||||
# - IPv6 by default disabled since docker does not support it out-of-the box
|
||||
# (4) local/backend config. Native only
|
||||
# - The tests runs through both (if compiled with native)
|
||||
# See also test_restconf_op.sh
|
||||
# See test_restconf_rpc.sh for cases when CLICON_BACKEND_RESTCONF_PROCESS is set
|
||||
# NMAP ssl script testing.
|
||||
# The following tests are run:
|
||||
# - ssl-ccs-injection, but not deterministic, need to repeat (10 times) maybe this is wrong?
|
||||
# - ssl-cert-intaddr
|
||||
# - ssl-cert
|
||||
# - ssl-date
|
||||
# - ssl-dh-params
|
||||
# - ssl-enum-ciphers
|
||||
# - ssl-heartbleed
|
||||
# - ssl-known-key
|
||||
# - ssl-poodle
|
||||
# - sslv2-drown
|
||||
# - sslv2
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
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
|
||||
cacerts $cakey $cacert
|
||||
servercerts $cakey $cacert $srvkey $srvcert
|
||||
USEBACKEND=true
|
||||
else
|
||||
# Define default restconfig config: RESTCONFIG
|
||||
RESTCONFIG=$(restconf_config none false)
|
||||
USEBACKEND=false
|
||||
fi
|
||||
|
||||
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
|
||||
state='{"clixon-example:state":{"op":\["41","42","43"\]}'
|
||||
|
||||
if $IPv6; then
|
||||
# For backend config, create 4 sockets, all combinations IPv4/IPv6 + http/https
|
||||
RESTCONFIG1=$(cat <<EOF
|
||||
<restconf xmlns="http://clicon.org/restconf">
|
||||
# Create a single IPv4 https socket
|
||||
RESTCONFIG=$(cat <<EOF
|
||||
<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>::</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>
|
||||
</restconf>
|
||||
EOF
|
||||
)
|
||||
fi
|
||||
|
||||
|
||||
# Clixon config
|
||||
cat <<EOF > $cfg
|
||||
|
|
@ -124,8 +95,8 @@ cat <<EOF > $cfg
|
|||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
|
||||
<CLICON_BACKEND_RESTCONF_PROCESS>$USEBACKEND</CLICON_BACKEND_RESTCONF_PROCESS>
|
||||
$RESTCONFIG <!-- only fcgi -->
|
||||
<CLICON_BACKEND_RESTCONF_PROCESS>false</CLICON_BACKEND_RESTCONF_PROCESS>
|
||||
$RESTCONFIG
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
|
|
@ -145,11 +116,11 @@ fi
|
|||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
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>]]>]]>$"
|
||||
#new "netconf edit config"
|
||||
#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"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||
#new "netconf commit"
|
||||
#expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
if [ $RC -ne 0 ]; then
|
||||
new "kill old restconf daemon"
|
||||
|
|
@ -158,7 +129,7 @@ if [ $RC -ne 0 ]; then
|
|||
new "start restconf daemon"
|
||||
# inline of start_restconf, cant make quotes to work
|
||||
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
|
||||
err1 "expected 0" "$?"
|
||||
fi
|
||||
|
|
@ -167,10 +138,54 @@ fi
|
|||
new "wait restconf"
|
||||
wait_restconf
|
||||
|
||||
sleep 1 # Sometimes nmap test fails with no reply from server, _maybe_ this helps?
|
||||
new "nmap test"
|
||||
# Try 10 times, dont know why this is undeterministic?
|
||||
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
|
||||
new "Kill restconf daemon"
|
||||
|
|
@ -192,8 +207,8 @@ fi
|
|||
unset RCPROTO
|
||||
|
||||
# Set by restconf_config
|
||||
unset result
|
||||
unset RESTCONFIG
|
||||
unset RESTCONFIG1
|
||||
|
||||
rm -rf $dir
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue