corosync  3.0.1
totemip.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005-2019 Red Hat, Inc.
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 
37 #include <config.h>
38 
39 #include <sys/ioctl.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #include <net/if.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <errno.h>
49 #include <assert.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <ifaddrs.h>
53 
54 #include <corosync/totem/totemip.h>
55 #include <corosync/logsys.h>
56 #include <corosync/swab.h>
57 
58 #define LOCALHOST_IPV4 "127.0.0.1"
59 #define LOCALHOST_IPV6 "::1"
60 
61 #define NETLINK_BUFSIZE 16384
62 
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 }
69 #endif
70 
71 /* Compare two addresses */
72 int totemip_equal(const struct totem_ip_address *addr1,
73  const struct totem_ip_address *addr2)
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 
95 /* Copy a totem_ip_address */
96 void totemip_copy(struct totem_ip_address *addr1,
97  const struct totem_ip_address *addr2)
98 {
99  memcpy(addr1, addr2, sizeof(struct totem_ip_address));
100 }
101 
103  const struct totem_ip_address *addr2)
104 {
105  addr1->nodeid = swab32(addr2->nodeid);
106  addr1->family = swab16(addr2->family);
107  memcpy(addr1->addr, addr2->addr, TOTEMIP_ADDRLEN);
108 }
109 
110 /*
111  * Multicast address range is 224.0.0.0 to 239.255.255.255 this
112  * translates to the first 4 bits == 1110 (0xE).
113  * http://en.wikipedia.org/wiki/Multicast_address
114  */
115 int32_t totemip_is_mcast(struct totem_ip_address *ip_addr)
116 {
117  uint32_t addr = 0;
118 
119  memcpy (&addr, ip_addr->addr, sizeof (uint32_t));
120 
121  if (ip_addr->family == AF_INET) {
122  addr = ntohl(addr);
123  if ((addr >> 28) != 0xE) {
124  return -1;
125  }
126  }
127  return 0;
128 }
129 
130 /* For sorting etc. params are void * for qsort's benefit */
131 int totemip_compare(const void *a, const void *b)
132 {
133  int i;
134  const struct totem_ip_address *totemip_a = (const struct totem_ip_address *)a;
135  const struct totem_ip_address *totemip_b = (const struct totem_ip_address *)b;
136  struct in_addr ipv4_a1;
137  struct in_addr ipv4_a2;
138  struct in6_addr ipv6_a1;
139  struct in6_addr ipv6_a2;
140  unsigned short family;
141 
142  /*
143  * Use memcpy to align since totem_ip_address is unaligned on various archs
144  */
145  memcpy (&family, &totemip_a->family, sizeof (unsigned short));
146 
147  if (family == AF_INET) {
148  memcpy (&ipv4_a1, totemip_a->addr, sizeof (struct in_addr));
149  memcpy (&ipv4_a2, totemip_b->addr, sizeof (struct in_addr));
150  if (ipv4_a1.s_addr == ipv4_a2.s_addr) {
151  return (0);
152  }
153  if (htonl(ipv4_a1.s_addr) < htonl(ipv4_a2.s_addr)) {
154  return -1;
155  } else {
156  return +1;
157  }
158  } else
159  if (family == AF_INET6) {
160  /*
161  * We can only compare 8 bits at time for portability reasons
162  */
163  memcpy (&ipv6_a1, totemip_a->addr, sizeof (struct in6_addr));
164  memcpy (&ipv6_a2, totemip_b->addr, sizeof (struct in6_addr));
165  for (i = 0; i < 16; i++) {
166  int res = ipv6_a1.s6_addr[i] -
167  ipv6_a2.s6_addr[i];
168  if (res) {
169  return res;
170  }
171  }
172  return 0;
173  } else {
174  /*
175  * Family not set, should be!
176  */
177  assert (0);
178  }
179  return 0;
180 }
181 
182 /* Build a localhost totem_ip_address */
183 int totemip_localhost(int family, struct totem_ip_address *localhost)
184 {
185  const char *addr_text;
186 
187  memset (localhost, 0, sizeof (struct totem_ip_address));
188 
189  if (family == AF_INET) {
190  addr_text = LOCALHOST_IPV4;
191  if (inet_pton(family, addr_text, (char *)&localhost->nodeid) <= 0) {
192  return -1;
193  }
194  } else {
195  addr_text = LOCALHOST_IPV6;
196  }
197 
198  if (inet_pton(family, addr_text, (char *)localhost->addr) <= 0)
199  return -1;
200 
201  localhost->family = family;
202 
203  return 0;
204 }
205 
207 {
208  struct totem_ip_address localhost;
209 
210  if (totemip_localhost(addr->family, &localhost))
211  return 0;
212  return totemip_equal(addr, &localhost);
213 }
214 
215 const char *totemip_sa_print(const struct sockaddr *sa)
216 {
217  static char buf[INET6_ADDRSTRLEN];
218 
219  buf[0] = 0;
220 
221  switch (sa->sa_family) {
222  case AF_INET:
223  inet_ntop(sa->sa_family, &((struct sockaddr_in *)(sa))->sin_addr, buf,
224  INET6_ADDRSTRLEN);
225  break;
226  case AF_INET6:
227  inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)(sa))->sin6_addr, buf,
228  INET6_ADDRSTRLEN);
229  break;
230  default:
231  return (NULL);
232  }
233 
234  return (buf);
235 }
236 
237 const char *totemip_print(const struct totem_ip_address *addr)
238 {
239  static char buf[INET6_ADDRSTRLEN];
240 
241  return (inet_ntop(addr->family, addr->addr, buf, sizeof(buf)));
242 }
243 
244 /* Make a totem_ip_address into a usable sockaddr_storage */
246  uint16_t port, struct sockaddr_storage *saddr, int *addrlen)
247 {
248  int ret = -1;
249 
250  if (ip_addr->family == AF_INET) {
251  struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
252 
253  memset(sin, 0, sizeof(struct sockaddr_in));
254 #ifdef HAVE_SOCK_SIN_LEN
255  sin->sin_len = sizeof(struct sockaddr_in);
256 #endif
257  sin->sin_family = ip_addr->family;
258  sin->sin_port = ntohs(port);
259  memcpy(&sin->sin_addr, ip_addr->addr, sizeof(struct in_addr));
260  *addrlen = sizeof(struct sockaddr_in);
261  ret = 0;
262  }
263 
264  if (ip_addr->family == AF_INET6) {
265  struct sockaddr_in6 *sin = (struct sockaddr_in6 *)saddr;
266 
267  memset(sin, 0, sizeof(struct sockaddr_in6));
268 #ifdef HAVE_SOCK_SIN6_LEN
269  sin->sin6_len = sizeof(struct sockaddr_in6);
270 #endif
271  sin->sin6_family = ip_addr->family;
272  sin->sin6_port = ntohs(port);
273  sin->sin6_scope_id = 2;
274  memcpy(&sin->sin6_addr, ip_addr->addr, sizeof(struct in6_addr));
275 
276  *addrlen = sizeof(struct sockaddr_in6);
277  ret = 0;
278  }
279 
280  return ret;
281 }
282 
283 /*
284  * Converts an address string string into a totem_ip_address. ip_version enum
285  * defines order.
286  */
287 int totemip_parse(struct totem_ip_address *totemip, const char *addr,
288  enum totem_ip_version_enum ip_version)
289 {
290  struct addrinfo *ainfo;
291  struct addrinfo *ainfo_iter;
292  struct addrinfo *ainfo_ipv4;
293  struct addrinfo *ainfo_ipv6;
294  struct addrinfo *ainfo_final;
295  struct addrinfo ahints;
296  struct sockaddr_in *sa;
297  struct sockaddr_in6 *sa6;
298  int ret;
299  int debug_ip_family;
300  int ai_family;
301 
302  memset(&ahints, 0, sizeof(ahints));
303  ahints.ai_socktype = SOCK_DGRAM;
304  ahints.ai_protocol = IPPROTO_UDP;
305 
306  ai_family = AF_UNSPEC;
307  debug_ip_family = 0;
308 
309  switch (ip_version) {
310  case TOTEM_IP_VERSION_4:
311  ai_family = AF_INET;
312  debug_ip_family = 4;
313  break;
314  case TOTEM_IP_VERSION_6:
315  ai_family = AF_INET6;
316  debug_ip_family = 6;
317  break;
320  /*
321  * ai_family and debug_ip_family are already set correctly
322  */
323  break;
324  }
325 
326  ahints.ai_family = ai_family;
327 
328  ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
329 
330  if (ret == 0 && ai_family == AF_UNSPEC) {
331  ainfo_ipv4 = ainfo_ipv6 = NULL;
332 
333  /*
334  * Walk thru results and store first AF_INET and AF_INET6
335  */
336  for (ainfo_iter = ainfo; ainfo_iter != NULL; ainfo_iter = ainfo_iter->ai_next) {
337  if (ainfo_iter->ai_family == AF_INET && ainfo_ipv4 == NULL) {
338  ainfo_ipv4 = ainfo_iter;
339  }
340 
341  if (ainfo_iter->ai_family == AF_INET6 && ainfo_ipv6 == NULL) {
342  ainfo_ipv6 = ainfo_iter;
343  }
344  }
345 
346  if (ip_version == TOTEM_IP_VERSION_6_4) {
347  if (ainfo_ipv6 != NULL) {
348  ainfo_final = ainfo_ipv6;
349  } else {
350  ainfo_final = ainfo_ipv4;
351  }
352  } else {
353  if (ainfo_ipv4 != NULL) {
354  ainfo_final = ainfo_ipv4;
355  } else {
356  ainfo_final = ainfo_ipv6;
357  }
358  }
359  } else if (ret == 0) {
360  ainfo_final = ainfo;
361  } else {
362  ainfo_final = NULL;
363  }
364 
365  if (ainfo_final == NULL) {
366  if (ret == 0) {
367  freeaddrinfo(ainfo);
368  }
369 
370  if (debug_ip_family == 0) {
371  log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IP address of %s not resolvable",
372  addr);
373  } else {
374  log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IPv%u address of %s not resolvable",
375  debug_ip_family, addr);
376  }
377 
378  return (-1);
379  }
380 
381  totemip->family = ainfo_final->ai_family;
382  if (ainfo_final->ai_family == AF_INET) {
383  sa = (struct sockaddr_in *)ainfo_final->ai_addr;
384  memcpy(totemip->addr, &sa->sin_addr, sizeof(struct in_addr));
385  debug_ip_family = 4;
386  } else {
387  sa6 = (struct sockaddr_in6 *)ainfo_final->ai_addr;
388  memcpy(totemip->addr, &sa6->sin6_addr, sizeof(struct in6_addr));
389  debug_ip_family = 6;
390  }
391 
392  log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IPv%u address of %s resolved as %s",
393  debug_ip_family, addr, totemip_print(totemip));
394 
395  freeaddrinfo(ainfo);
396 
397  return (0);
398 }
399 
400 /* Make a sockaddr_* into a totem_ip_address */
401 int totemip_sockaddr_to_totemip_convert(const struct sockaddr_storage *saddr,
402  struct totem_ip_address *ip_addr)
403 {
404  int ret = -1;
405 
406  ip_addr->family = saddr->ss_family;
407  ip_addr->nodeid = 0;
408 
409  if (saddr->ss_family == AF_INET) {
410  const struct sockaddr_in *sin = (const struct sockaddr_in *)saddr;
411 
412  memcpy(ip_addr->addr, &sin->sin_addr, sizeof(struct in_addr));
413  ret = 0;
414  }
415 
416  if (saddr->ss_family == AF_INET6) {
417  const struct sockaddr_in6 *sin
418  = (const struct sockaddr_in6 *)saddr;
419 
420  memcpy(ip_addr->addr, &sin->sin6_addr, sizeof(struct in6_addr));
421 
422  ret = 0;
423  }
424  return ret;
425 }
426 
427 int totemip_getifaddrs(struct qb_list_head *addrs)
428 {
429  struct ifaddrs *ifap, *ifa;
430  struct totem_ip_if_address *if_addr;
431 
432  if (getifaddrs(&ifap) != 0)
433  return (-1);
434 
435  qb_list_init(addrs);
436 
437  for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
438  if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL)
439  continue ;
440 
441  if ((ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6) ||
442  (ifa->ifa_netmask->sa_family != AF_INET && ifa->ifa_netmask->sa_family != AF_INET6 &&
443  ifa->ifa_netmask->sa_family != 0))
444  continue ;
445 
446  if (ifa->ifa_netmask->sa_family == 0) {
447  ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
448  }
449 
450  if_addr = malloc(sizeof(struct totem_ip_if_address));
451  if (if_addr == NULL) {
452  goto error_free_ifaddrs;
453  }
454 
455  qb_list_init(&if_addr->list);
456 
457  memset(if_addr, 0, sizeof(struct totem_ip_if_address));
458 
459  if_addr->interface_up = ifa->ifa_flags & IFF_UP;
460  if_addr->interface_num = if_nametoindex(ifa->ifa_name);
461  if_addr->name = strdup(ifa->ifa_name);
462  if (if_addr->name == NULL) {
463  goto error_free_addr;
464  }
465 
466  if (totemip_sockaddr_to_totemip_convert((const struct sockaddr_storage *)ifa->ifa_addr,
467  &if_addr->ip_addr) == -1) {
468  goto error_free_addr_name;
469  }
470 
471  if (totemip_sockaddr_to_totemip_convert((const struct sockaddr_storage *)ifa->ifa_netmask,
472  &if_addr->mask_addr) == -1) {
473  goto error_free_addr_name;
474  }
475 
476  qb_list_add_tail(&if_addr->list, addrs);
477  }
478 
479  freeifaddrs(ifap);
480 
481  return (0);
482 
483 error_free_addr_name:
484  free(if_addr->name);
485 
486 error_free_addr:
487  free(if_addr);
488 
489 error_free_ifaddrs:
490  totemip_freeifaddrs(addrs);
491  freeifaddrs(ifap);
492  return (-1);
493 }
494 
495 void totemip_freeifaddrs(struct qb_list_head *addrs)
496 {
497  struct totem_ip_if_address *if_addr;
498  struct qb_list_head *list, *tmp_iter;
499 
500  qb_list_for_each_safe(list, tmp_iter, addrs) {
501  if_addr = qb_list_entry(list, struct totem_ip_if_address, list);
502 
503  free(if_addr->name);
504  qb_list_del(&if_addr->list);
505  free(if_addr);
506  }
507  qb_list_init(addrs);
508 }
509 
511  struct totem_ip_address *boundto,
512  int *interface_up,
513  int *interface_num,
514  int mask_high_bit)
515 {
516  struct qb_list_head addrs;
517  struct qb_list_head *list;
518  struct totem_ip_if_address *if_addr;
519  struct totem_ip_address bn_netaddr, if_netaddr;
520  socklen_t addr_len;
521  socklen_t si;
522  int res = -1;
523  int exact_match_found = 0;
524  int net_match_found = 0;
525 
526  *interface_up = 0;
527  *interface_num = 0;
528 
529  if (totemip_getifaddrs(&addrs) == -1) {
530  return (-1);
531  }
532 
533  qb_list_for_each(list, &addrs) {
534  if_addr = qb_list_entry(list, struct totem_ip_if_address, list);
535 
536  if (bindnet->family != if_addr->ip_addr.family)
537  continue ;
538 
539  addr_len = 0;
540 
541  switch (bindnet->family) {
542  case AF_INET:
543  addr_len = sizeof(struct in_addr);
544  break;
545  case AF_INET6:
546  addr_len = sizeof(struct in6_addr);
547  break;
548  }
549 
550  if (addr_len == 0)
551  continue ;
552 
553  totemip_copy(&bn_netaddr, bindnet);
554  totemip_copy(&if_netaddr, &if_addr->ip_addr);
555 
556  if (totemip_equal(&bn_netaddr, &if_netaddr)) {
557  exact_match_found = 1;
558  }
559 
560  for (si = 0; si < addr_len; si++) {
561  bn_netaddr.addr[si] = bn_netaddr.addr[si] & if_addr->mask_addr.addr[si];
562  if_netaddr.addr[si] = if_netaddr.addr[si] & if_addr->mask_addr.addr[si];
563  }
564 
565  if (exact_match_found || (!net_match_found && totemip_equal(&bn_netaddr, &if_netaddr))) {
566  totemip_copy(boundto, &if_addr->ip_addr);
567  boundto->nodeid = bindnet->nodeid;
568  *interface_up = if_addr->interface_up;
569  *interface_num = if_addr->interface_num;
570 
571  net_match_found = 1;
572  res = 0;
573 
574  if (exact_match_found) {
575  goto finished;
576  }
577  }
578  }
579 
580 finished:
581  totemip_freeifaddrs(&addrs);
582  return (res);
583 }
584 
585 #define TOTEMIP_UDP_HEADER_SIZE 8
586 #define TOTEMIP_IPV4_HEADER_SIZE 20
587 #define TOTEMIP_IPV6_HEADER_SIZE 40
588 
590 {
591  size_t header_size;
592 
593  header_size = 0;
594 
595  switch (family) {
596  case AF_INET:
598  break;
599  case AF_INET6:
601  break;
602  }
603 
604  return (header_size);
605 }
unsigned short family
Definition: coroapi.h:113
#define TOTEMIP_IPV4_HEADER_SIZE
Definition: totemip.c:586
totem_ip_version_enum
Definition: totemip.h:70
struct qb_list_head list
Definition: totemip.h:84
The totem_ip_address struct.
Definition: coroapi.h:111
unsigned char addr[TOTEMIP_ADDRLEN]
Definition: coroapi.h:114
void totemip_copy(struct totem_ip_address *addr1, const struct totem_ip_address *addr2)
Definition: totemip.c:96
unsigned char addr[TOTEMIP_ADDRLEN]
Definition: coroapi.h:77
int totemip_localhost(int family, struct totem_ip_address *localhost)
Definition: totemip.c:183
#define log_printf(level, format, args...)
Definition: logsys.h:323
#define totemip_nosigpipe(s)
Definition: totemip.h:56
const char * totemip_print(const struct totem_ip_address *addr)
Definition: totemip.c:237
int32_t totemip_is_mcast(struct totem_ip_address *ip_addr)
Definition: totemip.c:115
int totemip_localhost_check(const struct totem_ip_address *addr)
Definition: totemip.c:206
void totemip_freeifaddrs(struct qb_list_head *addrs)
Definition: totemip.c:495
int totemip_totemip_to_sockaddr_convert(struct totem_ip_address *ip_addr, uint16_t port, struct sockaddr_storage *saddr, int *addrlen)
Definition: totemip.c:245
int totemip_getifaddrs(struct qb_list_head *addrs)
Definition: totemip.c:427
int totemip_iface_check(struct totem_ip_address *bindnet, struct totem_ip_address *boundto, int *interface_up, int *interface_num, int mask_high_bit)
Definition: totemip.c:510
unsigned int nodeid
Definition: coroapi.h:112
size_t totemip_udpip_header_size(int family)
Definition: totemip.c:589
const char * totemip_sa_print(const struct sockaddr *sa)
Definition: totemip.c:215
#define LOGSYS_LEVEL_DEBUG
Definition: logsys.h:76
struct totem_ip_address mask_addr
Definition: totemip.h:80
#define LOCALHOST_IPV4
Definition: totemip.c:58
int totemip_compare(const void *a, const void *b)
Definition: totemip.c:131
#define swab32(x)
The swab32 macro.
Definition: swab.h:51
#define TOTEMIP_ADDRLEN
Definition: coroapi.h:86
int totemip_parse(struct totem_ip_address *totemip, const char *addr, enum totem_ip_version_enum ip_version)
Definition: totemip.c:287
#define LOCALHOST_IPV6
Definition: totemip.c:59
int totemip_equal(const struct totem_ip_address *addr1, const struct totem_ip_address *addr2)
Definition: totemip.c:72
#define swab16(x)
The swab16 macro.
Definition: swab.h:39
unsigned short family
Definition: coroapi.h:76
int totemip_sockaddr_to_totemip_convert(const struct sockaddr_storage *saddr, struct totem_ip_address *ip_addr)
Definition: totemip.c:401
#define TOTEMIP_IPV6_HEADER_SIZE
Definition: totemip.c:587
#define TOTEMIP_UDP_HEADER_SIZE
Definition: totemip.c:585
struct totem_ip_address ip_addr
Definition: totemip.h:79
void totemip_copy_endian_convert(struct totem_ip_address *addr1, const struct totem_ip_address *addr2)
Definition: totemip.c:102