19b589ffbSDaniel P. Berrange /* 29b589ffbSDaniel P. Berrange * Helper functions for tests using sockets 39b589ffbSDaniel P. Berrange * 49b589ffbSDaniel P. Berrange * Copyright 2015-2018 Red Hat, Inc. 59b589ffbSDaniel P. Berrange * 69b589ffbSDaniel P. Berrange * This program is free software; you can redistribute it and/or 79b589ffbSDaniel P. Berrange * modify it under the terms of the GNU General Public License as 89b589ffbSDaniel P. Berrange * published by the Free Software Foundation; either version 2 or 99b589ffbSDaniel P. Berrange * (at your option) version 3 of the License. 109b589ffbSDaniel P. Berrange * 119b589ffbSDaniel P. Berrange * This program is distributed in the hope that it will be useful, 129b589ffbSDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of 139b589ffbSDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149b589ffbSDaniel P. Berrange * GNU General Public License for more details. 159b589ffbSDaniel P. Berrange * 169b589ffbSDaniel P. Berrange * You should have received a copy of the GNU General Public License 179b589ffbSDaniel P. Berrange * along with this program; if not, see <http://www.gnu.org/licenses/>. 189b589ffbSDaniel P. Berrange * 199b589ffbSDaniel P. Berrange */ 209b589ffbSDaniel P. Berrange 219b589ffbSDaniel P. Berrange #include "qemu/osdep.h" 229b589ffbSDaniel P. Berrange #include "qemu-common.h" 239b589ffbSDaniel P. Berrange #include "qemu/sockets.h" 249b589ffbSDaniel P. Berrange #include "socket-helpers.h" 259b589ffbSDaniel P. Berrange 269b589ffbSDaniel P. Berrange #ifndef AI_ADDRCONFIG 279b589ffbSDaniel P. Berrange # define AI_ADDRCONFIG 0 289b589ffbSDaniel P. Berrange #endif 299b589ffbSDaniel P. Berrange #ifndef EAI_ADDRFAMILY 309b589ffbSDaniel P. Berrange # define EAI_ADDRFAMILY 0 319b589ffbSDaniel P. Berrange #endif 329b589ffbSDaniel P. Berrange 33*71714178SMarc-André Lureau /* 34*71714178SMarc-André Lureau * @hostname: a DNS name or numeric IP address 35*71714178SMarc-André Lureau * 36*71714178SMarc-André Lureau * Check whether it is possible to bind & connect to ports 37*71714178SMarc-André Lureau * on the DNS name or IP address @hostname. If an IP address 38*71714178SMarc-André Lureau * is used, it must not be a wildcard address. 39*71714178SMarc-André Lureau * 40*71714178SMarc-André Lureau * Returns 0 on success, -1 on error with errno set 41*71714178SMarc-André Lureau */ 42*71714178SMarc-André Lureau static int socket_can_bind_connect(const char *hostname, int family) 439b589ffbSDaniel P. Berrange { 44abd983c0SDaniel P. Berrange int lfd = -1, cfd = -1, afd = -1; 459b589ffbSDaniel P. Berrange struct addrinfo ai, *res = NULL; 46abd983c0SDaniel P. Berrange struct sockaddr_storage ss; 47abd983c0SDaniel P. Berrange socklen_t sslen = sizeof(ss); 48abd983c0SDaniel P. Berrange int soerr; 49abd983c0SDaniel P. Berrange socklen_t soerrlen = sizeof(soerr); 50abd983c0SDaniel P. Berrange bool check_soerr = false; 519b589ffbSDaniel P. Berrange int rc; 529b589ffbSDaniel P. Berrange int ret = -1; 539b589ffbSDaniel P. Berrange 549b589ffbSDaniel P. Berrange memset(&ai, 0, sizeof(ai)); 559b589ffbSDaniel P. Berrange ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; 56*71714178SMarc-André Lureau ai.ai_family = family; 579b589ffbSDaniel P. Berrange ai.ai_socktype = SOCK_STREAM; 589b589ffbSDaniel P. Berrange 599b589ffbSDaniel P. Berrange /* lookup */ 609b589ffbSDaniel P. Berrange rc = getaddrinfo(hostname, NULL, &ai, &res); 619b589ffbSDaniel P. Berrange if (rc != 0) { 629b589ffbSDaniel P. Berrange if (rc == EAI_ADDRFAMILY || 639b589ffbSDaniel P. Berrange rc == EAI_FAMILY) { 649b589ffbSDaniel P. Berrange errno = EADDRNOTAVAIL; 659b589ffbSDaniel P. Berrange } else { 669b589ffbSDaniel P. Berrange errno = EINVAL; 679b589ffbSDaniel P. Berrange } 689b589ffbSDaniel P. Berrange goto cleanup; 699b589ffbSDaniel P. Berrange } 709b589ffbSDaniel P. Berrange 71abd983c0SDaniel P. Berrange lfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol); 72abd983c0SDaniel P. Berrange if (lfd < 0) { 739b589ffbSDaniel P. Berrange goto cleanup; 749b589ffbSDaniel P. Berrange } 759b589ffbSDaniel P. Berrange 76abd983c0SDaniel P. Berrange cfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol); 77abd983c0SDaniel P. Berrange if (cfd < 0) { 789b589ffbSDaniel P. Berrange goto cleanup; 799b589ffbSDaniel P. Berrange } 809b589ffbSDaniel P. Berrange 81abd983c0SDaniel P. Berrange if (bind(lfd, res->ai_addr, res->ai_addrlen) < 0) { 82abd983c0SDaniel P. Berrange goto cleanup; 83abd983c0SDaniel P. Berrange } 84abd983c0SDaniel P. Berrange 85abd983c0SDaniel P. Berrange if (listen(lfd, 1) < 0) { 86abd983c0SDaniel P. Berrange goto cleanup; 87abd983c0SDaniel P. Berrange } 88abd983c0SDaniel P. Berrange 89abd983c0SDaniel P. Berrange if (getsockname(lfd, (struct sockaddr *)&ss, &sslen) < 0) { 90abd983c0SDaniel P. Berrange goto cleanup; 91abd983c0SDaniel P. Berrange } 92abd983c0SDaniel P. Berrange 93abd983c0SDaniel P. Berrange qemu_set_nonblock(cfd); 94abd983c0SDaniel P. Berrange if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) { 95abd983c0SDaniel P. Berrange if (errno == EINPROGRESS) { 96abd983c0SDaniel P. Berrange check_soerr = true; 97abd983c0SDaniel P. Berrange } else { 98abd983c0SDaniel P. Berrange goto cleanup; 99abd983c0SDaniel P. Berrange } 100abd983c0SDaniel P. Berrange } 101abd983c0SDaniel P. Berrange 102abd983c0SDaniel P. Berrange sslen = sizeof(ss); 103abd983c0SDaniel P. Berrange afd = accept(lfd, (struct sockaddr *)&ss, &sslen); 104abd983c0SDaniel P. Berrange if (afd < 0) { 105abd983c0SDaniel P. Berrange goto cleanup; 106abd983c0SDaniel P. Berrange } 107abd983c0SDaniel P. Berrange 108abd983c0SDaniel P. Berrange if (check_soerr) { 109abd983c0SDaniel P. Berrange if (qemu_getsockopt(cfd, SOL_SOCKET, SO_ERROR, &soerr, &soerrlen) < 0) { 110abd983c0SDaniel P. Berrange goto cleanup; 111abd983c0SDaniel P. Berrange } 112abd983c0SDaniel P. Berrange if (soerr) { 113abd983c0SDaniel P. Berrange errno = soerr; 114abd983c0SDaniel P. Berrange goto cleanup; 115abd983c0SDaniel P. Berrange } 116abd983c0SDaniel P. Berrange } 117abd983c0SDaniel P. Berrange 1189b589ffbSDaniel P. Berrange ret = 0; 1199b589ffbSDaniel P. Berrange 1209b589ffbSDaniel P. Berrange cleanup: 121abd983c0SDaniel P. Berrange if (afd != -1) { 122abd983c0SDaniel P. Berrange close(afd); 123abd983c0SDaniel P. Berrange } 124abd983c0SDaniel P. Berrange if (cfd != -1) { 125abd983c0SDaniel P. Berrange close(cfd); 126abd983c0SDaniel P. Berrange } 127abd983c0SDaniel P. Berrange if (lfd != -1) { 128abd983c0SDaniel P. Berrange close(lfd); 1299b589ffbSDaniel P. Berrange } 1309b589ffbSDaniel P. Berrange if (res) { 1319b589ffbSDaniel P. Berrange freeaddrinfo(res); 1329b589ffbSDaniel P. Berrange } 1339b589ffbSDaniel P. Berrange return ret; 1349b589ffbSDaniel P. Berrange } 1359b589ffbSDaniel P. Berrange 1369b589ffbSDaniel P. Berrange 1379b589ffbSDaniel P. Berrange int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6) 1389b589ffbSDaniel P. Berrange { 1399b589ffbSDaniel P. Berrange *has_ipv4 = *has_ipv6 = false; 1409b589ffbSDaniel P. Berrange 141*71714178SMarc-André Lureau if (socket_can_bind_connect("127.0.0.1", PF_INET) < 0) { 1429b589ffbSDaniel P. Berrange if (errno != EADDRNOTAVAIL) { 1439b589ffbSDaniel P. Berrange return -1; 1449b589ffbSDaniel P. Berrange } 1459b589ffbSDaniel P. Berrange } else { 1469b589ffbSDaniel P. Berrange *has_ipv4 = true; 1479b589ffbSDaniel P. Berrange } 1489b589ffbSDaniel P. Berrange 149*71714178SMarc-André Lureau if (socket_can_bind_connect("::1", PF_INET6) < 0) { 1509b589ffbSDaniel P. Berrange if (errno != EADDRNOTAVAIL) { 1519b589ffbSDaniel P. Berrange return -1; 1529b589ffbSDaniel P. Berrange } 1539b589ffbSDaniel P. Berrange } else { 1549b589ffbSDaniel P. Berrange *has_ipv6 = true; 1559b589ffbSDaniel P. Berrange } 1569b589ffbSDaniel P. Berrange 1579b589ffbSDaniel P. Berrange return 0; 1589b589ffbSDaniel P. Berrange } 159