/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipike_util.c,v $ $Revision: 1.82.10.12 $ * $Source: /home/interpeak/CVSRoot/ipike/src/ipike_util.c,v $ * $Author: jren $ $Date: 2023-10-20 05:56:11 $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* Helper functions not directly releated to IKE */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipike_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #include "ipike_h.h" #include "ipike_util.h" #include "ipike_attributes.h" #include "ipike_configuration.h" #include "ipike_configuration_parse.h" #include #include #include /* **************************************************************************** * 4 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 5 DEFINES **************************************************************************** */ /* **************************************************************************** * 6 TYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* *=========================================================================== * ipike_inet_pton *=========================================================================== */ IP_STATIC int ipike_inet_pton(int family, IP_CONST char *strptr, void *addrptr); /* *=========================================================================== * ipike_get_first_if_name *=========================================================================== * Description: Get first available interface name. * Parameters: name - buffer that will receive the null terminated interface * name. * size - size of name buffer. * Returns: IP_TRUE if success (else IP_FALSE) */ IP_STATIC Ip_bool ipike_get_first_if_name(char *name, Ip_u32 size); /* *=========================================================================== * ipike_add_delete_ipv4_address *=========================================================================== * Description: Add/Delete IPv4 address from interface. * Parameters: add - Set to IP_TRUE for add address (IP_FALSE for delete) * ifname - Interface name, set to IP_NULL to get first available * interface. * addr - The ip address to set * netmask - The ip netmask to set * Returns: IPIKE_SUCCESS, IPIKE_FAILED */ #ifdef IPCOM_USE_INET IP_STATIC Ipike_error ipike_add_delete_ipv4_address( Ip_bool add, const char *ifname, struct Ip_sockaddr_in *addr, struct Ip_sockaddr_in *netmask); #endif /* IPCOM_USE_INET */ /* *=========================================================================== * ipike_add_delete_ipv6_address *=========================================================================== * Description: Add/Delete IPv6 address from interface. * Parameters: add - Set to IP_TRUE for add address (IP_FALSE for delete) * ifname - Interface name, set to IP_NULL to get first available * interface. * addr - The ip address to set * netmask - The ip netmask to set * Returns: IPIKE_SUCCESS, IPIKE_FAILED */ #ifdef IPCOM_USE_INET6 IP_STATIC Ipike_error ipike_add_delete_ipv6_address( Ip_bool add, const char *ifname, struct Ip_sockaddr_in6 *addr, struct Ip_sockaddr_in6 *netmask); #endif /* IPCOM_USE_INET6 */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipike_inet_pton *=========================================================================== */ IP_STATIC int ipike_inet_pton(int family, IP_CONST char *strptr, void *addrptr) { char strbuf[128]; ipcom_strncpy(strbuf, strptr,127); #ifdef IPCOM_USE_INET /* Remove trailing ':' in address */ if (family == IP_AF_INET) { char *delim; delim = ipcom_strrchr(strbuf, ':'); if (delim != IP_NULL) *delim = '\0'; } #endif /* IPCOM_USE_INET */ return ipcom_inet_pton(family, strbuf, addrptr); } /* *=========================================================================== * ipike_get_first_if_name *=========================================================================== */ IP_STATIC Ip_bool ipike_get_first_if_name(char *name, Ip_u32 size) { struct Ip_if_nameindex *ni; int i; name[0] = 0; if ((ni = ipcom_if_nameindex()) == IP_NULL) { IPCOM_LOG0(ERR, "ipike_get_first_if_name: failed to get interface list"); } else { for (i = 0; (ni[i].if_name != IP_NULL) && (name[0] == 0); i++) { if ((ipcom_strcmp(ni[i].if_name, "lo0") == 0) || (ipcom_strcmp(ni[i].if_name, "lo") == 0)) continue; if (size <= (Ip_u32)ipcom_strlen(ni[i].if_name)) continue; ipcom_strcpy(name, ni[i].if_name); } ipcom_if_freenameindex(ni); } return (name[0] != 0); } #ifdef IPCOM_USE_INET /* *=========================================================================== * ipike_add_delete_ipv4_address *=========================================================================== */ IP_STATIC Ipike_error ipike_add_delete_ipv4_address( Ip_bool add, const char *ifname, struct Ip_sockaddr_in *addr, struct Ip_sockaddr_in *netmask) { Ipike_error err = IPIKE_SUCCESS; Ip_fd fd = IP_INVALID_SOCKET; struct Ip_ifaliasreq ifal; struct Ip_sockaddr_in *in; unsigned long request; ipcom_memset(&ifal, 0, sizeof(ifal)); if (ifname == IP_NULL) { if (!ipike_get_first_if_name(ifal.ifra_name, sizeof(ifal.ifra_name))) ifal.ifra_name[0] = 0; } else { if (ipcom_strlen(ifname) < sizeof(ifal.ifra_name)) ipcom_strcpy(ifal.ifra_name, ifname); } if ((addr == IP_NULL) || (ifal.ifra_name[0] == 0)) { IPCOM_LOG0(DEBUG, "ipike_add_ipv4_address: bad arguments"); err = IPIKE_FAILED; } else { fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, 0); if (fd == IP_INVALID_SOCKET) { IPCOM_LOG0(DEBUG, "ipike_add_ipv4_address: failed to open socket"); err = IPIKE_FAILED; } else { in = (struct Ip_sockaddr_in *) &ifal.ifra_addr; in->sin_addr = addr->sin_addr; in->sin_family = addr->sin_family; IPCOM_SA_LEN_SET(in, IPCOM_SA_LEN_GET(addr)); in = (struct Ip_sockaddr_in *) &ifal.ifra_mask; if ((netmask != IP_NULL) && (netmask->sin_family == IP_AF_INET)) in->sin_addr = netmask->sin_addr; else ipcom_memset(&in->sin_addr, 0xff, sizeof(in->sin_addr)); request = ipike.dynamic_ip_homeaddr ? IP_SIOCAHOMEADDR : IP_SIOCAIFADDR; if (ipcom_socketioctl(fd, add ? request : IP_SIOCDIFADDR, &ifal) < 0) { IPCOM_LOG3(DEBUG, "ipike_add_ipv4_address: set address failed (%d)", ifal.ifra_name, ipike_addr_to_str((union Ip_sockaddr_union *)addr), ipcom_errno); err = IPIKE_FAILED; } } } if (fd != IP_INVALID_SOCKET) (void)ipcom_socketclose(fd); return err; } #endif /* IPCOM_USE_INET */ /* *=========================================================================== * ipike_add_delete_ipv6_address *=========================================================================== */ #ifdef IPCOM_USE_INET6 IP_STATIC Ipike_error ipike_add_delete_ipv6_address( Ip_bool add, const char *ifname, struct Ip_sockaddr_in6 *addr, struct Ip_sockaddr_in6 *netmask) { Ipike_error err = IPIKE_SUCCESS; Ip_fd fd = IP_INVALID_SOCKET; struct Ip_in6_aliasreq ifareq; ipcom_memset(&ifareq, 0, sizeof(ifareq)); if (ifname == IP_NULL) { if (!ipike_get_first_if_name(ifareq.ifra_name, sizeof(ifareq.ifra_name))) ifareq.ifra_name[0] = 0; } else { if (ipcom_strlen(ifname) < sizeof(ifareq.ifra_name)) ipcom_strcpy(ifareq.ifra_name, ifname); } if ((addr == IP_NULL) || (ifareq.ifra_name[0] == 0)) { IPCOM_LOG0(DEBUG, "ipike_add_ipv6_address: bad arguments"); err = IPIKE_FAILED; } else { fd = ipcom_socket(IP_AF_INET6, IP_SOCK_DGRAM, 0); if (fd == IP_INVALID_SOCKET) { IPCOM_LOG0(DEBUG, "ipike_add_ipv6_address: failed to open socket"); err = IPIKE_FAILED; } else { ifareq.ifra_addr.sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&ifareq.ifra_addr, sizeof(struct Ip_sockaddr_in6)); ifareq.ifra_addr.sin6_addr = addr->sin6_addr; ifareq.ifra_addr.sin6_scope_id = 0; if (add) { ifareq.ifra_prefixmask.sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&ifareq.ifra_prefixmask, sizeof(struct Ip_sockaddr_in6)); if ((netmask != IP_NULL) && (netmask->sin6_family == IP_AF_INET6)) ifareq.ifra_prefixmask.sin6_addr = netmask->sin6_addr; else ipcom_memset(&ifareq.ifra_prefixmask.sin6_addr, 0xff, sizeof(ifareq.ifra_prefixmask.sin6_addr)); ifareq.ifra_lifetime.ia6t_preferred = (Ip_time_t)IPCOM_ADDR_INFINITE; ifareq.ifra_lifetime.ia6t_expire = (Ip_time_t)IPCOM_ADDR_INFINITE; if (ipike.dynamic_ip_homeaddr) ifareq.ifra_flags |= IP_IN6_IFF_HOMEADDRESS; if (ipcom_socketioctl(fd, IP_SIOCAIFADDR_IN6, &ifareq) < 0) { IPCOM_LOG0(DEBUG, "ipike_add_ipv6_address: failed to add address"); err = IPIKE_FAILED; } } else { if (ipcom_socketioctl(fd, IP_SIOCDIFADDR_IN6, &ifareq) < 0) { IPCOM_LOG0(DEBUG, "ipike_add_ipv6_address: failed to delete address"); err = IPIKE_FAILED; } } } if (fd != IP_INVALID_SOCKET) (void)ipcom_socketclose(fd); } return err; } #endif /* IPCOM_USE_INET6 */ /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipike_are_values_equal *=========================================================================== */ IP_GLOBAL Ip_bool ipike_are_values_equal(const Ipike_value *val1, const Ipike_value *val2) { if (IP_NULL == val1 || IP_NULL == val2) return IP_FALSE; if (val1->len != val2->len) return IP_FALSE; return 0 == ipcom_memcmp(val1->value, val2->value, val1->len); } /* *=========================================================================== * ipike_are_cookies_equal *=========================================================================== */ IP_GLOBAL Ip_bool ipike_are_cookies_equal(const Ip_u8 cookie1[], const Ip_u8 cookie2[]) { if (ipike_is_zero_cookie(cookie1) || ipike_is_zero_cookie(cookie2)) return IP_TRUE; return 0 == ipcom_memcmp(cookie1, cookie2, IPIKE_ISAKMP_COOKIE_SIZE); } /* *=========================================================================== * ipike_set_value *=========================================================================== */ IP_GLOBAL Ipike_error ipike_set_value(Ipike_value *destination, const Ipike_value *source) { destination->value = IP_NULL; destination->len = 0; return ipike_set_data(destination, source->value, source->len); } /* *=========================================================================== * ipike_cpy_value *=========================================================================== */ IP_GLOBAL Ipike_error ipike_cpy_value(Ipike_value *destination, const Ipike_value *source) { IPIKE_FREEP(destination->value); return ipike_set_value(destination, source); } /* *=========================================================================== * ipike_swap_value *=========================================================================== */ IP_GLOBAL void ipike_swap_value(Ipike_value *v1, Ipike_value *v2) { Ipike_value tmp; tmp.len = v1->len; tmp.value = v1->value; v1->len = v2->len; v1->value = v2->value; v2->len = tmp.len; v2->value = tmp.value; } /* *=========================================================================== * ipike_set_data *=========================================================================== */ #ifdef IPCOM_USE_DMALLOC IP_GLOBAL Ipike_error ipike_set_data_debug(Ipike_value *destination, const void *data, Ip_size_t len, const char *file, const char *function, Ip_u32 line) #else IP_GLOBAL Ipike_error ipike_set_data(Ipike_value *destination, const void* data, Ip_size_t len) #endif { destination->value = IP_NULL; destination->len = 0; if (data == IP_NULL || len == 0) return IPIKE_SUCCESS; #ifdef IPCOM_USE_DMALLOC destination->value = ipcom_dmalloc(len, file, function, line); #else destination->value = ipcom_malloc(len); #endif if (destination->value == IP_NULL) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } ipcom_memcpy(destination->value, data, len); destination->len = len; return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_cpy_data *=========================================================================== */ #ifdef IPCOM_USE_DMALLOC IP_GLOBAL Ipike_error ipike_cpy_data_debug(Ipike_value *destination, const void *data, Ip_size_t len, const char *file, const char *function, Ip_u32 line) #else IP_GLOBAL Ipike_error ipike_cpy_data(Ipike_value *destination, const void *data, Ip_size_t len) #endif { IPIKE_FREEP(destination->value); #ifdef IPCOM_USE_DMALLOC return ipike_set_data_debug(destination, data, len, file, function, line); #else return ipike_set_data(destination, data, len); #endif } /* *=========================================================================== * ipike_appende_value *=========================================================================== */ IP_GLOBAL Ipike_error ipike_append_value(Ipike_value* destination, const Ipike_value* source) { return ipike_append_data(destination, source->value, source->len); } /* *=========================================================================== * ipike_append_data *=========================================================================== */ IP_GLOBAL Ipike_error ipike_append_data(Ipike_value* destination, const void* src_data, Ip_size_t src_len) { if( (src_data == IP_NULL) || (src_len == 0)) return IPIKE_SUCCESS; destination->value = ipcom_realloc(destination->value, destination->len + src_len); if (IP_NULL == destination->value) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } ipcom_memcpy(destination->value+destination->len, src_data, src_len); destination->len += src_len; return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_is_zero_cookie *=========================================================================== */ IP_GLOBAL Ip_bool ipike_is_zero_cookie(const Ip_u8 cookie[]) { int i; for (i = 0; i < IPIKE_ISAKMP_COOKIE_SIZE; i++) if (0 != cookie[i]) return IP_FALSE; return IP_TRUE; } /* *=========================================================================== * ipike_cookie_to_string *=========================================================================== */ IP_GLOBAL const char * ipike_cookie_to_string(const Ip_u8 cookie[]) { static char buf[20] = { '0', 'x' }; int i, j; int nibble; for (i = 0; i < IPIKE_ISAKMP_COOKIE_SIZE; i++) for (j = 1; j >= 0; j--) { nibble = (cookie[i] >> (j * 4)) & 0x0F; buf[2 + i * 2 + (1 - j)] = (char) (nibble + (char) (nibble < 10 ? '0' : (char) ('a' - 10))); } buf[2 + 2 * i] = '\0'; return buf; } /* *=========================================================================== * ipike_memory_to_string *=========================================================================== */ IP_GLOBAL char * ipike_memory_to_string(const Ip_u8 *ptr, Ip_size_t size, Ip_u8 alignment) { const Ip_u32 MAX_SIZE = 256; static const char hex_char[] = "0123456789abcdef"; static const unsigned int byte_per_row = 32; char* buf; Ip_size_t row_size; Ip_size_t i, j, k = 0; Ip_size_t ws_per_row; Ip_size_t full_rows, blr; Ip_bool is_cut = IP_FALSE; if (size > MAX_SIZE) { size = MAX_SIZE; is_cut = IP_TRUE; } ws_per_row = byte_per_row / alignment; row_size = 2 * byte_per_row + ws_per_row; full_rows = size / byte_per_row; blr = size % byte_per_row; buf = ipcom_malloc(full_rows * row_size + 2 * blr + blr / alignment + 1 + 3); if (IP_NULL == buf) return IP_NULL; for (i = 0; i <= full_rows; i++) { k = 0; for (j = 0; j < (i == full_rows ? blr : byte_per_row); j++) { if (j != 0 && j % alignment == 0) buf[i * row_size + 2 * j + k++] = ' '; buf[i * row_size + 2 * j + k] = hex_char[ptr[i * byte_per_row + j] >> 4]; buf[i * row_size + 2 * j + k + 1] = hex_char[ptr[i * byte_per_row + j] & 0x0F]; } buf[i * row_size + 2 * j + k] = '\n'; } buf[full_rows * row_size + 2 * blr + k] = '\0'; if (is_cut) ipcom_strcat(buf, "..."); return buf; } /* *=========================================================================== * ipike_print_memory *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ipike_error ipike_print_memory(Ip_u32 priority, const char *prefix, const Ip_u8 *data, Ip_size_t len) { char *hex_mem; if (data == IP_NULL) { IPCOM_LOG1(ERR, "%sNULL-data error", prefix); return IPIKE_SUCCESS; } hex_mem = ipike_memory_to_string(data, len, 4); if (hex_mem == IP_NULL) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } /* Make sure fit into syslog buffer */ if ((ipcom_strlen(hex_mem) + ipcom_strlen(prefix)) >= IPCOM_SYSLOG_MAX_SIZE) { len = IPCOM_SYSLOG_MAX_SIZE - ipcom_strlen(prefix); hex_mem[len-4] = '.'; hex_mem[len-3] = '.'; hex_mem[len-2] = '.'; hex_mem[len-1] = 0; } switch (priority) { case IPCOM_LOG_EMERG: IPCOM_LOG2(EMERG, "%s%s", prefix, hex_mem); break; case IPCOM_LOG_CRIT: IPCOM_LOG2(CRIT, "%s%s", prefix, hex_mem); break; case IPCOM_LOG_ERR: IPCOM_LOG2(ERR, "%s%s", prefix, hex_mem); break; case IPCOM_LOG_WARNING: IPCOM_LOG2(WARNING, "%s%s", prefix, hex_mem); break; case IPCOM_LOG_NOTICE: IPCOM_LOG2(NOTICE, "%s%s", prefix, hex_mem); break; case IPCOM_LOG_INFO: IPCOM_LOG2(INFO, "%s%s", prefix, hex_mem); break; case IPCOM_LOG_DEBUG: IPCOM_LOG2(DEBUG, "%s%s", prefix, hex_mem); break; case IPCOM_LOG_DEBUG2: IPCOM_LOG2(DEBUG2, "%s%s", prefix, hex_mem); break; default: break; } ipcom_free(hex_mem); return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_array_add *=========================================================================== */ IP_GLOBAL Ipike_error ipike_array_add(void ***array, void *elem) { void **new_array; Ip_u32 length; if (elem == IP_NULL) { IPCOM_LOG0(ERR, "ipike_array_add: elem is NULL"); return IPIKE_TRIED_TO_ADD_NULL; } if (IP_NULL == *array && IP_NULL == (*array = ipcom_calloc(1, sizeof(void*)))) goto out_of_memory; length = ipike_array_size(*array); if (IP_NULL == (new_array = ipcom_realloc(*array, (2 + length) * sizeof(void*)))) goto out_of_memory; new_array[length] = elem; new_array[length + 1] = IP_NULL; *array = new_array; return IPIKE_SUCCESS; out_of_memory: IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } /* *=========================================================================== * ipike_array_remove *=========================================================================== */ IP_GLOBAL void ipike_array_remove(void ***array, void *elem, void(*free_func)(void*)) { Ip_u32 i = 0; #ifdef IPCOM_USE_DMALLOC if (free_func == ipcom_free) /*lint !e123 */ free_func = ipcom_dfree; #endif while ((*array)[i] != IP_NULL) { if (elem == (*array)[i]) { while ((*array)[i+1] != IP_NULL) { (*array)[i] = (*array)[i+1]; i++; } (*array)[i] = IP_NULL; if (free_func) free_func(elem); break; } i++; } } /* *=========================================================================== * ipike_array_size *=========================================================================== */ IP_GLOBAL Ip_u32 ipike_array_size(void **array) { Ip_u32 length = 0; if (IP_NULL != array) while (array[length] != IP_NULL) length++; return length; } /* *=========================================================================== * ipike_array_free *=========================================================================== */ IP_GLOBAL void ipike_array_free(void **array, void(*free_func)(void*)) { int i = 0; #ifdef IPCOM_USE_DMALLOC if (free_func == ipcom_free) /*lint !e123 */ free_func = ipcom_dfree; #endif if (IP_NULL == array) return; while (array[i] != IP_NULL) { void* ptr = array[i]; /* Fill the array with illegal addresses to catch usage of the array after it has been freed. Can not use IP_NULL since that is the end of array marker */ array[i++] = (void*) -1; if (free_func) free_func(ptr); } ipcom_free(array); } /* *=========================================================================== * ipike_array_free_elements *=========================================================================== */ IP_GLOBAL void ipike_array_free_elements(void ***array, void(*free_func)(void*)) { Ip_u32 i = 0; void *ptr; #ifdef IPCOM_USE_DMALLOC if (free_func == ipcom_free) /*lint !e123 */ free_func = ipcom_dfree; #endif if (IP_NULL == array) return; while (*array && (*array)[i] != IP_NULL) { ptr = (*array)[i]; (*array)[i++] = IP_NULL; if (free_func) free_func(ptr); } } /* *=========================================================================== * ipike_array_add_u8 *=========================================================================== */ IP_GLOBAL Ipike_error ipike_array_add_u8(Ip_u8 n, Ip_u8*** array) { Ip_u8* p; p = ipcom_malloc(sizeof(n)); if (IP_NULL == p) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } *p = n; if (IPIKE_SUCCESS != ipike_array_add((void***)array, p)) { IP_PANIC(); ipcom_free(p); return IPIKE_OUT_OF_MEMORY; } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_array_add_u32 *=========================================================================== */ IP_GLOBAL Ipike_error ipike_array_add_u32(Ip_u32 n, Ip_u32*** array) { Ip_u32* p; p = ipcom_malloc(sizeof(n)); if (IP_NULL == p) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } *p = n; if (IPIKE_SUCCESS != ipike_array_add((void***)array, p)) { IP_PANIC(); ipcom_free(p); return IPIKE_OUT_OF_MEMORY; } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_array_add_u64 *=========================================================================== */ IP_GLOBAL Ipike_error ipike_array_add_u64(Ip_u64 n, Ip_u64*** array) { Ip_u64* p; p = ipcom_malloc(sizeof(n)); if (IP_NULL == p) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } *p = n; if (IPIKE_SUCCESS != ipike_array_add((void***)array, p)) { IP_PANIC(); ipcom_free(p); return IPIKE_OUT_OF_MEMORY; } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_array_copy_u32 *=========================================================================== */ IP_GLOBAL Ipike_error ipike_array_copy_u32(Ip_u32*** array_dst, Ip_u32** array_src) { Ipike_error err; int i; if (IP_NULL != array_src) { for (i=0; array_src[i] != IP_NULL; i++) { if (IPIKE_SUCCESS != (err = ipike_array_add_u32( *array_src[i], array_dst))) { return err; } } } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_array_copy_u64 *=========================================================================== */ IP_GLOBAL Ipike_error ipike_array_copy_u64(Ip_u64*** array_dst, Ip_u64** array_src) { Ipike_error err; int i; if (IP_NULL != array_src) { for (i=0; array_src[i] != IP_NULL; i++) { if (IPIKE_SUCCESS != (err = ipike_array_add_u64( *array_src[i], array_dst))) { return err; } } } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_map_int *=========================================================================== */ IP_GLOBAL Ipike_error ipike_map_int(const Ipike_string_int_map map[], const char *key, int *value) { Ipike_error err; const Ipike_string_int_map *map_iter; char *tmp; if ((key == IP_NULL) || (map == IP_NULL)) return IPIKE_INVALID_VALUE; /* key may be a list of entries separated with ',' */ if (IPIKE_SUCCESS != (err = ipike_parse_get_first_string(key, ',', &tmp))) return err; for (map_iter = map; map_iter->key != IP_NULL; map_iter++) { if (0 == ipcom_strcasecmp(tmp, map_iter->key)) { ipcom_free(tmp); *value = map_iter->value; return IPIKE_SUCCESS; } } ipcom_free(tmp); return IPIKE_VALUE_NOT_FOUND; } /* *=========================================================================== * ipike_map_string *=========================================================================== */ IP_GLOBAL Ipike_error ipike_map_string(const Ipike_string_int_map map[], int key, const char **value) { const Ipike_string_int_map* map_iter; if (map == IP_NULL) return IPIKE_INVALID_VALUE; for (map_iter = map; map_iter->key != IP_NULL; map_iter++) { if (map_iter->value == key) { *value = map_iter->key; return IPIKE_SUCCESS; } } return IPIKE_VALUE_NOT_FOUND; } /* *=========================================================================== * ipike_strvec *=========================================================================== */ IP_GLOBAL char ** ipike_strvec(const char* s, const char* delimiter) { char **ret = IP_NULL; char *token; char *str; char *last; Ip_bool success = IP_FALSE; if (s == IP_NULL) return IP_NULL; str = ipcom_strdup(s); if (str == IP_NULL) return IP_FALSE; for (token = ipcom_strtok_r(str, delimiter, &last); token != IP_NULL; token = ipcom_strtok_r(IP_NULL, delimiter, &last)) { char* arr_add = ipcom_strdup(token); if (IP_NULL == arr_add) goto cleanup; if (ipike_array_add((void***) &ret, arr_add)) goto cleanup; } success = IP_TRUE; cleanup: if (!success) { ipike_array_free((void**) ret, ipcom_free); /*lint !e123 */ ret = IP_NULL; } ipcom_free(str); return ret; } /* *=========================================================================== * ipike_addr_to_str *=========================================================================== */ IP_GLOBAL const char * ipike_addr_to_str(const union Ip_sockaddr_union* addr) { return ipike_addr_to_str_buf(addr, ipike.addr_buf, sizeof(ipike.addr_buf)); } /* *=========================================================================== * ipike_addr_to_str_buf *=========================================================================== */ IP_GLOBAL const char * ipike_addr_to_str_buf( const union Ip_sockaddr_union* addr, char* buf, Ip_size_t size) { switch (addr->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: return ipcom_inet_ntop(IP_AF_INET, &addr->sin.sin_addr, buf, size); #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return ipcom_inet_ntop(IP_AF_INET6, &addr->sin6.sin6_addr, buf, size); #endif default: return IP_NULL; } } /* *=========================================================================== * ipike_addr_subnet_to_str *=========================================================================== */ IP_GLOBAL const char * ipike_addr_subnet_to_str( const union Ip_sockaddr_union* addr, const union Ip_sockaddr_union* mask) { return ipike_addr_subnet_to_str_buf(addr, mask, ipike.addr_buf, sizeof(ipike.addr_buf)); } /* *=========================================================================== * ipike_addr_subnet_to_str_buf *=========================================================================== */ IP_GLOBAL const char * ipike_addr_subnet_to_str_buf( const union Ip_sockaddr_union* addr, const union Ip_sockaddr_union* mask, char* buf, Ip_size_t size) { int prefix_len; const char* psz; switch (addr->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: psz = ipcom_inet_ntop(IP_AF_INET, &addr->sin.sin_addr, buf, size); break; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: psz = ipcom_inet_ntop(IP_AF_INET6, &addr->sin6.sin6_addr, buf, size); break; #endif default: return IP_NULL; } prefix_len = ipcom_sockaddr_to_prefixlen((struct Ip_sockaddr*)mask); if (psz==IP_NULL) return IP_NULL; ipcom_sprintf((char*)&psz[ipcom_strlen(psz)], "/%d", prefix_len); return psz; } /* *=========================================================================== * ipike_addr_range_to_str_buf *=========================================================================== */ IP_GLOBAL const char * ipike_addr_range_to_str_buf( const union Ip_sockaddr_union* low, const union Ip_sockaddr_union* high, char* buf, Ip_size_t size) { Ip_size_t low_len; if ( !ipike_addr_to_str_buf(low, buf, size) ) return IP_NULL; low_len = ipcom_strlen(buf); if ( size <= low_len + 1) return IP_NULL; /* Replace '\0' with '-' */ buf[low_len] = '-'; if ( !ipike_addr_to_str_buf(high, buf + low_len + 1, size - low_len - 1) ) return IP_NULL; return buf; } /* *=========================================================================== * ipike_addr_compare *=========================================================================== */ IP_GLOBAL int ipike_addr_compare( const union Ip_sockaddr_union* addr1, const union Ip_sockaddr_union* addr2) { if (!addr1 || !addr2 || addr1->sa.sa_family != addr2->sa.sa_family) { return 0; } switch (addr1->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: if (ip_ntohl(addr1->sin.sin_addr.s_addr) > ip_ntohl(addr2->sin.sin_addr.s_addr)) return 1; else if (ip_ntohl(addr1->sin.sin_addr.s_addr) < ip_ntohl(addr2->sin.sin_addr.s_addr)) return -1; break; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: { int i; for (i = 0; i < 4; i++) { if (ip_ntohl(addr1->sin6.sin6_addr.in6.addr32[i]) > ip_ntohl(addr2->sin6.sin6_addr.in6.addr32[i])) return 1; if (ip_ntohl(addr1->sin6.sin6_addr.in6.addr32[i]) < ip_ntohl(addr2->sin6.sin6_addr.in6.addr32[i])) return -1; } break; } #endif default: return 0; } /* Same */ return 0; } /* *=========================================================================== * ipike_addr_match_socket *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_match_socket(union Ip_sockaddr_union* bind_addr, int sock) { union Ip_sockaddr_union name; Ip_socklen_t namelen = sizeof(name); int ret; ret = ipcom_getsockname(sock, &name.sa, &namelen); if (ret < 0) { IPCOM_LOG1(ERR, "ipike_addr_match_socket() :: "\ "ipcom_getsockname failed returned: errno=%d", ipcom_errno); return IP_FALSE; } /* This check is only needed if :: or 0.0.0.0 is allowed */ #if defined(IPIKE_USE_PKTINFO) if ( #ifdef IPCOM_USE_INET ( name.sa.sa_family == IP_AF_INET && name.sin.sin_addr.s_addr == IP_INADDR_ANY && name.sa.sa_family == bind_addr->sa.sa_family && name.sin.sin_port == bind_addr->sin.sin_port) #else 0 #endif #ifdef IPCOM_USE_INET6 || (name.sa.sa_family == IP_AF_INET6 && IP_IN6_ARE_ADDR_EQUAL(&(name.sin6.sin6_addr),&ip_in6addr_any) && name.sa.sa_family == bind_addr->sa.sa_family && name.sin6.sin6_port == bind_addr->sin6.sin6_port) #else || 0 #endif ) return IP_TRUE; #endif return ipike_addr_are_equal_port(&name, bind_addr); } /* *=========================================================================== * ipike_are_addr_equal *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_are_equal( const union Ip_sockaddr_union* a1, const union Ip_sockaddr_union* a2) { switch (a1->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: { struct Ip_sockaddr_in* in1 = (struct Ip_sockaddr_in*) &a1->sin; struct Ip_sockaddr_in* in2 = (struct Ip_sockaddr_in*) &a2->sin; return a2->sa.sa_family == IP_AF_INET && in1->sin_addr.s_addr == in2->sin_addr.s_addr; } #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: { struct Ip_sockaddr_in6* in1 = (struct Ip_sockaddr_in6*) &a1->sin6; struct Ip_sockaddr_in6* in2 = (struct Ip_sockaddr_in6*) &a2->sin6; return a2->sa.sa_family == IP_AF_INET6 && IP_IN6_ARE_ADDR_EQUAL(&in1->sin6_addr, &in2->sin6_addr); } #endif default: IP_PANIC(); return IP_FALSE; } } /* *=========================================================================== * ipike_addr_are_equal_port *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_are_equal_port( const union Ip_sockaddr_union* a1, const union Ip_sockaddr_union* a2) { if (!ipike_addr_are_equal(a1, a2)) return IP_FALSE; switch (a1->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: return (a1->sin.sin_port == a2->sin.sin_port); #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return (a1->sin6.sin6_port == a2->sin6.sin6_port); #endif } IP_PANIC(); return IP_FALSE; } /* *=========================================================================== * ipike_get_addr_ptr *=========================================================================== */ IP_GLOBAL void * ipike_addr_get_ptr(union Ip_sockaddr_union *addr) { switch (addr->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: return &addr->sin.sin_addr; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return &addr->sin6.sin6_addr; #endif default: IP_PANIC(); return IP_FALSE; } } /* *=========================================================================== * ipike_get_addr_len *=========================================================================== */ IP_GLOBAL Ip_u8 ipike_addr_get_len(const union Ip_sockaddr_union *addr) { switch (addr->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: return 4; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return 16; #endif default: IP_PANIC(); return 0; } } /* *=========================================================================== * ipike_is_zero_addr *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_is_zero(union Ip_sockaddr_union *addr) { Ip_u8* p; Ip_u32 n; p = ipike_addr_get_ptr(addr); n = ipike_addr_get_len(addr); while (n > 0) if (p[--n] != 0) return IP_FALSE; return IP_TRUE; } /* *=========================================================================== * ipike_set_address *=========================================================================== */ IP_GLOBAL Ipike_error ipike_addr_set( union Ip_sockaddr_union* addr, const char* ip) { if (IP_NULL == ip) return IPIKE_FAILED; ipcom_memset(addr, 0, sizeof(*addr)); /* Assume interface name and try to get primary address */ if (!ipike_get_if_addr(ip, addr)) { /* Assume IPv4 address and try IPv6 if fails */ #ifdef IPCOM_USE_INET if (addr->sa.sa_family == 0) { if (ipike_inet_pton(IP_AF_INET, ip, &addr->sin.sin_addr) != 0) { addr->sa.sa_family = IP_AF_INET; IPCOM_SA_LEN_SET(&addr->sa, sizeof (struct Ip_sockaddr_in)); } else { addr->sa.sa_family = 0; } } #endif #ifdef IPCOM_USE_INET6 if (addr->sa.sa_family == 0) { if (ipike_inet_pton(IP_AF_INET6, ip, &addr->sin6.sin6_addr) != 0) { /* getsockaddrbyaddr for obtaining scope of v6 llocal addrs */ ipcom_getsockaddrbyaddr(IP_AF_INET6,ip,&addr->sa); } else { addr->sa.sa_family = 0; } } #endif } if (addr->sa.sa_family == 0) { IPCOM_LOG1(DEBUG, "ipike_addr_set() :: bad address: %s", ip); return IPIKE_FAILED; } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_set_address_from_data *=========================================================================== */ IP_GLOBAL Ipike_error ipike_addr_set_from_data( Ip_u8* data, Ip_size_t len, union Ip_sockaddr_union* addr) { ipcom_memset(addr, 0, sizeof(*addr)); #ifdef IPCOM_USE_INET if (len == 4) { addr->sa.sa_family = IP_AF_INET; IPCOM_SA_LEN_SET(&addr->sa, sizeof (struct Ip_sockaddr_in)); ipcom_memcpy((void*)&addr->sin.sin_addr, data, len); } #endif #ifdef IPCOM_USE_INET6 if (len == 16) { addr->sa.sa_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&addr->sa, sizeof (struct Ip_sockaddr_in6)); ipcom_memcpy((void*)&addr->sin6.sin6_addr, data, len); } #endif if (addr->sa.sa_family == 0) return IPIKE_FAILED; return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_append_address_from_data *=========================================================================== */ IP_GLOBAL Ipike_error ipike_addr_append_from_data(Ip_u8* data, Ip_size_t len, union Ip_sockaddr_union*** list) { Ipike_error err = IPIKE_SUCCESS; union Ip_sockaddr_union* addr = IP_NULL; addr = ipcom_calloc(1, sizeof(*addr)); if (IP_NULL == addr) { IP_PANIC(); err = IPIKE_OUT_OF_MEMORY; } else { err = ipike_addr_set_from_data(data, len, addr); if (IPIKE_SUCCESS == err) err = ipike_array_add((void***)list, addr); if (IPIKE_SUCCESS != err) ipcom_free(addr); } return err; } /* *=========================================================================== * ipike_set_port *=========================================================================== */ IP_GLOBAL void ipike_addr_set_port(union Ip_sockaddr_union* addr, Ip_u16 port) { switch (addr->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: addr->sin.sin_port = ip_htons(port); break; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: addr->sin6.sin6_port = ip_htons(port); break; #endif default: #if defined(IPCOM_USE_INET6) addr->sin6.sin6_port = ip_htons(port); #elif defined(IPCOM_USE_INET) addr->sin.sin_port = ip_htons(port); #endif break; } } /* *=========================================================================== * ipike_addr_get_port *=========================================================================== */ IP_GLOBAL Ip_u16 ipike_addr_get_port(const union Ip_sockaddr_union* addr) { Ip_u16 port = 0; switch (addr->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: port = ip_ntohs(addr->sin.sin_port); break; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: port = ip_ntohs(addr->sin6.sin6_port); break; #endif default: /* Try get any port information */ #ifdef IPCOM_USE_INET6 port = ip_ntohs(addr->sin6.sin6_port); #endif #ifdef IPCOM_USE_INET port = ip_ntohs(addr->sin.sin_port); #endif break; } return port; } /* *=========================================================================== * ipike_copy_address *=========================================================================== */ IP_GLOBAL Ipike_error ipike_addr_copy( union Ip_sockaddr_union *to, const union Ip_sockaddr_union *from) { Ipike_error err = IPIKE_SUCCESS; ipcom_memset(to, 0, sizeof(*to)); switch (from->sa.sa_family) { #ifdef IPCOM_USE_INET case IP_AF_INET: ipcom_memcpy((void*)to, (void*)from, sizeof (struct Ip_sockaddr_in)); IPCOM_SA_LEN_SET(&to->sa, sizeof (struct Ip_sockaddr_in)); break; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: ipcom_memcpy((void*)to, (void*)from, sizeof (struct Ip_sockaddr_in6)); IPCOM_SA_LEN_SET(&to->sa, sizeof (struct Ip_sockaddr_in6)); break; #endif default: /* Should never happen */ IP_PANIC(); err = IPIKE_FAILED; break; } return err; } /* *=========================================================================== * ipike_has_valid_address *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_is_valid(const union Ip_sockaddr_union* addr) { #ifdef IPCOM_USE_INET if (addr->sa.sa_family == IP_AF_INET) return IP_TRUE; #endif #ifdef IPCOM_USE_INET6 if (addr->sa.sa_family == IP_AF_INET6) return IP_TRUE; #endif return IP_FALSE; } /* *=========================================================================== * ipike_addr_match_network *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_match_network( union Ip_sockaddr_union* address, union Ip_sockaddr_union* network, union Ip_sockaddr_union* netmask) { union Ip_sockaddr_union address2; union Ip_sockaddr_union address3; if ((ipike_addr_copy(&address2, address) == IPIKE_SUCCESS) && (ipike_addr_copy(&address3, network) == IPIKE_SUCCESS) && (ipike_addr_apply_network_mask(&address2, netmask) == IPIKE_SUCCESS) && (ipike_addr_apply_network_mask(&address3, netmask) == IPIKE_SUCCESS) && (ipike_addr_compare(&address2, &address3) == 0)) { return IP_TRUE; } return IP_FALSE; } /* *=========================================================================== * ipike_addr_match_range *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_match_range( const union Ip_sockaddr_union* addr, const union Ip_sockaddr_union* low, const union Ip_sockaddr_union* high) { if ( ipike_addr_compare(addr, low) < 0 ) return IP_FALSE; if ( ipike_addr_compare(addr, high) > 0 ) return IP_FALSE; return IP_TRUE; } /* *=========================================================================== * ipike_addr_range_to_mask *=========================================================================== */ IP_GLOBAL Ipike_error ipike_addr_range_to_mask( union Ip_sockaddr_union* addr, union Ip_sockaddr_union* mask) { Ip_u8* p1; Ip_u8* p2; Ip_u32 len; Ip_u32 i; p1 = ipike_addr_get_ptr(addr); len = ipike_addr_get_len(addr); p2 = ipike_addr_get_ptr(mask); if (len != ipike_addr_get_len(mask)) return IPIKE_FAILED; for (i=0; i (int) n ) { IPCOM_LOG1(ERR, "ipike_load_subnet: bad netmask (%d)", n2); return IPIKE_CONF_INVALID_VALUE; } ipike_addr_create_mask(pb,n2, IP_FALSE); } else { /* default 0xff */ ipcom_memset(pb, 0xff, n); } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_addr_create_mask *=========================================================================== * Description: Creates a network mask with the 'netbits' leftmost bits set. * Parameters: [in] mask - Pointer to a buffer where the mask should be stored. * [in] netbits - The number of set bits. * [in] inverse - inverse of netmask if true * Returns: * */ IP_GLOBAL void ipike_addr_create_mask(void *mask, int netbits, Ip_bool inverse) { int i; for (i = 0; i < netbits; i++) { if (inverse == IP_TRUE) IP_BIT_CLR(((Ip_u16*) mask)[i / 16], ip_htons(0x8000 >> (i % 16))); else IP_BIT_SET(((Ip_u16*) mask)[i / 16], ip_htons(0x8000 >> (i % 16))); } } /* *=========================================================================== * ipike_increment_v6_address *=========================================================================== * Description: Given an v6 address and mask increments it * Parameters: [in] address - v6 address * [in] prefixlen - v6 prefix * Returns: * */ IP_GLOBAL Ipike_error ipike_addr_increment_v6(union Ip_sockaddr_union *address, int prefixlen) { #ifdef IPCOM_USE_INET6 int i; Ip_u32 addrcur, tmp; Ip_u8 *ptmpaddr, *pmaxaddr; struct Ip_in6_addr *addr; union Ip_sockaddr_union tmpaddr, maxaddr, tmpaddr1; Ip_bool overflow = IP_TRUE; /* Make a copy of the address */ ipcom_memcpy(&maxaddr,address,sizeof(union Ip_sockaddr_union)); /* Backup copy used to revert */ ipcom_memcpy(&tmpaddr1,address,sizeof(union Ip_sockaddr_union)); tmpaddr.sa.sa_family = IP_AF_INET6; ptmpaddr = (Ip_u8*)ipike_addr_get_ptr(&tmpaddr); pmaxaddr = (Ip_u8*)ipike_addr_get_ptr(&maxaddr); if (prefixlen == 128 || prefixlen == 0) { /* Max addr is FFFF...FFFF */ ipcom_memset(pmaxaddr,0xFF,16); } else { i = ipike_addr_get_len(address); ipcom_memset(ptmpaddr,0x00,(Ip_size_t) i); tmpaddr.sa.sa_family = IP_AF_INET6; ipike_addr_create_mask(ptmpaddr,prefixlen,IP_FALSE); (void)ipike_addr_apply_network_mask(&maxaddr,&tmpaddr); ipcom_memset(ptmpaddr,0xFF,(Ip_size_t) i); tmpaddr.sa.sa_family = IP_AF_INET6; ipike_addr_create_mask(ptmpaddr,prefixlen,IP_TRUE); /* Add the maxaddr + inverse mask to get max addr */ i--; /* i = addr_len -1 => 15 */ for (; i >= 0; i--) pmaxaddr[i] |= ptmpaddr[i]; } addr = ipike_addr_get_ptr(address); for (i = 3; i >= 0; i--) { addrcur = (IP_GET_32ON16(&((struct Ip_in6_addr *)(addr))->in6.addr32[i])); /* Handle overflo */ if (addrcur == 0xffffffffU && overflow == IP_TRUE) { IP_SET_32ON16(&(addr)->in6.addr32[i], 0); } else { tmp = ip_ntohl(addrcur) + 1; IP_SET_HTONL(&(addr)->in6.addr32[i], tmp); overflow = IP_FALSE; break; } } if (IP_IN6_ARE_ADDR_EQUAL((struct Ip_in6_addr*)addr, (struct Ip_in6_addr*)pmaxaddr)) { IPCOM_LOG3(ERR, "ipike_increment_v6_address: Max limit addr:%s max:%s resetting to %s \n", ipike_addr_to_str(address), ipike_addr_to_str(&maxaddr), ipike_addr_to_str(&tmpaddr1) ); return IPIKE_FAILED; } #endif /* IPCOM_USE_INET6 */ return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_load_ike_address *=========================================================================== */ IP_GLOBAL void ipike_to_lower_string(char *str) { int i = 0; if (IP_NULL != str) { while (str[i] != 0) { str[i] = (char)ipcom_tolower(str[i]); i++; } } } /* *=========================================================================== * ipike_hex2bin *=========================================================================== */ IP_GLOBAL Ip_u8* ipike_hex2bin(const char* value, Ip_size_t* len) { Ip_u8* res; Ip_size_t i; char c; *len = *len / 2; res = ipcom_malloc(*len); if (res != IP_NULL) { for (i=0; i<*len; i++) { c = value[2*i]; if ((c >= '0') && (c <= '9')) res[i] = (Ip_u8)((c - '0') << 4); else if ((c >= 'A') && (c <= 'F')) res[i] = (Ip_u8)((c - 'A' + 10) << 4); else if ((c >= 'a') && (c <= 'f')) res[i] = (Ip_u8)((c - 'a' + 10) << 4); else res[i] = 0; c = value[2*i+1]; if ((c >= '0') && (c <= '9')) res[i] = (Ip_u8)(res[i] + c - '0'); else if ((c >= 'A') && (c <= 'F')) res[i] = (Ip_u8)(res[i] + c - 'A' + 10); else if ((c >= 'a') && (c <= 'f')) res[i] = (Ip_u8)(res[i] + c - 'a' + 10); } } return res; } /* *=========================================================================== * ipike_bin2hex *=========================================================================== */ IP_GLOBAL void ipike_bin2hex(unsigned char* buf, Ip_size_t len, char* value) { Ip_size_t i; char nibble; for (i = 0; i < len; i++) { /* First nibble */ nibble = (char)((buf[i] >> 4) & 0x0F); if (nibble < 10) value[i * 2] = (char)(nibble + '0'); else value[i * 2] = (char)(nibble + 'a' - 10); /* Second nibble */ nibble = (char)(buf[i] & 0x0F); if (nibble < 10) value[i * 2 + 1] = (char)(nibble + '0'); else value[i * 2 + 1] = (char)(nibble + 'a' - 10); } value[2 * len] = '\0'; return; } /* *=========================================================================== * ipike_write_file *=========================================================================== */ IP_GLOBAL Ipike_error ipike_write_file(const char* filename, Ip_u8* buf, Ip_size_t buf_len) { Ipike_error err = 0; IP_FILE* file = IP_NULL; Ip_size_t total = 0; Ip_size_t len = 0; file = ipcom_fopen(filename, "w"); if (IP_NULL == file) { err = IPIKE_FAILED; } else { while ((IPIKE_SUCCESS == err) && (total < buf_len)) { len = ipcom_fwrite(&buf[len], 1, buf_len, file); if (len <= 0) err = IPIKE_FAILED; else total += len; } (void)ipcom_fclose(file); } return err; } /* *=========================================================================== * ipike_read_file *=========================================================================== */ IP_GLOBAL Ipike_error ipike_read_file(const char* filename, Ip_u8** buf, Ip_size_t* buf_len) { Ipike_error err = 0; IP_FILE* file = IP_NULL; Ip_size_t total = 0; Ip_size_t len = 0; file = ipcom_fopen(filename, "r"); if (IP_NULL == file) { err = IPIKE_FAILED; } else { *buf_len = 0; while (total == *buf_len) { len = (1024 + *buf_len)*2; total += len; *buf = ipcom_realloc(*buf, total); len = ipcom_fread(&(*buf)[*buf_len], 1, len, file); *buf_len += len; } (void)ipcom_fclose(file); } return err; } /* *=========================================================================== * ipike_tmo2_cancel *=========================================================================== */ IP_GLOBAL void ipike_tmo2_cancel(Ipcom_tmo2 *tmo) { if (IPCOM_TMO2_PENDING(tmo) == IP_TRUE) { (void)ipcom_tmo2_cancel(tmo); ipcom_memset(tmo, 0, sizeof(*tmo)); } return; } /* *=========================================================================== * ipike_get_if_addr *=========================================================================== */ IP_GLOBAL Ip_bool ipike_get_if_addr(const char* name, union Ip_sockaddr_union* addr) { Ip_bool found_address = IP_FALSE; struct Ip_if_nameindex *ni; int i; #ifdef IPCOM_USE_INET struct Ip_ifreq ifreq; #else struct Ip_in6_ifreq ifxreq; #endif Ip_fd s; int retry_count; if ((ni = ipcom_if_nameindex()) == IP_NULL) { IPCOM_LOG0(ERR, "ipike_get_if_addr: failed to get interface list"); } else { for (i = 0; ni[i].if_name != IP_NULL && !found_address; i++) { if ((ipcom_strcmp(ni[i].if_name, "lo0") == 0) || (ipcom_strcmp(ni[i].if_name, "lo") == 0)) continue; if ((name != IP_NULL) && (ipcom_strcmp(ni[i].if_name, name) != 0)) continue; #ifdef IPCOM_USE_INET ipcom_strncpy(ifreq.ifr_name, ni[i].if_name,IP_IFNAMSIZ - 1); #else ipcom_strncpy(ifxreq.ifr_name, ni[i].if_name,IP_IFNAMSIZ - 1); ifxreq.ifr_ifru.ifru_addr.sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&ifxreq.ifr_ifru.ifru_addr, sizeof(struct Ip_sockaddr_in6)); #endif #ifdef IPCOM_USE_INET if ((s = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, 0)) == IP_INVALID_SOCKET) #else if ((s = ipcom_socket(IP_AF_INET6, IP_SOCK_DGRAM, 0)) == IP_INVALID_SOCKET) #endif { IPCOM_LOG0(ERR, "ipike_get_if_addr: failed to create socket"); } else { /* We have found the interface, let's get the primary address. * Loop for X seconds, since DHCP client may be trying to get * the address */ retry_count = ipcom_sysvar_get_as_int("ipike.get_address_retry", 30); if (retry_count == 0) retry_count = 1; while (retry_count > 0) { #ifdef IPCOM_USE_INET if ((ipcom_socketioctl(s, IP_SIOCGIFADDR, &ifreq) < 0) || ipike_addr_is_zero((union Ip_sockaddr_union*)&ifreq.ip_ifr_addr)) #else if ((ipcom_socketioctl(s, IP_SIOCGIFADDR_IN6, &ifxreq) < 0) || ipike_addr_is_zero((union Ip_sockaddr_union*)&ifxreq.ifr_ifru.ifru_addr)) #endif { IPCOM_LOG1(DEBUG2, "ipike_get_if_addr: failed to get primary address from %s", ni[i].if_name); (void)ipcom_sleep(1); retry_count--; } else { break; } } if ((retry_count == 0) || #ifdef IPCOM_USE_INET (ipike_addr_copy(addr, (union Ip_sockaddr_union*)&ifreq.ip_ifr_addr) != IPIKE_SUCCESS) || #else (ipike_addr_copy(addr, (union Ip_sockaddr_union*)&ifxreq.ifr_ifru.ifru_addr) != IPIKE_SUCCESS) || #endif ipike_addr_is_zero(addr)) { IPCOM_LOG0(ERR, "ipike_get_if_addr: failed to get address"); } else { found_address = IP_TRUE; } ipcom_socketclose(s); } } ipcom_if_freenameindex(ni); } return found_address; } /* *=========================================================================== * ipike_add_delete_address *=========================================================================== */ IP_GLOBAL Ipike_error ipike_add_delete_address( Ip_bool add, const char *ifname, union Ip_sockaddr_union *addr, union Ip_sockaddr_union *netmask) { Ipike_error err = IPIKE_FAILED; if (addr != IP_NULL) { #ifdef IPCOM_USE_INET if (addr->sa.sa_family == IP_AF_INET) { if (netmask == IP_NULL) err = ipike_add_delete_ipv4_address(add, ifname, &addr->sin, IP_NULL); else err = ipike_add_delete_ipv4_address(add, ifname, &addr->sin, &netmask->sin); } #endif #ifdef IPCOM_USE_INET6 if (addr->sa.sa_family == IP_AF_INET6) { if (netmask == IP_NULL) err = ipike_add_delete_ipv6_address(add, ifname, &addr->sin6, IP_NULL); else err = ipike_add_delete_ipv6_address(add, ifname, &addr->sin6, &netmask->sin6); } #endif IPCOM_LOG3(DEBUG2, "%s address %s %s", add ? "Add" : "Delete", ipike_addr_to_str(addr), (err == IPIKE_SUCCESS) ? "succeeded" : "failed"); } return err; } /* *=========================================================================== * ipike_validate_str *=========================================================================== */ IP_GLOBAL Ipike_error ipike_validate_str(const char *input_str, char *ctx) { (void)ctx; if (input_str == IP_NULL || *input_str == IP_NULL || IP_NULL != ipcom_strchr(input_str,'{') || IP_NULL != ipcom_strchr(input_str,'}') || IP_NULL != ipcom_strchr(input_str,';')) { IPCOM_LOG2(ERR, "Bad configuration, invalid config value '%s'='%s'", ctx, input_str ? input_str : "(null)"); return IPIKE_FAILED; } return IPIKE_SUCCESS; } #ifdef IP_DEBUG /* Suppress prototype warnings */ IP_GLOBAL Ipike_error ipike_test_v6_increment(void); IP_GLOBAL Ipike_error ipike_test_v6_increment(void) { union Ip_sockaddr_union addr,mask; int prefix = 0; int safecount = 0; for (prefix = 64; prefix <= 128 ; prefix += 32) { switch (prefix) { case 32: (void)ipike_addr_load_subnet("2000:0000:ffff:ffff:ffff:ffff:ffff:ff00/128",&addr,&mask); break; case 64: (void)ipike_addr_load_subnet("2000:0000:0000:0000:ffff:ffff:ffff:ff00/128",&addr,&mask); break; case 96: (void)ipike_addr_load_subnet("2000:0000:0000:0000:0000:0000:ffff:ff00/128",&addr,&mask); break; case 128: (void)ipike_addr_load_subnet("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/128",&addr,&mask); break; default: (void)ipike_addr_load_subnet("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128",&addr,&mask); break; } ipcom_printf(" Testing for prefix %d addr %s \n",prefix, ipike_addr_to_str(&addr)); while (ipike_addr_increment_v6(&addr, prefix) != IPIKE_FAILED && (safecount < 1000000)) { if (!(safecount % 10000)) ipcom_printf("Incremented address is %s \n",ipike_addr_to_str(&addr)); safecount++; } safecount = 0; ipcom_printf("Failed to increment address : %s \n",ipike_addr_to_str(&addr)); ipcom_printf("-------------------------------------------------\n\n"); } return IPIKE_SUCCESS; } #endif /* *=========================================================================== * ipike_is_any_addr *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_is_any(union Ip_sockaddr_union* addr) { #if defined(IPCOM_USE_INET) if (addr->sin.sin_family == IP_AF_INET) return ( addr->sin.sin_addr.s_addr == IP_INADDR_ANY ); #endif #if defined(IPCOM_USE_INET6) if ( addr->sin6.sin6_family == IP_AF_INET6 ) return IP_IN6_ARE_ADDR_EQUAL(&addr->sin6.sin6_addr, &ip_in6addr_any); #endif /* Should not happen */ return IP_FALSE; } /* *=========================================================================== * ipike_addr_is_host_mask *=========================================================================== */ IP_GLOBAL Ip_bool ipike_addr_is_host_mask(union Ip_sockaddr_union* addr) { Ip_u8* p; Ip_u32 n; p = ipike_addr_get_ptr(addr); n = ipike_addr_get_len(addr); while (n > 0) if (p[--n] != 0xff) return IP_FALSE; return IP_TRUE; } /* *=========================================================================== * ipike_util_str_is_hex *=========================================================================== */ IP_GLOBAL Ip_bool ipike_util_str_is_hex(const char *str) { const char *c; if ( ipcom_strncmp(str, "0x", 2) ) return IP_FALSE; c = str + 2; if ( *c == '\0' ) return IP_FALSE; for (; *c; c++) { if ( !ipcom_isxdigit((int)*c) ) return IP_FALSE; } return IP_TRUE; } /* *=========================================================================== * ipike_util_str_hex2bin *=========================================================================== */ IP_GLOBAL Ip_u8* ipike_util_str_hex2bin(const char *str, Ip_size_t *len) { Ip_u8 *ret; if (!str || !len) return IP_NULL; /* Remove '0x' prefix */ *len = ipcom_strlen(str) - 2; ret = ipike_hex2bin(str + 2 , len); if ( ret == IP_NULL ) *len = 0; return ret; } /* *=========================================================================== * ipike_time_diff *=========================================================================== */ IP_GLOBAL long ipike_time_diff_sec( const struct Ip_timeval * t1, const struct Ip_timeval * t2) { struct Ip_timeval diff; ip_timeval_sub(t1, t2, &diff); return (long)(diff.tv_sec + ((diff.tv_usec + 500000)/ 1000000)); } /* *=========================================================================== * ipike_time *=========================================================================== */ IP_GLOBAL long ipike_time(void) { struct Ip_timeval now; ipcom_microtime(&now); return (long)(now.tv_sec + ((now.tv_usec + 500000) / 1000000)); } /* **************************************************************************** * END OF FILE **************************************************************************** */