/** * virSocketAddrMaskByPrefix: * @addr: address that needs to be masked * @prefix: prefix (# of 1 bits) of netmask to apply * @network: where to store the result, can be same as @addr * * Mask off the host bits of @addr according to @prefix, turning it * into a network address. * * Returns 0 in case of success, or -1 on error. */ int virSocketAddrMaskByPrefix(const virSocketAddrPtr addr, unsigned int prefix, virSocketAddrPtr network) { virSocketAddr netmask; if (virSocketAddrPrefixToNetmask(prefix, &netmask, addr->data.stor.ss_family) < 0) { network->data.stor.ss_family = AF_UNSPEC; return -1; } return virSocketAddrMask(addr, &netmask, network); }
virNetDevIPRoutePtr virNetDevIPRouteCreate(const char *errorDetail, const char *family, const char *address, const char *netmask, const char *gateway, unsigned int prefix, bool hasPrefix, unsigned int metric, bool hasMetric) { virNetDevIPRoutePtr def = NULL; virSocketAddr testAddr; if (VIR_ALLOC(def) < 0) return NULL; if (VIR_STRDUP(def->family, family) < 0) goto error; def->prefix = prefix; def->has_prefix = hasPrefix; def->metric = metric; def->has_metric = hasMetric; /* Note: both network and gateway addresses must be specified */ if (!address) { virReportError(VIR_ERR_XML_ERROR, _("%s: Missing required address attribute " "in route definition"), errorDetail); goto error; } if (!gateway) { virReportError(VIR_ERR_XML_ERROR, _("%s: Missing required gateway attribute " "in route definition"), errorDetail); goto error; } if (virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) { virReportError(VIR_ERR_XML_ERROR, _("%s: Bad network address '%s' " "in route definition"), errorDetail, address); goto error; } if (virSocketAddrParse(&def->gateway, gateway, AF_UNSPEC) < 0) { virReportError(VIR_ERR_XML_ERROR, _("%s: Bad gateway address '%s' " "in route definition"), errorDetail, gateway); goto error; } /* validate network address, etc. for each family */ if ((def->family == NULL) || (STREQ(def->family, "ipv4"))) { if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) || VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_UNSPEC))) { virReportError(VIR_ERR_XML_ERROR, def->family == NULL ? _("%s: No family specified for non-IPv4 address '%s' " "in route definition") : _("%s: IPv4 family specified for non-IPv4 address '%s' " "in route definition"), errorDetail, address); goto error; } if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET)) { virReportError(VIR_ERR_XML_ERROR, def->family == NULL ? _("%s: No family specified for non-IPv4 gateway '%s' " "in route definition") : _("%s: IPv4 family specified for non-IPv4 gateway '%s' " "in route definition"), errorDetail, address); goto error; } if (netmask) { if (virSocketAddrParse(&def->netmask, netmask, AF_UNSPEC) < 0) { virReportError(VIR_ERR_XML_ERROR, _("%s: Bad netmask address '%s' " "in route definition"), errorDetail, netmask); goto error; } if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) { virReportError(VIR_ERR_XML_ERROR, _("%s: Invalid netmask '%s' " "for address '%s' (both must be IPv4)"), errorDetail, netmask, address); goto error; } if (def->has_prefix) { /* can't have both netmask and prefix at the same time */ virReportError(VIR_ERR_XML_ERROR, _("%s: Route definition cannot have both " "a prefix and a netmask"), errorDetail); goto error; } } if (def->prefix > 32) { virReportError(VIR_ERR_XML_ERROR, _("%s: Invalid prefix %u specified " "in route definition, " "must be 0 - 32"), errorDetail, def->prefix); goto error; } } else if (STREQ(def->family, "ipv6")) { if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) { virReportError(VIR_ERR_XML_ERROR, _("%s: ipv6 family specified for non-IPv6 address '%s' " "in route definition"), errorDetail, address); goto error; } if (netmask) { virReportError(VIR_ERR_XML_ERROR, _("%s: Specifying netmask invalid for IPv6 address '%s' " "in route definition"), errorDetail, address); goto error; } if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET6)) { virReportError(VIR_ERR_XML_ERROR, _("%s: ipv6 specified for non-IPv6 gateway address '%s' " "in route definition"), errorDetail, gateway); goto error; } if (def->prefix > 128) { virReportError(VIR_ERR_XML_ERROR, _("%s: Invalid prefix %u specified " "in route definition, " "must be 0 - 128"), errorDetail, def->prefix); goto error; } } else { virReportError(VIR_ERR_XML_ERROR, _("%s: Unrecognized family '%s' " "in route definition"), errorDetail, def->family); goto error; } /* make sure the address is a network address */ if (netmask) { if (virSocketAddrMask(&def->address, &def->netmask, &testAddr) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: Error converting address '%s' with netmask '%s' " "to network-address " "in route definition"), errorDetail, address, netmask); goto error; } } else { if (virSocketAddrMaskByPrefix(&def->address, def->prefix, &testAddr) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: Error converting address '%s' with prefix %u " "to network-address " "in route definition"), errorDetail, address, def->prefix); goto error; } } if (!virSocketAddrEqual(&def->address, &testAddr)) { virReportError(VIR_ERR_XML_ERROR, _("%s: Address '%s' in route definition " "is not a network address"), errorDetail, address); goto error; } return def; error: virNetDevIPRouteFree(def); return NULL; }
/** * 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; }