Refactoring of RESTCONF/TLS close code
Single closing function: restconf_close_ssl_socket Added constant HTTP_ON_HTTPS_REPLY for http request on https socket
This commit is contained in:
parent
e39d18d59f
commit
c1e4595949
11 changed files with 354 additions and 272 deletions
|
|
@ -67,6 +67,7 @@ Users may have to change how they access the system
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
|
|
||||||
|
* Fixed: [yang regular char \w not include underline char](https://github.com/clicon/clixon/issues/357)
|
||||||
* Fixed: [Clixon backend transactions for choice/case is not logical](https://github.com/clicon/clixon/issues/361)
|
* Fixed: [Clixon backend transactions for choice/case is not logical](https://github.com/clicon/clixon/issues/361)
|
||||||
* Fixed: [Clixon backend transaction callback fails for empty types](https://github.com/clicon/clixon/issues/360)
|
* Fixed: [Clixon backend transaction callback fails for empty types](https://github.com/clicon/clixon/issues/360)
|
||||||
* Fixed: [with-defaults=trim does not work due to dodgy handling of state data marked as default](https://github.com/clicon/clixon/issues/348)
|
* Fixed: [with-defaults=trim does not work due to dodgy handling of state data marked as default](https://github.com/clicon/clixon/issues/348)
|
||||||
|
|
|
||||||
|
|
@ -346,7 +346,7 @@ cli_auto_top(clicon_handle h,
|
||||||
* <dbname> "running"|"candidate"|"startup"
|
* <dbname> "running"|"candidate"|"startup"
|
||||||
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
||||||
* <pretty> true|false: pretty-print or not
|
* <pretty> true|false: pretty-print or not
|
||||||
* <state> true|false: pretty-print or not
|
* <state> true|false: include state in output
|
||||||
* <default> Retrieval default mode: report-all, trim, explicit, report-all-tagged,
|
* <default> Retrieval default mode: report-all, trim, explicit, report-all-tagged,
|
||||||
* report-all-tagged-default, report-all-tagged-strip
|
* report-all-tagged-default, report-all-tagged-strip
|
||||||
* <prefix> CLI prefix: to print before cli syntax output
|
* <prefix> CLI prefix: to print before cli syntax output
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,22 @@
|
||||||
* Data structures:
|
* Data structures:
|
||||||
* 1 1
|
* 1 1
|
||||||
* +--------------------+ restconf_handle_get +--------------------+
|
* +--------------------+ restconf_handle_get +--------------------+
|
||||||
* | rh restconf_handle | <--------------------- | h clicon_handle |
|
* | rn restconf_native | <--------------------- | h clicon_handle |
|
||||||
* +--------------------+ +--------------------+
|
* | _handle | +--------------------+
|
||||||
* common SSL config \ ^
|
* +--------------------+ ^
|
||||||
* \ | n
|
* common SSL config \ |
|
||||||
* \ rh_sockets +--------------------+
|
* \ | n
|
||||||
|
* \ rn_sockets +--------------------+
|
||||||
* +-----------> | rs restconf_socket |
|
* +-----------> | rs restconf_socket |
|
||||||
* +--------------------+
|
* +--------------------+
|
||||||
* n per-socket SSL config
|
* per-server socket (per config)
|
||||||
|
* | ^
|
||||||
|
* rs_conns v | n
|
||||||
|
* +--------------------+
|
||||||
|
* | rc restconf_conn |
|
||||||
|
* +--------------------+
|
||||||
|
* per-connection (transient)
|
||||||
|
* n
|
||||||
* +--------------------+
|
* +--------------------+
|
||||||
* | rr restconf_request| per-packet
|
* | rr restconf_request| per-packet
|
||||||
* +--------------------+
|
* +--------------------+
|
||||||
|
|
@ -449,38 +457,6 @@ restconf_ssl_context_configure(clixon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Utility function to close restconf server ssl socket.
|
|
||||||
* There are many variants to closing, one could probably make this more generic
|
|
||||||
* and always use this function, but it is difficult.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
restconf_close_ssl_socket(restconf_conn *rc,
|
|
||||||
int shutdown)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (rc->rc_ssl != NULL){
|
|
||||||
if (shutdown && (ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
|
||||||
#if 0
|
|
||||||
case SSL_ERROR_ZERO_RETURN: /* 6 */
|
|
||||||
Note that in this case SSL_ERROR_ZERO_RETURN does not necessarily indicate that the underlying transport has been closed.
|
|
||||||
#endif
|
|
||||||
int e = SSL_get_error(rc->rc_ssl, ret);
|
|
||||||
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
SSL_free(rc->rc_ssl);
|
|
||||||
rc->rc_ssl = NULL;
|
|
||||||
}
|
|
||||||
if (restconf_connection_close(rc->rc_h, rc->rc_s, rc->rc_socket) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0 /* debug */
|
#if 0 /* debug */
|
||||||
/*! Debug print all loaded certs
|
/*! Debug print all loaded certs
|
||||||
*/
|
*/
|
||||||
|
|
@ -581,7 +557,7 @@ restconf_accept_client(int fd,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Accept SSL */
|
/* Accept SSL */
|
||||||
if (restconf_ssl_accept_client(h, s, rsock) < 0)
|
if (restconf_ssl_accept_client(h, s, rsock, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -596,22 +572,29 @@ restconf_accept_client(int fd,
|
||||||
static int
|
static int
|
||||||
restconf_native_terminate(clicon_handle h)
|
restconf_native_terminate(clicon_handle h)
|
||||||
{
|
{
|
||||||
restconf_native_handle *rh;
|
restconf_native_handle *rn;
|
||||||
restconf_socket *rsock;
|
restconf_socket *rsock;
|
||||||
|
restconf_conn *rc;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((rh = restconf_native_handle_get(h)) != NULL){
|
if ((rn = restconf_native_handle_get(h)) != NULL){
|
||||||
while ((rsock = rh->rh_sockets) != NULL){
|
while ((rsock = rn->rn_sockets) != NULL){
|
||||||
|
while ((rc = rsock->rs_conns) != NULL){
|
||||||
|
if (rc->rc_s != -1){
|
||||||
|
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||||
|
close(rc->rc_s);
|
||||||
|
}
|
||||||
|
DELQ(rc, rsock->rs_conns, restconf_conn *);
|
||||||
|
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
|
||||||
|
}
|
||||||
if (rsock->rs_callhome){
|
if (rsock->rs_callhome){
|
||||||
restconf_callhome_timer_unreg(rsock);
|
restconf_callhome_timer_unreg(rsock);
|
||||||
if (rsock->rs_periodic)
|
|
||||||
restconf_idle_timer_unreg(rsock);
|
|
||||||
}
|
}
|
||||||
else if (rsock->rs_ss != -1){
|
else if (rsock->rs_ss != -1){
|
||||||
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, rn->rn_sockets, restconf_socket *);
|
||||||
if (rsock->rs_description)
|
if (rsock->rs_description)
|
||||||
free(rsock->rs_description);
|
free(rsock->rs_description);
|
||||||
if (rsock->rs_addrstr)
|
if (rsock->rs_addrstr)
|
||||||
|
|
@ -620,9 +603,9 @@ restconf_native_terminate(clicon_handle h)
|
||||||
free(rsock->rs_addrtype);
|
free(rsock->rs_addrtype);
|
||||||
free(rsock);
|
free(rsock);
|
||||||
}
|
}
|
||||||
if (rh->rh_ctx)
|
if (rn->rn_ctx)
|
||||||
SSL_CTX_free(rh->rh_ctx);
|
SSL_CTX_free(rn->rn_ctx);
|
||||||
free(rh);
|
free(rn);
|
||||||
}
|
}
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -716,7 +699,7 @@ openssl_init_socket(clicon_handle h,
|
||||||
char *addrtype = NULL;
|
char *addrtype = NULL;
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
int ss = -1;
|
int ss = -1;
|
||||||
restconf_native_handle *rh = NULL;
|
restconf_native_handle *rn = NULL;
|
||||||
restconf_socket *rsock = NULL; /* openssl per socket struct */
|
restconf_socket *rsock = NULL; /* openssl per socket struct */
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
|
||||||
|
|
@ -755,7 +738,7 @@ openssl_init_socket(clicon_handle h,
|
||||||
) < 0)
|
) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
if ((rn = restconf_native_handle_get(h)) == NULL){
|
||||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -768,7 +751,7 @@ openssl_init_socket(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
rsock->rs_port = port;
|
rsock->rs_port = port;
|
||||||
INSQ(rsock, rh->rh_sockets);
|
INSQ(rsock, rn->rn_sockets);
|
||||||
|
|
||||||
if (rsock->rs_callhome){
|
if (rsock->rs_callhome){
|
||||||
rsock->rs_ss = -1; /* Not applicable from callhome */
|
rsock->rs_ss = -1; /* Not applicable from callhome */
|
||||||
|
|
@ -809,7 +792,7 @@ restconf_openssl_init(clicon_handle h,
|
||||||
char *server_cert_path = NULL;
|
char *server_cert_path = NULL;
|
||||||
char *server_key_path = NULL;
|
char *server_key_path = NULL;
|
||||||
char *server_ca_cert_path = NULL;
|
char *server_ca_cert_path = NULL;
|
||||||
restconf_native_handle *rh;
|
restconf_native_handle *rn;
|
||||||
clixon_auth_type_t auth_type;
|
clixon_auth_type_t auth_type;
|
||||||
int dbg;
|
int dbg;
|
||||||
char *bstr;
|
char *bstr;
|
||||||
|
|
@ -868,8 +851,8 @@ restconf_openssl_init(clicon_handle h,
|
||||||
if (restconf_ssl_context_configure(h, ctx, server_cert_path, server_key_path, server_ca_cert_path) < 0)
|
if (restconf_ssl_context_configure(h, ctx, server_cert_path, server_key_path, server_ca_cert_path) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
rh = restconf_native_handle_get(h);
|
rn = restconf_native_handle_get(h);
|
||||||
rh->rh_ctx = ctx;
|
rn->rn_ctx = ctx;
|
||||||
/* 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;
|
||||||
|
|
@ -1123,7 +1106,7 @@ main(int argc,
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
int dbg = 0;
|
int dbg = 0;
|
||||||
int logdst = CLICON_LOG_SYSLOG;
|
int logdst = CLICON_LOG_SYSLOG;
|
||||||
restconf_native_handle *rh = NULL;
|
restconf_native_handle *rn = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
cxobj *xrestconf = NULL;
|
cxobj *xrestconf = NULL;
|
||||||
char *inline_config = NULL;
|
char *inline_config = NULL;
|
||||||
|
|
@ -1286,12 +1269,12 @@ main(int argc,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Create and stroe global openssl handle */
|
/* Create and stroe global openssl handle */
|
||||||
if ((rh = malloc(sizeof *rh)) == NULL){
|
if ((rn = malloc(sizeof *rn)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memset(rh, 0, sizeof *rh);
|
memset(rn, 0, sizeof *rn);
|
||||||
if (restconf_native_handle_set(h, rh) < 0)
|
if (restconf_native_handle_set(h, rn) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Openssl inits */
|
/* Openssl inits */
|
||||||
if (restconf_openssl_init(h, dbg, xrestconf) < 0)
|
if (restconf_openssl_init(h, dbg, xrestconf) < 0)
|
||||||
|
|
@ -1305,7 +1288,6 @@ main(int argc,
|
||||||
/* Main event loop */
|
/* Main event loop */
|
||||||
if (clixon_event_loop(h) < 0)
|
if (clixon_event_loop(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_debug(1, "%s after", __FUNCTION__);
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "restconf_main_openssl done");
|
clicon_debug(1, "restconf_main_openssl done");
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,10 @@ api_data_get2(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (xmlns_set_all(x, nscd) < 0)
|
if (xmlns_set_all(x, nscd) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (nscd){
|
||||||
|
cvec_free(nscd);
|
||||||
|
nscd = NULL;
|
||||||
|
}
|
||||||
if (clixon_xml2cbuf(cbx, x, 0, pretty, -1, 0) < 0) /* Dont print top object? */
|
if (clixon_xml2cbuf(cbx, x, 0, pretty, -1, 0) < 0) /* Dont print top object? */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -301,7 +305,7 @@ api_data_get2(clicon_handle h,
|
||||||
if (xpath)
|
if (xpath)
|
||||||
free(xpath);
|
free(xpath);
|
||||||
if (nscd)
|
if (nscd)
|
||||||
xml_nsctx_free(nscd);
|
cvec_free(nscd);
|
||||||
if (nsc)
|
if (nsc)
|
||||||
xml_nsctx_free(nsc);
|
xml_nsctx_free(nsc);
|
||||||
if (xtop)
|
if (xtop)
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,12 @@ restconf_stream_free(restconf_stream_data *sd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Create restconf connection struct
|
/*! Create restconf connection struct, per connect, ie transient
|
||||||
|
*
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in] s Connected socket
|
||||||
|
* @param[in] rsock Backpointer to server struct
|
||||||
|
* @see restconf_conn_free
|
||||||
*/
|
*/
|
||||||
restconf_conn *
|
restconf_conn *
|
||||||
restconf_conn_new(clicon_handle h,
|
restconf_conn_new(clicon_handle h,
|
||||||
|
|
@ -180,22 +185,30 @@ restconf_conn_new(clicon_handle h,
|
||||||
memset(rc, 0, sizeof(restconf_conn));
|
memset(rc, 0, sizeof(restconf_conn));
|
||||||
rc->rc_h = h;
|
rc->rc_h = h;
|
||||||
rc->rc_s = s;
|
rc->rc_s = s;
|
||||||
|
rc->rc_callhome = rsock->rs_callhome;
|
||||||
rc->rc_socket = rsock;
|
rc->rc_socket = rsock;
|
||||||
|
INSQ(rc, rsock->rs_conns);
|
||||||
|
clicon_debug(1, "%s %p", __FUNCTION__, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Free clixon/cbuf resources related to a connection
|
/*! Free clixon/cbuf resources related to a connection
|
||||||
* @param[in] rc restconf connection
|
* @param[in] rc restconf connection
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
restconf_conn_free(restconf_conn *rc)
|
restconf_conn_free(restconf_conn *rc)
|
||||||
{
|
{
|
||||||
|
int retval = -1;
|
||||||
restconf_stream_data *sd;
|
restconf_stream_data *sd;
|
||||||
|
restconf_socket *rsock;
|
||||||
|
restconf_conn *rc1;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (rc == NULL){
|
if (rc == NULL){
|
||||||
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
|
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
|
clicon_debug(1, "%s %p", __FUNCTION__, rc);
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
if (rc->rc_ngsession)
|
if (rc->rc_ngsession)
|
||||||
nghttp2_session_del(rc->rc_ngsession);
|
nghttp2_session_del(rc->rc_ngsession);
|
||||||
|
|
@ -206,8 +219,21 @@ restconf_conn_free(restconf_conn *rc)
|
||||||
if (sd)
|
if (sd)
|
||||||
restconf_stream_free(sd);
|
restconf_stream_free(sd);
|
||||||
}
|
}
|
||||||
|
/* Free connect from server sock */
|
||||||
|
if ((rsock = rc->rc_socket) != NULL &&
|
||||||
|
(rc1 = rsock->rs_conns) != NULL){
|
||||||
|
do {
|
||||||
|
if (rc == rc1){
|
||||||
|
DELQ(rc, rsock->rs_conns, restconf_conn *);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rc1 = NEXTQ(restconf_conn *, rc1);
|
||||||
|
} while (rc1 && rc1 != rsock->rs_conns);
|
||||||
|
}
|
||||||
free(rc);
|
free(rc);
|
||||||
return 0;
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given SSL connection, get peer certificate one-line name
|
/*! Given SSL connection, get peer certificate one-line name
|
||||||
|
|
@ -337,20 +363,27 @@ restconf_connection_sanity(clicon_handle h,
|
||||||
|
|
||||||
/* Write buf to socket
|
/* Write buf to socket
|
||||||
* see also this function in restcont_api_openssl.c
|
* see also this function in restcont_api_openssl.c
|
||||||
|
* @retval 1 OK
|
||||||
|
* @retval 0 OK, but socket write returned error, caller should close rc
|
||||||
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
native_buf_write(clicon_handle h,
|
native_buf_write(clicon_handle h,
|
||||||
char *buf,
|
char *buf,
|
||||||
size_t buflen,
|
size_t buflen,
|
||||||
int s,
|
restconf_conn *rc)
|
||||||
SSL *ssl,
|
|
||||||
restconf_socket *rsock)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
ssize_t totlen = 0;
|
ssize_t totlen = 0;
|
||||||
int er;
|
int er;
|
||||||
|
SSL *ssl;
|
||||||
|
|
||||||
|
if (rc == NULL){
|
||||||
|
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ssl = rc->rc_ssl;
|
||||||
/* Two problems with debugging buffers that this fixes:
|
/* Two problems with debugging buffers that this fixes:
|
||||||
* 1. they are not "strings" in the sense they are not NULL-terminated
|
* 1. they are not "strings" in the sense they are not NULL-terminated
|
||||||
* 2. they are often very long
|
* 2. they are often very long
|
||||||
|
|
@ -376,12 +409,9 @@ native_buf_write(clicon_handle h,
|
||||||
case SSL_ERROR_SYSCALL: /* 5 */
|
case SSL_ERROR_SYSCALL: /* 5 */
|
||||||
if (er == ECONNRESET || /* Connection reset by peer */
|
if (er == ECONNRESET || /* Connection reset by peer */
|
||||||
er == EPIPE) { /* Reading end of socket is closed */
|
er == EPIPE) { /* Reading end of socket is closed */
|
||||||
if (ssl){
|
if (0 && restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
SSL_free(ssl);
|
|
||||||
}
|
|
||||||
if (restconf_connection_close(h, s, rsock) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
goto ok; /* Close socket and ssl */
|
goto closed; /* Close socket and ssl */
|
||||||
}
|
}
|
||||||
else if (er == EAGAIN){
|
else if (er == EAGAIN){
|
||||||
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
|
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
|
||||||
|
|
@ -402,7 +432,7 @@ native_buf_write(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if ((len = write(s, buf+totlen, buflen-totlen)) < 0){
|
if ((len = write(rc->rc_s, buf+totlen, buflen-totlen)) < 0){
|
||||||
switch (errno){
|
switch (errno){
|
||||||
case EAGAIN: /* Operation would block */
|
case EAGAIN: /* Operation would block */
|
||||||
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
|
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
|
||||||
|
|
@ -412,9 +442,9 @@ native_buf_write(clicon_handle h,
|
||||||
// case EBADF: // XXX if this happens there is some larger error
|
// case EBADF: // XXX if this happens there is some larger error
|
||||||
case ECONNRESET: /* Connection reset by peer */
|
case ECONNRESET: /* Connection reset by peer */
|
||||||
case EPIPE: /* Broken pipe */
|
case EPIPE: /* Broken pipe */
|
||||||
if (restconf_connection_close(h, s, rsock) < 0)
|
if (0 && restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok; /* Close socket and ssl */
|
goto closed; /* Close socket and ssl */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
clicon_err(OE_UNIX, errno, "write %d", errno);
|
clicon_err(OE_UNIX, errno, "write %d", errno);
|
||||||
|
|
@ -426,27 +456,30 @@ native_buf_write(clicon_handle h,
|
||||||
}
|
}
|
||||||
totlen += len;
|
totlen += len;
|
||||||
} /* while */
|
} /* while */
|
||||||
ok:
|
retval = 1;
|
||||||
retval = 0;
|
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
return retval;
|
return retval;
|
||||||
|
closed:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Send early handcoded bad request reply before actual packet received, just after accept
|
/*! Send early handcoded bad request reply before actual packet received, just after accept
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @param[in] s Socket
|
* @param[in] media
|
||||||
* @param[in] ssl If set, it will be freed
|
|
||||||
* @param[in] body If given add message body using media
|
* @param[in] body If given add message body using media
|
||||||
|
* @param[in] rc Restconf connection, note may be closed in this
|
||||||
|
* @retval 1 OK
|
||||||
|
* @retval 0 OK, but socket write returned error, caller should close rc
|
||||||
|
* @retval -1 Error
|
||||||
* @see restconf_badrequest which can only be called in a request context
|
* @see restconf_badrequest which can only be called in a request context
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
native_send_badrequest(clicon_handle h,
|
native_send_badrequest(clicon_handle h,
|
||||||
int s,
|
char *media,
|
||||||
SSL *ssl,
|
char *body,
|
||||||
char *media,
|
restconf_conn *rc)
|
||||||
char *body,
|
|
||||||
restconf_socket *rsock)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
|
@ -466,9 +499,7 @@ native_send_badrequest(clicon_handle h,
|
||||||
cprintf(cb, "\r\n");
|
cprintf(cb, "\r\n");
|
||||||
if (body)
|
if (body)
|
||||||
cprintf(cb, "%s\r\n", body);
|
cprintf(cb, "%s\r\n", body);
|
||||||
if (native_buf_write(h, cbuf_get(cb), cbuf_len(cb), s, ssl, rsock) < 0) // XXX rsock
|
retval = native_buf_write(h, cbuf_get(cb), cbuf_len(cb), rc);
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
done:
|
||||||
if (cb)
|
if (cb)
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
|
|
@ -579,9 +610,8 @@ read_regular(restconf_conn *rc,
|
||||||
switch(errno){
|
switch(errno){
|
||||||
case ECONNRESET:/* Connection reset by peer */
|
case ECONNRESET:/* Connection reset by peer */
|
||||||
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
|
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
|
||||||
if (restconf_connection_close(rc->rc_h, rc->rc_s, rc->rc_socket) < 0)
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
restconf_conn_free(rc);
|
|
||||||
retval = 0; /* Close socket and ssl */
|
retval = 0; /* Close socket and ssl */
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
|
|
@ -614,10 +644,10 @@ read_regular(restconf_conn *rc,
|
||||||
* @retval 1 OK
|
* @retval 1 OK
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
restconf_http1_process(restconf_conn *rc,
|
restconf_http1_process(restconf_conn *rc,
|
||||||
char *buf,
|
char *buf,
|
||||||
size_t n,
|
size_t n,
|
||||||
int *readmore)
|
int *readmore)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
restconf_stream_data *sd;
|
restconf_stream_data *sd;
|
||||||
|
|
@ -680,7 +710,7 @@ restconf_http1_process(restconf_conn *rc,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
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>%s</error-message></error></errors>", clicon_err_reason);
|
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>%s</error-message></error></errors>", clicon_err_reason);
|
||||||
if (native_send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml", cbuf_get(cberr), rc->rc_socket) < 0)
|
if ((ret = native_send_badrequest(h, "application/yang-data+xml", cbuf_get(cberr), rc)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
@ -690,11 +720,17 @@ restconf_http1_process(restconf_conn *rc,
|
||||||
if ((ret = http1_check_expect(h, rc, sd)) < 0)
|
if ((ret = http1_check_expect(h, rc, sd)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 1){
|
if (ret == 1){
|
||||||
if (native_buf_write(h, cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
|
if ((ret = native_buf_write(h, cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf), rc)) < 0)
|
||||||
rc->rc_s, rc->rc_ssl, rc->rc_socket) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
cvec_reset(sd->sd_outp_hdrs);
|
cvec_reset(sd->sd_outp_hdrs);
|
||||||
cbuf_reset(sd->sd_outp_buf);
|
cbuf_reset(sd->sd_outp_buf);
|
||||||
|
if (ret == 0){
|
||||||
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
|
goto done;
|
||||||
|
rc = NULL;
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Check whole message is read.
|
/* Check whole message is read.
|
||||||
|
|
@ -718,19 +754,15 @@ restconf_http1_process(restconf_conn *rc,
|
||||||
/* main restconf processing */
|
/* main restconf processing */
|
||||||
if (restconf_http1_path_root(h, rc) < 0)
|
if (restconf_http1_path_root(h, rc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (native_buf_write(h, cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
|
if ((ret = native_buf_write(h, cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf), rc)) < 0)
|
||||||
rc->rc_s, rc->rc_ssl, rc->rc_socket) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */
|
cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */
|
||||||
cbuf_reset(sd->sd_outp_buf);
|
cbuf_reset(sd->sd_outp_buf);
|
||||||
cbuf_reset(sd->sd_inbuf);
|
cbuf_reset(sd->sd_inbuf);
|
||||||
cbuf_reset(sd->sd_indata);
|
cbuf_reset(sd->sd_indata);
|
||||||
if (rc->rc_exit){ /* Server-initiated exit */
|
if (ret == 0 || rc->rc_exit){ /* Server-initiated exit */
|
||||||
SSL_free(rc->rc_ssl);
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
rc->rc_ssl = NULL;
|
|
||||||
if (restconf_connection_close(h, rc->rc_s, rc->rc_socket) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
restconf_conn_free(rc);
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -761,7 +793,7 @@ restconf_http2_upgrade(restconf_conn *rc)
|
||||||
/* Switch to http/2 according to RFC 7540 Sec 3.2 and RFC 7230 Sec 6.7 */
|
/* Switch to http/2 according to RFC 7540 Sec 3.2 and RFC 7230 Sec 6.7 */
|
||||||
rc->rc_proto = HTTP_2;
|
rc->rc_proto = HTTP_2;
|
||||||
if (http2_session_init(rc) < 0){
|
if (http2_session_init(rc) < 0){
|
||||||
restconf_close_ssl_socket(rc, 1);
|
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* The HTTP/1.1 request that is sent prior to upgrade is assigned a
|
/* The HTTP/1.1 request that is sent prior to upgrade is assigned a
|
||||||
|
|
@ -780,7 +812,7 @@ restconf_http2_upgrade(restconf_conn *rc)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (http2_send_server_connection(rc) < 0){
|
if (http2_send_server_connection(rc) < 0){
|
||||||
restconf_close_ssl_socket(rc, 1);
|
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Use params from original http/1 session to http/2 stream */
|
/* Use params from original http/1 session to http/2 stream */
|
||||||
|
|
@ -836,8 +868,7 @@ restconf_http2_process(restconf_conn *rc,
|
||||||
if ((ret = http2_recv(rc, (unsigned char *)buf, n)) < 0)
|
if ((ret = http2_recv(rc, (unsigned char *)buf, n)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
restconf_close_ssl_socket(rc, 0);
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
if (restconf_conn_free(rc) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -860,7 +891,7 @@ restconf_http2_process(restconf_conn *rc,
|
||||||
|
|
||||||
/*! Get restconf native handle
|
/*! Get restconf native handle
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @retval rh Restconf native handle
|
* @retval rn Restconf native handle
|
||||||
*/
|
*/
|
||||||
restconf_native_handle *
|
restconf_native_handle *
|
||||||
restconf_native_handle_get(clicon_handle h)
|
restconf_native_handle_get(clicon_handle h)
|
||||||
|
|
@ -925,9 +956,8 @@ restconf_connection(int s,
|
||||||
continue;
|
continue;
|
||||||
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 (restconf_close_ssl_socket(rc, 0) < 0)
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
restconf_conn_free(rc);
|
|
||||||
rc = NULL;
|
rc = NULL;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
@ -966,27 +996,33 @@ restconf_connection(int s,
|
||||||
return retval;
|
return retval;
|
||||||
} /* restconf_connection */
|
} /* restconf_connection */
|
||||||
|
|
||||||
|
/*----------------------------- Close socket ------------------------------*/
|
||||||
|
|
||||||
/*! Close Restconf native connection socket and unregister callback
|
/*! Close Restconf native connection socket and unregister callback
|
||||||
* For callhome also start reconnect timer
|
* For callhome also start reconnect timer
|
||||||
|
* @param[in] rc rstconf connection
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
restconf_connection_close(clicon_handle h,
|
restconf_connection_close1(restconf_conn *rc)
|
||||||
int s,
|
|
||||||
restconf_socket *rsock)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
restconf_socket *rsock;
|
||||||
|
|
||||||
clicon_debug(1, "%s %s", __FUNCTION__, rsock->rs_description);
|
if (rc == NULL){
|
||||||
if (close(s) < 0){
|
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
rsock = rc->rc_socket;
|
||||||
|
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||||
|
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);
|
||||||
/* re-set timer */
|
/* re-set timer */
|
||||||
if (rsock->rs_callhome){
|
if (rc->rc_callhome){
|
||||||
if (rsock->rs_periodic &&
|
if (rsock->rs_periodic)
|
||||||
restconf_idle_timer_unreg(rsock) < 0)
|
restconf_idle_timer_unreg(rc);
|
||||||
goto done;
|
|
||||||
if (restconf_callhome_timer(rsock, 1) < 0)
|
if (restconf_callhome_timer(rsock, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -996,6 +1032,61 @@ restconf_connection_close(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Utility function to close restconf server ssl socket.
|
||||||
|
* There are many variants to closing, one could probably make this more generic
|
||||||
|
* and always use this function, but it is difficult.
|
||||||
|
* @param[in] rc restconf connection
|
||||||
|
* @param[in] callfn For debug
|
||||||
|
* @param[in] dontshutdown If != 0, do not shutdown
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
restconf_close_ssl_socket(restconf_conn *rc,
|
||||||
|
const char *callfn,
|
||||||
|
int dontshutdown)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int ret;
|
||||||
|
int sslerr;
|
||||||
|
int er;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
|
if (rc->rc_ssl != NULL){
|
||||||
|
if (!dontshutdown &&
|
||||||
|
(ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
||||||
|
er = errno;
|
||||||
|
sslerr = SSL_get_error(rc->rc_ssl, ret);
|
||||||
|
clicon_debug(1, "%s errno:%d sslerr:%d", __FUNCTION__, er, sslerr);
|
||||||
|
// case SSL_ERROR_ZERO_RETURN: /* 6 */
|
||||||
|
// Note that in this case SSL_ERROR_ZERO_RETURN does not necessarily indicate that the underlying transport has been closed.
|
||||||
|
if (sslerr == SSL_ERROR_SSL){ /* 1 */
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (sslerr == SSL_ERROR_SYSCALL){ /* 5 */
|
||||||
|
/* Some non-recoverable, fatal I/O error occurred. The OpenSSL error queue
|
||||||
|
may contain more information on the error. For socket I/O on Unix systems,
|
||||||
|
consult errno for details. If this error occurs then no further I/O
|
||||||
|
operations should be performed on the connection and SSL_shutdown() must
|
||||||
|
not be called.*/
|
||||||
|
/* Ignore eg EBADF/ECONNRESET/EPIPE */
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
clicon_err(OE_SSL, sslerr, "SSL_shutdown, %s err:%d %d", callfn, sslerr, er);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SSL_free(rc->rc_ssl);
|
||||||
|
rc->rc_ssl = NULL;
|
||||||
|
}
|
||||||
|
if (restconf_connection_close1(rc) < 0)
|
||||||
|
goto done;
|
||||||
|
if (restconf_conn_free(rc) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*------------------------------ Accept--------------------------------*/
|
/*------------------------------ Accept--------------------------------*/
|
||||||
|
|
||||||
/*! Check ALPN result
|
/*! Check ALPN result
|
||||||
|
|
@ -1012,7 +1103,6 @@ ssl_alpn_check(clicon_handle h,
|
||||||
restconf_http_proto *proto)
|
restconf_http_proto *proto)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int ret;
|
|
||||||
cbuf *cberr = NULL;
|
cbuf *cberr = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
|
|
@ -1037,34 +1127,17 @@ ssl_alpn_check(clicon_handle h,
|
||||||
if (alpn != NULL){
|
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);
|
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_INFO, "%s Warning: %s", __FUNCTION__, cbuf_get(cberr));
|
clicon_log(LOG_INFO, "%s Warning: %s", __FUNCTION__, cbuf_get(cberr));
|
||||||
if (native_send_badrequest(h, rc->rc_s, rc->rc_ssl,
|
if (native_send_badrequest(h,
|
||||||
"application/yang-data+xml",
|
"application/yang-data+xml",
|
||||||
cbuf_get(cberr), rc->rc_socket) < 0)
|
cbuf_get(cberr), rc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
/* XXX Sending badrequest here gives a segv in SSL_shutdown() later or a SIGPIPE here */
|
/* XXX Sending badrequest here gives a segv in SSL_shutdown() later or a SIGPIPE here */
|
||||||
clicon_log(LOG_INFO, "%s Warning: ALPN: No protocol selected, or no ALPN?", __FUNCTION__);
|
clicon_log(LOG_INFO, "%s Warning: ALPN: No protocol selected, or no ALPN?", __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
if (rc->rc_ssl){
|
goto done;
|
||||||
/* 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_INFO, "%s Warning: SSL_shutdown SSL_ERROR_SYSCALL", __FUNCTION__);
|
|
||||||
/* Continue */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SSL_free(rc->rc_ssl);
|
|
||||||
}
|
|
||||||
restconf_conn_free(rc);
|
|
||||||
}
|
}
|
||||||
retval = 0; /* ALPN not OK */
|
retval = 0; /* ALPN not OK */
|
||||||
done:
|
done:
|
||||||
|
|
@ -1078,15 +1151,18 @@ ssl_alpn_check(clicon_handle h,
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @param[in] s Socket (unix or ip)
|
* @param[in] s Socket (unix or ip)
|
||||||
* @param[in] rsock Socket struct
|
* @param[in] rsock Socket struct
|
||||||
|
* @param[out] rcp Restconf connection
|
||||||
* @see openssl_init_socket where this callback is registered
|
* @see openssl_init_socket where this callback is registered
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
restconf_ssl_accept_client(clicon_handle h,
|
restconf_ssl_accept_client(clicon_handle h,
|
||||||
int s,
|
int s,
|
||||||
restconf_socket *rsock)
|
restconf_socket *rsock,
|
||||||
|
restconf_conn **rcp
|
||||||
|
)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
restconf_native_handle *rh = NULL;
|
restconf_native_handle *rn = NULL;
|
||||||
restconf_conn *rc = NULL;
|
restconf_conn *rc = NULL;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -1103,7 +1179,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
||||||
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
|
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
if ((rn = restconf_native_handle_get(h)) == NULL){
|
||||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1114,7 +1190,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
clicon_debug(1, "%s s:%d", __FUNCTION__, rc->rc_s);
|
clicon_debug(1, "%s s:%d", __FUNCTION__, rc->rc_s);
|
||||||
if (rsock->rs_ssl){
|
if (rsock->rs_ssl){
|
||||||
if ((rc->rc_ssl = SSL_new(rh->rh_ctx)) == NULL){
|
if ((rc->rc_ssl = SSL_new(rn->rn_ctx)) == NULL){
|
||||||
clicon_err(OE_SSL, 0, "SSL_new");
|
clicon_err(OE_SSL, 0, "SSL_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1160,11 +1236,15 @@ restconf_ssl_accept_client(clicon_handle h,
|
||||||
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__);
|
||||||
|
#ifdef HTTP_ON_HTTPS_REPLY
|
||||||
SSL_free(rc->rc_ssl);
|
SSL_free(rc->rc_ssl);
|
||||||
rc->rc_ssl = NULL;
|
rc->rc_ssl = NULL;
|
||||||
if (restconf_connection_close(h, rc->rc_s, rc->rc_socket) < 0)
|
if (native_send_badrequest(h, "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>", rc) < 0)
|
||||||
|
goto done;
|
||||||
|
#endif
|
||||||
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
restconf_conn_free(rc);
|
|
||||||
goto ok;
|
goto ok;
|
||||||
break;
|
break;
|
||||||
case SSL_ERROR_SYSCALL: /* 5 */
|
case SSL_ERROR_SYSCALL: /* 5 */
|
||||||
|
|
@ -1174,9 +1254,8 @@ restconf_ssl_accept_client(clicon_handle h,
|
||||||
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 (restconf_close_ssl_socket(rc, 0) < 0)
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
restconf_conn_free(rc);
|
|
||||||
rc = NULL;
|
rc = NULL;
|
||||||
goto ok;
|
goto ok;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1237,18 +1316,10 @@ restconf_ssl_accept_client(clicon_handle h,
|
||||||
else { /* Get certificates (if available) */
|
else { /* Get certificates (if available) */
|
||||||
if (proto != HTTP_2 &&
|
if (proto != HTTP_2 &&
|
||||||
native_send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml",
|
native_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>", rc->rc_socket) < 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>Peer certificate required</error-message></error></errors>", rc->rc_socket, rc) < 0)
|
||||||
|
goto done;
|
||||||
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
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(rc->rc_ssl);
|
|
||||||
rc->rc_ssl = NULL;
|
|
||||||
}
|
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1291,25 +1362,11 @@ restconf_ssl_accept_client(clicon_handle h,
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
case HTTP_2:{
|
case HTTP_2:{
|
||||||
if (http2_session_init(rc) < 0){
|
if (http2_session_init(rc) < 0){
|
||||||
restconf_close_ssl_socket(rc, 1);
|
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (http2_send_server_connection(rc) < 0){
|
if (http2_send_server_connection(rc) < 0){
|
||||||
restconf_close_ssl_socket(rc, 1);
|
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
|
||||||
#ifdef NYI
|
|
||||||
if (ssl) {
|
|
||||||
SSL_shutdown(ssl);
|
|
||||||
}
|
|
||||||
bufferevent_free(session_data->bev);
|
|
||||||
nghttp2_session_del(session_data->session);
|
|
||||||
for (stream_data = session_data->root.next; stream_data;) {
|
|
||||||
http2_stream_data *next = stream_data->next;
|
|
||||||
delete_http2_stream_data(stream_data);
|
|
||||||
stream_data = next;
|
|
||||||
}
|
|
||||||
free(session_data->client_addr);
|
|
||||||
free(session_data);
|
|
||||||
#endif
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -1320,6 +1377,8 @@ restconf_ssl_accept_client(clicon_handle h,
|
||||||
} /* switch proto */
|
} /* switch proto */
|
||||||
if (clixon_event_reg_fd(rc->rc_s, restconf_connection, (void*)rc, "restconf client socket") < 0)
|
if (clixon_event_reg_fd(rc->rc_s, restconf_connection, (void*)rc, "restconf client socket") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (rcp)
|
||||||
|
*rcp = rc;
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -1330,6 +1389,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
||||||
} /* restconf_ssl_accept_client */
|
} /* restconf_ssl_accept_client */
|
||||||
|
|
||||||
/*! idle timeout timer callback
|
/*! idle timeout timer callback
|
||||||
|
* @param[in] rc restconf connection, more specifically: callhome connection
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
restconf_idle_cb(int fd,
|
restconf_idle_cb(int fd,
|
||||||
|
|
@ -1337,15 +1397,20 @@ restconf_idle_cb(int fd,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
restconf_socket *rsock;
|
restconf_socket *rsock;
|
||||||
|
restconf_conn *rc;
|
||||||
|
|
||||||
if ((rsock = (restconf_socket *)arg) == NULL){
|
if ((rc = (restconf_conn *)arg) == NULL){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "rc is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((rsock = rc->rc_socket) == 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 %s", __FUNCTION__, rsock->rs_description);
|
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||||
/* sanity */
|
/* sanity */
|
||||||
if (rsock->rs_callhome && rsock->rs_periodic && rsock->rs_idle_timeout && rsock->rs_ss > 0){
|
if (rc->rc_callhome && rsock->rs_periodic && rsock->rs_idle_timeout && rc->rc_s > 0){
|
||||||
if (restconf_connection_close(rsock->rs_h, rsock->rs_ss, rsock) < 0)
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -1354,9 +1419,9 @@ restconf_idle_cb(int fd,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
restconf_idle_timer_unreg(restconf_socket *rsock)
|
restconf_idle_timer_unreg(restconf_conn *rc)
|
||||||
{
|
{
|
||||||
return clixon_event_unreg_timeout(restconf_idle_cb, rsock);
|
return clixon_event_unreg_timeout(restconf_idle_cb, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set callhome periodic idle-timeout
|
/*! Set callhome periodic idle-timeout
|
||||||
|
|
@ -1370,19 +1435,25 @@ restconf_idle_timer_unreg(restconf_socket *rsock)
|
||||||
* @see restconf_idle_timer_unreg
|
* @see restconf_idle_timer_unreg
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
restconf_idle_timer(restconf_socket *rsock)
|
restconf_idle_timer(restconf_conn *rc)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
struct timeval t;
|
struct timeval t;
|
||||||
struct timeval t1 = {0, 0};
|
struct timeval t1 = {0, 0};
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
restconf_socket *rsock;
|
||||||
|
|
||||||
if (rsock == NULL || !rsock->rs_callhome || !rsock->rs_periodic || rsock->rs_idle_timeout==0){
|
if (rc == NULL || !rc->rc_callhome){
|
||||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not periodic callhome");
|
clicon_err(OE_YANG, EINVAL, "rc is NULL or not callhome");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s %s register", __FUNCTION__, rsock->rs_description);
|
rsock = rc->rc_socket;
|
||||||
|
if (rsock == NULL || !rsock->rs_periodic || rsock->rs_idle_timeout==0){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not periodic");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
clicon_debug(1, "%s \"%s\" register", __FUNCTION__, rsock->rs_description);
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1394,7 +1465,7 @@ restconf_idle_timer(restconf_socket *rsock)
|
||||||
clicon_debug(1, "%s now:%lu timeout:%lu.%lu", __FUNCTION__, now.tv_sec, t.tv_sec, t.tv_usec);
|
clicon_debug(1, "%s now:%lu timeout:%lu.%lu", __FUNCTION__, now.tv_sec, t.tv_sec, t.tv_usec);
|
||||||
if (clixon_event_reg_timeout(t,
|
if (clixon_event_reg_timeout(t,
|
||||||
restconf_idle_cb,
|
restconf_idle_cb,
|
||||||
rsock,
|
rc,
|
||||||
cbuf_get(cb)) < 0)
|
cbuf_get(cb)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -1423,13 +1494,14 @@ restconf_callhome_cb(int fd,
|
||||||
struct sockaddr *sa = (struct sockaddr *)&sin6;
|
struct sockaddr *sa = (struct sockaddr *)&sin6;
|
||||||
size_t sa_len;
|
size_t sa_len;
|
||||||
int s;
|
int s;
|
||||||
|
restconf_conn *rc = NULL;
|
||||||
|
|
||||||
rsock = (restconf_socket *)arg;
|
rsock = (restconf_socket *)arg;
|
||||||
if (rsock == NULL || !rsock->rs_callhome){
|
if (rsock == NULL || !rsock->rs_callhome){
|
||||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s %s", __FUNCTION__, rsock->rs_description);
|
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||||
h = rsock->rs_h;
|
h = rsock->rs_h;
|
||||||
/* Already computed in restconf_socket_init, could be saved in rsock? */
|
/* Already computed in restconf_socket_init, could be saved in rsock? */
|
||||||
if (clixon_inet2sin(rsock->rs_addrtype, rsock->rs_addrstr, rsock->rs_port, sa, &sa_len) < 0)
|
if (clixon_inet2sin(rsock->rs_addrtype, rsock->rs_addrstr, rsock->rs_port, sa, &sa_len) < 0)
|
||||||
|
|
@ -1438,26 +1510,23 @@ restconf_callhome_cb(int fd,
|
||||||
clicon_err(OE_UNIX, errno, "socket");
|
clicon_err(OE_UNIX, errno, "socket");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s connect %hu", __FUNCTION__, rsock->rs_port);
|
|
||||||
if (connect(s, sa, sa_len) < 0){
|
if (connect(s, sa, sa_len) < 0){
|
||||||
clicon_debug(1, "%s connect:%d %s", __FUNCTION__, errno, strerror(errno));
|
clicon_debug(1, "%s connect %hu fail:%d %s", __FUNCTION__, rsock->rs_port, errno, strerror(errno));
|
||||||
close(s);
|
close(s);
|
||||||
rsock->rs_attempts++;
|
rsock->rs_attempts++;
|
||||||
rsock->rs_ss = -1;
|
|
||||||
/* Fail: Initiate new timer */
|
/* Fail: Initiate new timer */
|
||||||
if (restconf_callhome_timer(rsock, 0) < 0)
|
if (restconf_callhome_timer(rsock, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rsock->rs_ss = s;
|
clicon_debug(1, "%s connect %hu OK", __FUNCTION__, rsock->rs_port);
|
||||||
rsock->rs_attempts = 0;
|
rsock->rs_attempts = 0;
|
||||||
if (restconf_ssl_accept_client(h, s, rsock) < 0)
|
if (restconf_ssl_accept_client(h, s, rsock, &rc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (rsock->rs_periodic && rsock->rs_idle_timeout &&
|
if (rsock->rs_periodic && rsock->rs_idle_timeout &&
|
||||||
restconf_idle_timer(rsock) < 0)
|
restconf_idle_timer(rc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s connect done", __FUNCTION__);
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -1491,7 +1560,7 @@ restconf_callhome_timer(restconf_socket *rsock,
|
||||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not callhome");
|
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not callhome");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s %s", __FUNCTION__, rsock->rs_description);
|
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||||
if (!rsock->rs_callhome)
|
if (!rsock->rs_callhome)
|
||||||
goto ok; /* shouldnt happen */
|
goto ok; /* shouldnt happen */
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
|
|
@ -1519,7 +1588,7 @@ restconf_callhome_timer(restconf_socket *rsock,
|
||||||
}
|
}
|
||||||
cprintf(cb, "restconf callhome timer %s", rsock->rs_description);
|
cprintf(cb, "restconf callhome timer %s", rsock->rs_description);
|
||||||
if (rsock->rs_description)
|
if (rsock->rs_description)
|
||||||
clicon_debug(1, "%s registering %s: %lu", __FUNCTION__, rsock->rs_description, t.tv_sec);
|
clicon_debug(1, "%s registering \"%s\": %lu", __FUNCTION__, rsock->rs_description, t.tv_sec);
|
||||||
else
|
else
|
||||||
clicon_debug(1, "%s: %lu", __FUNCTION__, t.tv_sec);
|
clicon_debug(1, "%s: %lu", __FUNCTION__, t.tv_sec);
|
||||||
/* Should be only place restconf_callhome_cb is registered */
|
/* Should be only place restconf_callhome_cb is registered */
|
||||||
|
|
|
||||||
|
|
@ -32,16 +32,25 @@
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
*
|
*
|
||||||
|
* Data structures:
|
||||||
* 1 1
|
* 1 1
|
||||||
* +--------------------+ restconf_handle_get +--------------------+
|
* +--------------------+ restconf_handle_get +--------------------+
|
||||||
* | rh restconf_handle | <--------------------- | h clicon_handle |
|
* | rn restconf_native | <--------------------- | h clicon_handle |
|
||||||
* +--------------------+ +--------------------+
|
* | _handle | +--------------------+
|
||||||
* common SSL config \ ^
|
* +--------------------+ ^
|
||||||
* \ | n
|
* common SSL config \ |
|
||||||
* \ rh_sockets +--------------------+
|
* \ | n
|
||||||
|
* \ rn_sockets +--------------------+
|
||||||
* +-----------> | rs restconf_socket |
|
* +-----------> | rs restconf_socket |
|
||||||
* +--------------------+
|
* +--------------------+
|
||||||
* n per-socket SSL config
|
* per-server socket (per config)
|
||||||
|
* | ^
|
||||||
|
* rs_conns v | n
|
||||||
|
* +--------------------+
|
||||||
|
* | rc restconf_conn |
|
||||||
|
* +--------------------+
|
||||||
|
* per-connection (transient)
|
||||||
|
* n
|
||||||
* +--------------------+
|
* +--------------------+
|
||||||
* | rr restconf_request| per-packet
|
* | rr restconf_request| per-packet
|
||||||
* +--------------------+
|
* +--------------------+
|
||||||
|
|
@ -85,44 +94,17 @@ typedef struct {
|
||||||
uint8_t *sd_settings2; /* Settings for upgrade to http/2 request */
|
uint8_t *sd_settings2; /* Settings for upgrade to http/2 request */
|
||||||
} restconf_stream_data;
|
} restconf_stream_data;
|
||||||
|
|
||||||
/* Restconf per socket handle
|
typedef struct restconf_socket restconf_socket;
|
||||||
* Two types: listen and callhome.
|
|
||||||
* Listen: Uses socket rs_ss to listen for connections and accepts them, creates one
|
|
||||||
* restconf_conn for each new accept.
|
|
||||||
* Callhome: Calls connect according to timer to setup single restconf_conn.
|
|
||||||
* when this is closed, new connect is made, according to connection-type.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
qelem_t rs_qelem; /* List header */
|
|
||||||
clicon_handle rs_h; /* Clixon handle */
|
|
||||||
char *rs_description; /* Description */
|
|
||||||
int rs_callhome; /* 0: listen, 1: callhome */
|
|
||||||
int rs_ss; /* Listen: Server socket, ready for accept
|
|
||||||
* Callhome: connect socket (same as restconf_conn->rc_s) */
|
|
||||||
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 */
|
|
||||||
int rs_periodic; /* 0: persistent, 1: periodic (if callhome) */
|
|
||||||
uint32_t rs_period; /* Period in s (if callhome & periodic) */
|
|
||||||
uint8_t rs_max_attempts; /* max connect attempts (if callhome) */
|
|
||||||
uint16_t rs_idle_timeout; /* Max underlying TCP session remains idle (if callhome and periodic) */
|
|
||||||
uint64_t rs_start; /* First period start, next is start+periods*period */
|
|
||||||
uint64_t rs_period_nr; /* Dynamic succeeding or timed out periods.
|
|
||||||
Set in restconf_callhome_timer*/
|
|
||||||
uint8_t rs_attempts; /* Dynamic connect attempts in this round (if callhome)
|
|
||||||
* Set in restconf_callhome_cb
|
|
||||||
*/
|
|
||||||
} restconf_socket;
|
|
||||||
|
|
||||||
/* Restconf connection handle
|
/* Restconf connection handle
|
||||||
* Per connection request
|
* Per connection request
|
||||||
*/
|
*/
|
||||||
typedef struct restconf_conn {
|
typedef struct restconf_conn {
|
||||||
|
qelem_t rc_qelem; /* List header */
|
||||||
/* XXX rc_proto and rc_proto_d1/d2 may not both be necessary.
|
/* XXX rc_proto and rc_proto_d1/d2 may not both be necessary.
|
||||||
* remove rc_proto?
|
* remove rc_proto?
|
||||||
*/
|
*/
|
||||||
|
int rc_callhome; /* 0: listen, 1: callhome */
|
||||||
restconf_http_proto rc_proto; /* HTTP protocol: http/1 or http/2 */
|
restconf_http_proto rc_proto; /* HTTP protocol: http/1 or http/2 */
|
||||||
int rc_proto_d1; /* parsed version digit 1 */
|
int rc_proto_d1; /* parsed version digit 1 */
|
||||||
int rc_proto_d2; /* parsed version digit 2 */
|
int rc_proto_d2; /* parsed version digit 2 */
|
||||||
|
|
@ -139,14 +121,47 @@ typedef struct restconf_conn {
|
||||||
restconf_socket *rc_socket; /* Backpointer to restconf_socket needed for callhome */
|
restconf_socket *rc_socket; /* Backpointer to restconf_socket needed for callhome */
|
||||||
} restconf_conn;
|
} restconf_conn;
|
||||||
|
|
||||||
|
/* Restconf per socket handle
|
||||||
|
* Two types: listen and callhome.
|
||||||
|
* Listen: Uses socket rs_ss to listen for connections and accepts them, creates one
|
||||||
|
* restconf_conn for each new accept.
|
||||||
|
* Callhome: Calls connect according to timer to setup single restconf_conn.
|
||||||
|
* when this is closed, new connect is made, according to connection-type.
|
||||||
|
*/
|
||||||
|
typedef struct restconf_socket{
|
||||||
|
qelem_t rs_qelem; /* List header */
|
||||||
|
clicon_handle rs_h; /* Clixon handle */
|
||||||
|
char *rs_description; /* Description */
|
||||||
|
int rs_callhome; /* 0: listen, 1: callhome */
|
||||||
|
int rs_ss; /* Listen: Server socket, ready for accept
|
||||||
|
* XXXCallhome: connect socket (same as restconf_conn->rc_s)
|
||||||
|
* Callhome: No-op, see restconf_conn->rc_s
|
||||||
|
*/
|
||||||
|
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 */
|
||||||
|
int rs_periodic; /* 0: persistent, 1: periodic (if callhome) */
|
||||||
|
uint32_t rs_period; /* Period in s (if callhome & periodic) */
|
||||||
|
uint8_t rs_max_attempts; /* max connect attempts (if callhome) */
|
||||||
|
uint16_t rs_idle_timeout; /* Max underlying TCP session remains idle (if callhome and periodic) */
|
||||||
|
uint64_t rs_start; /* First period start, next is start+periods*period */
|
||||||
|
uint64_t rs_period_nr; /* Dynamic succeeding or timed out periods.
|
||||||
|
Set in restconf_callhome_timer*/
|
||||||
|
uint8_t rs_attempts; /* Dynamic connect attempts in this round (if callhome)
|
||||||
|
* Set in restconf_callhome_cb
|
||||||
|
*/
|
||||||
|
restconf_conn *rs_conns; /* List of transient connect sockets */
|
||||||
|
} restconf_socket;
|
||||||
|
|
||||||
/* Restconf handle
|
/* Restconf handle
|
||||||
* Global data about ssl (not per packet/request)
|
* Global data about ssl (not per packet/request)
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SSL_CTX *rh_ctx; /* SSL context */
|
SSL_CTX *rn_ctx; /* SSL context */
|
||||||
restconf_socket *rh_sockets; /* List of restconf server (ready for accept) sockets */
|
restconf_socket *rn_sockets; /* List of restconf server (ready for accept) sockets */
|
||||||
void *rh_arg; /* Packet specific handle */
|
void *rn_arg; /* Packet specific handle */
|
||||||
} restconf_native_handle;
|
} restconf_native_handle;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -156,17 +171,15 @@ restconf_stream_data *restconf_stream_data_new(restconf_conn *rc, int32_t stream
|
||||||
restconf_stream_data *restconf_stream_find(restconf_conn *rc, int32_t id);
|
restconf_stream_data *restconf_stream_find(restconf_conn *rc, int32_t id);
|
||||||
int restconf_stream_free(restconf_stream_data *sd);
|
int restconf_stream_free(restconf_stream_data *sd);
|
||||||
restconf_conn *restconf_conn_new(clicon_handle h, int s, restconf_socket *socket);
|
restconf_conn *restconf_conn_new(clicon_handle h, int s, restconf_socket *socket);
|
||||||
int restconf_conn_free(restconf_conn *rc);
|
|
||||||
int ssl_x509_name_oneline(SSL *ssl, char **oneline);
|
int ssl_x509_name_oneline(SSL *ssl, char **oneline);
|
||||||
|
|
||||||
int restconf_close_ssl_socket(restconf_conn *rc, int shutdown); /* XXX in restconf_main_native.c */
|
int restconf_close_ssl_socket(restconf_conn *rc, const char *callfn, int sslerr0);
|
||||||
int restconf_connection_sanity(clicon_handle h, restconf_conn *rc, restconf_stream_data *sd);
|
int restconf_connection_sanity(clicon_handle h, restconf_conn *rc, restconf_stream_data *sd);
|
||||||
restconf_native_handle *restconf_native_handle_get(clicon_handle h);
|
restconf_native_handle *restconf_native_handle_get(clicon_handle h);
|
||||||
int restconf_connection(int s, void *arg);
|
int restconf_connection(int s, void *arg);
|
||||||
int restconf_connection_close(clicon_handle h, int s, restconf_socket *rsock);
|
int restconf_ssl_accept_client(clicon_handle h, int s, restconf_socket *rsock, restconf_conn **rcp);
|
||||||
int restconf_ssl_accept_client(clicon_handle h, int s, restconf_socket *rsock);
|
int restconf_idle_timer_unreg(restconf_conn *rc);
|
||||||
int restconf_idle_timer_unreg(restconf_socket *rsock);
|
int restconf_idle_timer(restconf_conn *rc);
|
||||||
int restconf_idle_timer(restconf_socket *rsock);
|
|
||||||
int restconf_callhome_timer_unreg(restconf_socket *rsock);
|
int restconf_callhome_timer_unreg(restconf_socket *rsock);
|
||||||
int restconf_callhome_timer(restconf_socket *rsock, int status);
|
int restconf_callhome_timer(restconf_socket *rsock, int status);
|
||||||
int restconf_socket_extract(clicon_handle h, cxobj *xs, cvec *nsc, restconf_socket *rsock,
|
int restconf_socket_extract(clicon_handle h, cxobj *xs, cvec *nsc, restconf_socket *rsock,
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ session_send_callback(nghttp2_session *session,
|
||||||
if ((len = SSL_write(rc->rc_ssl, buf+totlen, buflen-totlen)) <= 0){
|
if ((len = SSL_write(rc->rc_ssl, buf+totlen, buflen-totlen)) <= 0){
|
||||||
er = errno;
|
er = errno;
|
||||||
sslerr = SSL_get_error(rc->rc_ssl, len);
|
sslerr = SSL_get_error(rc->rc_ssl, len);
|
||||||
clicon_debug(1, "%s errno:%d sslerr:%d", __FUNCTION__, errno, sslerr);
|
clicon_debug(1, "%s errno:%d sslerr:%d", __FUNCTION__, er, sslerr);
|
||||||
switch (sslerr){
|
switch (sslerr){
|
||||||
case SSL_ERROR_WANT_WRITE: /* 3 */
|
case SSL_ERROR_WANT_WRITE: /* 3 */
|
||||||
clicon_debug(1, "%s write SSL_ERROR_WANT_WRITE", __FUNCTION__);
|
clicon_debug(1, "%s write SSL_ERROR_WANT_WRITE", __FUNCTION__);
|
||||||
|
|
@ -640,11 +640,9 @@ on_stream_close_callback(nghttp2_session *session,
|
||||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||||
|
|
||||||
clicon_debug(1, "%s %d %s", __FUNCTION__, error_code, nghttp2_strerror(error_code));
|
clicon_debug(1, "%s %d %s", __FUNCTION__, error_code, nghttp2_strerror(error_code));
|
||||||
#ifdef NOTNEEDED /* XXX think this is not necessary? */
|
#if 0 // NOTNEEDED /* XXX think this is not necessary? */
|
||||||
if (error_code){
|
if (error_code){
|
||||||
if (restconf_close_ssl_socket(rc, 0) < 0)
|
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||||
return -1;
|
|
||||||
if (restconf_conn_free(rc) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -164,3 +164,18 @@
|
||||||
* This means that text output can not be parsed and loaded.
|
* This means that text output can not be parsed and loaded.
|
||||||
*/
|
*/
|
||||||
#undef TEXT_SYNTAX_NOPREFIX
|
#undef TEXT_SYNTAX_NOPREFIX
|
||||||
|
|
||||||
|
/*! Reply with HTTP error when HTTP request on HTTPS socket
|
||||||
|
* If not set, just close socket and return with TCP reset.
|
||||||
|
* If set: Incoming request on an SSL socket is known to be non-TLS.
|
||||||
|
* Problematic part is it is not known it is proper non-TLS HTTP, for that it
|
||||||
|
* needs parsing/ALPN etc.
|
||||||
|
* This is the approx algorithm:
|
||||||
|
* s = accept();
|
||||||
|
* ssl = SSL_new()
|
||||||
|
* if (SSL_accept(ssl) < 0){
|
||||||
|
* if (SSL_get_error(ssl, ) == SSL_ERROR_SSL){
|
||||||
|
* SSL_free(ssl);
|
||||||
|
* // Here "s" is still open and you can reply on the non-ssl underlying socket
|
||||||
|
*/
|
||||||
|
#define HTTP_ON_HTTPS_REPLY
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ enum clicon_err{
|
||||||
OE_FATAL, /* Fatal error */
|
OE_FATAL, /* Fatal error */
|
||||||
OE_UNDEF,
|
OE_UNDEF,
|
||||||
/*-- From here error extensions using clixon_err_cat_reg, XXX register dynamically? --*/
|
/*-- From here error extensions using clixon_err_cat_reg, XXX register dynamically? --*/
|
||||||
OE_SSL, /* Openssl errors, see eg ssl_get_error */
|
OE_SSL, /* Openssl errors, see eg ssl_get_error and clixon_openssl_log_cb */
|
||||||
OE_SNMP , /* Netsnmp error */
|
OE_SNMP , /* Netsnmp error */
|
||||||
OE_NGHTTP2, /* nghttp2 errors, see HAVE_LIBNGHTTP2 */
|
OE_NGHTTP2, /* nghttp2 errors, see HAVE_LIBNGHTTP2 */
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -210,9 +210,9 @@ function testrun()
|
||||||
new "Wrong proto=https on http port, expect err 35 wrong version number"
|
new "Wrong proto=https on http port, expect err 35 wrong version number"
|
||||||
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 http1+2"
|
||||||
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"
|
||||||
# expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta)" 0 "HTTP/" "400"
|
expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta)" 0 "HTTP/" "400"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -263,7 +263,7 @@ function testrun()
|
||||||
new "Wrong proto=https on http port, expect err 35 wrong version number"
|
new "Wrong proto=https on http port, expect err 35 wrong version number"
|
||||||
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 http2-only"
|
||||||
expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta)" "16 52 55 56" --not-- 'HTTP'
|
expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta)" "16 52 55 56" --not-- 'HTTP'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -304,9 +304,9 @@ function testrun()
|
||||||
new "Wrong proto=https on http port, expect err 35 wrong version number"
|
new "Wrong proto=https on http port, expect err 35 wrong version number"
|
||||||
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 http/1 only"
|
||||||
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"
|
||||||
# expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta)" 0 "HTTP/" "400"
|
expectpart "$(curl $CURLOPTS -X GET http://$addr:443/.well-known/host-meta)" 0 "HTTP/" "400"
|
||||||
fi
|
fi
|
||||||
fi # HTTP/2
|
fi # HTTP/2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -246,12 +246,12 @@ expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+jso
|
||||||
new 'B.3.5. "insert/point" leaf-list check order (2,4,3,1)'
|
new 'B.3.5. "insert/point" leaf-list check order (2,4,3,1)'
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-jukebox:extra -H 'Accept: application/yang-data+xml')" 0 "HTTP/$HVER 200" '<extra xmlns="http://example.com/ns/example-jukebox">2</extra><extra xmlns="http://example.com/ns/example-jukebox" xmlns:jbox="http://example.com/ns/example-jukebox">4</extra><extra xmlns="http://example.com/ns/example-jukebox">3</extra><extra xmlns="http://example.com/ns/example-jukebox">1</extra>'
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-jukebox:extra -H 'Accept: application/yang-data+xml')" 0 "HTTP/$HVER 200" '<extra xmlns="http://example.com/ns/example-jukebox">2</extra><extra xmlns="http://example.com/ns/example-jukebox" xmlns:jbox="http://example.com/ns/example-jukebox">4</extra><extra xmlns="http://example.com/ns/example-jukebox">3</extra><extra xmlns="http://example.com/ns/example-jukebox">1</extra>'
|
||||||
|
|
||||||
new "B.2.2. Detect Datastore Resource Entity-Tag Change" # XXX done except entity-changed
|
#new "B.2.2. Detect Datastore Resource Entity-Tag Change" # XXX done except entity-changed
|
||||||
new 'B.3.3. "fields" Parameter'
|
#new 'B.3.3. "fields" Parameter'
|
||||||
new 'B.3.6. "filter" Parameter'
|
#new 'B.3.6. "filter" Parameter'
|
||||||
new 'B.3.7. "start-time" Parameter'
|
#new 'B.3.7. "start-time" Parameter'
|
||||||
new 'B.3.8. "stop-time" Parameter'
|
#new 'B.3.8. "stop-time" Parameter'
|
||||||
new 'B.3.9. "with-defaults" Parameter'
|
#new 'B.3.9. "with-defaults" Parameter'
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
if [ $RC -ne 0 ]; then
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue