2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2017-05-15 07:19:43 +02:00
|
|
|
/*
|
|
|
|
* IP address structure (for generic IPv4 or IPv6 address)
|
|
|
|
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __IPADDR_H__
|
|
|
|
#define __IPADDR_H__
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
2020-07-20 13:43:54 +02:00
|
|
|
#include "lib/log.h"
|
|
|
|
|
2019-02-07 23:10:31 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2017-05-15 07:19:43 +02:00
|
|
|
/*
|
|
|
|
* Generic IP address - union of IPv4 and IPv6 address.
|
|
|
|
*/
|
|
|
|
enum ipaddr_type_t {
|
2020-03-29 11:05:30 +02:00
|
|
|
IPADDR_NONE = AF_UNSPEC,
|
|
|
|
IPADDR_V4 = AF_INET,
|
|
|
|
IPADDR_V6 = AF_INET6,
|
2017-05-15 07:19:43 +02:00
|
|
|
};
|
|
|
|
|
2017-05-26 19:44:29 +02:00
|
|
|
struct ipaddr {
|
2017-05-15 07:19:43 +02:00
|
|
|
enum ipaddr_type_t ipa_type;
|
|
|
|
union {
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t addr;
|
2023-09-20 15:27:23 +02:00
|
|
|
uint8_t addrbytes[16];
|
2017-05-15 07:19:43 +02:00
|
|
|
struct in_addr _v4_addr;
|
|
|
|
struct in6_addr _v6_addr;
|
|
|
|
} ip;
|
|
|
|
#define ipaddr_v4 ip._v4_addr
|
|
|
|
#define ipaddr_v6 ip._v6_addr
|
2017-05-26 19:44:29 +02:00
|
|
|
};
|
2017-05-15 07:19:43 +02:00
|
|
|
|
|
|
|
#define IS_IPADDR_NONE(p) ((p)->ipa_type == IPADDR_NONE)
|
|
|
|
#define IS_IPADDR_V4(p) ((p)->ipa_type == IPADDR_V4)
|
|
|
|
#define IS_IPADDR_V6(p) ((p)->ipa_type == IPADDR_V6)
|
|
|
|
|
2024-05-31 15:41:07 +02:00
|
|
|
#define SET_IPADDR_NONE(p) ((p)->ipa_type = IPADDR_NONE)
|
|
|
|
#define SET_IPADDR_V4(p) ((p)->ipa_type = IPADDR_V4)
|
|
|
|
#define SET_IPADDR_V6(p) ((p)->ipa_type = IPADDR_V6)
|
2017-05-15 07:19:43 +02:00
|
|
|
|
2019-02-01 22:23:02 +01:00
|
|
|
#define IPADDRSZ(p) \
|
2019-04-18 22:03:35 +02:00
|
|
|
(IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr))
|
2019-02-01 22:23:02 +01:00
|
|
|
|
2022-07-19 14:59:23 +02:00
|
|
|
#define IPADDR_STRING_SIZE 46
|
|
|
|
|
2020-07-20 13:43:54 +02:00
|
|
|
static inline int ipaddr_family(const struct ipaddr *ip)
|
|
|
|
{
|
|
|
|
switch (ip->ipa_type) {
|
|
|
|
case IPADDR_V4:
|
|
|
|
return AF_INET;
|
|
|
|
case IPADDR_V6:
|
|
|
|
return AF_INET6;
|
2023-01-30 16:06:29 +01:00
|
|
|
case IPADDR_NONE:
|
2020-07-20 13:43:54 +02:00
|
|
|
return AF_UNSPEC;
|
|
|
|
}
|
2023-01-30 16:06:29 +01:00
|
|
|
|
|
|
|
assert(!"Reached end of function where we should never hit");
|
2020-07-20 13:43:54 +02:00
|
|
|
}
|
|
|
|
|
2017-05-26 19:44:29 +02:00
|
|
|
static inline int str2ipaddr(const char *str, struct ipaddr *ip)
|
2017-05-15 07:19:43 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2017-05-26 19:44:29 +02:00
|
|
|
memset(ip, 0, sizeof(struct ipaddr));
|
2017-05-15 07:19:43 +02:00
|
|
|
|
|
|
|
ret = inet_pton(AF_INET, str, &ip->ipaddr_v4);
|
|
|
|
if (ret > 0) /* Valid IPv4 address. */
|
|
|
|
{
|
|
|
|
ip->ipa_type = IPADDR_V4;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = inet_pton(AF_INET6, str, &ip->ipaddr_v6);
|
|
|
|
if (ret > 0) /* Valid IPv6 address. */
|
|
|
|
{
|
|
|
|
ip->ipa_type = IPADDR_V6;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-07-17 22:59:41 +02:00
|
|
|
static inline char *ipaddr2str(const struct ipaddr *ip, char *buf, int size)
|
2017-05-15 07:19:43 +02:00
|
|
|
{
|
|
|
|
buf[0] = '\0';
|
2020-03-29 11:05:30 +02:00
|
|
|
if (ip)
|
|
|
|
inet_ntop(ip->ipa_type, &ip->ip.addr, buf, size);
|
2017-05-15 07:19:43 +02:00
|
|
|
return buf;
|
|
|
|
}
|
2018-02-28 03:07:23 +01:00
|
|
|
|
2020-07-29 17:48:57 +02:00
|
|
|
#define IS_MAPPED_IPV6(A) \
|
|
|
|
((A)->s6_addr32[0] == 0x00000000 \
|
|
|
|
? ((A)->s6_addr32[1] == 0x00000000 \
|
|
|
|
? (ntohl((A)->s6_addr32[2]) == 0xFFFF ? 1 : 0) \
|
|
|
|
: 0) \
|
|
|
|
: 0)
|
|
|
|
|
2018-03-06 23:19:24 +01:00
|
|
|
/*
|
|
|
|
* Convert IPv4 address to IPv4-mapped IPv6 address which is of the
|
|
|
|
* form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then
|
|
|
|
* be used to represent the IPv4 address, wherever only an IPv6 address
|
|
|
|
* is required.
|
|
|
|
*/
|
2018-02-28 03:07:23 +01:00
|
|
|
static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6,
|
|
|
|
struct in_addr in)
|
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t addr_type = htonl(0xFFFF);
|
2018-03-01 20:50:46 +01:00
|
|
|
|
2018-02-28 03:07:23 +01:00
|
|
|
memset(in6, 0, sizeof(struct in6_addr));
|
|
|
|
memcpy((char *)in6 + 8, &addr_type, sizeof(addr_type));
|
|
|
|
memcpy((char *)in6 + 12, &in, sizeof(struct in_addr));
|
|
|
|
}
|
|
|
|
|
2018-04-09 06:04:11 +02:00
|
|
|
/*
|
|
|
|
* convert an ipv4 mapped ipv6 address back to ipv4 address
|
|
|
|
*/
|
2019-11-08 20:13:33 +01:00
|
|
|
static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6,
|
2018-04-09 06:04:11 +02:00
|
|
|
struct in_addr *in)
|
|
|
|
{
|
|
|
|
memset(in, 0, sizeof(struct in_addr));
|
|
|
|
memcpy(in, (char *)in6 + 12, sizeof(struct in_addr));
|
|
|
|
}
|
|
|
|
|
2019-12-11 16:40:39 +01:00
|
|
|
/*
|
|
|
|
* generic ordering comparison between IP addresses
|
|
|
|
*/
|
|
|
|
static inline int ipaddr_cmp(const struct ipaddr *a, const struct ipaddr *b)
|
|
|
|
{
|
|
|
|
uint32_t va, vb;
|
|
|
|
va = a->ipa_type;
|
|
|
|
vb = b->ipa_type;
|
|
|
|
if (va != vb)
|
|
|
|
return (va < vb) ? -1 : 1;
|
|
|
|
switch (a->ipa_type) {
|
|
|
|
case IPADDR_V4:
|
|
|
|
va = ntohl(a->ipaddr_v4.s_addr);
|
|
|
|
vb = ntohl(b->ipaddr_v4.s_addr);
|
|
|
|
if (va != vb)
|
|
|
|
return (va < vb) ? -1 : 1;
|
|
|
|
return 0;
|
|
|
|
case IPADDR_V6:
|
|
|
|
return memcmp((void *)&a->ipaddr_v6, (void *)&b->ipaddr_v6,
|
|
|
|
sizeof(a->ipaddr_v6));
|
2023-01-30 16:06:29 +01:00
|
|
|
case IPADDR_NONE:
|
2019-12-11 16:40:39 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2023-01-30 16:06:29 +01:00
|
|
|
|
|
|
|
assert(!"Reached end of function we should never hit");
|
2019-12-11 16:40:39 +01:00
|
|
|
}
|
|
|
|
|
2022-01-19 21:06:45 +01:00
|
|
|
static inline bool ipaddr_is_zero(const struct ipaddr *ip)
|
|
|
|
{
|
|
|
|
switch (ip->ipa_type) {
|
|
|
|
case IPADDR_NONE:
|
|
|
|
return true;
|
|
|
|
case IPADDR_V4:
|
|
|
|
return ip->ipaddr_v4.s_addr == INADDR_ANY;
|
|
|
|
case IPADDR_V6:
|
|
|
|
return IN6_IS_ADDR_UNSPECIFIED(&ip->ipaddr_v6);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-05-31 15:42:12 +02:00
|
|
|
static inline bool ipaddr_is_same(const struct ipaddr *ip1,
|
|
|
|
const struct ipaddr *ip2)
|
|
|
|
{
|
|
|
|
return ipaddr_cmp(ip1, ip2) == 0;
|
|
|
|
}
|
|
|
|
|
2024-05-21 16:07:43 +02:00
|
|
|
/* clang-format off */
|
2020-03-29 11:09:14 +02:00
|
|
|
#ifdef _FRR_ATTRIBUTE_PRINTFRR
|
|
|
|
#pragma FRR printfrr_ext "%pIA" (struct ipaddr *)
|
|
|
|
#endif
|
2024-05-21 16:07:43 +02:00
|
|
|
/* clang-format on */
|
2020-03-29 11:09:14 +02:00
|
|
|
|
2019-02-07 23:10:31 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-05-15 07:19:43 +02:00
|
|
|
#endif /* __IPADDR_H__ */
|