Restconf RFC8071 call-home first working prototype
This commit is contained in:
parent
a3b94f4781
commit
7d8ddf7697
18 changed files with 1115 additions and 122 deletions
|
|
@ -455,6 +455,8 @@ restconf_http1_path_root(clicon_handle h,
|
|||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
if (subject)
|
||||
free(subject);
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
if (cvv)
|
||||
|
|
|
|||
|
|
@ -820,6 +820,7 @@ restconf_config_init(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/*! Create and bind restconf socket
|
||||
*
|
||||
* @param[in] netns0 Network namespace, special value "default" is same as NULL
|
||||
|
|
@ -840,10 +841,8 @@ restconf_socket_init(const char *netns0,
|
|||
int *ss)
|
||||
{
|
||||
int retval = -1;
|
||||
struct sockaddr * sa;
|
||||
struct sockaddr_in6 sin6 = { 0 };
|
||||
struct sockaddr_in sin = { 0 };
|
||||
size_t sin_len;
|
||||
struct sockaddr sa = {0,};
|
||||
size_t sa_len;
|
||||
const char *netns;
|
||||
|
||||
clicon_debug(1, "%s %s %s %s %hu", __FUNCTION__, netns0, addrtype, addrstr, port);
|
||||
|
|
@ -852,27 +851,9 @@ restconf_socket_init(const char *netns0,
|
|||
netns = NULL;
|
||||
else
|
||||
netns = netns0;
|
||||
if (strcmp(addrtype, "inet:ipv6-address") == 0) {
|
||||
sin_len = sizeof(struct sockaddr_in6);
|
||||
sin6.sin6_port = htons(port);
|
||||
sin6.sin6_family = AF_INET6;
|
||||
|
||||
inet_pton(AF_INET6, addrstr, &sin6.sin6_addr);
|
||||
sa = (struct sockaddr *)&sin6;
|
||||
}
|
||||
else if (strcmp(addrtype, "inet:ipv4-address") == 0) {
|
||||
sin_len = sizeof(struct sockaddr_in);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
sin.sin_addr.s_addr = inet_addr(addrstr);
|
||||
|
||||
sa = (struct sockaddr *)&sin;
|
||||
}
|
||||
else{
|
||||
clicon_err(OE_XML, EINVAL, "Unexpected addrtype: %s", addrtype);
|
||||
return -1;
|
||||
}
|
||||
if (clixon_netns_socket(netns, sa, sin_len, backlog, flags, addrstr, ss) < 0)
|
||||
if (clixon_inet2sin(addrtype, addrstr, port, &sa, &sa_len) < 0)
|
||||
goto done;
|
||||
if (clixon_netns_socket(netns, &sa, sa_len, backlog, flags, addrstr, ss) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s ss=%d", __FUNCTION__, *ss);
|
||||
retval = 0;
|
||||
|
|
@ -888,8 +869,9 @@ restconf_socket_init(const char *netns0,
|
|||
* @param[out] namespace
|
||||
* @param[out] address Address as string, eg "0.0.0.0", "::"
|
||||
* @param[out] addrtype One of inet:ipv4-address or inet:ipv6-address
|
||||
* @param[out] port
|
||||
* @param[out] ssl
|
||||
* @param[out] port TCP Port
|
||||
* @param[out] ssl SSL enabled?
|
||||
* @param[out] callhome Callhome enabled?
|
||||
*/
|
||||
int
|
||||
restconf_socket_extract(clicon_handle h,
|
||||
|
|
@ -899,7 +881,8 @@ restconf_socket_extract(clicon_handle h,
|
|||
char **address,
|
||||
char **addrtype,
|
||||
uint16_t *port,
|
||||
uint16_t *ssl)
|
||||
uint16_t *ssl,
|
||||
int *callhome)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x;
|
||||
|
|
@ -979,6 +962,10 @@ restconf_socket_extract(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
if ((x = xpath_first(xs, nsc, "call-home")) != NULL)
|
||||
*callhome = 1;
|
||||
else
|
||||
*callhome = 0;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cv)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ int restconf_drop_privileges(clicon_handle h);
|
|||
int restconf_authentication_cb(clicon_handle h, void *req, int pretty, restconf_media media_out);
|
||||
int restconf_config_init(clicon_handle h, cxobj *xrestconf);
|
||||
int restconf_socket_init(const char *netns0, const char *addrstr, const char *addrtype, uint16_t port, int backlog, int flags, int *ss);
|
||||
int restconf_socket_extract(clicon_handle h, cxobj *xs, cvec *nsc, char **namespace, char **address, char **addrtype, uint16_t *port, uint16_t *ssl);
|
||||
int restconf_socket_extract(clicon_handle h, cxobj *xs, cvec *nsc, char **namespace, char **address, char **addrtype, uint16_t *port, uint16_t *ssl, int *callhome);
|
||||
|
||||
#endif /* _RESTCONF_LIB_H_ */
|
||||
|
||||
|
|
|
|||
|
|
@ -583,7 +583,7 @@ ssl_alpn_check(clicon_handle h,
|
|||
int ret;
|
||||
cbuf *cberr = NULL;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, alpn);
|
||||
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;
|
||||
|
|
@ -642,23 +642,20 @@ ssl_alpn_check(clicon_handle h,
|
|||
return retval;
|
||||
} /* ssl_alpn_check */
|
||||
|
||||
/*! Accept new socket client
|
||||
|
||||
/*! Accept new socket client (ssl not ip)
|
||||
* @param[in] fd Socket (unix or ip)
|
||||
* @param[in] arg typecast clicon_handle
|
||||
* @see openssl_init_socket where this callback is registered
|
||||
*/
|
||||
static int
|
||||
restconf_accept_client(int fd,
|
||||
void *arg)
|
||||
restconf_ssl_accept_client(clicon_handle h,
|
||||
int s,
|
||||
restconf_socket *rsock)
|
||||
{
|
||||
int retval = -1;
|
||||
restconf_socket *rsock;
|
||||
restconf_native_handle *rh = NULL;
|
||||
restconf_conn *rc = NULL;
|
||||
clicon_handle h;
|
||||
int s;
|
||||
struct sockaddr from = {0,};
|
||||
socklen_t len;
|
||||
char *name = NULL;
|
||||
int ret;
|
||||
int e;
|
||||
|
|
@ -668,30 +665,18 @@ restconf_accept_client(int fd,
|
|||
unsigned int alpnlen = 0;
|
||||
restconf_http_proto proto = HTTP_11; /* Non-SSL negotiation NYI */
|
||||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#ifndef HAVE_HTTP1
|
||||
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
|
||||
#endif
|
||||
#endif
|
||||
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 1
|
||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||
goto done;
|
||||
}
|
||||
len = sizeof(from);
|
||||
if ((s = accept(rsock->rs_ss, &from, &len)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "accept");
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Register callbacks for actual data socket
|
||||
*/
|
||||
|
|
@ -919,6 +904,50 @@ restconf_accept_client(int fd,
|
|||
if (name)
|
||||
free(name);
|
||||
return retval;
|
||||
} /* restconf_ssl_accept_client */
|
||||
|
||||
/*! Accept new socket client
|
||||
* @param[in] fd Socket (unix or ip)
|
||||
* @param[in] arg typecast clicon_handle
|
||||
* @see openssl_init_socket where this callback is registered
|
||||
*/
|
||||
static int
|
||||
restconf_accept_client(int fd,
|
||||
void *arg)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
restconf_socket *rsock;
|
||||
clicon_handle h;
|
||||
int s;
|
||||
struct sockaddr from = {0,};
|
||||
socklen_t len;
|
||||
char *name = NULL;
|
||||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||
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;
|
||||
len = sizeof(from);
|
||||
if ((s = accept(rsock->rs_ss, &from, &len)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "accept");
|
||||
goto done;
|
||||
}
|
||||
/* Accept SSL */
|
||||
if (restconf_ssl_accept_client(h, s, rsock) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
|
||||
if (name)
|
||||
free(name);
|
||||
return retval;
|
||||
} /* restconf_accept_client */
|
||||
|
||||
/*!
|
||||
|
|
@ -1019,10 +1048,63 @@ restconf_clixon_backend(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Periodically try to connect to callhome client
|
||||
*/
|
||||
int
|
||||
restconf_callhome_timer(int fd,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
clicon_handle h;
|
||||
struct timeval now;
|
||||
struct timeval t;
|
||||
struct timeval t1 = {1, 0}; // XXX once every second
|
||||
restconf_socket *rs;
|
||||
struct sockaddr sa = {0,};
|
||||
size_t sa_len;
|
||||
int s;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
gettimeofday(&now, NULL);
|
||||
if ((rs = (restconf_socket *)arg) == NULL){
|
||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||
goto done;
|
||||
}
|
||||
h = rs->rs_h;
|
||||
if (clixon_inet2sin(rs->rs_addrtype, rs->rs_addrstr, rs->rs_port, &sa, &sa_len) < 0)
|
||||
goto done;
|
||||
if ((s = socket(sa.sa_family, SOCK_STREAM, 0)) < 0) {
|
||||
clicon_err(OE_UNIX, errno, "socket");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s connect", __FUNCTION__);
|
||||
if (connect(s, &sa, sa_len) < 0){
|
||||
close(s);
|
||||
/* Fail: Initiate new timer */
|
||||
timeradd(&now, &t1, &t);
|
||||
if (clixon_event_reg_timeout(t,
|
||||
restconf_callhome_timer, /* this function */
|
||||
rs,
|
||||
"restconf callhome timer") < 0)
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
rs->rs_ss = s;
|
||||
if (restconf_ssl_accept_client(h, rs->rs_ss, rs) < 0)
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s connect done", __FUNCTION__);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Per-socket openssl inits
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xs XML config of single restconf socket
|
||||
* @param[in] nsc Namespace context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
openssl_init_socket(clicon_handle h,
|
||||
|
|
@ -1033,6 +1115,7 @@ openssl_init_socket(clicon_handle h,
|
|||
char *netns = NULL;
|
||||
char *address = NULL;
|
||||
char *addrtype = NULL;
|
||||
int callhome = 0;
|
||||
uint16_t ssl = 0;
|
||||
uint16_t port = 0;
|
||||
int ss = -1;
|
||||
|
|
@ -1041,23 +1124,9 @@ openssl_init_socket(clicon_handle h,
|
|||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
/* Extract socket parameters from single socket config: ns, addr, port, ssl */
|
||||
if (restconf_socket_extract(h, xs, nsc, &netns, &address, &addrtype, &port, &ssl) < 0)
|
||||
if (restconf_socket_extract(h, xs, nsc, &netns, &address, &addrtype, &port, &ssl, &callhome) < 0)
|
||||
goto done;
|
||||
/* Open restconf socket and bind */
|
||||
if (restconf_socket_init(netns, address, addrtype, port,
|
||||
SOCKET_LISTEN_BACKLOG,
|
||||
#ifdef RESTCONF_OPENSSL_NONBLOCKING
|
||||
SOCK_NONBLOCK, /* Also 0 is possible */
|
||||
#else /* blocking */
|
||||
0,
|
||||
#endif
|
||||
&ss
|
||||
) < 0)
|
||||
goto done;
|
||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create per-socket openssl handle
|
||||
* See restconf_native_terminate for freeing
|
||||
|
|
@ -1068,8 +1137,33 @@ openssl_init_socket(clicon_handle h,
|
|||
}
|
||||
memset(rsock, 0, sizeof *rsock);
|
||||
rsock->rs_h = h;
|
||||
rsock->rs_ssl = ssl; /* true/false */
|
||||
if (callhome){
|
||||
if (!ssl){
|
||||
clicon_err(OE_SSL, EINVAL, "Restconf callhome requires SSL");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else { /* listen/accept */
|
||||
/* Open restconf socket and bind for later accept */
|
||||
if (restconf_socket_init(netns, address, addrtype, port,
|
||||
SOCKET_LISTEN_BACKLOG,
|
||||
#ifdef RESTCONF_OPENSSL_NONBLOCKING
|
||||
SOCK_NONBLOCK, /* Also 0 is possible */
|
||||
#else /* blocking */
|
||||
0,
|
||||
#endif
|
||||
&ss
|
||||
) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||
goto done;
|
||||
}
|
||||
|
||||
rsock->rs_ss = ss;
|
||||
rsock->rs_ssl = ssl;
|
||||
|
||||
if ((rsock->rs_addrstr = strdup(address)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
|
|
@ -1081,29 +1175,24 @@ openssl_init_socket(clicon_handle h,
|
|||
rsock->rs_port = port;
|
||||
INSQ(rsock, rh->rh_sockets);
|
||||
|
||||
/* ss is a server socket that the clients connect to. The callback
|
||||
therefore accepts clients on ss */
|
||||
#ifdef RESTCONF_HTTP1_UNITTEST
|
||||
{
|
||||
restconf_conn *rc;
|
||||
if ((rc = restconf_conn_new(h, 0)) == NULL)
|
||||
goto done;
|
||||
rc->rc_s = 0;
|
||||
if (restconf_stream_data_new(rc, 0) == NULL)
|
||||
goto done;
|
||||
if (clixon_event_reg_fd(0, restconf_connection, rc, "restconf socket") < 0)
|
||||
if (callhome){
|
||||
if (restconf_callhome_timer(ss, rsock) < 0)
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
/* ss is a server socket that the clients connect to. The callback
|
||||
therefore accepts clients on ss */
|
||||
if (clixon_event_reg_fd(ss, restconf_accept_client, rsock, "restconf socket") < 0)
|
||||
goto done;
|
||||
}
|
||||
#else
|
||||
if (clixon_event_reg_fd(ss, restconf_accept_client, rsock, "restconf socket") < 0)
|
||||
goto done;
|
||||
#endif
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Init openssl, open and register server socket (ready for accept)
|
||||
*
|
||||
* Given a fully populated configuration tree.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] dbg0 Manually set debug flag, if set overrides configuration setting
|
||||
* @param[in] xrestconf XML tree containing restconf config
|
||||
|
|
|
|||
|
|
@ -702,12 +702,10 @@ restconf_http1_process(restconf_conn *rc,
|
|||
*/
|
||||
if ((ret = http1_check_content_length(h, sd, &status)) < 0)
|
||||
goto done;
|
||||
#ifndef RESTCONF_HTTP1_UNITTEST /* Ignore content-length */
|
||||
if (status == 1){
|
||||
(*readmore)++;
|
||||
goto ok;
|
||||
}
|
||||
#endif
|
||||
/* nginx compatible, set HTTPS parameter if SSL */
|
||||
if (rc->rc_ssl)
|
||||
if (restconf_param_set(h, "HTTPS", "https") < 0)
|
||||
|
|
@ -715,15 +713,9 @@ restconf_http1_process(restconf_conn *rc,
|
|||
/* main restconf processing */
|
||||
if (restconf_http1_path_root(h, rc) < 0)
|
||||
goto done;
|
||||
#ifdef RESTCONF_HTTP1_UNITTEST
|
||||
if (native_buf_write(cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
|
||||
1, rc->rc_ssl) < 0)
|
||||
goto done;
|
||||
#else
|
||||
if (native_buf_write(cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
|
||||
rc->rc_s, rc->rc_ssl) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */
|
||||
cbuf_reset(sd->sd_outp_buf);
|
||||
cbuf_reset(sd->sd_inbuf);
|
||||
|
|
@ -951,16 +943,5 @@ restconf_connection(int s,
|
|||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
|
||||
#ifdef RESTCONF_HTTP1_UNITTEST /* unit test */
|
||||
if (rc){
|
||||
if (close(rc->rc_s) < 0){
|
||||
clicon_err(OE_UNIX, errno, "close");
|
||||
goto done;
|
||||
}
|
||||
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||
restconf_conn_free(rc);
|
||||
}
|
||||
exit(0);
|
||||
#endif
|
||||
return retval;
|
||||
} /* restconf_connection */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue