]>
Commit | Line | Data |
---|---|---|
e4dfef72 | 1 | /* |
38d1d10d | 2 | * Copyright (c) 2005-2020 Red Hat, Inc. |
e4dfef72 SD |
3 | * |
4 | * All rights reserved. | |
5 | * | |
6 | * Author: Patrick Caulfield (pcaulfie@redhat.com) | |
7 | * | |
8 | * This software licensed under BSD license, the text of which follows: | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions are met: | |
12 | * | |
13 | * - Redistributions of source code must retain the above copyright notice, | |
14 | * this list of conditions and the following disclaimer. | |
15 | * - Redistributions in binary form must reproduce the above copyright notice, | |
16 | * this list of conditions and the following disclaimer in the documentation | |
17 | * and/or other materials provided with the distribution. | |
18 | * - Neither the name of the MontaVista Software, Inc. nor the names of its | |
19 | * contributors may be used to endorse or promote products derived from this | |
20 | * software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | /* IPv4/6 abstraction */ | |
36 | ||
0bc9cd90 | 37 | #include <config.h> |
031c02f5 | 38 | |
cf160dd9 SD |
39 | #include <sys/ioctl.h> |
40 | #include <sys/types.h> | |
41 | #include <sys/socket.h> | |
e4dfef72 | 42 | #include <netinet/in.h> |
cf160dd9 SD |
43 | #include <arpa/inet.h> |
44 | #include <netdb.h> | |
1e0e9a56 | 45 | #include <net/if.h> |
e4dfef72 SD |
46 | #include <string.h> |
47 | #include <stdio.h> | |
48 | #include <errno.h> | |
49 | #include <assert.h> | |
50 | #include <stdlib.h> | |
51 | #include <unistd.h> | |
27e99884 | 52 | #include <ifaddrs.h> |
27e99884 | 53 | |
e1f53138 | 54 | #include <corosync/totem/totemip.h> |
aa7daf8c | 55 | #include <corosync/logsys.h> |
e1f53138 | 56 | #include <corosync/swab.h> |
e4dfef72 SD |
57 | |
58 | #define LOCALHOST_IPV4 "127.0.0.1" | |
59 | #define LOCALHOST_IPV6 "::1" | |
60 | ||
61 | #define NETLINK_BUFSIZE 16384 | |
62 | ||
cf160dd9 SD |
63 | #ifdef SO_NOSIGPIPE |
64 | void totemip_nosigpipe(int s) | |
65 | { | |
66 | int on = 1; | |
67 | setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on)); | |
68 | } | |
7eb9ed2c | 69 | #endif |
cf160dd9 | 70 | |
e4dfef72 | 71 | /* Compare two addresses */ |
eb5919f0 JM |
72 | int totemip_equal(const struct totem_ip_address *addr1, |
73 | const struct totem_ip_address *addr2) | |
e4dfef72 SD |
74 | { |
75 | int addrlen = 0; | |
76 | ||
77 | if (addr1->family != addr2->family) | |
78 | return 0; | |
79 | ||
80 | if (addr1->family == AF_INET) { | |
81 | addrlen = sizeof(struct in_addr); | |
82 | } | |
83 | if (addr1->family == AF_INET6) { | |
84 | addrlen = sizeof(struct in6_addr); | |
85 | } | |
86 | assert(addrlen); | |
87 | ||
88 | if (memcmp(addr1->addr, addr2->addr, addrlen) == 0) | |
89 | return 1; | |
90 | else | |
91 | return 0; | |
92 | ||
93 | } | |
94 | ||
72737d39 JF |
95 | int totemip_sa_equal(const struct totem_ip_address *totem_ip, |
96 | const struct sockaddr *sa) | |
97 | { | |
98 | int res; | |
99 | ||
d4d48d92 | 100 | res = 0; |
72737d39 JF |
101 | |
102 | if (totem_ip->family != sa->sa_family) { | |
d4d48d92 | 103 | return (res); |
72737d39 JF |
104 | } |
105 | ||
106 | switch (totem_ip->family) { | |
107 | case AF_INET: | |
108 | res = (memcmp(totem_ip->addr, | |
109 | &((const struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr)) == 0); | |
110 | break; | |
111 | case AF_INET6: | |
112 | res = (memcmp(totem_ip->addr, | |
113 | &((const struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr)) == 0); | |
114 | break; | |
115 | default: | |
116 | assert(0); | |
117 | } | |
118 | ||
119 | return (res); | |
120 | } | |
121 | ||
e4dfef72 | 122 | /* Copy a totem_ip_address */ |
eb5919f0 JM |
123 | void totemip_copy(struct totem_ip_address *addr1, |
124 | const struct totem_ip_address *addr2) | |
e4dfef72 SD |
125 | { |
126 | memcpy(addr1, addr2, sizeof(struct totem_ip_address)); | |
127 | } | |
128 | ||
10be299e AS |
129 | /* |
130 | * Multicast address range is 224.0.0.0 to 239.255.255.255 this | |
131 | * translates to the first 4 bits == 1110 (0xE). | |
132 | * http://en.wikipedia.org/wiki/Multicast_address | |
133 | */ | |
134 | int32_t totemip_is_mcast(struct totem_ip_address *ip_addr) | |
135 | { | |
136 | uint32_t addr = 0; | |
137 | ||
83f528b4 SD |
138 | memcpy (&addr, ip_addr->addr, sizeof (uint32_t)); |
139 | ||
10be299e | 140 | if (ip_addr->family == AF_INET) { |
83f528b4 | 141 | addr = ntohl(addr); |
10be299e AS |
142 | if ((addr >> 28) != 0xE) { |
143 | return -1; | |
144 | } | |
145 | } | |
146 | return 0; | |
147 | } | |
148 | ||
e4dfef72 SD |
149 | /* For sorting etc. params are void * for qsort's benefit */ |
150 | int totemip_compare(const void *a, const void *b) | |
151 | { | |
152 | int i; | |
3b9f70d2 SD |
153 | const struct totem_ip_address *totemip_a = (const struct totem_ip_address *)a; |
154 | const struct totem_ip_address *totemip_b = (const struct totem_ip_address *)b; | |
1c58c5ad SD |
155 | struct in_addr ipv4_a1; |
156 | struct in_addr ipv4_a2; | |
157 | struct in6_addr ipv6_a1; | |
158 | struct in6_addr ipv6_a2; | |
159 | unsigned short family; | |
160 | ||
161 | /* | |
162 | * Use memcpy to align since totem_ip_address is unaligned on various archs | |
163 | */ | |
164 | memcpy (&family, &totemip_a->family, sizeof (unsigned short)); | |
165 | ||
166 | if (family == AF_INET) { | |
167 | memcpy (&ipv4_a1, totemip_a->addr, sizeof (struct in_addr)); | |
168 | memcpy (&ipv4_a2, totemip_b->addr, sizeof (struct in_addr)); | |
169 | if (ipv4_a1.s_addr == ipv4_a2.s_addr) { | |
170 | return (0); | |
171 | } | |
172 | if (htonl(ipv4_a1.s_addr) < htonl(ipv4_a2.s_addr)) { | |
e4dfef72 | 173 | return -1; |
1c58c5ad | 174 | } else { |
e4dfef72 | 175 | return +1; |
1c58c5ad SD |
176 | } |
177 | } else | |
178 | if (family == AF_INET6) { | |
1c58c5ad | 179 | /* |
e8225b66 | 180 | * We can only compare 8 bits at time for portability reasons |
1c58c5ad SD |
181 | */ |
182 | memcpy (&ipv6_a1, totemip_a->addr, sizeof (struct in6_addr)); | |
183 | memcpy (&ipv6_a2, totemip_b->addr, sizeof (struct in6_addr)); | |
e8225b66 SD |
184 | for (i = 0; i < 16; i++) { |
185 | int res = ipv6_a1.s6_addr[i] - | |
186 | ipv6_a2.s6_addr[i]; | |
1c58c5ad SD |
187 | if (res) { |
188 | return res; | |
189 | } | |
e4dfef72 | 190 | } |
1c58c5ad SD |
191 | return 0; |
192 | } else { | |
193 | /* | |
194 | * Family not set, should be! | |
195 | */ | |
196 | assert (0); | |
e4dfef72 | 197 | } |
e1f53138 | 198 | return 0; |
e4dfef72 SD |
199 | } |
200 | ||
201 | /* Build a localhost totem_ip_address */ | |
202 | int totemip_localhost(int family, struct totem_ip_address *localhost) | |
203 | { | |
3b9f70d2 | 204 | const char *addr_text; |
e4dfef72 | 205 | |
7b2ddfa4 SD |
206 | memset (localhost, 0, sizeof (struct totem_ip_address)); |
207 | ||
f99f3836 | 208 | if (family == AF_INET) { |
e4dfef72 | 209 | addr_text = LOCALHOST_IPV4; |
a7f4b6d8 | 210 | if (inet_pton(family, addr_text, (char *)&localhost->nodeid) <= 0) { |
f99f3836 SD |
211 | return -1; |
212 | } | |
213 | } else { | |
e4dfef72 | 214 | addr_text = LOCALHOST_IPV6; |
f99f3836 | 215 | } |
e4dfef72 SD |
216 | |
217 | if (inet_pton(family, addr_text, (char *)localhost->addr) <= 0) | |
218 | return -1; | |
219 | ||
f99f3836 SD |
220 | localhost->family = family; |
221 | ||
e4dfef72 SD |
222 | return 0; |
223 | } | |
224 | ||
eb5919f0 | 225 | int totemip_localhost_check(const struct totem_ip_address *addr) |
e4dfef72 SD |
226 | { |
227 | struct totem_ip_address localhost; | |
228 | ||
229 | if (totemip_localhost(addr->family, &localhost)) | |
230 | return 0; | |
231 | return totemip_equal(addr, &localhost); | |
232 | } | |
233 | ||
69857efb JF |
234 | const char *totemip_sa_print(const struct sockaddr *sa) |
235 | { | |
236 | static char buf[INET6_ADDRSTRLEN]; | |
237 | ||
238 | buf[0] = 0; | |
239 | ||
240 | switch (sa->sa_family) { | |
241 | case AF_INET: | |
242 | inet_ntop(sa->sa_family, &((struct sockaddr_in *)(sa))->sin_addr, buf, | |
243 | INET6_ADDRSTRLEN); | |
244 | break; | |
245 | case AF_INET6: | |
246 | inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)(sa))->sin6_addr, buf, | |
247 | INET6_ADDRSTRLEN); | |
248 | break; | |
249 | default: | |
250 | return (NULL); | |
251 | } | |
252 | ||
253 | return (buf); | |
254 | } | |
255 | ||
a6603416 | 256 | const char *totemip_print(const struct totem_ip_address *addr) |
e4dfef72 SD |
257 | { |
258 | static char buf[INET6_ADDRSTRLEN]; | |
259 | ||
3b9f70d2 | 260 | return (inet_ntop(addr->family, addr->addr, buf, sizeof(buf))); |
e4dfef72 SD |
261 | } |
262 | ||
263 | /* Make a totem_ip_address into a usable sockaddr_storage */ | |
264 | int totemip_totemip_to_sockaddr_convert(struct totem_ip_address *ip_addr, | |
265 | uint16_t port, struct sockaddr_storage *saddr, int *addrlen) | |
266 | { | |
267 | int ret = -1; | |
268 | ||
269 | if (ip_addr->family == AF_INET) { | |
270 | struct sockaddr_in *sin = (struct sockaddr_in *)saddr; | |
271 | ||
272 | memset(sin, 0, sizeof(struct sockaddr_in)); | |
6098ef2c | 273 | #ifdef HAVE_SOCK_SIN_LEN |
cf160dd9 SD |
274 | sin->sin_len = sizeof(struct sockaddr_in); |
275 | #endif | |
e4dfef72 | 276 | sin->sin_family = ip_addr->family; |
476bc5e2 | 277 | sin->sin_port = ntohs(port); |
e4dfef72 | 278 | memcpy(&sin->sin_addr, ip_addr->addr, sizeof(struct in_addr)); |
e4dfef72 SD |
279 | *addrlen = sizeof(struct sockaddr_in); |
280 | ret = 0; | |
281 | } | |
282 | ||
283 | if (ip_addr->family == AF_INET6) { | |
284 | struct sockaddr_in6 *sin = (struct sockaddr_in6 *)saddr; | |
285 | ||
286 | memset(sin, 0, sizeof(struct sockaddr_in6)); | |
6098ef2c | 287 | #ifdef HAVE_SOCK_SIN6_LEN |
cf160dd9 SD |
288 | sin->sin6_len = sizeof(struct sockaddr_in6); |
289 | #endif | |
e4dfef72 | 290 | sin->sin6_family = ip_addr->family; |
476bc5e2 | 291 | sin->sin6_port = ntohs(port); |
cd6cc90a | 292 | sin->sin6_scope_id = 2; |
e4dfef72 SD |
293 | memcpy(&sin->sin6_addr, ip_addr->addr, sizeof(struct in6_addr)); |
294 | ||
295 | *addrlen = sizeof(struct sockaddr_in6); | |
296 | ret = 0; | |
297 | } | |
298 | ||
299 | return ret; | |
300 | } | |
301 | ||
a84ade70 JF |
302 | /* |
303 | * Converts an address string string into a totem_ip_address. ip_version enum | |
304 | * defines order. | |
305 | */ | |
306 | int totemip_parse(struct totem_ip_address *totemip, const char *addr, | |
307 | enum totem_ip_version_enum ip_version) | |
e4dfef72 | 308 | { |
cf160dd9 | 309 | struct addrinfo *ainfo; |
2ab4d418 JF |
310 | struct addrinfo *ainfo_iter; |
311 | struct addrinfo *ainfo_ipv4; | |
312 | struct addrinfo *ainfo_ipv6; | |
313 | struct addrinfo *ainfo_final; | |
cf160dd9 | 314 | struct addrinfo ahints; |
e4dfef72 SD |
315 | struct sockaddr_in *sa; |
316 | struct sockaddr_in6 *sa6; | |
317 | int ret; | |
aa7daf8c | 318 | int debug_ip_family; |
2ab4d418 | 319 | int ai_family; |
e4dfef72 | 320 | |
cf160dd9 SD |
321 | memset(&ahints, 0, sizeof(ahints)); |
322 | ahints.ai_socktype = SOCK_DGRAM; | |
323 | ahints.ai_protocol = IPPROTO_UDP; | |
e4dfef72 | 324 | |
2ab4d418 JF |
325 | ai_family = AF_UNSPEC; |
326 | debug_ip_family = 0; | |
a84ade70 JF |
327 | |
328 | switch (ip_version) { | |
329 | case TOTEM_IP_VERSION_4: | |
2ab4d418 JF |
330 | ai_family = AF_INET; |
331 | debug_ip_family = 4; | |
a84ade70 JF |
332 | break; |
333 | case TOTEM_IP_VERSION_6: | |
2ab4d418 JF |
334 | ai_family = AF_INET6; |
335 | debug_ip_family = 6; | |
a84ade70 JF |
336 | break; |
337 | case TOTEM_IP_VERSION_6_4: | |
2ab4d418 JF |
338 | case TOTEM_IP_VERSION_4_6: |
339 | /* | |
340 | * ai_family and debug_ip_family are already set correctly | |
341 | */ | |
a84ade70 JF |
342 | break; |
343 | } | |
344 | ||
2ab4d418 JF |
345 | ahints.ai_family = ai_family; |
346 | ||
a84ade70 | 347 | ret = getaddrinfo(addr, NULL, &ahints, &ainfo); |
aa7daf8c | 348 | |
2ab4d418 JF |
349 | if (ret == 0 && ai_family == AF_UNSPEC) { |
350 | ainfo_ipv4 = ainfo_ipv6 = NULL; | |
351 | ||
352 | /* | |
353 | * Walk thru results and store first AF_INET and AF_INET6 | |
354 | */ | |
355 | for (ainfo_iter = ainfo; ainfo_iter != NULL; ainfo_iter = ainfo_iter->ai_next) { | |
356 | if (ainfo_iter->ai_family == AF_INET && ainfo_ipv4 == NULL) { | |
357 | ainfo_ipv4 = ainfo_iter; | |
358 | } | |
aa7daf8c | 359 | |
2ab4d418 JF |
360 | if (ainfo_iter->ai_family == AF_INET6 && ainfo_ipv6 == NULL) { |
361 | ainfo_ipv6 = ainfo_iter; | |
362 | } | |
363 | } | |
aa7daf8c | 364 | |
2ab4d418 JF |
365 | if (ip_version == TOTEM_IP_VERSION_6_4) { |
366 | if (ainfo_ipv6 != NULL) { | |
367 | ainfo_final = ainfo_ipv6; | |
368 | } else { | |
369 | ainfo_final = ainfo_ipv4; | |
370 | } | |
371 | } else { | |
372 | if (ainfo_ipv4 != NULL) { | |
373 | ainfo_final = ainfo_ipv4; | |
374 | } else { | |
375 | ainfo_final = ainfo_ipv6; | |
376 | } | |
377 | } | |
378 | } else if (ret == 0) { | |
379 | ainfo_final = ainfo; | |
380 | } else { | |
381 | ainfo_final = NULL; | |
aa7daf8c | 382 | } |
e4dfef72 | 383 | |
2ab4d418 JF |
384 | if (ainfo_final == NULL) { |
385 | if (ret == 0) { | |
386 | freeaddrinfo(ainfo); | |
387 | } | |
388 | ||
389 | if (debug_ip_family == 0) { | |
390 | log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IP address of %s not resolvable", | |
391 | addr); | |
392 | } else { | |
393 | log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IPv%u address of %s not resolvable", | |
394 | debug_ip_family, addr); | |
395 | } | |
e4dfef72 | 396 | |
2ab4d418 JF |
397 | return (-1); |
398 | } | |
399 | ||
400 | totemip->family = ainfo_final->ai_family; | |
401 | if (ainfo_final->ai_family == AF_INET) { | |
402 | sa = (struct sockaddr_in *)ainfo_final->ai_addr; | |
e4dfef72 | 403 | memcpy(totemip->addr, &sa->sin_addr, sizeof(struct in_addr)); |
2ab4d418 JF |
404 | debug_ip_family = 4; |
405 | } else { | |
406 | sa6 = (struct sockaddr_in6 *)ainfo_final->ai_addr; | |
e4dfef72 | 407 | memcpy(totemip->addr, &sa6->sin6_addr, sizeof(struct in6_addr)); |
2ab4d418 JF |
408 | debug_ip_family = 6; |
409 | } | |
e4dfef72 | 410 | |
2ab4d418 | 411 | log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IPv%u address of %s resolved as %s", |
aa7daf8c JF |
412 | debug_ip_family, addr, totemip_print(totemip)); |
413 | ||
390391ac | 414 | freeaddrinfo(ainfo); |
2ab4d418 JF |
415 | |
416 | return (0); | |
e4dfef72 SD |
417 | } |
418 | ||
419 | /* Make a sockaddr_* into a totem_ip_address */ | |
eb5919f0 JM |
420 | int totemip_sockaddr_to_totemip_convert(const struct sockaddr_storage *saddr, |
421 | struct totem_ip_address *ip_addr) | |
e4dfef72 SD |
422 | { |
423 | int ret = -1; | |
424 | ||
425 | ip_addr->family = saddr->ss_family; | |
426 | ip_addr->nodeid = 0; | |
427 | ||
428 | if (saddr->ss_family == AF_INET) { | |
eb5919f0 | 429 | const struct sockaddr_in *sin = (const struct sockaddr_in *)saddr; |
e4dfef72 SD |
430 | |
431 | memcpy(ip_addr->addr, &sin->sin_addr, sizeof(struct in_addr)); | |
432 | ret = 0; | |
433 | } | |
434 | ||
435 | if (saddr->ss_family == AF_INET6) { | |
eb5919f0 JM |
436 | const struct sockaddr_in6 *sin |
437 | = (const struct sockaddr_in6 *)saddr; | |
e4dfef72 SD |
438 | |
439 | memcpy(ip_addr->addr, &sin->sin6_addr, sizeof(struct in6_addr)); | |
440 | ||
441 | ret = 0; | |
442 | } | |
443 | return ret; | |
444 | } | |
445 | ||
b4c06e52 | 446 | int totemip_getifaddrs(struct qb_list_head *addrs) |
27e99884 JF |
447 | { |
448 | struct ifaddrs *ifap, *ifa; | |
449 | struct totem_ip_if_address *if_addr; | |
450 | ||
451 | if (getifaddrs(&ifap) != 0) | |
452 | return (-1); | |
453 | ||
b4c06e52 | 454 | qb_list_init(addrs); |
27e99884 JF |
455 | |
456 | for (ifa = ifap; ifa; ifa = ifa->ifa_next) { | |
457 | if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL) | |
458 | continue ; | |
459 | ||
460 | if ((ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6) || | |
ee59122a JF |
461 | (ifa->ifa_netmask->sa_family != AF_INET && ifa->ifa_netmask->sa_family != AF_INET6 && |
462 | ifa->ifa_netmask->sa_family != 0)) | |
27e99884 JF |
463 | continue ; |
464 | ||
ee59122a JF |
465 | if (ifa->ifa_netmask->sa_family == 0) { |
466 | ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; | |
467 | } | |
468 | ||
27e99884 JF |
469 | if_addr = malloc(sizeof(struct totem_ip_if_address)); |
470 | if (if_addr == NULL) { | |
471 | goto error_free_ifaddrs; | |
472 | } | |
473 | ||
b4c06e52 | 474 | qb_list_init(&if_addr->list); |
27e99884 JF |
475 | |
476 | memset(if_addr, 0, sizeof(struct totem_ip_if_address)); | |
477 | ||
478 | if_addr->interface_up = ifa->ifa_flags & IFF_UP; | |
479 | if_addr->interface_num = if_nametoindex(ifa->ifa_name); | |
480 | if_addr->name = strdup(ifa->ifa_name); | |
481 | if (if_addr->name == NULL) { | |
482 | goto error_free_addr; | |
483 | } | |
484 | ||
485 | if (totemip_sockaddr_to_totemip_convert((const struct sockaddr_storage *)ifa->ifa_addr, | |
486 | &if_addr->ip_addr) == -1) { | |
487 | goto error_free_addr_name; | |
488 | } | |
489 | ||
490 | if (totemip_sockaddr_to_totemip_convert((const struct sockaddr_storage *)ifa->ifa_netmask, | |
491 | &if_addr->mask_addr) == -1) { | |
492 | goto error_free_addr_name; | |
493 | } | |
494 | ||
b4c06e52 | 495 | qb_list_add_tail(&if_addr->list, addrs); |
27e99884 JF |
496 | } |
497 | ||
498 | freeifaddrs(ifap); | |
499 | ||
500 | return (0); | |
501 | ||
502 | error_free_addr_name: | |
503 | free(if_addr->name); | |
504 | ||
505 | error_free_addr: | |
506 | free(if_addr); | |
507 | ||
508 | error_free_ifaddrs: | |
509 | totemip_freeifaddrs(addrs); | |
510 | freeifaddrs(ifap); | |
511 | return (-1); | |
512 | } | |
27e99884 | 513 | |
b4c06e52 | 514 | void totemip_freeifaddrs(struct qb_list_head *addrs) |
27e99884 JF |
515 | { |
516 | struct totem_ip_if_address *if_addr; | |
1f90c31b | 517 | struct qb_list_head *list, *tmp_iter; |
27e99884 | 518 | |
1f90c31b | 519 | qb_list_for_each_safe(list, tmp_iter, addrs) { |
b4c06e52 | 520 | if_addr = qb_list_entry(list, struct totem_ip_if_address, list); |
27e99884 JF |
521 | |
522 | free(if_addr->name); | |
b4c06e52 | 523 | qb_list_del(&if_addr->list); |
27e99884 JF |
524 | free(if_addr); |
525 | } | |
b4c06e52 | 526 | qb_list_init(addrs); |
27e99884 | 527 | } |
fd47fddc JF |
528 | |
529 | int totemip_iface_check(struct totem_ip_address *bindnet, | |
530 | struct totem_ip_address *boundto, | |
531 | int *interface_up, | |
532 | int *interface_num, | |
533 | int mask_high_bit) | |
534 | { | |
b4c06e52 MJ |
535 | struct qb_list_head addrs; |
536 | struct qb_list_head *list; | |
fd47fddc JF |
537 | struct totem_ip_if_address *if_addr; |
538 | struct totem_ip_address bn_netaddr, if_netaddr; | |
539 | socklen_t addr_len; | |
540 | socklen_t si; | |
541 | int res = -1; | |
2894f33c JF |
542 | int exact_match_found = 0; |
543 | int net_match_found = 0; | |
fd47fddc | 544 | |
25381738 JF |
545 | *interface_up = 0; |
546 | *interface_num = 0; | |
547 | ||
fd47fddc JF |
548 | if (totemip_getifaddrs(&addrs) == -1) { |
549 | return (-1); | |
550 | } | |
551 | ||
1f90c31b | 552 | qb_list_for_each(list, &addrs) { |
b4c06e52 | 553 | if_addr = qb_list_entry(list, struct totem_ip_if_address, list); |
fd47fddc JF |
554 | |
555 | if (bindnet->family != if_addr->ip_addr.family) | |
556 | continue ; | |
557 | ||
558 | addr_len = 0; | |
559 | ||
560 | switch (bindnet->family) { | |
561 | case AF_INET: | |
562 | addr_len = sizeof(struct in_addr); | |
563 | break; | |
564 | case AF_INET6: | |
565 | addr_len = sizeof(struct in6_addr); | |
566 | break; | |
567 | } | |
568 | ||
569 | if (addr_len == 0) | |
570 | continue ; | |
571 | ||
572 | totemip_copy(&bn_netaddr, bindnet); | |
573 | totemip_copy(&if_netaddr, &if_addr->ip_addr); | |
574 | ||
2894f33c JF |
575 | if (totemip_equal(&bn_netaddr, &if_netaddr)) { |
576 | exact_match_found = 1; | |
577 | } | |
578 | ||
fd47fddc JF |
579 | for (si = 0; si < addr_len; si++) { |
580 | bn_netaddr.addr[si] = bn_netaddr.addr[si] & if_addr->mask_addr.addr[si]; | |
581 | if_netaddr.addr[si] = if_netaddr.addr[si] & if_addr->mask_addr.addr[si]; | |
582 | } | |
583 | ||
2894f33c | 584 | if (exact_match_found || (!net_match_found && totemip_equal(&bn_netaddr, &if_netaddr))) { |
fd47fddc JF |
585 | totemip_copy(boundto, &if_addr->ip_addr); |
586 | boundto->nodeid = bindnet->nodeid; | |
587 | *interface_up = if_addr->interface_up; | |
588 | *interface_num = if_addr->interface_num; | |
589 | ||
2894f33c | 590 | net_match_found = 1; |
fd47fddc | 591 | res = 0; |
2894f33c JF |
592 | |
593 | if (exact_match_found) { | |
594 | goto finished; | |
595 | } | |
fd47fddc JF |
596 | } |
597 | } | |
598 | ||
599 | finished: | |
600 | totemip_freeifaddrs(&addrs); | |
601 | return (res); | |
602 | } | |
03f95dda JF |
603 | |
604 | #define TOTEMIP_UDP_HEADER_SIZE 8 | |
605 | #define TOTEMIP_IPV4_HEADER_SIZE 20 | |
606 | #define TOTEMIP_IPV6_HEADER_SIZE 40 | |
607 | ||
608 | size_t totemip_udpip_header_size(int family) | |
609 | { | |
610 | size_t header_size; | |
611 | ||
612 | header_size = 0; | |
613 | ||
614 | switch (family) { | |
615 | case AF_INET: | |
616 | header_size = TOTEMIP_UDP_HEADER_SIZE + TOTEMIP_IPV4_HEADER_SIZE; | |
617 | break; | |
618 | case AF_INET6: | |
619 | header_size = TOTEMIP_UDP_HEADER_SIZE + TOTEMIP_IPV6_HEADER_SIZE; | |
620 | break; | |
621 | } | |
622 | ||
623 | return (header_size); | |
624 | } |