Line data Source code
1 : /*
2 : * IP address structure (for generic IPv4 or IPv6 address)
3 : * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
4 : *
5 : * This file is part of FRR.
6 : *
7 : * FRR is free software; you can redistribute it and/or modify it
8 : * under the terms of the GNU General Public License as published by the
9 : * Free Software Foundation; either version 2, or (at your option) any
10 : * later version.
11 : *
12 : * FRR is distributed in the hope that it will be useful, but
13 : * WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with FRR; see the file COPYING. If not, write to the Free
19 : * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : * 02111-1307, USA.
21 : */
22 :
23 : #ifndef __IPADDR_H__
24 : #define __IPADDR_H__
25 :
26 : #include <zebra.h>
27 :
28 : #include "lib/log.h"
29 :
30 : #ifdef __cplusplus
31 : extern "C" {
32 : #endif
33 :
34 : /*
35 : * Generic IP address - union of IPv4 and IPv6 address.
36 : */
37 : enum ipaddr_type_t {
38 : IPADDR_NONE = AF_UNSPEC,
39 : IPADDR_V4 = AF_INET,
40 : IPADDR_V6 = AF_INET6,
41 : };
42 :
43 : struct ipaddr {
44 : enum ipaddr_type_t ipa_type;
45 : union {
46 : uint8_t addr;
47 : struct in_addr _v4_addr;
48 : struct in6_addr _v6_addr;
49 : } ip;
50 : #define ipaddr_v4 ip._v4_addr
51 : #define ipaddr_v6 ip._v6_addr
52 : };
53 :
54 : #define IS_IPADDR_NONE(p) ((p)->ipa_type == IPADDR_NONE)
55 : #define IS_IPADDR_V4(p) ((p)->ipa_type == IPADDR_V4)
56 : #define IS_IPADDR_V6(p) ((p)->ipa_type == IPADDR_V6)
57 :
58 : #define SET_IPADDR_V4(p) (p)->ipa_type = IPADDR_V4
59 : #define SET_IPADDR_V6(p) (p)->ipa_type = IPADDR_V6
60 :
61 : #define IPADDRSZ(p) \
62 : (IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr))
63 :
64 : #define IPADDR_STRING_SIZE 46
65 :
66 0 : static inline int ipaddr_family(const struct ipaddr *ip)
67 : {
68 0 : switch (ip->ipa_type) {
69 : case IPADDR_V4:
70 : return AF_INET;
71 0 : case IPADDR_V6:
72 0 : return AF_INET6;
73 0 : case IPADDR_NONE:
74 0 : return AF_UNSPEC;
75 : }
76 :
77 0 : assert(!"Reached end of function where we should never hit");
78 : }
79 :
80 3 : static inline int str2ipaddr(const char *str, struct ipaddr *ip)
81 : {
82 3 : int ret;
83 :
84 3 : memset(ip, 0, sizeof(struct ipaddr));
85 :
86 3 : ret = inet_pton(AF_INET, str, &ip->ipaddr_v4);
87 3 : if (ret > 0) /* Valid IPv4 address. */
88 : {
89 0 : ip->ipa_type = IPADDR_V4;
90 0 : return 0;
91 : }
92 3 : ret = inet_pton(AF_INET6, str, &ip->ipaddr_v6);
93 3 : if (ret > 0) /* Valid IPv6 address. */
94 : {
95 3 : ip->ipa_type = IPADDR_V6;
96 3 : return 0;
97 : }
98 :
99 : return -1;
100 : }
101 :
102 0 : static inline char *ipaddr2str(const struct ipaddr *ip, char *buf, int size)
103 : {
104 0 : buf[0] = '\0';
105 0 : if (ip)
106 0 : inet_ntop(ip->ipa_type, &ip->ip.addr, buf, size);
107 0 : return buf;
108 : }
109 :
110 : #define IS_MAPPED_IPV6(A) \
111 : ((A)->s6_addr32[0] == 0x00000000 \
112 : ? ((A)->s6_addr32[1] == 0x00000000 \
113 : ? (ntohl((A)->s6_addr32[2]) == 0xFFFF ? 1 : 0) \
114 : : 0) \
115 : : 0)
116 :
117 : /*
118 : * Convert IPv4 address to IPv4-mapped IPv6 address which is of the
119 : * form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then
120 : * be used to represent the IPv4 address, wherever only an IPv6 address
121 : * is required.
122 : */
123 : static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6,
124 : struct in_addr in)
125 : {
126 : uint32_t addr_type = htonl(0xFFFF);
127 :
128 : memset(in6, 0, sizeof(struct in6_addr));
129 : memcpy((char *)in6 + 8, &addr_type, sizeof(addr_type));
130 : memcpy((char *)in6 + 12, &in, sizeof(struct in_addr));
131 : }
132 :
133 : /*
134 : * convert an ipv4 mapped ipv6 address back to ipv4 address
135 : */
136 0 : static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6,
137 : struct in_addr *in)
138 : {
139 0 : memset(in, 0, sizeof(struct in_addr));
140 0 : memcpy(in, (char *)in6 + 12, sizeof(struct in_addr));
141 0 : }
142 :
143 : /*
144 : * generic ordering comparison between IP addresses
145 : */
146 0 : static inline int ipaddr_cmp(const struct ipaddr *a, const struct ipaddr *b)
147 : {
148 0 : uint32_t va, vb;
149 0 : va = a->ipa_type;
150 0 : vb = b->ipa_type;
151 0 : if (va != vb)
152 0 : return (va < vb) ? -1 : 1;
153 0 : switch (a->ipa_type) {
154 0 : case IPADDR_V4:
155 0 : va = ntohl(a->ipaddr_v4.s_addr);
156 0 : vb = ntohl(b->ipaddr_v4.s_addr);
157 0 : if (va != vb)
158 0 : return (va < vb) ? -1 : 1;
159 : return 0;
160 0 : case IPADDR_V6:
161 0 : return memcmp((void *)&a->ipaddr_v6, (void *)&b->ipaddr_v6,
162 : sizeof(a->ipaddr_v6));
163 : case IPADDR_NONE:
164 : return 0;
165 : }
166 :
167 0 : assert(!"Reached end of function we should never hit");
168 : }
169 :
170 : static inline bool ipaddr_is_zero(const struct ipaddr *ip)
171 : {
172 : switch (ip->ipa_type) {
173 : case IPADDR_NONE:
174 : return true;
175 : case IPADDR_V4:
176 : return ip->ipaddr_v4.s_addr == INADDR_ANY;
177 : case IPADDR_V6:
178 : return IN6_IS_ADDR_UNSPECIFIED(&ip->ipaddr_v6);
179 : }
180 : return true;
181 : }
182 :
183 : #ifdef _FRR_ATTRIBUTE_PRINTFRR
184 : #pragma FRR printfrr_ext "%pIA" (struct ipaddr *)
185 : #endif
186 :
187 : #ifdef __cplusplus
188 : }
189 : #endif
190 :
191 : #endif /* __IPADDR_H__ */
|