1 /* $NetBSD: decodenetnum.c,v 1.6 2020/05/25 20:47:24 christos Exp $ */ 2 3 /* 4 * decodenetnum - return a net number (this is crude, but careful) 5 */ 6 #include <config.h> 7 #include <sys/types.h> 8 #include <ctype.h> 9 #ifdef HAVE_SYS_SOCKET_H 10 #include <sys/socket.h> 11 #endif 12 #ifdef HAVE_NETINET_IN_H 13 #include <netinet/in.h> 14 #endif 15 16 #include "ntp.h" 17 #include "ntp_stdlib.h" 18 #include "ntp_assert.h" 19 20 #define PORTSTR(x) _PORTSTR(x) 21 #define _PORTSTR(x) #x 22 23 static int 24 isnumstr( 25 const char *s 26 ) 27 { 28 while (*s >= '0' && *s <= '9') 29 ++s; 30 return !*s; 31 } 32 33 /* 34 * decodenetnum convert text IP address and port to sockaddr_u 35 * 36 * Returns 0 for failure, 1 for success. 37 */ 38 int 39 decodenetnum( 40 const char *num, 41 sockaddr_u *netnum 42 ) 43 { 44 static const char * const servicename = "ntp"; 45 static const char * const serviceport = PORTSTR(NTP_PORT); 46 47 struct addrinfo hints, *ai = NULL; 48 int err; 49 const char *host_str; 50 const char *port_str; 51 char *pp; 52 char *np; 53 char nbuf[80]; 54 55 REQUIRE(num != NULL); 56 57 if (strlen(num) >= sizeof(nbuf)) { 58 printf("length error\n"); 59 return FALSE; 60 } 61 62 port_str = servicename; 63 if ('[' != num[0]) { 64 /* 65 * to distinguish IPv6 embedded colons from a port 66 * specification on an IPv4 address, assume all 67 * legal IPv6 addresses have at least two colons. 68 */ 69 pp = strchr(num, ':'); 70 if (NULL == pp) 71 host_str = num; /* no colons */ 72 else if (NULL != strchr(pp + 1, ':')) 73 host_str = num; /* two or more colons */ 74 else { /* one colon */ 75 strlcpy(nbuf, num, sizeof(nbuf)); 76 host_str = nbuf; 77 pp = strchr(nbuf, ':'); 78 *pp = '\0'; 79 port_str = pp + 1; 80 } 81 } else { 82 host_str = np = nbuf; 83 while (*++num && ']' != *num) 84 *np++ = *num; 85 *np = 0; 86 if (']' == num[0] && ':' == num[1] && '\0' != num[2]) 87 port_str = &num[2]; 88 } 89 if ( ! *host_str) 90 return FALSE; 91 if ( ! *port_str) 92 port_str = servicename; 93 94 ZERO(hints); 95 hints.ai_flags |= Z_AI_NUMERICHOST; 96 if (isnumstr(port_str)) 97 hints.ai_flags |= Z_AI_NUMERICSERV; 98 err = getaddrinfo(host_str, port_str, &hints, &ai); 99 /* retry with default service name if the service lookup failed */ 100 if (err == EAI_SERVICE && strcmp(port_str, servicename)) { 101 hints.ai_flags &= ~Z_AI_NUMERICSERV; 102 port_str = servicename; 103 err = getaddrinfo(host_str, port_str, &hints, &ai); 104 } 105 /* retry another time with default service port if the service lookup failed */ 106 if (err == EAI_SERVICE && strcmp(port_str, serviceport)) { 107 hints.ai_flags |= Z_AI_NUMERICSERV; 108 port_str = serviceport; 109 err = getaddrinfo(host_str, port_str, &hints, &ai); 110 } 111 if (err != 0) 112 return FALSE; 113 114 INSIST(ai->ai_addrlen <= sizeof(*netnum)); 115 ZERO(*netnum); 116 memcpy(netnum, ai->ai_addr, ai->ai_addrlen); 117 freeaddrinfo(ai); 118 119 return TRUE; 120 } 121