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