809 lines
19 KiB
C
809 lines
19 KiB
C
/******************************************************************************
|
|
* Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
|
|
* clibcni licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
* PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
* Author: tanyifeng
|
|
* Create: 2019-04-25
|
|
* Description: provide types functions
|
|
*********************************************************************************/
|
|
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include "types.h"
|
|
#include "utils.h"
|
|
#include "log.h"
|
|
|
|
#define IPV4_TO_V6_EMPTY_PREFIX_BYTES 12
|
|
|
|
void free_ipnet_type(struct ipnet *val)
|
|
{
|
|
if (val == NULL) {
|
|
return;
|
|
}
|
|
free(val->ip);
|
|
val->ip = NULL;
|
|
free(val->ip_mask);
|
|
val->ip_mask = NULL;
|
|
free(val);
|
|
}
|
|
|
|
void free_ipconfig_type(struct ipconfig *ipc)
|
|
{
|
|
if (ipc == NULL) {
|
|
return;
|
|
}
|
|
free(ipc->gateway);
|
|
ipc->gateway = NULL;
|
|
free(ipc->version);
|
|
ipc->version = NULL;
|
|
free_ipnet_type(ipc->address);
|
|
ipc->address = NULL;
|
|
free(ipc->interface);
|
|
ipc->interface = NULL;
|
|
free(ipc);
|
|
}
|
|
|
|
void free_route_type(struct route *val)
|
|
{
|
|
if (val == NULL) {
|
|
return;
|
|
}
|
|
free(val->gw);
|
|
val->gw = NULL;
|
|
free_ipnet_type(val->dst);
|
|
val->dst = NULL;
|
|
free(val);
|
|
}
|
|
|
|
void free_interface_type(struct interface *val)
|
|
{
|
|
if (val == NULL) {
|
|
return;
|
|
}
|
|
free(val->mac);
|
|
val->mac = NULL;
|
|
free(val->name);
|
|
val->name = NULL;
|
|
free(val->sandbox);
|
|
val->sandbox = NULL;
|
|
free(val);
|
|
}
|
|
|
|
void free_dns_type(struct dns *val)
|
|
{
|
|
size_t i = 0;
|
|
if (val == NULL) {
|
|
return;
|
|
}
|
|
free(val->domain);
|
|
val->domain = NULL;
|
|
for (i = 0; i < val->name_servers_len; i++) {
|
|
free(val->name_servers[i]);
|
|
val->name_servers[i] = NULL;
|
|
}
|
|
free(val->name_servers);
|
|
val->name_servers = NULL;
|
|
for (i = 0; i < val->options_len; i++) {
|
|
free(val->options[i]);
|
|
val->options[i] = NULL;
|
|
}
|
|
free(val->options);
|
|
val->options = NULL;
|
|
for (i = 0; i < (val->search_len); i++) {
|
|
free(val->search[i]);
|
|
val->search[i] = NULL;
|
|
}
|
|
free(val->search);
|
|
val->search = NULL;
|
|
free(val);
|
|
}
|
|
|
|
void free_result(struct result *val)
|
|
{
|
|
size_t i = 0;
|
|
|
|
if (val == NULL) {
|
|
return;
|
|
}
|
|
|
|
free(val->cniversion);
|
|
val->cniversion = NULL;
|
|
for (i = 0; i < val->interfaces_len; i++) {
|
|
free_interface_type(val->interfaces[i]);
|
|
val->interfaces[i] = NULL;
|
|
}
|
|
free(val->interfaces);
|
|
val->interfaces = NULL;
|
|
for (i = 0; i < val->ips_len; i++) {
|
|
free_ipconfig_type(val->ips[i]);
|
|
val->ips[i] = NULL;
|
|
}
|
|
free(val->ips);
|
|
val->ips = NULL;
|
|
for (i = 0; i < val->routes_len; i++) {
|
|
free_route_type(val->routes[i]);
|
|
val->routes[i] = NULL;
|
|
}
|
|
free(val->routes);
|
|
val->routes = NULL;
|
|
free_dns_type(val->my_dns);
|
|
val->my_dns = NULL;
|
|
free(val);
|
|
}
|
|
|
|
static bool is_ipv4(const uint8_t *ip, size_t len)
|
|
{
|
|
size_t i = 0;
|
|
bool invalid_arg = (ip == NULL || len < 10);
|
|
|
|
if (invalid_arg) {
|
|
return false;
|
|
}
|
|
for (i = 0; i < 10; i++) {
|
|
if (ip[i] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int simple_mask_len(const uint8_t *mask, size_t len)
|
|
{
|
|
size_t i = 0;
|
|
int ret = 0;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
uint8_t work = mask[i];
|
|
if (work == 0xff) {
|
|
ret += 8;
|
|
continue;
|
|
}
|
|
|
|
while ((work & 0x80) != 0) {
|
|
ret++;
|
|
work <<= 1;
|
|
}
|
|
|
|
if (work != 0) {
|
|
return -1;
|
|
}
|
|
|
|
size_t j = i;
|
|
for (j++; j < len; j++) {
|
|
if (mask[j] != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static size_t to_ipv4(const uint8_t *src, size_t src_len, uint8_t **ipv4)
|
|
{
|
|
uint8_t *ip = NULL;
|
|
bool invalid_arg = (src == NULL || ipv4 == NULL);
|
|
|
|
if (invalid_arg) {
|
|
return 0;
|
|
}
|
|
if (src_len == IPV4LEN) {
|
|
ip = clibcni_util_smart_calloc_s(IPV4LEN, sizeof(uint8_t));
|
|
if (ip == NULL) {
|
|
return 0;
|
|
}
|
|
(void)memcpy(ip, src, IPV4LEN);
|
|
*ipv4 = ip;
|
|
return IPV4LEN;
|
|
}
|
|
|
|
if (src_len == IPV6LEN && is_ipv4(src, src_len) && src[10] == 0xff && src[11] == 0xff) {
|
|
ip = clibcni_util_smart_calloc_s(IPV4LEN, sizeof(uint8_t));
|
|
if (ip == NULL) {
|
|
return 0;
|
|
}
|
|
size_t i = 0;
|
|
for (i = 0; i < IPV4LEN; i++) {
|
|
ip[i] = src[i + 12];
|
|
}
|
|
*ipv4 = ip;
|
|
return IPV4LEN;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// IPV6 max address "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
|
|
#define IPV6_MAX_ADDR_LEN 40
|
|
const char g_HEX_DICT[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
|
|
|
/*
|
|
* return:
|
|
* 0 means continue to find ip
|
|
* 1 means get right ip
|
|
* -1 means something wrong
|
|
* */
|
|
static int do_parse_ip_to_string(const uint8_t *ip, size_t len, char **result)
|
|
{
|
|
char *tmp = NULL;
|
|
int ret = 0;
|
|
int nret = 0;
|
|
size_t res_len = 0;
|
|
|
|
tmp = clibcni_util_uint8_join("", "%x", ip, len);
|
|
if (tmp == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (strlen(tmp) > (SIZE_MAX - 2)) {
|
|
ret = -1;
|
|
goto free_out;
|
|
}
|
|
|
|
res_len = 1 + strlen(tmp) + 1;
|
|
*result = clibcni_util_common_calloc_s(res_len);
|
|
if (*result == NULL) {
|
|
ret = -1;
|
|
goto free_out;
|
|
}
|
|
nret = snprintf(*result, res_len, "%s%s", "?", tmp);
|
|
if (nret < 0 || (size_t)nret >= res_len) {
|
|
free(*result);
|
|
*result = NULL;
|
|
ret = -1;
|
|
} else {
|
|
ret = 1;
|
|
}
|
|
|
|
free_out:
|
|
free(tmp);
|
|
return ret;
|
|
}
|
|
|
|
static int get_ip_string(const uint8_t *ip, size_t len, char **result)
|
|
{
|
|
size_t work_ip_len = 0;
|
|
uint8_t *work_ip = NULL;
|
|
int ret = 0;
|
|
|
|
work_ip_len = to_ipv4(ip, len, &work_ip);
|
|
if (work_ip_len == IPV4LEN) {
|
|
*result = clibcni_util_uint8_join(".", "%u", work_ip, work_ip_len);
|
|
ret = 1; // get right result
|
|
goto free_out;
|
|
}
|
|
if (len != IPV6LEN) {
|
|
ret = do_parse_ip_to_string(ip, len, result);
|
|
}
|
|
|
|
free_out:
|
|
free(work_ip);
|
|
return ret;
|
|
}
|
|
|
|
static void generate_ip_string(const uint8_t *ip, int e0, int e1, char **result)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
*result = clibcni_util_common_calloc_s(IPV6_MAX_ADDR_LEN);
|
|
if (*result == NULL) {
|
|
return;
|
|
}
|
|
for (i = 0, j = 0; i < IPV6LEN; i += 2) {
|
|
if (i == e0) {
|
|
(*result)[j++] = ':';
|
|
(*result)[j++] = ':';
|
|
i = e1;
|
|
if (i >= IPV6LEN) {
|
|
break;
|
|
}
|
|
} else if (i > 0) {
|
|
(*result)[j++] = ':';
|
|
}
|
|
int nret = (ip[i] >> 4);
|
|
(*result)[j++] = g_HEX_DICT[nret];
|
|
nret = (ip[i] & 0x0f);
|
|
(*result)[j++] = g_HEX_DICT[nret];
|
|
}
|
|
return;
|
|
}
|
|
|
|
char *ip_to_string(const uint8_t *ip, size_t len)
|
|
{
|
|
char *result = NULL;
|
|
int i = 0;
|
|
int j = 0;
|
|
int e0 = 0;
|
|
int e1 = 0;
|
|
|
|
if (len == 0) {
|
|
return clibcni_util_strdup_s("<nil>");
|
|
}
|
|
|
|
if (get_ip_string(ip, len, &result) != 0) {
|
|
goto free_out;
|
|
}
|
|
|
|
/* find zeros */
|
|
e0 = e1 = -1;
|
|
for (i = 0; i < IPV6LEN; i += 2) {
|
|
j = i;
|
|
while (j < IPV6LEN && ip[j] == 0 && ip[j + 1] == 0) {
|
|
j += 2;
|
|
}
|
|
if (j > i && (j - i) > (e1 - e0)) {
|
|
e0 = i;
|
|
e1 = j;
|
|
i = j;
|
|
}
|
|
}
|
|
|
|
if (e1 - e0 <= 2) {
|
|
e1 = -1;
|
|
e0 = -1;
|
|
}
|
|
|
|
generate_ip_string(ip, e0, e1, &result);
|
|
|
|
free_out:
|
|
return result;
|
|
}
|
|
|
|
static char *mask_hex_string(const uint8_t *mask, size_t len)
|
|
{
|
|
char *result = NULL;
|
|
size_t res_len = 0;
|
|
size_t i = 0;
|
|
size_t j = 0;
|
|
|
|
if (len == 0) {
|
|
return clibcni_util_strdup_s("<nil>");
|
|
}
|
|
|
|
if (len > ((SIZE_MAX - 1) / 2)) {
|
|
return NULL;
|
|
}
|
|
res_len = (len * 2) + 1;
|
|
|
|
result = clibcni_util_common_calloc_s(res_len);
|
|
if (result == NULL) {
|
|
return NULL;
|
|
}
|
|
for (i = 0, j = 0; i < len; i++) {
|
|
int tmp = (mask[i] >> 4);
|
|
result[j++] = g_HEX_DICT[tmp];
|
|
tmp = (mask[i] & 0x0f);
|
|
result[j++] = g_HEX_DICT[tmp];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static size_t try_to_ipv4(const struct ipnet *value, uint8_t **pip, char **err)
|
|
{
|
|
size_t iplen = 0;
|
|
|
|
iplen = to_ipv4(value->ip, value->ip_len, pip);
|
|
if (iplen == 0) {
|
|
if (value->ip_len == IPV6LEN) {
|
|
*pip = clibcni_util_smart_calloc_s(IPV6LEN, sizeof(uint8_t));
|
|
if (*pip == NULL) {
|
|
ERROR("Out of memory");
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
return 0;
|
|
}
|
|
(void)memcpy(*pip, value->ip, IPV6LEN);
|
|
iplen = IPV6LEN;
|
|
} else {
|
|
if (asprintf(err, "Invalid ip, len=%lu", iplen) < 0) {
|
|
ERROR("Out of memory");
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return iplen;
|
|
}
|
|
|
|
static int get_ipv4_mask(const struct ipnet *value, size_t iplen, uint8_t **mask, char **err)
|
|
{
|
|
if (iplen != IPV4LEN) {
|
|
int nret = asprintf(err, "len of IP: %lu diffrent to len of mask: %lu", iplen, value->ip_mask_len);
|
|
if (nret < 0) {
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
ERROR("Out of memory");
|
|
}
|
|
return 0;
|
|
}
|
|
*mask = clibcni_util_smart_calloc_s(IPV4LEN, sizeof(uint8_t));
|
|
if (*mask == NULL) {
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
ERROR("Out of memory");
|
|
return -1;
|
|
}
|
|
(void)memcpy(*mask, value->ip_mask, IPV4LEN);
|
|
return IPV4LEN;
|
|
}
|
|
|
|
static int get_ipv6_mask(const struct ipnet *value, size_t iplen, uint8_t **mask, char **err)
|
|
{
|
|
if (iplen == IPV4LEN) {
|
|
*mask = clibcni_util_smart_calloc_s(IPV4LEN, sizeof(uint8_t));
|
|
if (*mask == NULL) {
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
ERROR("Out of memory");
|
|
return 0;
|
|
}
|
|
(void)memcpy(*mask, (value->ip_mask + IPV4_TO_V6_EMPTY_PREFIX_BYTES), IPV4LEN);
|
|
return IPV4LEN;
|
|
} else {
|
|
(void)memcpy(*mask, value->ip_mask, IPV6LEN);
|
|
return IPV6LEN;
|
|
}
|
|
}
|
|
|
|
static size_t try_get_mask(const struct ipnet *value, size_t iplen, uint8_t **mask, char **err)
|
|
{
|
|
size_t masklen = 0;
|
|
int nret = 0;
|
|
|
|
switch (value->ip_mask_len) {
|
|
case IPV4LEN:
|
|
nret = get_ipv4_mask(value, iplen, mask, err);
|
|
if (nret == 0) {
|
|
return 0;
|
|
} else if (nret < 0) {
|
|
goto free_out;
|
|
}
|
|
masklen = (size_t)nret;
|
|
break;
|
|
case IPV6LEN:
|
|
nret = get_ipv6_mask(value, iplen, mask, err);
|
|
if (nret == 0) {
|
|
return 0;
|
|
} else if (nret < 0) {
|
|
goto free_out;
|
|
}
|
|
masklen = (size_t)nret;
|
|
break;
|
|
default:
|
|
nret = asprintf(err, "Invalid mask len: %lu", value->ip_mask_len);
|
|
if (nret < 0) {
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
ERROR("Out of memory");
|
|
}
|
|
goto free_out;
|
|
}
|
|
return masklen;
|
|
free_out:
|
|
free(*mask);
|
|
*mask = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static char *do_generate_ip_with_mask(const uint8_t *mask, size_t masklen, const char *ip, char **err)
|
|
{
|
|
char *tmp_mask = NULL;
|
|
char *result = NULL;
|
|
int nret = 0;
|
|
size_t res_len = 0;
|
|
|
|
if (ip == NULL) {
|
|
return NULL;
|
|
}
|
|
tmp_mask = mask_hex_string(mask, masklen);
|
|
if (tmp_mask == NULL) {
|
|
*err = clibcni_util_strdup_s("Mask toString failed");
|
|
ERROR("Mask toString failed");
|
|
goto free_out;
|
|
}
|
|
|
|
if (strlen(ip) > ((SIZE_MAX - 2) - strlen(tmp_mask))) {
|
|
*err = clibcni_util_strdup_s("Too long ips");
|
|
ERROR("Too long ips");
|
|
goto free_out;
|
|
}
|
|
|
|
res_len = strlen(ip) + 1 + strlen(tmp_mask) + 1;
|
|
result = clibcni_util_common_calloc_s(res_len);
|
|
if (result == NULL) {
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
ERROR("Out of memory");
|
|
goto free_out;
|
|
}
|
|
nret = snprintf(result, res_len, "%s/%s", ip, tmp_mask);
|
|
if (nret < 0 || (size_t)nret >= res_len) {
|
|
*err = clibcni_util_strdup_s("Sprintf first type failed");
|
|
ERROR("Sprintf failed");
|
|
free(result);
|
|
result = NULL;
|
|
}
|
|
free_out:
|
|
free(tmp_mask);
|
|
return result;
|
|
}
|
|
|
|
char *ipnet_to_string(const struct ipnet *value, char **err)
|
|
{
|
|
char *result = NULL;
|
|
char *tmp_ip = NULL;
|
|
uint8_t *ip = NULL;
|
|
uint8_t *mask = NULL;
|
|
size_t iplen = 0;
|
|
size_t masklen = 0;
|
|
int slen = 0;
|
|
int nret = 0;
|
|
size_t res_len = 0;
|
|
|
|
iplen = try_to_ipv4(value, &ip, err);
|
|
if (iplen == 0) {
|
|
goto free_out;
|
|
}
|
|
|
|
masklen = try_get_mask(value, iplen, &mask, err);
|
|
if (masklen == 0) {
|
|
goto free_out;
|
|
}
|
|
|
|
slen = simple_mask_len(mask, masklen);
|
|
tmp_ip = ip_to_string(ip, iplen);
|
|
if (tmp_ip == NULL) {
|
|
*err = clibcni_util_strdup_s("IP toString failed");
|
|
ERROR("IP toString failed");
|
|
goto free_out;
|
|
}
|
|
if (slen == -1) {
|
|
result = do_generate_ip_with_mask(mask, masklen, tmp_ip, err);
|
|
goto free_out;
|
|
}
|
|
|
|
if (strlen(tmp_ip) > (SIZE_MAX - 5)) {
|
|
*err = clibcni_util_strdup_s("Too long ips");
|
|
goto free_out;
|
|
}
|
|
|
|
res_len = strlen(tmp_ip) + 1 + 3 + 1;
|
|
result = clibcni_util_common_calloc_s(res_len);
|
|
if (result == NULL) {
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
ERROR("Out of memory");
|
|
goto free_out;
|
|
}
|
|
nret = snprintf(result, res_len, "%s/%d", tmp_ip, slen);
|
|
if (nret < 0 || (size_t)nret >= res_len) {
|
|
ERROR("Sprintf failed");
|
|
*err = clibcni_util_strdup_s("Sprintf second type failed");
|
|
free(result);
|
|
result = NULL;
|
|
}
|
|
|
|
free_out:
|
|
free(tmp_ip);
|
|
free(mask);
|
|
free(ip);
|
|
return result;
|
|
}
|
|
|
|
static int get_ip_from_in6_addr(const struct in6_addr *ipv6, uint8_t **ip, size_t *len)
|
|
{
|
|
uint8_t *result = NULL;
|
|
|
|
if (ipv6 == NULL) {
|
|
return 0;
|
|
}
|
|
result = clibcni_util_smart_calloc_s(IPV6LEN, sizeof(uint8_t));
|
|
if (result == NULL) {
|
|
ERROR("Out of memory");
|
|
return -1;
|
|
}
|
|
(void)memcpy(result, ipv6->s6_addr, IPV6LEN * sizeof(uint8_t));
|
|
|
|
*ip = result;
|
|
*len = IPV6LEN;
|
|
return 0;
|
|
}
|
|
|
|
static int get_ip_from_in_addr(const struct in_addr *ipv4, uint8_t **ip, size_t *len)
|
|
{
|
|
uint8_t *result = NULL;
|
|
size_t i = 0;
|
|
uint32_t work = 0;
|
|
|
|
if (ipv4 == NULL) {
|
|
return 0;
|
|
}
|
|
result = clibcni_util_smart_calloc_s(IPV4LEN, sizeof(uint8_t));
|
|
if (result == NULL) {
|
|
ERROR("Out of memory");
|
|
return -1;
|
|
}
|
|
work = ipv4->s_addr;
|
|
for (i = 0; i < IPV4LEN; i++) {
|
|
result[i] = (uint8_t)(work & 0x0ff);
|
|
work >>= 8;
|
|
}
|
|
|
|
*ip = result;
|
|
*len = IPV4LEN;
|
|
return 0;
|
|
}
|
|
|
|
static int do_parse_ipv6_from_str(const char *addr, struct in6_addr *ipv6, uint8_t **ips, size_t *len, int *ret,
|
|
char **err)
|
|
{
|
|
int nret = 0;
|
|
|
|
if (addr == NULL) {
|
|
ERROR("Empty address");
|
|
return -1;
|
|
}
|
|
nret = inet_pton(AF_INET6, addr, ipv6);
|
|
if (nret < 0) {
|
|
nret = asprintf(err, "ipv6 inet_pton %s", strerror(errno));
|
|
if (nret < 0) {
|
|
ERROR("Sprintf failed");
|
|
*ret = 1;
|
|
}
|
|
return -1;
|
|
} else if (nret == 0) {
|
|
nret = asprintf(err, "Invalid ip address: %s", addr);
|
|
if (nret < 0) {
|
|
ERROR("Sprintf failed");
|
|
*ret = 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
*ret = get_ip_from_in6_addr(ipv6, ips, len);
|
|
|
|
return *ret;
|
|
}
|
|
|
|
int parse_ip_from_str(const char *addr, uint8_t **ips, size_t *len, char **err)
|
|
{
|
|
int nret = 0;
|
|
struct in_addr ipv4;
|
|
struct in6_addr ipv6;
|
|
int ret = -1;
|
|
|
|
if (addr == NULL) {
|
|
ERROR("Empty address");
|
|
return -1;
|
|
}
|
|
nret = inet_pton(AF_INET, addr, &ipv4);
|
|
if (nret < 0) {
|
|
nret = asprintf(err, "ipv4 inet_pton %s", strerror(errno));
|
|
if (nret < 0) {
|
|
ERROR("Sprintf failed");
|
|
ret = 1;
|
|
}
|
|
goto free_out;
|
|
} else if (nret == 0) {
|
|
/* check ipv6 */
|
|
nret = do_parse_ipv6_from_str(addr, &ipv6, ips, len, &ret, err);
|
|
if (nret != 0) {
|
|
goto free_out;
|
|
}
|
|
} else {
|
|
nret = get_ip_from_in_addr(&ipv4, ips, len);
|
|
if (nret != 0) {
|
|
goto free_out;
|
|
}
|
|
}
|
|
ret = 0;
|
|
free_out:
|
|
return ret;
|
|
}
|
|
|
|
static int do_parse_mask_in_cidr(unsigned int mask_num, struct ipnet *result, char **err)
|
|
{
|
|
uint8_t full_mask = 0xff;
|
|
size_t j = 0;
|
|
size_t i = 0;
|
|
unsigned int mask_cnt = mask_num;
|
|
|
|
j = result->ip_len;
|
|
|
|
result->ip_mask = clibcni_util_smart_calloc_s(j, sizeof(uint8_t));
|
|
if (result->ip_mask == NULL) {
|
|
*err = clibcni_util_strdup_s("Out of memory");
|
|
ERROR("Out of memory");
|
|
return -1;
|
|
}
|
|
result->ip_mask_len = j;
|
|
for (i = 0; i < j; i++) {
|
|
if (mask_cnt >= 8) {
|
|
result->ip_mask[i] = full_mask;
|
|
mask_cnt -= 8;
|
|
continue;
|
|
}
|
|
result->ip_mask[i] = ~(full_mask >> mask_cnt);
|
|
mask_cnt = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int parse_cidr(const char *cidr_str, struct ipnet **ipnet_val, char **err)
|
|
{
|
|
char *pos = NULL;
|
|
char *addr = NULL;
|
|
char *mask = NULL;
|
|
char *work_cidr = NULL;
|
|
int nret = 0;
|
|
unsigned int mask_num = 0;
|
|
int ret = -1;
|
|
struct ipnet *result = NULL;
|
|
|
|
if (cidr_str == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
work_cidr = clibcni_util_strdup_s(cidr_str);
|
|
|
|
result = clibcni_util_common_calloc_s(sizeof(struct ipnet));
|
|
if (result == NULL) {
|
|
ERROR("Out of memory");
|
|
goto free_out;
|
|
}
|
|
pos = strchr(work_cidr, '/');
|
|
if (pos == NULL) {
|
|
nret = asprintf(err, "CIDR address %s", work_cidr);
|
|
if (nret < 0) {
|
|
ERROR("Sprintf failed");
|
|
ret = 1;
|
|
}
|
|
goto free_out;
|
|
}
|
|
*pos = '\0';
|
|
addr = work_cidr;
|
|
mask = pos + 1;
|
|
|
|
nret = parse_ip_from_str(addr, &(result->ip), &(result->ip_len), err);
|
|
if (nret != 0) {
|
|
ret = -1;
|
|
goto free_out;
|
|
}
|
|
|
|
nret = clibcni_util_safe_uint(mask, &mask_num);
|
|
if (nret != 0 || (size_t)(mask_num >> 3) > result->ip_len) {
|
|
nret = asprintf(err, "Invalid CIDR address %s", cidr_str);
|
|
if (nret < 0) {
|
|
ERROR("Sprintf failed");
|
|
*err = clibcni_util_strdup_s("Asprintf cidr failed");
|
|
ret = 1;
|
|
}
|
|
goto free_out;
|
|
}
|
|
|
|
/* parse mask */
|
|
if (do_parse_mask_in_cidr(mask_num, result, err) != 0) {
|
|
ret = -1;
|
|
goto free_out;
|
|
}
|
|
*ipnet_val = result;
|
|
result = NULL;
|
|
ret = 0;
|
|
|
|
free_out:
|
|
free(work_cidr);
|
|
if (result != NULL) {
|
|
free(result->ip);
|
|
free(result->ip_mask);
|
|
free(result);
|
|
}
|
|
return ret;
|
|
}
|
|
|