2010-12-06 17:03:35 +00:00
|
|
|
/*
|
2014-01-01 16:57:42 +00:00
|
|
|
* Copyright (C) 2011, 2014 Red Hat, Inc.
|
2010-12-06 17:03:35 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-12-06 17:03:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <signal.h>
|
|
|
|
#ifdef HAVE_IFADDRS_H
|
|
|
|
# include <ifaddrs.h>
|
|
|
|
#endif
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
#include <netdb.h>
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
#include "testutils.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
#include "rpc/virnetsocket.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_RPC
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("tests.netsockettest");
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
#if HAVE_IFADDRS_H
|
|
|
|
# define BASE_PORT 5672
|
|
|
|
|
|
|
|
static int
|
|
|
|
checkProtocols(bool *hasIPv4, bool *hasIPv6,
|
|
|
|
int *freePort)
|
|
|
|
{
|
|
|
|
struct sockaddr_in in4;
|
|
|
|
struct sockaddr_in6 in6;
|
|
|
|
int s4 = -1, s6 = -1;
|
Convert 'int i' to 'size_t i' in tests/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2010-12-06 17:03:35 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
*freePort = 0;
|
2015-05-21 15:27:15 +00:00
|
|
|
if (virNetSocketCheckProtocols(hasIPv4, hasIPv6) < 0)
|
|
|
|
return -1;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2013-05-21 07:53:48 +00:00
|
|
|
for (i = 0; i < 50; i++) {
|
2010-12-06 17:03:35 +00:00
|
|
|
int only = 1;
|
|
|
|
if ((s4 = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-07-22 17:04:16 +00:00
|
|
|
if (*hasIPv6) {
|
|
|
|
if ((s6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
|
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2012-07-22 17:04:16 +00:00
|
|
|
if (setsockopt(s6, IPPROTO_IPV6, IPV6_V6ONLY, &only, sizeof(only)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
memset(&in4, 0, sizeof(in4));
|
|
|
|
memset(&in6, 0, sizeof(in6));
|
|
|
|
|
|
|
|
in4.sin_family = AF_INET;
|
|
|
|
in4.sin_port = htons(BASE_PORT + i);
|
|
|
|
in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
|
|
in6.sin6_family = AF_INET6;
|
|
|
|
in6.sin6_port = htons(BASE_PORT + i);
|
|
|
|
in6.sin6_addr = in6addr_loopback;
|
|
|
|
|
|
|
|
if (bind(s4, (struct sockaddr *)&in4, sizeof(in4)) < 0) {
|
|
|
|
if (errno == EADDRINUSE) {
|
|
|
|
VIR_FORCE_CLOSE(s4);
|
|
|
|
VIR_FORCE_CLOSE(s6);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-22 17:04:16 +00:00
|
|
|
|
|
|
|
if (*hasIPv6) {
|
|
|
|
if (bind(s6, (struct sockaddr *)&in6, sizeof(in6)) < 0) {
|
|
|
|
if (errno == EADDRINUSE) {
|
|
|
|
VIR_FORCE_CLOSE(s4);
|
|
|
|
VIR_FORCE_CLOSE(s6);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*freePort = BASE_PORT + i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-10-27 18:14:01 +00:00
|
|
|
VIR_DEBUG("Choose port %d", *freePort);
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_FORCE_CLOSE(s4);
|
|
|
|
VIR_FORCE_CLOSE(s6);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-05-01 10:55:02 +00:00
|
|
|
struct testClientData {
|
|
|
|
const char *path;
|
|
|
|
const char *cnode;
|
|
|
|
const char *portstr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
testSocketClient(void *opaque)
|
|
|
|
{
|
|
|
|
struct testClientData *data = opaque;
|
|
|
|
char c;
|
|
|
|
virNetSocketPtr csock = NULL;
|
|
|
|
|
|
|
|
if (data->path) {
|
|
|
|
if (virNetSocketNewConnectUNIX(data->path, false,
|
|
|
|
NULL, &csock) < 0)
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (virNetSocketNewConnectTCP(data->cnode, data->portstr,
|
|
|
|
AF_UNSPEC,
|
|
|
|
&csock) < 0)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
virNetSocketSetBlocking(csock, true);
|
|
|
|
|
|
|
|
if (virNetSocketRead(csock, &c, 1) != 1) {
|
|
|
|
VIR_DEBUG("Cannot read from server");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (virNetSocketWrite(csock, &c, 1) != 1) {
|
|
|
|
VIR_DEBUG("Cannot write to server");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
virObjectUnref(csock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
testSocketIncoming(virNetSocketPtr sock,
|
|
|
|
int events ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetSocketPtr *retsock = opaque;
|
2018-09-17 15:06:30 +00:00
|
|
|
VIR_DEBUG("Incoming sock=%p events=%d", sock, events);
|
2018-05-01 10:55:02 +00:00
|
|
|
*retsock = sock;
|
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2018-05-01 10:34:51 +00:00
|
|
|
struct testSocketData {
|
2010-12-06 17:03:35 +00:00
|
|
|
const char *lnode;
|
|
|
|
int port;
|
|
|
|
const char *cnode;
|
|
|
|
};
|
|
|
|
|
2018-05-01 10:55:02 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
testSocketAccept(const void *opaque)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
virNetSocketPtr *lsock = NULL; /* Listen socket */
|
|
|
|
size_t nlsock = 0, i;
|
|
|
|
virNetSocketPtr ssock = NULL; /* Server socket */
|
2018-05-01 10:55:02 +00:00
|
|
|
virNetSocketPtr rsock = NULL; /* Incoming client socket */
|
2018-05-01 10:34:51 +00:00
|
|
|
const struct testSocketData *data = opaque;
|
2010-12-06 17:03:35 +00:00
|
|
|
int ret = -1;
|
|
|
|
char portstr[100];
|
2018-05-01 10:34:51 +00:00
|
|
|
char *tmpdir = NULL;
|
|
|
|
char *path = NULL;
|
|
|
|
char template[] = "/tmp/libvirt_XXXXXX";
|
2018-05-01 10:55:02 +00:00
|
|
|
virThread th;
|
|
|
|
struct testClientData cdata = { 0 };
|
|
|
|
bool goodsock = false;
|
|
|
|
char a = 'a';
|
|
|
|
char b = '\0';
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2018-05-01 10:34:51 +00:00
|
|
|
if (!data) {
|
|
|
|
virNetSocketPtr usock;
|
|
|
|
tmpdir = mkdtemp(template);
|
|
|
|
if (tmpdir == NULL) {
|
|
|
|
VIR_WARN("Failed to create temporary directory");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (virAsprintf(&path, "%s/test.sock", tmpdir) < 0)
|
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2018-05-01 10:34:51 +00:00
|
|
|
if (virNetSocketNewListenUNIX(path, 0700, -1, getegid(), &usock) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(lsock, 1) < 0) {
|
|
|
|
virObjectUnref(usock);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
lsock[0] = usock;
|
|
|
|
nlsock = 1;
|
2018-05-01 10:55:02 +00:00
|
|
|
|
|
|
|
cdata.path = path;
|
2018-05-01 10:34:51 +00:00
|
|
|
} else {
|
|
|
|
snprintf(portstr, sizeof(portstr), "%d", data->port);
|
|
|
|
if (virNetSocketNewListenTCP(data->lnode, portstr,
|
|
|
|
AF_UNSPEC,
|
|
|
|
&lsock, &nlsock) < 0)
|
|
|
|
goto cleanup;
|
2018-05-01 10:55:02 +00:00
|
|
|
|
|
|
|
cdata.cnode = data->cnode;
|
|
|
|
cdata.portstr = portstr;
|
2018-05-01 10:34:51 +00:00
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2013-05-21 07:53:48 +00:00
|
|
|
for (i = 0; i < nlsock; i++) {
|
2011-08-12 09:07:51 +00:00
|
|
|
if (virNetSocketListen(lsock[i], 0) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2018-05-01 10:55:02 +00:00
|
|
|
if (virNetSocketAddIOCallback(lsock[i],
|
|
|
|
VIR_EVENT_HANDLE_READABLE,
|
|
|
|
testSocketIncoming,
|
|
|
|
&rsock,
|
|
|
|
NULL) < 0) {
|
2018-05-01 10:34:51 +00:00
|
|
|
goto cleanup;
|
2018-05-01 10:55:02 +00:00
|
|
|
}
|
2018-05-01 10:34:51 +00:00
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2018-05-01 10:55:02 +00:00
|
|
|
if (virThreadCreate(&th, true,
|
|
|
|
testSocketClient,
|
|
|
|
&cdata) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-09-07 12:20:15 +00:00
|
|
|
while (rsock == NULL) {
|
|
|
|
if (virEventRunDefaultImpl() < 0)
|
|
|
|
break;
|
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2013-05-21 07:53:48 +00:00
|
|
|
for (i = 0; i < nlsock; i++) {
|
2018-05-01 10:55:02 +00:00
|
|
|
if (lsock[i] == rsock) {
|
|
|
|
goodsock = true;
|
|
|
|
break;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 10:55:02 +00:00
|
|
|
if (!goodsock) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
"Unexpected server socket seen");
|
|
|
|
goto join;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetSocketAccept(rsock, &ssock) < 0)
|
|
|
|
goto join;
|
|
|
|
|
|
|
|
if (!ssock) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
"Client went away unexpectedly");
|
|
|
|
goto join;
|
|
|
|
}
|
|
|
|
|
|
|
|
virNetSocketSetBlocking(ssock, true);
|
|
|
|
|
|
|
|
if (virNetSocketWrite(ssock, &a, 1) < 0 ||
|
|
|
|
virNetSocketRead(ssock, &b, 1) < 0) {
|
|
|
|
goto join;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a != b) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Bad data received '%x' != '%x'", a, b);
|
|
|
|
goto join;
|
|
|
|
}
|
|
|
|
|
|
|
|
virObjectUnref(ssock);
|
|
|
|
ssock = NULL;
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2018-05-01 10:55:02 +00:00
|
|
|
join:
|
|
|
|
virThreadJoin(&th);
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(ssock);
|
2018-05-01 10:55:02 +00:00
|
|
|
for (i = 0; i < nlsock; i++) {
|
|
|
|
virNetSocketRemoveIOCallback(lsock[i]);
|
|
|
|
virNetSocketClose(lsock[i]);
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(lsock[i]);
|
2018-05-01 10:55:02 +00:00
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_FREE(lsock);
|
|
|
|
VIR_FREE(path);
|
2011-11-02 21:06:44 +00:00
|
|
|
if (tmpdir)
|
|
|
|
rmdir(tmpdir);
|
2010-12-06 17:03:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2018-05-01 10:34:51 +00:00
|
|
|
#endif
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
|
2018-05-01 10:34:51 +00:00
|
|
|
#ifndef WIN32
|
2010-12-06 17:03:35 +00:00
|
|
|
static int testSocketUNIXAddrs(const void *data ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virNetSocketPtr lsock = NULL; /* Listen socket */
|
|
|
|
virNetSocketPtr ssock = NULL; /* Server socket */
|
|
|
|
virNetSocketPtr csock = NULL; /* Client socket */
|
|
|
|
int ret = -1;
|
|
|
|
|
2013-01-22 14:15:40 +00:00
|
|
|
char *path = NULL;
|
2011-11-02 21:06:44 +00:00
|
|
|
char *tmpdir;
|
|
|
|
char template[] = "/tmp/libvirt_XXXXXX";
|
|
|
|
|
|
|
|
tmpdir = mkdtemp(template);
|
|
|
|
if (tmpdir == NULL) {
|
2011-11-03 10:52:44 +00:00
|
|
|
VIR_WARN("Failed to create temporary directory");
|
2011-11-02 21:06:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-11-03 10:52:44 +00:00
|
|
|
if (virAsprintf(&path, "%s/test.sock", tmpdir) < 0)
|
2011-11-02 21:06:44 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2013-10-09 11:13:45 +00:00
|
|
|
if (virNetSocketNewListenUNIX(path, 0700, -1, getegid(), &lsock) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2016-06-20 14:01:50 +00:00
|
|
|
if (STRNEQ(virNetSocketLocalAddrStringSASL(lsock), "127.0.0.1;0")) {
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_DEBUG("Unexpected local address");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-06-20 14:01:50 +00:00
|
|
|
if (virNetSocketRemoteAddrStringSASL(lsock) != NULL) {
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_DEBUG("Unexpected remote address");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-08-12 09:07:51 +00:00
|
|
|
if (virNetSocketListen(lsock, 0) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virNetSocketNewConnectUNIX(path, false, NULL, &csock) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2016-06-20 14:01:50 +00:00
|
|
|
if (STRNEQ(virNetSocketLocalAddrStringSASL(csock), "127.0.0.1;0")) {
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_DEBUG("Unexpected local address");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-06-20 14:01:50 +00:00
|
|
|
if (STRNEQ(virNetSocketRemoteAddrStringSASL(csock), "127.0.0.1;0")) {
|
2016-06-20 13:52:55 +00:00
|
|
|
VIR_DEBUG("Unexpected remote address");
|
2010-12-06 17:03:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-06-20 13:48:47 +00:00
|
|
|
if (STRNEQ(virNetSocketRemoteAddrStringURI(csock), "127.0.0.1:0")) {
|
|
|
|
VIR_DEBUG("Unexpected remote address");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
if (virNetSocketAccept(lsock, &ssock) < 0) {
|
|
|
|
VIR_DEBUG("Unexpected client socket missing");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-20 14:01:50 +00:00
|
|
|
if (STRNEQ(virNetSocketLocalAddrStringSASL(ssock), "127.0.0.1;0")) {
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_DEBUG("Unexpected local address");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-06-20 14:01:50 +00:00
|
|
|
if (STRNEQ(virNetSocketRemoteAddrStringSASL(ssock), "127.0.0.1;0")) {
|
2016-06-20 13:52:55 +00:00
|
|
|
VIR_DEBUG("Unexpected remote address");
|
2010-12-06 17:03:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-06-20 13:48:47 +00:00
|
|
|
if (STRNEQ(virNetSocketRemoteAddrStringURI(ssock), "127.0.0.1:0")) {
|
|
|
|
VIR_DEBUG("Unexpected remote address");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_FREE(path);
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(lsock);
|
|
|
|
virObjectUnref(ssock);
|
|
|
|
virObjectUnref(csock);
|
2011-11-02 21:06:44 +00:00
|
|
|
if (tmpdir)
|
|
|
|
rmdir(tmpdir);
|
2010-12-06 17:03:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int testSocketCommandNormal(const void *data ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virNetSocketPtr csock = NULL; /* Client socket */
|
|
|
|
char buf[100];
|
|
|
|
size_t i;
|
|
|
|
int ret = -1;
|
|
|
|
virCommandPtr cmd = virCommandNewArgList("/bin/cat", "/dev/zero", NULL);
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
|
|
|
|
|
|
|
if (virNetSocketNewConnectCommand(cmd, &csock) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virNetSocketSetBlocking(csock, true);
|
|
|
|
|
|
|
|
if (virNetSocketRead(csock, buf, sizeof(buf)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-05-21 07:53:48 +00:00
|
|
|
for (i = 0; i < sizeof(buf); i++)
|
2010-12-06 17:03:35 +00:00
|
|
|
if (buf[i] != '\0')
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(csock);
|
2010-12-06 17:03:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int testSocketCommandFail(const void *data ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virNetSocketPtr csock = NULL; /* Client socket */
|
|
|
|
char buf[100];
|
|
|
|
int ret = -1;
|
|
|
|
virCommandPtr cmd = virCommandNewArgList("/bin/cat", "/dev/does-not-exist", NULL);
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
|
|
|
|
|
|
|
if (virNetSocketNewConnectCommand(cmd, &csock) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virNetSocketSetBlocking(csock, true);
|
|
|
|
|
|
|
|
if (virNetSocketRead(csock, buf, sizeof(buf)) == 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(csock);
|
2010-12-06 17:03:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct testSSHData {
|
|
|
|
const char *nodename;
|
|
|
|
const char *service;
|
|
|
|
const char *binary;
|
|
|
|
const char *username;
|
|
|
|
bool noTTY;
|
2011-07-11 19:50:31 +00:00
|
|
|
bool noVerify;
|
2010-12-06 17:03:35 +00:00
|
|
|
const char *netcat;
|
2011-07-19 17:52:21 +00:00
|
|
|
const char *keyfile;
|
2010-12-06 17:03:35 +00:00
|
|
|
const char *path;
|
|
|
|
|
|
|
|
const char *expectOut;
|
|
|
|
bool failConnect;
|
|
|
|
bool dieEarly;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int testSocketSSH(const void *opaque)
|
|
|
|
{
|
|
|
|
const struct testSSHData *data = opaque;
|
|
|
|
virNetSocketPtr csock = NULL; /* Client socket */
|
|
|
|
int ret = -1;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
if (virNetSocketNewConnectSSH(data->nodename,
|
|
|
|
data->service,
|
|
|
|
data->binary,
|
|
|
|
data->username,
|
|
|
|
data->noTTY,
|
2011-07-11 19:50:31 +00:00
|
|
|
data->noVerify,
|
2010-12-06 17:03:35 +00:00
|
|
|
data->netcat,
|
2011-07-19 17:52:21 +00:00
|
|
|
data->keyfile,
|
2010-12-06 17:03:35 +00:00
|
|
|
data->path,
|
|
|
|
&csock) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virNetSocketSetBlocking(csock, true);
|
|
|
|
|
|
|
|
if (data->failConnect) {
|
|
|
|
if (virNetSocketRead(csock, buf, sizeof(buf)-1) >= 0) {
|
|
|
|
VIR_DEBUG("Expected connect failure, but got some socket data");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ssize_t rv;
|
|
|
|
if ((rv = virNetSocketRead(csock, buf, sizeof(buf)-1)) < 0) {
|
|
|
|
VIR_DEBUG("Didn't get any socket data");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
buf[rv] = '\0';
|
|
|
|
|
2015-10-20 16:15:12 +00:00
|
|
|
if (STRNEQ(buf, data->expectOut)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, data->expectOut, buf);
|
2010-12-06 17:03:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data->dieEarly &&
|
|
|
|
virNetSocketRead(csock, buf, sizeof(buf)-1) >= 0) {
|
|
|
|
VIR_DEBUG("Got too much socket data");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(csock);
|
2010-12-06 17:03:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
mymain(void)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
#ifdef HAVE_IFADDRS_H
|
|
|
|
bool hasIPv4, hasIPv6;
|
|
|
|
int freePort;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
2018-05-01 10:55:02 +00:00
|
|
|
virEventRegisterDefaultImpl();
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
#ifdef HAVE_IFADDRS_H
|
|
|
|
if (checkProtocols(&hasIPv4, &hasIPv6, &freePort) < 0) {
|
|
|
|
fprintf(stderr, "Cannot identify IPv4/6 availability\n");
|
2012-03-22 11:33:35 +00:00
|
|
|
return EXIT_FAILURE;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hasIPv4) {
|
2018-05-01 10:34:51 +00:00
|
|
|
struct testSocketData tcpData = { "127.0.0.1", freePort, "127.0.0.1" };
|
|
|
|
if (virTestRun("Socket TCP/IPv4 Accept", testSocketAccept, &tcpData) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
if (hasIPv6) {
|
2018-05-01 10:34:51 +00:00
|
|
|
struct testSocketData tcpData = { "::1", freePort, "::1" };
|
|
|
|
if (virTestRun("Socket TCP/IPv6 Accept", testSocketAccept, &tcpData) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
if (hasIPv6 && hasIPv4) {
|
2018-05-01 10:34:51 +00:00
|
|
|
struct testSocketData tcpData = { NULL, freePort, "127.0.0.1" };
|
|
|
|
if (virTestRun("Socket TCP/IPv4+IPv6 Accept", testSocketAccept, &tcpData) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
tcpData.cnode = "::1";
|
2018-05-01 10:34:51 +00:00
|
|
|
if (virTestRun("Socket TCP/IPv4+IPv6 Accept", testSocketAccept, &tcpData) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef WIN32
|
2018-05-01 10:34:51 +00:00
|
|
|
if (virTestRun("Socket UNIX Accept", testSocketAccept, NULL) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("Socket UNIX Addrs", testSocketUNIXAddrs, NULL) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("Socket External Command /dev/zero", testSocketCommandNormal, NULL) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("Socket External Command /dev/does-not-exist", testSocketCommandFail, NULL) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
struct testSSHData sshData1 = {
|
|
|
|
.nodename = "somehost",
|
|
|
|
.path = "/tmp/socket",
|
2017-08-30 08:50:17 +00:00
|
|
|
.expectOut = "-- somehost sh -c 'if 'nc' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
|
2011-07-08 19:07:29 +00:00
|
|
|
"ARG=-q0;"
|
|
|
|
"else "
|
|
|
|
"ARG=;"
|
|
|
|
"fi;"
|
2011-10-13 19:49:01 +00:00
|
|
|
"'nc' $ARG -U /tmp/socket'\n",
|
2010-12-06 17:03:35 +00:00
|
|
|
};
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("SSH test 1", testSocketSSH, &sshData1) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
struct testSSHData sshData2 = {
|
|
|
|
.nodename = "somehost",
|
|
|
|
.service = "9000",
|
|
|
|
.username = "fred",
|
|
|
|
.netcat = "netcat",
|
|
|
|
.noTTY = true,
|
2011-07-11 19:50:31 +00:00
|
|
|
.noVerify = false,
|
2010-12-06 17:03:35 +00:00
|
|
|
.path = "/tmp/socket",
|
2017-08-30 08:50:17 +00:00
|
|
|
.expectOut = "-p 9000 -l fred -T -o BatchMode=yes -e none -- somehost sh -c '"
|
2011-10-13 19:49:01 +00:00
|
|
|
"if 'netcat' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
|
2011-07-08 19:07:29 +00:00
|
|
|
"ARG=-q0;"
|
|
|
|
"else "
|
|
|
|
"ARG=;"
|
|
|
|
"fi;"
|
2011-10-13 19:49:01 +00:00
|
|
|
"'netcat' $ARG -U /tmp/socket'\n",
|
2010-12-06 17:03:35 +00:00
|
|
|
};
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("SSH test 2", testSocketSSH, &sshData2) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
struct testSSHData sshData3 = {
|
2011-07-11 19:50:31 +00:00
|
|
|
.nodename = "somehost",
|
|
|
|
.service = "9000",
|
|
|
|
.username = "fred",
|
|
|
|
.netcat = "netcat",
|
|
|
|
.noTTY = false,
|
|
|
|
.noVerify = true,
|
2010-12-06 17:03:35 +00:00
|
|
|
.path = "/tmp/socket",
|
2017-08-30 08:50:17 +00:00
|
|
|
.expectOut = "-p 9000 -l fred -o StrictHostKeyChecking=no -- somehost sh -c '"
|
2011-10-13 19:49:01 +00:00
|
|
|
"if 'netcat' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
|
2011-07-08 19:07:29 +00:00
|
|
|
"ARG=-q0;"
|
|
|
|
"else "
|
|
|
|
"ARG=;"
|
|
|
|
"fi;"
|
2011-10-13 19:49:01 +00:00
|
|
|
"'netcat' $ARG -U /tmp/socket'\n",
|
2010-12-06 17:03:35 +00:00
|
|
|
};
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("SSH test 3", testSocketSSH, &sshData3) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
struct testSSHData sshData4 = {
|
2011-07-11 19:50:31 +00:00
|
|
|
.nodename = "nosuchhost",
|
|
|
|
.path = "/tmp/socket",
|
|
|
|
.failConnect = true,
|
|
|
|
};
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("SSH test 4", testSocketSSH, &sshData4) < 0)
|
2011-07-11 19:50:31 +00:00
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
struct testSSHData sshData5 = {
|
2010-12-06 17:03:35 +00:00
|
|
|
.nodename = "crashyhost",
|
|
|
|
.path = "/tmp/socket",
|
2017-08-30 08:50:17 +00:00
|
|
|
.expectOut = "-- crashyhost sh -c "
|
2011-10-13 19:49:01 +00:00
|
|
|
"'if 'nc' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
|
2011-07-08 19:07:29 +00:00
|
|
|
"ARG=-q0;"
|
|
|
|
"else "
|
|
|
|
"ARG=;"
|
|
|
|
"fi;"
|
2011-10-13 19:49:01 +00:00
|
|
|
"'nc' $ARG -U /tmp/socket'\n",
|
2010-12-06 17:03:35 +00:00
|
|
|
.dieEarly = true,
|
|
|
|
};
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("SSH test 5", testSocketSSH, &sshData5) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
ret = -1;
|
|
|
|
|
2011-07-19 17:52:21 +00:00
|
|
|
struct testSSHData sshData6 = {
|
|
|
|
.nodename = "example.com",
|
|
|
|
.path = "/tmp/socket",
|
|
|
|
.keyfile = "/root/.ssh/example_key",
|
|
|
|
.noVerify = true,
|
2017-08-30 08:50:17 +00:00
|
|
|
.expectOut = "-i /root/.ssh/example_key -o StrictHostKeyChecking=no -- example.com sh -c '"
|
2011-10-13 19:49:01 +00:00
|
|
|
"if 'nc' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
|
2011-07-08 19:07:29 +00:00
|
|
|
"ARG=-q0;"
|
|
|
|
"else "
|
|
|
|
"ARG=;"
|
|
|
|
"fi;"
|
2011-10-13 19:49:01 +00:00
|
|
|
"'nc' $ARG -U /tmp/socket'\n",
|
2011-07-19 17:52:21 +00:00
|
|
|
};
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("SSH test 6", testSocketSSH, &sshData6) < 0)
|
2011-07-19 17:52:21 +00:00
|
|
|
ret = -1;
|
|
|
|
|
2011-10-13 19:49:01 +00:00
|
|
|
struct testSSHData sshData7 = {
|
|
|
|
.nodename = "somehost",
|
|
|
|
.netcat = "nc -4",
|
|
|
|
.path = "/tmp/socket",
|
2017-08-30 08:50:17 +00:00
|
|
|
.expectOut = "-- somehost sh -c 'if ''nc -4'' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
|
2011-10-13 19:49:01 +00:00
|
|
|
"ARG=-q0;"
|
|
|
|
"else "
|
|
|
|
"ARG=;"
|
|
|
|
"fi;"
|
|
|
|
"''nc -4'' $ARG -U /tmp/socket'\n",
|
|
|
|
};
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("SSH test 7", testSocketSSH, &sshData7) < 0)
|
2011-10-13 19:49:01 +00:00
|
|
|
ret = -1;
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
#endif
|
|
|
|
|
2014-03-17 09:38:38 +00:00
|
|
|
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2017-03-29 14:45:42 +00:00
|
|
|
VIR_TEST_MAIN(mymain)
|