Added CLIXON_CLIENT_SSH to client API to communicate remotely via SSH netconf sub-system

configure: stringified SSH_BIN
C-API: Added `sock_flags` parameter to `clixon_proc_socket()`
This commit is contained in:
Olof Hagsand 2022-12-08 13:26:39 +01:00
parent 100f15b699
commit 6baa904039
10 changed files with 171 additions and 95 deletions

View file

@ -146,7 +146,7 @@ clixon_client_terminate(clicon_handle h)
* @retval 0 OK
* @retval -1 Error
*/
static int
int
clixon_client_lock(int sock,
const int lock,
const char *db)
@ -204,15 +204,14 @@ clixon_client_lock(int sock,
/*! Internal function to construct the encoding and hello message
*
* @param[in] sock Socket
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
* @param[in] xpath XPath
* @param[out] xdata XML data tree (may or may not include the intended data)
* @retval 0 OK
* @retval -1 Error
* @param[in] sock Socket to netconf server
* @param[in] version Netconf version for capability announcement
* @retval 0 OK
* @retval -1 Error
*/
static int
clixon_client_hello(int sock)
int
clixon_client_hello(int sock,
int version)
{
int retval = -1;
cbuf *msg = NULL;
@ -222,9 +221,11 @@ clixon_client_hello(int sock)
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
cprintf(msg, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
// cprintf(msg, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
cprintf(msg, "<hello xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
cprintf(msg, "<capabilities><capability>%s</capability></capabilities>", NETCONF_BASE_CAPABILITY_1_1);
cprintf(msg, "<capabilities>");
cprintf(msg, "<capability>%s</capability>", version==0?NETCONF_BASE_CAPABILITY_1_0:NETCONF_BASE_CAPABILITY_1_1);
cprintf(msg, "</capabilities>");
cprintf(msg, "</hello>");
cprintf(msg, "]]>]]>");
if (clicon_msg_send1(sock, msg) < 0)
@ -237,25 +238,112 @@ clixon_client_hello(int sock)
return retval;
}
/*!
*/
static int
clixon_client_connect_netconf(clicon_handle h,
struct clixon_client_handle *cch)
{
int retval = -1;
int nr;
int i;
char **argv = NULL;
char *netconf_bin = NULL;
struct stat st = {0,};
char dbgstr[8];
nr = 7;
if (clicon_debug_get() != 0)
nr += 2;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
}
i = 0;
if ((netconf_bin = getenv("CLIXON_NETCONF_BIN")) == NULL)
netconf_bin = CLIXON_NETCONF_BIN;
if (stat(netconf_bin, &st) < 0){
clicon_err(OE_NETCONF, errno, "netconf binary %s. Set with CLIXON_NETCONF_BIN=",
netconf_bin);
goto done;
}
argv[i++] = netconf_bin;
argv[i++] = "-q";
argv[i++] = "-f";
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
argv[i++] = "-l"; /* log to syslog */
argv[i++] = "s";
if (clicon_debug_get() != 0){
argv[i++] = "-D";
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get());
argv[i++] = dbgstr;
}
argv[i++] = NULL;
assert(i==nr);
if (clixon_proc_socket(argv, SOCK_DGRAM, &cch->cch_pid, &cch->cch_socket) < 0){
goto done;
}
retval = 0;
done:
return retval;
}
/*!
*/
static int
clixon_client_connect_ssh(clicon_handle h,
struct clixon_client_handle *cch,
const char *dest)
{
int retval = -1;
int nr;
int i;
char **argv = NULL;
char *ssh_bin = SSH_BIN;
struct stat st = {0,};
clicon_debug(1, "%s", __FUNCTION__);
nr = 5;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
}
i = 0;
if (stat(ssh_bin, &st) < 0){
clicon_err(OE_NETCONF, errno, "ssh binary %s", ssh_bin);
goto done;
}
argv[i++] = ssh_bin;
argv[i++] = (char*)dest;
argv[i++] = "-s";
argv[i++] = "netconf";
argv[i++] = NULL;
assert(i==nr);
for (i=0;i<nr;i++)
clicon_debug(1, "%s: argv[%d]:%s", __FUNCTION__, i, argv[i]);
if (clixon_proc_socket(argv, SOCK_STREAM, &cch->cch_pid, &cch->cch_socket) < 0){
goto done;
}
retval = 0;
done:
return retval;
}
/*! Connect client to clixon backend according to config and return a socket
* @param[in] h Clixon handle
* @param[in] socktype Type of socket, internal/external/netconf/ssh
* @param[in] dest Destination for some types
* @retval ch Clixon session handler
* @retval NULL Error
* @see clixon_client_disconnect Close the socket returned here
*/
clixon_client_handle
clixon_client_connect(clicon_handle h,
clixon_client_type socktype)
clixon_client_type socktype,
const char *dest)
{
struct clixon_client_handle *cch = NULL;
char **argv = NULL;
int nr;
int i;
char *netconf_bin = NULL;
struct stat st = {0,};
size_t sz = sizeof(struct clixon_client_handle);
char dbgstr[8];
clicon_debug(1, "%s", __FUNCTION__);
if ((cch = malloc(sz)) == NULL){
@ -271,48 +359,19 @@ clixon_client_connect(clicon_handle h,
goto err;
break;
case CLIXON_CLIENT_NETCONF:
nr = 7;
if (clicon_debug_get() != 0)
nr += 2;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto err;
}
i = 0;
if ((netconf_bin = getenv("CLIXON_NETCONF_BIN")) == NULL)
netconf_bin = CLIXON_NETCONF_BIN;
if (stat(netconf_bin, &st) < 0){
clicon_err(OE_NETCONF, errno, "netconf binary %s. Set with CLIXON_NETCONF_BIN=",
netconf_bin);
goto err;
}
argv[i++] = netconf_bin;
argv[i++] = "-q";
argv[i++] = "-f";
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
argv[i++] = "-l"; /* log to syslog */
argv[i++] = "s";
if (clicon_debug_get() != 0){
argv[i++] = "-D";
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get());
argv[i++] = dbgstr;
}
argv[i++] = NULL;
assert(i==nr);
if (clixon_proc_socket(argv, &cch->cch_pid, &cch->cch_socket) < 0){
goto err;
}
/* Start with encoding and hello message */
if (clixon_client_hello(cch->cch_socket) < 0)
if (clixon_client_connect_netconf(h, cch) < 0)
goto err;
break;
#ifdef SSH_BIN
case CLIXON_CLIENT_SSH:
if (clixon_client_connect_ssh(h, cch, dest) < 0)
goto err;
#else
clicon_err(OE_UNIX, 0, "No ssh bin");
goto done;
#endif
break;
} /* switch */
/* lock */
if (clixon_client_lock(cch->cch_socket, 1, "running") < 0)
goto err;
cch->cch_locked = 1;
done:
clicon_debug(1, "%s retval:%p", __FUNCTION__, cch);
return cch;
@ -347,13 +406,12 @@ clixon_client_disconnect(clixon_client_handle ch)
case CLIXON_CLIENT_IPC:
close(cch->cch_socket);
break;
case CLIXON_CLIENT_SSH:
case CLIXON_CLIENT_NETCONF:
if (clixon_proc_socket_close(cch->cch_pid,
cch->cch_socket) < 0)
goto done;
break;
case CLIXON_CLIENT_SSH:
break;
}
free(cch);
retval = 0;
@ -403,6 +461,7 @@ clixon_xml_bottom(cxobj *xtop,
* @param[out] xdata XML data tree (may or may not include the intended data)
* @retval 0 OK
* @retval -1 Error
* @note configurable netconf framing type, now hardwired to 0
*/
static int
clixon_client_get_xdata(int sock,
@ -445,9 +504,11 @@ clixon_client_get_xdata(int sock,
cprintf(msg, "/>");
}
cprintf(msg, "</get-config></rpc>");
if (netconf_output_encap(NETCONF_SSH_CHUNKED, msg) < 0)
if (netconf_output_encap(0, msg) < 0) // XXX configurable session
goto done;
if (clicon_rpc1(sock, msg, msgret, &eof) < 0)
if (clicon_msg_send1(sock, msg) < 0)
goto done;
if (clicon_msg_rcv1(sock, msgret, &eof) < 0)
goto done;
if (eof){
close(sock);

View file

@ -163,15 +163,18 @@ clixon_proc_sigint(int sig)
}
/*! Fork a child, exec a child and setup socket to child and return to caller
* @param[in] argv NULL-terminated Argument vector
* @param[in] doerr If non-zero, stderr will be directed to the pipe as well.
* @param[out] s Socket
* @retval O OK
* @retval -1 Error.
* @param[in] argv NULL-terminated Argument vector
* @param[in] sock_flags Socket type/flags, typically SOCK_DGRAM or SOCK_STREAM, see
* @param[out] pid Process-id of child
* @param[out] sock Socket
* @retval O OK
* @retval -1 Error.
* @see clixon_proc_socket_close close sockets, kill child and wait for child termination
* @see for flags usage see man sockerpair(2)
*/
int
clixon_proc_socket(char **argv,
int sock_flags,
pid_t *pid,
int *sock)
{
@ -182,12 +185,6 @@ clixon_proc_socket(char **argv,
sigset_t oset;
int sig = 0;
#ifdef __APPLE__
int sock_flags = SOCK_DGRAM;
#else
int sock_flags = SOCK_DGRAM | SOCK_CLOEXEC;
#endif
if (argv == NULL){
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
goto done;
@ -197,18 +194,6 @@ clixon_proc_socket(char **argv,
goto done;
}
#ifdef __APPLE__
if (fcntl(sp[0], O_CLOEXEC)) {
clicon_err(OE_UNIX, errno, "fcntl, sp[0]");
goto done;
}
if (fcntl(sp[1], O_CLOEXEC)) {
clicon_err(OE_UNIX, errno, "fcntl, sp[1]");
goto done;
}
#endif
sigprocmask(0, NULL, &oset);
set_signal(SIGINT, clixon_proc_sigint, &oldhandler);
sig++;

View file

@ -433,6 +433,7 @@ clicon_msg_rcv(int s,
* @param[out] eof Set if eof encountered
* @see netconf_input_cb()
* @see clicon_msg_rcv using IPC message struct
* @note only NETCONF version 1.0 EOM framing
*/
int
clicon_msg_rcv1(int s,
@ -502,7 +503,7 @@ clicon_msg_send1(int s,
int retval = -1;
if (atomicio((ssize_t (*)(int, void *, size_t))write,
s, cbuf_get(cb), cbuf_len(cb)+1) < 0){
s, cbuf_get(cb), cbuf_len(cb)) < 0){
clicon_err(OE_CFG, errno, "atomicio");
clicon_log(LOG_WARNING, "%s: write: %s", __FUNCTION__, strerror(errno));
goto done;