Beispiel #1
0
/* Allow all traffic destined to the bridge, with a valid network address
 */
static int
iptablesForwardAllowIn(iptablesContext *ctx,
                       virSocketAddr *netaddr,
                       unsigned int prefix,
                       const char *iface,
                       const char *physdev,
                       int action)
{
    int ret;
    char *networkstr;

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

    if (physdev && physdev[0]) {
        ret = iptablesAddRemoveRule(ctx->forward_filter,
                                    VIR_SOCKET_ADDR_FAMILY(netaddr),
                                    action,
                                    "--destination", networkstr,
                                    "--in-interface", physdev,
                                    "--out-interface", iface,
                                    "--jump", "ACCEPT",
                                    NULL);
    } else {
        ret = iptablesAddRemoveRule(ctx->forward_filter,
                                    VIR_SOCKET_ADDR_FAMILY(netaddr),
                                    action,
                                    "--destination", networkstr,
                                    "--out-interface", iface,
                                    "--jump", "ACCEPT",
                                    NULL);
    }
    VIR_FREE(networkstr);
    return ret;
}
Beispiel #2
0
/* Allow all traffic coming from the bridge, with a valid network address
 * to proceed to WAN
 */
static int
iptablesForwardAllowOut(iptablesContext *ctx,
                        virSocketAddr *netaddr,
                        unsigned int prefix,
                        const char *iface,
                        const char *physdev,
                        int action)
{
    int ret;
    char *networkstr;
    virCommandPtr cmd = NULL;

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

    cmd = iptablesCommandNew(ctx->forward_filter,
                             VIR_SOCKET_ADDR_FAMILY(netaddr),
                             action);
    virCommandAddArgList(cmd,
                         "--source", networkstr,
                         "--in-interface", iface, NULL);

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

    virCommandAddArgList(cmd, "--jump", "ACCEPT", NULL);

    ret = iptablesCommandRunAndFree(cmd);
    VIR_FREE(networkstr);
    return ret;
}
Beispiel #3
0
/* Allow all traffic destined to the bridge, with a valid network address
 */
static int
iptablesForwardAllowIn(virFirewallPtr fw,
                       virSocketAddr *netaddr,
                       unsigned int prefix,
                       const char *iface,
                       const char *physdev,
                       int action)
{
    virFirewallLayer layer = VIR_SOCKET_ADDR_FAMILY(netaddr) == AF_INET ?
        VIR_FIREWALL_LAYER_IPV4 : VIR_FIREWALL_LAYER_IPV6;
    VIR_AUTOFREE(char *) networkstr = NULL;

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

    if (physdev && physdev[0])
        virFirewallAddRule(fw, layer,
                           "--table", "filter",
                           action == ADD ? "--insert" : "--delete", "FORWARD",
                           "--destination", networkstr,
                           "--in-interface", physdev,
                           "--out-interface", iface,
                           "--jump", "ACCEPT",
                           NULL);
    else
        virFirewallAddRule(fw, layer,
                           "--table", "filter",
                           action == ADD ? "--insert" : "--delete", "FORWARD",
                           "--destination", networkstr,
                           "--out-interface", iface,
                           "--jump", "ACCEPT",
                           NULL);
    return 0;
}
Beispiel #4
0
/* Allow all traffic destined to the bridge, with a valid network address
 * and associated with an existing connection
 */
static int
iptablesForwardAllowRelatedIn(virSocketAddr *netaddr,
                              unsigned int prefix,
                              const char *iface,
                              const char *physdev,
                              int action)
{
    int ret;
    char *networkstr;

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

    if (physdev && physdev[0]) {
        ret = iptablesAddRemoveRule("filter", "FORWARD",
                                    VIR_SOCKET_ADDR_FAMILY(netaddr),
                                    action,
                                    "--destination", networkstr,
                                    "--in-interface", physdev,
                                    "--out-interface", iface,
                                    "--match", "conntrack",
                                    "--ctstate", "ESTABLISHED,RELATED",
                                    "--jump", "ACCEPT",
                                    NULL);
    } else {
        ret = iptablesAddRemoveRule("filter", "FORWARD",
                                    VIR_SOCKET_ADDR_FAMILY(netaddr),
                                    action,
                                    "--destination", networkstr,
                                    "--out-interface", iface,
                                    "--match", "conntrack",
                                    "--ctstate", "ESTABLISHED,RELATED",
                                    "--jump", "ACCEPT",
                                    NULL);
    }
    VIR_FREE(networkstr);
    return ret;
}
Beispiel #5
0
static int
virNetDevGetIPAddressBinary(virSocketAddr *addr, void **data, size_t *len)
{
    if (!addr)
        return -1;

    switch (VIR_SOCKET_ADDR_FAMILY(addr)) {
    case AF_INET:
        *data = &addr->data.inet4.sin_addr;
        *len = sizeof(struct in_addr);
        break;
    case AF_INET6:
        *data = &addr->data.inet6.sin6_addr;
        *len = sizeof(struct in6_addr);
        break;
    default:
        return -1;
    }
    return 0;
}
Beispiel #6
0
static struct nl_msg *
virNetDevCreateNetlinkAddressMessage(int messageType,
                                     const char *ifname,
                                     virSocketAddr *addr,
                                     unsigned int prefix,
                                     virSocketAddr *broadcast,
                                     virSocketAddr *peer)
{
    struct nl_msg *nlmsg = NULL;
    struct ifaddrmsg ifa;
    unsigned int ifindex;
    void *addrData = NULL;
    void *peerData = NULL;
    void *broadcastData = NULL;
    size_t addrDataLen;

    if (virNetDevGetIPAddressBinary(addr, &addrData, &addrDataLen) < 0)
        return NULL;

    if (peer && VIR_SOCKET_ADDR_VALID(peer)) {
        if (virNetDevGetIPAddressBinary(peer, &peerData, &addrDataLen) < 0)
            return NULL;
    } else if (broadcast) {
        if (virNetDevGetIPAddressBinary(broadcast, &broadcastData,
                                        &addrDataLen) < 0)
            return NULL;
    }

    /* Get the interface index */
    if ((ifindex = if_nametoindex(ifname)) == 0)
        return NULL;

    if (!(nlmsg = nlmsg_alloc_simple(messageType,
                                     NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL))) {
        virReportOOMError();
        return NULL;
    }

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

    ifa.ifa_prefixlen = prefix;
    ifa.ifa_family = VIR_SOCKET_ADDR_FAMILY(addr);
    ifa.ifa_index = ifindex;
    ifa.ifa_scope = 0;

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

    if (nla_put(nlmsg, IFA_LOCAL, addrDataLen, addrData) < 0)
        goto buffer_too_small;

    if (peerData) {
        if (nla_put(nlmsg, IFA_ADDRESS, addrDataLen, peerData) < 0)
            goto buffer_too_small;
    }

    if (broadcastData) {
        if (nla_put(nlmsg, IFA_BROADCAST, addrDataLen, broadcastData) < 0)
            goto buffer_too_small;
    }

    return nlmsg;

 buffer_too_small:
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("allocated netlink buffer is too small"));
    nlmsg_free(nlmsg);
    return NULL;
}
Beispiel #7
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;
}
Beispiel #8
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;
}
Beispiel #9
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;
}
Beispiel #10
0
/*
 * virSocketAddrFormatFull:
 * @addr: an initialized virSocketAddrPtr
 * @withService: if true, then service info is appended
 * @separator: separator between hostname & service.
 *
 * Returns a string representation of the given address. If a format conforming
 * to URI specification is required, NULL should be passed to separator.
 * Set @separator only if non-URI format is required, e.g. passing ';' for
 * @separator if the address should be used with SASL.
 * Caller must free the returned string.
 */
char *
virSocketAddrFormatFull(const virSocketAddr *addr,
                        bool withService,
                        const char *separator)
{
    char host[NI_MAXHOST], port[NI_MAXSERV];
    char *addrstr;
    int err;

    if (addr == NULL) {
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Missing address"));
        return NULL;
    }

    /* Short-circuit since getnameinfo doesn't work
     * nicely for UNIX sockets */
    if (addr->data.sa.sa_family == AF_UNIX) {
        if (withService) {
            if (virAsprintf(&addrstr, "127.0.0.1%s0",
                            separator ? separator : ":") < 0)
                goto error;
        } else {
            if (VIR_STRDUP(addrstr, "127.0.0.1") < 0)
                goto error;
        }
        return addrstr;
    }

    if ((err = getnameinfo(&addr->data.sa,
                           addr->len,
                           host, sizeof(host),
                           port, sizeof(port),
                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
        virReportError(VIR_ERR_SYSTEM_ERROR,
                       _("Cannot convert socket address to string: %s"),
                       gai_strerror(err));
        return NULL;
    }

    if (withService) {
        char *ipv6_host = NULL;
        /* sasl_new_client demands the socket address to be in an odd format:
         * a.b.c.d;port or e:f:g:h:i:j:k:l;port, so use square brackets for
         * IPv6 only if no separator is passed to the function
         */
        if (!separator && VIR_SOCKET_ADDR_FAMILY(addr) == AF_INET6) {
            if (virAsprintf(&ipv6_host, "[%s]", host) < 0)
                goto error;
        }

        if (virAsprintf(&addrstr, "%s%s%s",
                        ipv6_host ? ipv6_host : host,
                        separator ? separator : ":", port) == -1)
            goto error;

        VIR_FREE(ipv6_host);
    } else {
        if (VIR_STRDUP(addrstr, host) < 0)
            goto error;
    }

    return addrstr;

 error:
    return NULL;
}