Exemplo n.º 1
0
static int testMaskNetwork(const char *addrstr,
                           int prefix,
                           const char *networkstr)
{
    virSocketAddr addr;
    virSocketAddr network;
    char *gotnet = NULL;

    /* Intentionally fill with garbage */
    memset(&network, 1, sizeof(network));

    if (virSocketAddrParse(&addr, addrstr, AF_UNSPEC) < 0)
        return -1;

    if (virSocketAddrMaskByPrefix(&addr, prefix, &network) < 0)
        return -1;

    if (!(gotnet = virSocketAddrFormat(&network)))
        return -1;

    if (STRNEQ(networkstr, gotnet)) {
        VIR_FREE(gotnet);
        fprintf(stderr, "Expected %s, got %s\n", networkstr, gotnet);
        return -1;
    }
    VIR_FREE(gotnet);
    return 0;
}
Exemplo n.º 2
0
static char *iptablesFormatNetwork(virSocketAddr *netaddr,
                                   unsigned int prefix)
{
    virSocketAddr network;
    char *netstr;
    char *ret;

    if (!(VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET) ||
          VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET6))) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Only IPv4 or IPv6 addresses can be used with iptables"));
        return NULL;
    }

    if (virSocketAddrMaskByPrefix(netaddr, prefix, &network) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failure to mask address"));
        return NULL;
    }

    netstr = virSocketAddrFormat(&network);

    if (!netstr)
        return NULL;

    if (virAsprintf(&ret, "%s/%d", netstr, prefix) < 0)
        virReportOOMError();

    VIR_FREE(netstr);
    return ret;
}
Exemplo n.º 3
0
static int
hostsfileAdd(dnsmasqHostsfile *hostsfile,
             const char *mac,
             virSocketAddr *ip,
             const char *name)
{
    char *ipstr = NULL;
    if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0)
        goto alloc_error;

    if (!(ipstr = virSocketAddrFormat(ip)))
        return -1;

    if (name) {
        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s",
                        mac, ipstr, name) < 0) {
            goto alloc_error;
        }
    } else {
        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s",
                        mac, ipstr) < 0) {
            goto alloc_error;
        }
    }
    VIR_FREE(ipstr);

    hostsfile->nhosts++;

    return 0;

 alloc_error:
    virReportOOMError();
    VIR_FREE(ipstr);
    return -1;
}
Exemplo n.º 4
0
/* Note:  There are many additional dhcp-host specifications
 * supported by dnsmasq.  There are only the basic ones.
 */
static int
hostsfileAdd(dnsmasqHostsfile *hostsfile,
             const char *mac,
             virSocketAddr *ip,
             const char *name,
             const char *id,
             bool ipv6)
{
    char *ipstr = NULL;
    if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0)
        goto alloc_error;

    if (!(ipstr = virSocketAddrFormat(ip)))
        return -1;

    /* the first test determines if it is a dhcpv6 host */
    if (ipv6) {
        if (name && id) {
            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
                            "id:%s,%s,[%s]", id, name, ipstr) < 0)
                goto alloc_error;
        } else if (name && !id) {
            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
                            "%s,[%s]", name, ipstr) < 0)
                goto alloc_error;
        } else if (!name && id) {
            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
                            "id:%s,[%s]", id, ipstr) < 0)
                goto alloc_error;
        }
    } else if (name && mac) {
        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s",
                        mac, ipstr, name) < 0)
            goto alloc_error;
    } else if (name && !mac){
        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s",
                        name, ipstr) < 0)
            goto alloc_error;
    } else {
        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s",
                        mac, ipstr) < 0)
            goto alloc_error;
    }
    VIR_FREE(ipstr);

    hostsfile->nhosts++;

    return 0;

 alloc_error:
    virReportOOMError();
    VIR_FREE(ipstr);
    return -1;
}
Exemplo n.º 5
0
static int
addnhostsAdd(dnsmasqAddnHostsfile *addnhostsfile,
             virSocketAddr *ip,
             const char *name)
{
    char *ipstr = NULL;
    int idx = -1;
    int i;

    if (!(ipstr = virSocketAddrFormat(ip)))
        return -1;

    for (i = 0; i < addnhostsfile->nhosts; i++) {
        if (STREQ((const char *)addnhostsfile->hosts[i].ip, (const char *)ipstr)) {
            idx = i;
            break;
        }
    }

    if (idx < 0) {
        if (VIR_REALLOC_N(addnhostsfile->hosts, addnhostsfile->nhosts + 1) < 0)
            goto alloc_error;

        idx = addnhostsfile->nhosts;
        if (VIR_ALLOC(addnhostsfile->hosts[idx].hostnames) < 0)
            goto alloc_error;

        if (!(addnhostsfile->hosts[idx].ip = strdup(ipstr)))
            goto alloc_error;

        addnhostsfile->hosts[idx].nhostnames = 0;
        addnhostsfile->nhosts++;
    }

    if (VIR_REALLOC_N(addnhostsfile->hosts[idx].hostnames, addnhostsfile->hosts[idx].nhostnames + 1) < 0)
        goto alloc_error;

    if (!(addnhostsfile->hosts[idx].hostnames[addnhostsfile->hosts[idx].nhostnames]
          = strdup(name)))
        goto alloc_error;

    VIR_FREE(ipstr);

    addnhostsfile->hosts[idx].nhostnames++;

    return 0;

 alloc_error:
    virReportOOMError();
    VIR_FREE(ipstr);
    return -1;
}
Exemplo n.º 6
0
int
virNetDevIPRouteFormat(virBufferPtr buf,
                       const virNetDevIPRoute *def)
{
    int result = -1;
    char *addr = NULL;

    virBufferAddLit(buf, "<route");

    if (def->family)
        virBufferAsprintf(buf, " family='%s'", def->family);

    if (!(addr = virSocketAddrFormat(&def->address)))
        goto cleanup;
    virBufferAsprintf(buf, " address='%s'", addr);
    VIR_FREE(addr);

    if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
        if (!(addr = virSocketAddrFormat(&def->netmask)))
            goto cleanup;
        virBufferAsprintf(buf, " netmask='%s'", addr);
        VIR_FREE(addr);
    }
    if (def->has_prefix)
        virBufferAsprintf(buf, " prefix='%u'", def->prefix);

    if (!(addr = virSocketAddrFormat(&def->gateway)))
        goto cleanup;
    virBufferAsprintf(buf, " gateway='%s'", addr);
    VIR_FREE(addr);

    if (def->has_metric && def->metric > 0)
        virBufferAsprintf(buf, " metric='%u'", def->metric);
    virBufferAddLit(buf, "/>\n");

    result = 0;
 cleanup:
    return result;
}
Exemplo n.º 7
0
static int
addnhostsAdd(dnsmasqAddnHostsfile *addnhostsfile,
             virSocketAddr *ip,
             const char *name)
{
    char *ipstr = NULL;
    int idx = -1;
    size_t i;

    if (!(ipstr = virSocketAddrFormat(ip)))
        return -1;

    for (i = 0; i < addnhostsfile->nhosts; i++) {
        if (STREQ((const char *)addnhostsfile->hosts[i].ip, (const char *)ipstr)) {
            idx = i;
            break;
        }
    }

    if (idx < 0) {
        if (VIR_REALLOC_N(addnhostsfile->hosts, addnhostsfile->nhosts + 1) < 0)
            goto error;

        idx = addnhostsfile->nhosts;
        if (VIR_ALLOC(addnhostsfile->hosts[idx].hostnames) < 0)
            goto error;

        if (VIR_STRDUP(addnhostsfile->hosts[idx].ip, ipstr) < 0)
            goto error;

        addnhostsfile->hosts[idx].nhostnames = 0;
        addnhostsfile->nhosts++;
    }

    if (VIR_REALLOC_N(addnhostsfile->hosts[idx].hostnames, addnhostsfile->hosts[idx].nhostnames + 1) < 0)
        goto error;

    if (VIR_STRDUP(addnhostsfile->hosts[idx].hostnames[addnhostsfile->hosts[idx].nhostnames],
                   name) < 0)
        goto error;

    VIR_FREE(ipstr);

    addnhostsfile->hosts[idx].nhostnames++;

    return 0;

 error:
    VIR_FREE(ipstr);
    return -1;
}
Exemplo n.º 8
0
/* Note:  There are many additional dhcp-host specifications
 * supported by dnsmasq.  There are only the basic ones.
 */
static int
hostsfileAdd(dnsmasqHostsfile *hostsfile,
             const char *mac,
             virSocketAddr *ip,
             const char *name,
             const char *id,
             const char *leasetime,
             bool ipv6)
{
    int ret = -1;
    char *ipstr = NULL;
    virBuffer hostbuf = VIR_BUFFER_INITIALIZER;

    if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0)
        goto error;

    if (!(ipstr = virSocketAddrFormat(ip)))
        goto error;

    /* the first test determines if it is a dhcpv6 host */
    if (ipv6) {
        if (name && id)
            virBufferAsprintf(&hostbuf, "id:%s,%s,[%s]", id, name, ipstr);
        else if (name && !id)
            virBufferAsprintf(&hostbuf, "%s,[%s]", name, ipstr);
        else if (!name && id)
            virBufferAsprintf(&hostbuf, "id:%s,[%s]", id, ipstr);
    } else if (name && mac) {
        virBufferAsprintf(&hostbuf, "%s,%s,%s", mac, ipstr, name);
    } else if (name && !mac) {
        virBufferAsprintf(&hostbuf, "%s,%s", name, ipstr);
    } else {
        virBufferAsprintf(&hostbuf, "%s,%s", mac, ipstr);
    }

    /* The leasetime string already includes comma if there's any value at all */
    virBufferAsprintf(&hostbuf, "%s", leasetime);

    if (!(hostsfile->hosts[hostsfile->nhosts].host = virBufferContentAndReset (&hostbuf)))
      goto error;

    hostsfile->nhosts++;
    ret = 0;
 error:
    virBufferFreeAndReset(&hostbuf);
    VIR_FREE(ipstr);
    return ret;
}
Exemplo n.º 9
0
static PRUnichar *
vboxSocketFormatAddrUtf16(vboxDriverPtr data, virSocketAddrPtr addr)
{
    char *utf8 = NULL;
    PRUnichar *utf16 = NULL;

    utf8 = virSocketAddrFormat(addr);

    if (utf8 == NULL)
        return NULL;

    VBOX_UTF8_TO_UTF16(utf8, &utf16);
    VIR_FREE(utf8);

    return utf16;
}
Exemplo n.º 10
0
static int testFormat(virSocketAddr *addr, const char *addrstr, bool pass)
{
    char *newaddrstr;

    newaddrstr = virSocketAddrFormat(addr);
    if (!newaddrstr)
        return pass ? -1 : 0;

    if (STRNEQ(newaddrstr, addrstr)) {
        virtTestDifference(stderr, newaddrstr, addrstr);
        VIR_FREE(newaddrstr);
        return pass ? -1 : 0;
    } else {
        VIR_FREE(newaddrstr);
        return pass ? 0 : -1;
    }
}
Exemplo n.º 11
0
/**
 * virNetDevIPRouteAdd:
 * @ifname: the interface name
 * @addr: the IP network address (IPv4 or IPv6)
 * @prefix: number of 1 bits in the netmask
 * @gateway: via address for route (same as @addr)
 *
 * Add a route for a network IP address to an interface. This function
 * *does not* remove any previously added IP static routes.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
int
virNetDevIPRouteAdd(const char *ifname,
                    virSocketAddrPtr addr,
                    unsigned int prefix,
                    virSocketAddrPtr gateway,
                    unsigned int metric)
{
    int ret = -1;
    struct nl_msg *nlmsg = NULL;
    struct nlmsghdr *resp = NULL;
    unsigned int recvbuflen;
    unsigned int ifindex;
    struct rtmsg rtmsg;
    void *gatewayData = NULL;
    void *addrData = NULL;
    size_t addrDataLen;
    int errCode;
    virSocketAddr defaultAddr;
    virSocketAddrPtr actualAddr;
    char *toStr = NULL;
    char *viaStr = NULL;

    actualAddr = addr;

    /* If we have no valid network address, then use the default one */
    if (!addr || !VIR_SOCKET_ADDR_VALID(addr)) {
        VIR_DEBUG("computing default address");
        int family = VIR_SOCKET_ADDR_FAMILY(gateway);
        if (family == AF_INET) {
            if (virSocketAddrParseIPv4(&defaultAddr, VIR_SOCKET_ADDR_IPV4_ALL) < 0)
                goto cleanup;
        } else {
            if (virSocketAddrParseIPv6(&defaultAddr, VIR_SOCKET_ADDR_IPV6_ALL) < 0)
                goto cleanup;
        }

        actualAddr = &defaultAddr;
    }

    toStr = virSocketAddrFormat(actualAddr);
    viaStr = virSocketAddrFormat(gateway);
    VIR_DEBUG("Adding route %s/%d via %s", toStr, prefix, viaStr);

    if (virNetDevGetIPAddressBinary(actualAddr, &addrData, &addrDataLen) < 0 ||
        virNetDevGetIPAddressBinary(gateway, &gatewayData, &addrDataLen) < 0)
        goto cleanup;

    /* Get the interface index */
    if ((ifindex = if_nametoindex(ifname)) == 0)
        goto cleanup;

    if (!(nlmsg = nlmsg_alloc_simple(RTM_NEWROUTE,
                                     NLM_F_REQUEST | NLM_F_CREATE |
                                     NLM_F_EXCL))) {
        virReportOOMError();
        goto cleanup;
    }

    memset(&rtmsg, 0, sizeof(rtmsg));

    rtmsg.rtm_family = VIR_SOCKET_ADDR_FAMILY(gateway);
    rtmsg.rtm_table = RT_TABLE_MAIN;
    rtmsg.rtm_scope = RT_SCOPE_UNIVERSE;
    rtmsg.rtm_protocol = RTPROT_BOOT;
    rtmsg.rtm_type = RTN_UNICAST;
    rtmsg.rtm_dst_len = prefix;

    if (nlmsg_append(nlmsg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
        goto buffer_too_small;

    if (prefix > 0 && nla_put(nlmsg, RTA_DST, addrDataLen, addrData) < 0)
        goto buffer_too_small;

    if (nla_put(nlmsg, RTA_GATEWAY, addrDataLen, gatewayData) < 0)
        goto buffer_too_small;

    if (nla_put_u32(nlmsg, RTA_OIF, ifindex) < 0)
        goto buffer_too_small;

    if (metric > 0 && nla_put_u32(nlmsg, RTA_PRIORITY, metric) < 0)
        goto buffer_too_small;

    if (virNetlinkCommand(nlmsg, &resp, &recvbuflen, 0, 0,
                          NETLINK_ROUTE, 0) < 0)
        goto cleanup;

    if ((errCode = virNetlinkGetErrorCode(resp, recvbuflen)) < 0) {
        virReportSystemError(errCode, _("Error adding route to %s"), ifname);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    VIR_FREE(toStr);
    VIR_FREE(viaStr);
    nlmsg_free(nlmsg);
    return ret;

 buffer_too_small:
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("allocated netlink buffer is too small"));
    goto cleanup;
}
Exemplo n.º 12
0
/**
 * virNetDevIPAddrAdd:
 * @ifname: the interface name
 * @addr: the IP address (IPv4 or IPv6)
 * @peer: The IP address of peer (IPv4 or IPv6)
 * @prefix: number of 1 bits in the netmask
 *
 * Add an IP address to an interface. This function *does not* remove
 * any previously added IP addresses - that must be done separately with
 * virNetDevIPAddrClear.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
int
virNetDevIPAddrAdd(const char *ifname,
                   virSocketAddr *addr,
                   virSocketAddr *peer,
                   unsigned int prefix)
{
    virSocketAddr *broadcast = NULL;
    int ret = -1;
    struct nl_msg *nlmsg = NULL;
    struct nlmsghdr *resp = NULL;
    unsigned int recvbuflen;
    char *ipStr = NULL;
    char *peerStr = NULL;
    char *bcastStr = NULL;

    ipStr = virSocketAddrFormat(addr);
    if (peer && VIR_SOCKET_ADDR_VALID(peer))
       peerStr = virSocketAddrFormat(peer);

    /* The caller needs to provide a correct address */
    if (VIR_SOCKET_ADDR_FAMILY(addr) == AF_INET &&
        !(peer && VIR_SOCKET_ADDR_VALID(peer))) {
        /* compute a broadcast address if this is IPv4 */
        if (VIR_ALLOC(broadcast) < 0)
            goto cleanup;

        if (virSocketAddrBroadcastByPrefix(addr, prefix, broadcast) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to determine broadcast address for '%s/%d'"),
                       ipStr, prefix);
            goto cleanup;
        }
        bcastStr = virSocketAddrFormat(broadcast);
    }

    VIR_DEBUG("Adding IP address %s/%d%s%s%s%s to %s",
              NULLSTR(ipStr), prefix,
              peerStr ? " peer " : "", peerStr ? peerStr : "",
              bcastStr ? " bcast " : "", bcastStr ? bcastStr : "",
              ifname);

    if (!(nlmsg = virNetDevCreateNetlinkAddressMessage(RTM_NEWADDR, ifname,
                                                       addr, prefix,
                                                       broadcast, peer)))
        goto cleanup;

    if (virNetlinkCommand(nlmsg, &resp, &recvbuflen,
                          0, 0, NETLINK_ROUTE, 0) < 0)
        goto cleanup;


    if (virNetlinkGetErrorCode(resp, recvbuflen) < 0) {
        virReportError(VIR_ERR_SYSTEM_ERROR,
                       _("Failed to add IP address %s/%d%s%s%s%s to %s"),
                       ipStr, prefix,
                       peerStr ? " peer " : "", peerStr ? peerStr : "",
                       bcastStr ? " bcast " : "", bcastStr ? bcastStr : "",
                       ifname);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    VIR_FREE(ipStr);
    VIR_FREE(peerStr);
    VIR_FREE(bcastStr);
    nlmsg_free(nlmsg);
    VIR_FREE(resp);
    VIR_FREE(broadcast);
    return ret;
}
Exemplo n.º 13
0
/* Masquerade all traffic coming from the network associated
 * with the bridge
 */
static int
iptablesForwardMasquerade(iptablesContext *ctx,
                          virSocketAddr *netaddr,
                          unsigned int prefix,
                          const char *physdev,
                          virSocketAddr *addrStart,
                          virSocketAddr *addrEnd,
                          unsigned int portStart,
                          unsigned int portEnd,
                          const char *protocol,
                          int action)
{
    int ret = -1;
    char *networkstr = NULL;
    char *addrStartStr = NULL;
    char *addrEndStr = NULL;
    char *portRangeStr = NULL;
    char *natRangeStr = NULL;
    virCommandPtr cmd = NULL;

    if (!(networkstr = iptablesFormatNetwork(netaddr, prefix)))
        return -1;

    if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) {
        /* Higher level code *should* guaranteee it's impossible to get here. */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Attempted to NAT '%s'. NAT is only supported for IPv4."),
                       networkstr);
        goto cleanup;
    }

    if (VIR_SOCKET_ADDR_IS_FAMILY(addrStart, AF_INET)) {
        if (!(addrStartStr = virSocketAddrFormat(addrStart)))
            goto cleanup;
        if (VIR_SOCKET_ADDR_IS_FAMILY(addrEnd, AF_INET)) {
            if (!(addrEndStr = virSocketAddrFormat(addrEnd)))
                goto cleanup;
        }
    }

    cmd = iptablesCommandNew(ctx->nat_postrouting, AF_INET, action);
    virCommandAddArgList(cmd, "--source", networkstr, NULL);

    if (protocol && protocol[0])
        virCommandAddArgList(cmd, "-p", protocol, NULL);

    virCommandAddArgList(cmd, "!", "--destination", networkstr, NULL);

    if (physdev && physdev[0])
        virCommandAddArgList(cmd, "--out-interface", physdev, NULL);

    if (protocol && protocol[0]) {
        if (portStart == 0 && portEnd == 0) {
            portStart = 1024;
            portEnd = 65535;
        }

        if (portStart < portEnd && portEnd < 65536) {
            if (virAsprintf(&portRangeStr, ":%u-%u", portStart, portEnd) < 0) {
                virReportOOMError();
                goto cleanup;
            }
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid port range '%u-%u'."),
                           portStart, portEnd);
        }
    }

    /* Use --jump SNAT if public addr is specified */
    if (addrStartStr && addrStartStr[0]) {
        int r = 0;

        if (addrEndStr && addrEndStr[0]) {
            r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr,
                            portRangeStr ? portRangeStr : "");
        } else {
            r = virAsprintf(&natRangeStr, "%s%s", addrStartStr,
                            portRangeStr ? portRangeStr : "");
        }

        if (r < 0) {
            virReportOOMError();
            goto cleanup;
        }

        virCommandAddArgList(cmd, "--jump", "SNAT",
                                  "--to-source", natRangeStr, NULL);
     } else {
         virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL);

         if (portRangeStr && portRangeStr[0])
             virCommandAddArgList(cmd, "--to-ports", &portRangeStr[1], NULL);
     }

    ret = virCommandRun(cmd, NULL);
cleanup:
    virCommandFree(cmd);
    VIR_FREE(networkstr);
    VIR_FREE(addrStartStr);
    VIR_FREE(addrEndStr);
    VIR_FREE(portRangeStr);
    VIR_FREE(natRangeStr);
    return ret;
}
Exemplo n.º 14
0
static int
testGetHostByName(const void *opaque)
{
    const struct testNSSData *data = opaque;
    const bool existent = data->hostname && data->ipAddr && data->ipAddr[0];
    int ret = -1;
    struct hostent resolved;
    char buf[BUF_SIZE] = { 0 };
    char **addrList;
    int rv, tmp_errno = 0, tmp_herrno = 0;
    size_t i = 0, j = 0;

    memset(&resolved, 0, sizeof(resolved));

    rv = NSS_NAME(gethostbyname2)(data->hostname,
                                  data->af,
                                  &resolved,
                                  buf, sizeof(buf),
                                  &tmp_errno,
                                  &tmp_herrno);

    if (rv == NSS_STATUS_TRYAGAIN ||
        rv == NSS_STATUS_UNAVAIL ||
        rv == NSS_STATUS_RETURN) {
        /* Resolving failed in unexpected fashion. */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "Resolving of %s failed due to internal error",
                       data->hostname);
        goto cleanup;
    } else if (rv == NSS_STATUS_NOTFOUND) {
        /* Resolving failed. Should it? */
        if (!existent)
            ret = 0;
        else
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "Resolving of %s failed",
                           data->hostname);
        goto cleanup;
    }

    /* Resolving succeeded. Should it? */
    if (!existent) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "Resolving of %s succeeded but was expected to fail",
                       data->hostname);
        goto cleanup;
    }

    /* Now lets see if resolved address match our expectations. */

    if (!resolved.h_name) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       "resolved.h_name empty");
        goto cleanup;
    }

    if (data->af != AF_UNSPEC &&
        resolved.h_addrtype != data->af) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "Expected AF_INET (%d) got %d",
                       data->af, resolved.h_addrtype);
        goto cleanup;
    }

    if ((resolved.h_addrtype == AF_INET && resolved.h_length != 4) ||
        (resolved.h_addrtype == AF_INET6 && resolved.h_length != 16)) {
        /* IPv4 addresses are encoded into 4 bytes */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "Expected %d bytes long address, got %d",
                       resolved.h_addrtype == AF_INET ? 4 : 16,
                       resolved.h_length);
        goto cleanup;
    }

    if (!resolved.h_addr_list) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       "resolved.h_addr_list empty");
        goto cleanup;
    }

    addrList = resolved.h_addr_list;
    while (*addrList) {
        virSocketAddr sa;
        char *ipAddr;
        void *address = *addrList;

        memset(&sa, 0, sizeof(sa));

        if (resolved.h_addrtype == AF_INET) {
            virSocketAddrSetIPv4AddrNetOrder(&sa, *((uint32_t *) address));
        } else {
            virSocketAddrSetIPv6AddrNetOrder(&sa, address);
        }

        if (!(ipAddr = virSocketAddrFormat(&sa))) {
            /* error reported by helper */
            goto cleanup;
        }

        for (j = 0; data->ipAddr[j]; j++) {
            if (STREQ(data->ipAddr[j], ipAddr))
                break;
        }

        if (!data->ipAddr[j]) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "Unexpected address %s", ipAddr);
            VIR_FREE(ipAddr);
            goto cleanup;
        }
        VIR_FREE(ipAddr);

        addrList++;
        i++;
    }

    for (j = 0; data->ipAddr[j]; j++)
        ;

    if (i != j) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "Expected %zu addresses, got %zu", j, i);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    return ret;
}
Exemplo n.º 15
0
/* Masquerade all traffic coming from the network associated
 * with the bridge
 */
static int
iptablesForwardMasquerade(virFirewallPtr fw,
                          virSocketAddr *netaddr,
                          unsigned int prefix,
                          const char *physdev,
                          virSocketAddrRangePtr addr,
                          virPortRangePtr port,
                          const char *protocol,
                          int action)
{
    VIR_AUTOFREE(char *) networkstr = NULL;
    VIR_AUTOFREE(char *) addrStartStr = NULL;
    VIR_AUTOFREE(char *) addrEndStr = NULL;
    VIR_AUTOFREE(char *) portRangeStr = NULL;
    VIR_AUTOFREE(char *) natRangeStr = NULL;
    virFirewallRulePtr rule;

    if (!(networkstr = iptablesFormatNetwork(netaddr, prefix)))
        return -1;

    if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) {
        /* Higher level code *should* guaranteee it's impossible to get here. */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Attempted to NAT '%s'. NAT is only supported for IPv4."),
                       networkstr);
        return -1;
    }

    if (VIR_SOCKET_ADDR_IS_FAMILY(&addr->start, AF_INET)) {
        if (!(addrStartStr = virSocketAddrFormat(&addr->start)))
            return -1;
        if (VIR_SOCKET_ADDR_IS_FAMILY(&addr->end, AF_INET)) {
            if (!(addrEndStr = virSocketAddrFormat(&addr->end)))
                return -1;
        }
    }

    if (protocol && protocol[0]) {
        rule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_IPV4,
                                  "--table", "nat",
                                  action == ADD ? "--insert" : "--delete", "POSTROUTING",
                                  "--source", networkstr,
                                  "-p", protocol,
                                  "!", "--destination", networkstr,
                                  NULL);
    } else {
        rule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_IPV4,
                                  "--table", "nat",
                                  action == ADD ? "--insert" : "--delete", "POSTROUTING",
                                  "--source", networkstr,
                                  "!", "--destination", networkstr,
                                  NULL);
    }

    if (physdev && physdev[0])
        virFirewallRuleAddArgList(fw, rule, "--out-interface", physdev, NULL);

    if (protocol && protocol[0]) {
        if (port->start == 0 && port->end == 0) {
            port->start = 1024;
            port->end = 65535;
        }

        if (port->start < port->end && port->end < 65536) {
            if (virAsprintf(&portRangeStr, ":%u-%u",
                            port->start, port->end) < 0)
                return -1;
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid port range '%u-%u'."),
                           port->start, port->end);
        }
    }

    /* Use --jump SNAT if public addr is specified */
    if (addrStartStr && addrStartStr[0]) {
        int r = 0;

        if (addrEndStr && addrEndStr[0]) {
            r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr,
                            portRangeStr ? portRangeStr : "");
        } else {
            r = virAsprintf(&natRangeStr, "%s%s", addrStartStr,
                            portRangeStr ? portRangeStr : "");
        }

        if (r < 0)
            return -1;

        virFirewallRuleAddArgList(fw, rule,
                                  "--jump", "SNAT",
                                  "--to-source", natRangeStr, NULL);
    } else {
        virFirewallRuleAddArgList(fw, rule,
                                  "--jump", "MASQUERADE", NULL);

        if (portRangeStr && portRangeStr[0])
            virFirewallRuleAddArgList(fw, rule,
                                      "--to-ports", &portRangeStr[1], NULL);
    }

    return 0;
}
Exemplo n.º 16
0
/**
 * virSocketGetRange:
 * @start: start of an IP range
 * @end: end of an IP range
 * @network: IP address of network that should completely contain this range
 * @prefix: prefix of the network
 *
 * Check the order of the 2 addresses and compute the range, this will
 * return 1 for identical addresses. Errors can come from incompatible
 * addresses type, excessive range (>= 2^^16) where the two addresses
 * are unrelated, inverted start and end, or a range that is not
 * within network/prefix.
 *
 * Returns the size of the range or -1 in case of failure
 */
int
virSocketAddrGetRange(virSocketAddrPtr start, virSocketAddrPtr end,
                      virSocketAddrPtr network, int prefix)
{
    int ret = 0;
    size_t i;
    virSocketAddr netmask;
    char *startStr = NULL, *endStr = NULL, *netStr = NULL;

    if (start == NULL || end == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("NULL argument - %p %p"), start, end);
        goto error;
    }

    startStr = virSocketAddrFormat(start);
    endStr = virSocketAddrFormat(end);
    if (!startStr || !endStr)
        goto error; /*error already reported */

    if (VIR_SOCKET_ADDR_FAMILY(start) != VIR_SOCKET_ADDR_FAMILY(end)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("mismatch of address family in range %s - %s"),
                       startStr, endStr);
        goto error;
    }

    if (network) {
        /* some checks can only be done if we have details of the
         * network the range should be within
         */
        if (!(netStr = virSocketAddrFormat(network)))
            goto error;

        if (VIR_SOCKET_ADDR_FAMILY(start) != VIR_SOCKET_ADDR_FAMILY(network)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("mismatch of address family in "
                             "range %s - %s for network %s"),
                           startStr, endStr, netStr);
            goto error;
        }

        if (prefix < 0 ||
            virSocketAddrPrefixToNetmask(prefix, &netmask,
                                         VIR_SOCKET_ADDR_FAMILY(network)) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bad prefix %d for network %s when "
                             " checking range %s - %s"),
                           prefix, netStr, startStr, endStr);
            goto error;
        }

        /* both start and end of range need to be within network */
        if (virSocketAddrCheckNetmask(start, network, &netmask) <= 0 ||
            virSocketAddrCheckNetmask(end, network, &netmask) <= 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("range %s - %s is not entirely within "
                             "network %s/%d"),
                           startStr, endStr, netStr, prefix);
            goto error;
        }

        if (VIR_SOCKET_ADDR_IS_FAMILY(start, AF_INET)) {
            virSocketAddr netaddr, broadcast;

            if (virSocketAddrBroadcast(network, &netmask, &broadcast) < 0 ||
                virSocketAddrMask(network, &netmask, &netaddr) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("failed to construct broadcast or network "
                                 "address for network %s/%d"),
                               netStr, prefix);
                goto error;
            }

            /* Don't allow the start of the range to be the network
             * address (usually "...0") or the end of the range to be the
             * broadcast address (usually "...255"). (the opposite also
             * isn't allowed, but checking for that is implicit in all the
             * other combined checks) (IPv6 doesn't have broadcast and
             * network addresses, so this check is only done for IPv4)
             */
            if (virSocketAddrEqual(start, &netaddr)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("start of range %s - %s in network %s/%d "
                                 "is the network address"),
                               startStr, endStr, netStr, prefix);
                goto error;
            }

            if (virSocketAddrEqual(end, &broadcast)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("end of range %s - %s in network %s/%d "
                                 "is the broadcast address"),
                               startStr, endStr, netStr, prefix);
                goto error;
            }
        }
    }

    if (VIR_SOCKET_ADDR_IS_FAMILY(start, AF_INET)) {
        virSocketAddrIPv4 t1, t2;

        if (virSocketAddrGetIPv4Addr(start, &t1) < 0 ||
            virSocketAddrGetIPv4Addr(end, &t2) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to get IPv4 address "
                             "for start or end of range %s - %s"),
                           startStr, endStr);
            goto error;
        }

        /* legacy check that everything except the last two bytes
         * are the same
         */
        for (i = 0; i < 2; i++) {
            if (t1[i] != t2[i]) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("range %s - %s is too large (> 65535)"),
                           startStr, endStr);
            goto error;
            }
        }
        ret = (t2[2] - t1[2]) * 256 + (t2[3] - t1[3]);
        if (ret < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("range %s - %s is reversed "),
                           startStr, endStr);
            goto error;
        }
        ret++;
    } else if (VIR_SOCKET_ADDR_IS_FAMILY(start, AF_INET6)) {
        virSocketAddrIPv6 t1, t2;

        if (virSocketAddrGetIPv6Addr(start, &t1) < 0 ||
            virSocketAddrGetIPv6Addr(end, &t2) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to get IPv6 address "
                             "for start or end of range %s - %s"),
                           startStr, endStr);
            goto error;
        }

        /* legacy check that everything except the last two bytes are
         * the same
         */
        for (i = 0; i < 7; i++) {
            if (t1[i] != t2[i]) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("range %s - %s is too large (> 65535)"),
                               startStr, endStr);
                goto error;
            }
        }
        ret = t2[7] - t1[7];
        if (ret < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("range %s - %s start larger than end"),
                           startStr, endStr);
            goto error;
        }
        ret++;
    } else {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported address family "
                         "for range %s - %s, must be ipv4 or ipv6"),
                       startStr, endStr);
        goto error;
    }

 cleanup:
    VIR_FREE(startStr);
    VIR_FREE(endStr);
    VIR_FREE(netStr);
    return ret;

 error:
    ret = -1;
    goto cleanup;
}