cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

socket-helpers.c (3739B)


      1/*
      2 * Helper functions for tests using sockets
      3 *
      4 * Copyright 2015-2018 Red Hat, Inc.
      5 *
      6 * This program is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU General Public License as
      8 * published by the Free Software Foundation; either version 2 or
      9 * (at your option) version 3 of the License.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
     18 *
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "qemu-common.h"
     23#include "qemu/sockets.h"
     24#include "socket-helpers.h"
     25
     26#ifndef AI_ADDRCONFIG
     27# define AI_ADDRCONFIG 0
     28#endif
     29#ifndef EAI_ADDRFAMILY
     30# define EAI_ADDRFAMILY 0
     31#endif
     32
     33/*
     34 * @hostname: a DNS name or numeric IP address
     35 *
     36 * Check whether it is possible to bind & connect to ports
     37 * on the DNS name or IP address @hostname. If an IP address
     38 * is used, it must not be a wildcard address.
     39 *
     40 * Returns 0 on success, -1 on error with errno set
     41 */
     42static int socket_can_bind_connect(const char *hostname, int family)
     43{
     44    int lfd = -1, cfd = -1, afd = -1;
     45    struct addrinfo ai, *res = NULL;
     46    struct sockaddr_storage ss;
     47    socklen_t sslen = sizeof(ss);
     48    int soerr;
     49    socklen_t soerrlen = sizeof(soerr);
     50    bool check_soerr = false;
     51    int rc;
     52    int ret = -1;
     53
     54    memset(&ai, 0, sizeof(ai));
     55    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
     56    ai.ai_family = family;
     57    ai.ai_socktype = SOCK_STREAM;
     58
     59    /* lookup */
     60    rc = getaddrinfo(hostname, NULL, &ai, &res);
     61    if (rc != 0) {
     62        if (rc == EAI_ADDRFAMILY || rc == EAI_FAMILY || rc == EAI_NONAME) {
     63            errno = EADDRNOTAVAIL;
     64        } else {
     65            errno = EINVAL;
     66        }
     67        goto cleanup;
     68    }
     69
     70    lfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     71    if (lfd < 0) {
     72        goto cleanup;
     73    }
     74
     75    cfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     76    if (cfd < 0) {
     77        goto cleanup;
     78    }
     79
     80    if (bind(lfd, res->ai_addr, res->ai_addrlen) < 0) {
     81        goto cleanup;
     82    }
     83
     84    if (listen(lfd, 1) < 0) {
     85        goto cleanup;
     86    }
     87
     88    if (getsockname(lfd, (struct sockaddr *)&ss, &sslen) < 0) {
     89        goto cleanup;
     90    }
     91
     92    qemu_set_nonblock(cfd);
     93    if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) {
     94        if (errno == EINPROGRESS) {
     95            check_soerr = true;
     96        } else {
     97            goto cleanup;
     98        }
     99    }
    100
    101    sslen = sizeof(ss);
    102    afd = accept(lfd,  (struct sockaddr *)&ss, &sslen);
    103    if (afd < 0) {
    104        goto cleanup;
    105    }
    106
    107    if (check_soerr) {
    108        if (qemu_getsockopt(cfd, SOL_SOCKET, SO_ERROR, &soerr, &soerrlen) < 0) {
    109            goto cleanup;
    110        }
    111        if (soerr) {
    112            errno = soerr;
    113            goto cleanup;
    114        }
    115    }
    116
    117    ret = 0;
    118
    119 cleanup:
    120    if (afd != -1) {
    121        close(afd);
    122    }
    123    if (cfd != -1) {
    124        close(cfd);
    125    }
    126    if (lfd != -1) {
    127        close(lfd);
    128    }
    129    if (res) {
    130        freeaddrinfo(res);
    131    }
    132    return ret;
    133}
    134
    135
    136int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6)
    137{
    138    *has_ipv4 = *has_ipv6 = false;
    139
    140    if (socket_can_bind_connect("127.0.0.1", PF_INET) < 0) {
    141        if (errno != EADDRNOTAVAIL) {
    142            return -1;
    143        }
    144    } else {
    145        *has_ipv4 = true;
    146    }
    147
    148    if (socket_can_bind_connect("::1", PF_INET6) < 0) {
    149        if (errno != EADDRNOTAVAIL) {
    150            return -1;
    151        }
    152    } else {
    153        *has_ipv6 = true;
    154    }
    155
    156    return 0;
    157}