root/opal/util/net.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. opal_net_isaddr
  2. hostname_cleanup
  3. get_hostname_buffer
  4. opal_net_finalize
  5. opal_net_init
  6. opal_net_prefix2netmask
  7. opal_net_islocalhost
  8. opal_net_samenetwork
  9. opal_net_addr_isipv4public
  10. opal_net_addr_isipv6linklocal
  11. opal_net_get_hostname
  12. opal_net_get_port
  13. opal_net_init
  14. opal_net_finalize
  15. opal_net_prefix2netmask
  16. opal_net_islocalhost
  17. opal_net_samenetwork
  18. opal_net_addr_isipv4public
  19. opal_net_get_hostname
  20. opal_net_get_port

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   4  *                         University Research and Technology
   5  *                         Corporation.  All rights reserved.
   6  * Copyright (c) 2004-2005 The University of Tennessee and The University
   7  *                         of Tennessee Research Foundation.  All rights
   8  *                         reserved.
   9  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
  10  *                         University of Stuttgart.  All rights reserved.
  11  * Copyright (c) 2004-2005 The Regents of the University of California.
  12  *                         All rights reserved.
  13  * Copyright (c) 2007      Los Alamos National Security, LLC.  All rights
  14  *                         reserved.
  15  * Copyright (c) 2009-2015 Cisco Systems, Inc.  All rights reserved.
  16  * Copyright (c) 2013      Intel, Inc.  All rights reserved.
  17  * Copyright (c) 2015      Research Organization for Information Science
  18  *                         and Technology (RIST). All rights reserved.
  19  * Copyright (c) 2018      Amazon.com, Inc. or its affiliates.  All Rights
  20  *                         reserved.
  21  * Copyright (c) 2018      Triad National Security, LLC. All rights
  22  *                         reserved.
  23  * $COPYRIGHT$
  24  *
  25  * Additional copyrights may follow
  26  *
  27  * $HEADER$
  28  */
  29 
  30 #include "opal_config.h"
  31 
  32 #include <stdio.h>
  33 #include <string.h>
  34 #ifdef HAVE_UNISTD_H
  35 #include <unistd.h>
  36 #endif
  37 #include <errno.h>
  38 #ifdef HAVE_SYS_TYPES_H
  39 #include <sys/types.h>
  40 #endif
  41 #ifdef HAVE_SYS_SOCKET_H
  42 #include <sys/socket.h>
  43 #endif
  44 #ifdef HAVE_SYS_SOCKIO_H
  45 #include <sys/sockio.h>
  46 #endif
  47 #ifdef HAVE_SYS_IOCTL_H
  48 #include <sys/ioctl.h>
  49 #endif
  50 #ifdef HAVE_NETINET_IN_H
  51 #include <netinet/in.h>
  52 #endif
  53 #ifdef HAVE_ARPA_INET_H
  54 #include <arpa/inet.h>
  55 #endif
  56 #ifdef HAVE_NET_IF_H
  57 #include <net/if.h>
  58 #endif
  59 #ifdef HAVE_NETDB_H
  60 #include <netdb.h>
  61 #endif
  62 #ifdef HAVE_IFADDRS_H
  63 #include <ifaddrs.h>
  64 #endif
  65 
  66 #include "opal/runtime/opal.h"
  67 #include "opal/util/net.h"
  68 #include "opal/util/output.h"
  69 #include "opal/util/argv.h"
  70 #include "opal/util/show_help.h"
  71 #include "opal/constants.h"
  72 #include "opal/threads/tsd.h"
  73 #include "opal/runtime/opal_params.h"
  74 
  75 /* this function doesn't depend on sockaddr_h */
  76 bool opal_net_isaddr(const char *name)
  77 {
  78     struct addrinfo hint, *res = NULL;
  79 
  80     /* initialize the hint */
  81     memset(&hint, '\0', sizeof hint);
  82 
  83     /* indicate that we don't know the family */
  84     hint.ai_family = PF_UNSPEC;
  85     hint.ai_flags = AI_NUMERICHOST;
  86 
  87     if (0 != getaddrinfo(name, NULL, &hint, &res)) {
  88         /* the input wasn't a recognizable address */
  89         return false;
  90     }
  91     /* we don't care what family - all we care is that
  92      * it is indeed an address
  93      */
  94     freeaddrinfo(res);
  95     return true;
  96 }
  97 
  98 #ifdef HAVE_STRUCT_SOCKADDR_IN
  99 
 100 typedef struct private_ipv4_t {
 101     in_addr_t addr;
 102     uint32_t netmask_bits;
 103 } private_ipv4_t;
 104 
 105 static private_ipv4_t* private_ipv4 = NULL;
 106 
 107 #if OPAL_ENABLE_IPV6
 108 static opal_tsd_key_t hostname_tsd_key;
 109 
 110 
 111 static void
 112 hostname_cleanup(void *value)
 113 {
 114     if (NULL != value) free(value);
 115 }
 116 
 117 
 118 static char*
 119 get_hostname_buffer(void)
 120 {
 121     void *buffer;
 122     int ret;
 123 
 124     ret = opal_tsd_getspecific(hostname_tsd_key, &buffer);
 125     if (OPAL_SUCCESS != ret) return NULL;
 126 
 127     if (NULL == buffer) {
 128         buffer = (void*) malloc((NI_MAXHOST + 1) * sizeof(char));
 129         ret = opal_tsd_setspecific(hostname_tsd_key, buffer);
 130     }
 131 
 132     return (char*) buffer;
 133 }
 134 #endif
 135 
 136 /**
 137  * Finalize the network helper subsystem
 138  *
 139  * Finalize the network helper subsystem.  Should be called exactly
 140  * once for any process that will use any function in the network
 141  * helper subsystem.
 142  *
 143  * @retval OPAL_SUCCESS   Success
 144  */
 145 static void opal_net_finalize (void)
 146 {
 147     free(private_ipv4);
 148     private_ipv4 = NULL;
 149 }
 150 
 151 int
 152 opal_net_init(void)
 153 {
 154     char **args, *arg;
 155     uint32_t a, b, c, d, bits, addr;
 156     int i, count, found_bad = 0;
 157 
 158     args = opal_argv_split( opal_net_private_ipv4, ';' );
 159     if( NULL != args ) {
 160         count = opal_argv_count(args);
 161         private_ipv4 = (private_ipv4_t*)malloc( (count + 1) * sizeof(private_ipv4_t));
 162         if( NULL == private_ipv4 ) {
 163             opal_output(0, "Unable to allocate memory for the private addresses array" );
 164             opal_argv_free(args);
 165             goto do_local_init;
 166         }
 167         for( i = 0; i < count; i++ ) {
 168             arg = args[i];
 169 
 170             (void)sscanf( arg, "%u.%u.%u.%u/%u", &a, &b, &c, &d, &bits );
 171 
 172             if( (a > 255) || (b > 255) || (c > 255) ||
 173                 (d > 255) || (bits > 32) ) {
 174                 if (0 == found_bad) {
 175                     opal_show_help("help-opal-util.txt",
 176                                    "malformed net_private_ipv4",
 177                                    true, args[i]);
 178                     found_bad = 1;
 179                 }
 180                 continue;
 181             }
 182             addr = (a << 24) | (b << 16) | (c << 8) | d;
 183             private_ipv4[i].addr = htonl(addr);
 184             private_ipv4[i].netmask_bits = bits;
 185         }
 186         private_ipv4[i].addr         = 0;
 187         private_ipv4[i].netmask_bits = 0;
 188         opal_argv_free(args);
 189     }
 190 
 191     opal_finalize_register_cleanup (opal_net_finalize);
 192 
 193  do_local_init:
 194 #if OPAL_ENABLE_IPV6
 195     return opal_tsd_key_create(&hostname_tsd_key, hostname_cleanup);
 196 #else
 197     return OPAL_SUCCESS;
 198 #endif
 199 }
 200 
 201 /* convert a CIDR prefixlen to netmask (in network byte order) */
 202 uint32_t
 203 opal_net_prefix2netmask(uint32_t prefixlen)
 204 {
 205     return htonl (((1 << prefixlen) - 1) << (32 - prefixlen));
 206 }
 207 
 208 
 209 bool
 210 opal_net_islocalhost(const struct sockaddr *addr)
 211 {
 212     switch (addr->sa_family) {
 213     case AF_INET:
 214         {
 215             const struct sockaddr_in *inaddr = (struct sockaddr_in*) addr;
 216             /* if it's in the 127. domain, it shouldn't be routed
 217                (0x7f == 127) */
 218             if (0x7F000000 == (0x7F000000 & ntohl(inaddr->sin_addr.s_addr))) {
 219                 return true;
 220             }
 221             return false;
 222         }
 223         break;
 224 #if OPAL_ENABLE_IPV6
 225     case AF_INET6:
 226         {
 227             const struct sockaddr_in6 *inaddr = (struct sockaddr_in6*) addr;
 228             if (IN6_IS_ADDR_LOOPBACK (&inaddr->sin6_addr)) {
 229                return true; /* Bug, FIXME: check for 127.0.0.1/8 */
 230             }
 231             return false;
 232         }
 233         break;
 234 #endif
 235 
 236     default:
 237         opal_output(0, "unhandled sa_family %d passed to opal_net_islocalhost",
 238                     addr->sa_family);
 239         return false;
 240         break;
 241     }
 242 }
 243 
 244 
 245 bool
 246 opal_net_samenetwork(const struct sockaddr *addr1,
 247                      const struct sockaddr *addr2,
 248                      uint32_t plen)
 249 {
 250     uint32_t prefixlen;
 251 
 252     if(addr1->sa_family != addr2->sa_family) {
 253         return false; /* address families must be equal */
 254     }
 255 
 256     switch (addr1->sa_family) {
 257     case AF_INET:
 258         {
 259             if (0 == plen) {
 260                 prefixlen = 32;
 261             } else {
 262                 prefixlen = plen;
 263             }
 264             struct sockaddr_in inaddr1, inaddr2;
 265             /* Use temporary variables and memcpy's so that we don't
 266                run into bus errors on Solaris/SPARC */
 267             memcpy(&inaddr1, addr1, sizeof(inaddr1));
 268             memcpy(&inaddr2, addr2, sizeof(inaddr2));
 269             uint32_t netmask = opal_net_prefix2netmask (prefixlen);
 270 
 271             if((inaddr1.sin_addr.s_addr & netmask) ==
 272                (inaddr2.sin_addr.s_addr & netmask)) {
 273                 return true;
 274             }
 275             return false;
 276         }
 277         break;
 278 #if OPAL_ENABLE_IPV6
 279     case AF_INET6:
 280         {
 281             struct sockaddr_in6 inaddr1, inaddr2;
 282             /* Use temporary variables and memcpy's so that we don't
 283                run into bus errors on Solaris/SPARC */
 284             memcpy(&inaddr1, addr1, sizeof(inaddr1));
 285             memcpy(&inaddr2, addr2, sizeof(inaddr2));
 286             struct in6_addr *a6_1 = (struct in6_addr*) &inaddr1.sin6_addr;
 287             struct in6_addr *a6_2 = (struct in6_addr*) &inaddr2.sin6_addr;
 288 
 289             if (0 == plen) {
 290                 prefixlen = 64;
 291             } else {
 292                 prefixlen = plen;
 293             }
 294             if (64 == prefixlen) {
 295                 /* prefixlen is always /64, any other case would be routing.
 296                    Compare the first eight bytes (64 bits) and hope that
 297                    endianess is not an issue on any system as long as
 298                    addresses are always stored in network byte order.
 299                 */
 300                 if (((const uint32_t *) (a6_1))[0] ==
 301                     ((const uint32_t *) (a6_2))[0] &&
 302                     ((const uint32_t *) (a6_1))[1] ==
 303                     ((const uint32_t *) (a6_2))[1]) {
 304                     return true;
 305                 }
 306             }
 307             return false;
 308         }
 309         break;
 310 #endif
 311     default:
 312         opal_output(0, "unhandled sa_family %d passed to opal_samenetwork",
 313                     addr1->sa_family);
 314     }
 315 
 316     return false;
 317 }
 318 
 319 
 320 /**
 321  * Returns true if the given address is a public IPv4 address.
 322  */
 323 bool
 324 opal_net_addr_isipv4public(const struct sockaddr *addr)
 325 {
 326     switch (addr->sa_family) {
 327 #if OPAL_ENABLE_IPV6
 328         case AF_INET6:
 329             return false;
 330 #endif
 331         case AF_INET:
 332             {
 333                 const struct sockaddr_in *inaddr = (struct sockaddr_in*) addr;
 334                 int i;
 335 
 336                 if( NULL == private_ipv4 ) {
 337                     return true;
 338                 }
 339 
 340                 for( i = 0; private_ipv4[i].addr != 0; i++ ) {
 341                     if( private_ipv4[i].addr == (inaddr->sin_addr.s_addr &
 342                                                  opal_net_prefix2netmask(private_ipv4[i].netmask_bits)) )
 343                         return false;
 344                 }
 345 
 346             }
 347             return true;
 348         default:
 349             opal_output (0,
 350                          "unhandled sa_family %d passed to opal_net_addr_isipv4public\n",
 351                          addr->sa_family);
 352     }
 353 
 354     return false;
 355 }
 356 
 357 bool
 358 opal_net_addr_isipv6linklocal(const struct sockaddr *addr)
 359 {
 360 #if OPAL_ENABLE_IPV6
 361     struct sockaddr_in6 if_addr;
 362 #endif
 363 
 364     switch (addr->sa_family) {
 365 #if OPAL_ENABLE_IPV6
 366         case AF_INET6:
 367             if_addr.sin6_family = AF_INET6;
 368             if (1 != inet_pton(AF_INET6, "fe80::0000", &if_addr.sin6_addr)) {
 369                 return false;
 370             }
 371             return opal_net_samenetwork(addr, (struct sockaddr*)&if_addr, 64);
 372 #endif
 373         case AF_INET:
 374             return false;
 375         default:
 376             opal_output (0,
 377                          "unhandled sa_family %d passed to opal_net_addr_isipv6linklocal\n",
 378                          addr->sa_family);
 379     }
 380 
 381     return false;
 382 }
 383 
 384 char*
 385 opal_net_get_hostname(const struct sockaddr *addr)
 386 {
 387 #if OPAL_ENABLE_IPV6
 388     char *name = get_hostname_buffer();
 389     int error;
 390     socklen_t addrlen;
 391     char *p;
 392 
 393     if (NULL == name) {
 394         opal_output(0, "opal_sockaddr2str: malloc() failed\n");
 395         return NULL;
 396     }
 397     OPAL_DEBUG_ZERO(*name);
 398 
 399     switch (addr->sa_family) {
 400     case AF_INET:
 401         addrlen = sizeof (struct sockaddr_in);
 402         break;
 403     case AF_INET6:
 404 #if defined( __NetBSD__)
 405         /* hotfix for netbsd: on my netbsd machine, getnameinfo
 406            returns an unkown error code. */
 407         if(NULL == inet_ntop(AF_INET6, &((struct sockaddr_in6*) addr)->sin6_addr,
 408                              name, NI_MAXHOST)) {
 409             opal_output(0, "opal_sockaddr2str failed with error code %d", errno);
 410             return NULL;
 411         }
 412         return name;
 413 #else
 414         addrlen = sizeof (struct sockaddr_in6);
 415 #endif
 416         break;
 417     default:
 418         return NULL;
 419     }
 420 
 421     error = getnameinfo(addr, addrlen,
 422                         name, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
 423 
 424     if (error) {
 425        int err = errno;
 426        opal_output (0, "opal_sockaddr2str failed:%s (return code %i)\n",
 427                     gai_strerror(err), error);
 428        return NULL;
 429     }
 430     /* strip any trailing % data as it isn't pertinent */
 431     if (NULL != (p = strrchr(name, '%'))) {
 432         *p = '\0';
 433     }
 434     return name;
 435 #else
 436     return inet_ntoa(((struct sockaddr_in*) addr)->sin_addr);
 437 #endif
 438 }
 439 
 440 
 441 int
 442 opal_net_get_port(const struct sockaddr *addr)
 443 {
 444     switch (addr->sa_family) {
 445     case AF_INET:
 446         return ntohs(((struct sockaddr_in*) addr)->sin_port);
 447         break;
 448 #if OPAL_ENABLE_IPV6
 449     case AF_INET6:
 450         return ntohs(((struct sockaddr_in6*) addr)->sin6_port);
 451         break;
 452 #endif
 453     }
 454 
 455     return -1;
 456 }
 457 
 458 
 459 #else /* HAVE_STRUCT_SOCKADDR_IN */
 460 
 461 int
 462 opal_net_init()
 463 {
 464     return OPAL_SUCCESS;
 465 }
 466 
 467 
 468 int
 469 opal_net_finalize()
 470 {
 471     return OPAL_SUCCESS;
 472 }
 473 
 474 
 475 uint32_t
 476 opal_net_prefix2netmask(uint32_t prefixlen)
 477 {
 478     return 0;
 479 }
 480 
 481 
 482 bool
 483 opal_net_islocalhost(const struct sockaddr *addr)
 484 {
 485     return false;
 486 }
 487 
 488 
 489 bool
 490 opal_net_samenetwork(const struct sockaddr *addr1,
 491                      const struct sockaddr *addr2,
 492                      uint32_t prefixlen)
 493 {
 494     return false;
 495 }
 496 
 497 
 498 bool
 499 opal_net_addr_isipv4public(const struct sockaddr *addr)
 500 {
 501     return false;
 502 }
 503 
 504 
 505 char*
 506 opal_net_get_hostname(const struct sockaddr *addr)
 507 {
 508     return NULL;
 509 }
 510 
 511 
 512 int
 513 opal_net_get_port(const struct sockaddr *addr)
 514 {
 515     return -1;
 516 }
 517 
 518 #endif /* HAVE_STRUCT_SOCKADDR_IN */

/* [<][>][^][v][top][bottom][index][help] */