summaryrefslogtreecommitdiffstats
path: root/hicn-light/src/hicn/api/ip_address.h
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-light/src/hicn/api/ip_address.h')
-rw-r--r--hicn-light/src/hicn/api/ip_address.h221
1 files changed, 221 insertions, 0 deletions
diff --git a/hicn-light/src/hicn/api/ip_address.h b/hicn-light/src/hicn/api/ip_address.h
new file mode 100644
index 000000000..b58981d85
--- /dev/null
+++ b/hicn-light/src/hicn/api/ip_address.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file ip_address.h
+ * \brief IP address type support
+ */
+#ifndef IP_ADDRESS_H
+#define IP_ADDRESS_H
+
+#include <arpa/inet.h> // inet_ntop
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#define __bswap_constant_32(x) OSSwapInt32(x)
+#include <machine/endian.h>
+#else
+#include <endian.h>
+#endif
+#include <errno.h>
+#include <netdb.h> // struct addrinfo
+#include <netinet/in.h> // INET*_ADDRSTRLEN, IN*ADDR_LOOPBACK
+#include <stdlib.h>
+#include <string.h> // memset
+
+#include <hicn/api/types.h>
+
+#define bytes_to_bits(x) (x * 8)
+#define IPV6_ADDR_LEN 16 /* bytes */
+#define IPV4_ADDR_LEN 4 /* bytes */
+#define IPV6_ADDR_LEN_BITS bytes_to_bits(IPV6_ADDR_LEN)
+#define IPV4_ADDR_LEN_BITS bytes_to_bits(IPV4_ADDR_LEN)
+
+#define IP_MAX_ADDR_LEN IPV6_ADDR_LEN
+
+#define DUMMY_PORT 1234
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+typedef union {
+ union {
+ struct in_addr as_inaddr;
+ u8 as_u8[4];
+ u16 as_u16[2];
+ u32 as_u32;
+ } v4;
+ union {
+ struct in6_addr as_in6addr;
+ u8 as_u8[16];
+ u16 as_u16[8];
+ u32 as_u32[4];
+ u64 as_u64[2];
+ } v6;
+ u8 buffer[IP_MAX_ADDR_LEN];
+ u8 as_u8[IP_MAX_ADDR_LEN];
+ u16 as_u16[IP_MAX_ADDR_LEN >> 1];
+ u32 as_u32[IP_MAX_ADDR_LEN >> 2];
+ u64 as_u64[IP_MAX_ADDR_LEN >> 3];
+} ip_address_t;
+
+#define MAXSZ_IP4_ADDRESS_ INET_ADDRSTRLEN - 1
+#define MAXSZ_IP6_ADDRESS_ INET6_ADDRSTRLEN - 1
+#define MAXSZ_IP_ADDRESS_ MAXSZ_IP6_ADDRESS_
+#define MAXSZ_IP4_ADDRESS MAXSZ_IP4_ADDRESS_ + 1
+#define MAXSZ_IP6_ADDRESS MAXSZ_IP6_ADDRESS_ + 1
+#define MAXSZ_IP_ADDRESS MAXSZ_IP_ADDRESS_ + 1
+
+/* No htonl() with const */
+static const ip_address_t IPV4_LOOPBACK = {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ .v4.as_inaddr.s_addr = __bswap_constant_32(INADDR_LOOPBACK),
+#else
+ .v4.as_inaddr.s_addr = INADDR_LOOPBACK,
+#endif
+};
+
+static const ip_address_t IPV6_LOOPBACK = {
+ .v6.as_in6addr = IN6ADDR_LOOPBACK_INIT,
+};
+
+#define MAX_PORT 1 << (8 * sizeof(u16))
+#define IS_VALID_PORT(x) ((x > 0) && (x < MAX_PORT))
+
+#define MAXSZ_PORT_ 5
+#define MAXSZ_PORT MAXSZ_PORT_ + 1
+
+#define IS_VALID_FAMILY(x) ((x == AF_INET) || (x == AF_INET6))
+
+static inline int ip_address_get_family(const char *ip_address) {
+ struct addrinfo hint, *res = NULL;
+ int rc;
+
+ memset(&hint, '\0', sizeof hint);
+
+ hint.ai_family = PF_UNSPEC;
+ hint.ai_flags = AI_NUMERICHOST;
+
+ rc = getaddrinfo(ip_address, NULL, &hint, &res);
+ if (rc) {
+ return -1;
+ }
+ rc = res->ai_family;
+ freeaddrinfo(res);
+ return rc;
+}
+
+static inline int ip_address_len(const ip_address_t *ip_address, int family) {
+ return (family == AF_INET6) ? IPV6_ADDR_LEN
+ : (family == AF_INET) ? IPV4_ADDR_LEN : 0;
+}
+
+static inline int ip_address_ntop(const ip_address_t *ip_address, char *dst,
+ const size_t len, int family) {
+ const char *s = inet_ntop(family, ip_address->buffer, dst, len);
+ return (s ? 1 : -1);
+}
+
+/*
+ * Parse ip addresses in presentation format, or prefixes (in bits, separated by
+ * a slash)
+ */
+static inline int ip_address_pton(const char *ip_address_str,
+ ip_address_t *ip_address) {
+ int pton_fd;
+#ifdef IP_ADDRESS_PREFIX
+ char *p;
+ char *eptr;
+ u32 dst_len;
+#endif /* IP_ADDRESS_PREFIX */
+ char *addr = strdup(ip_address_str);
+ int family;
+
+#ifdef IP_ADDRESS_PREFIX
+ p = strchr(addr, '/');
+ if (!p) {
+ dst_len = 0; // until we get the ip address family
+ } else {
+ dst_len = strtoul(p + 1, &eptr, 10);
+ *p = 0;
+ }
+#endif /* IP_ADDRESS_PREFIX */
+
+ family = ip_address_get_family(addr);
+
+ switch (family) {
+ case AF_INET6:
+#ifdef IP_ADDRESS_PREFIX
+ if (dst_len > IPV6_ADDR_LEN_BITS) goto ERR;
+#endif /* IP_ADDRESS_PREFIX */
+ pton_fd = inet_pton(AF_INET6, addr, &ip_address->buffer);
+ break;
+ case AF_INET:
+#ifdef IP_ADDRESS_PREFIX
+ if (dst_len > IPV4_ADDR_LEN_BITS) goto ERR;
+#endif /* IP_ADDRESS_PREFIX */
+ pton_fd = inet_pton(AF_INET, addr, &ip_address->buffer);
+ break;
+ default:
+ goto ERR;
+ }
+
+ // 0 = not in presentation format
+ // < 0 = other error (use perror)
+ if (pton_fd <= 0) {
+ goto ERR;
+ }
+
+ return 1;
+ERR:
+ free(addr);
+ return -1;
+}
+
+static inline int ip_address_snprintf(char *s, size_t size,
+ const ip_address_t *ip_address,
+ int family) {
+ size_t len = family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
+ const char *rc = inet_ntop(family, ip_address->buffer, s, len);
+ return rc ? strlen(rc) : -1;
+}
+
+static inline int ip_address_to_sockaddr(const ip_address_t *ip_address,
+ struct sockaddr *sockaddr_address,
+ int family) {
+ struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *)sockaddr_address;
+ struct sockaddr_in *tmp4 = (struct sockaddr_in *)sockaddr_address;
+
+ switch (family) {
+ case AF_INET6:
+ tmp6->sin6_family = AF_INET6;
+ tmp6->sin6_port = DUMMY_PORT;
+ tmp6->sin6_scope_id = 0;
+ memcpy(&tmp6->sin6_addr, ip_address->buffer, IPV6_ADDR_LEN);
+ break;
+ case AF_INET:
+ tmp4->sin_family = AF_INET;
+ tmp4->sin_port = DUMMY_PORT;
+ memcpy(&tmp4->sin_addr, ip_address->buffer, IPV4_ADDR_LEN);
+ break;
+ default:
+ return -1;
+ }
+
+ return 1;
+}
+
+#endif /* IP_ADDRESS_H */