1 /* 2 * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Utility functions which help with address and hostname manipulation in a 10 * mixed IPv4 / IPv6 environment. 11 */ 12 13 #include "config.h" 14 #include <sys/socket.h> 15 #include <netinet/in.h> 16 #include <arpa/inet.h> 17 #include <netdb.h> 18 #include <string.h> 19 #include "proto.h" 20 21 #ifndef MAXHOSTNAMELEN 22 #define MAXHOSTNAMELEN 64 23 #endif 24 25 /* Converts a hostname into an IP address in presentation form */ 26 char *inet_htop(const char *hostname) 27 { 28 #ifdef INET6 29 static char abuf[INET6_ADDRSTRLEN]; 30 struct addrinfo hints, *result; 31 char *str = NULL; 32 void *addr = NULL; 33 34 memset(&hints, 0, sizeof(hints)); 35 hints.ai_flags = AI_CANONNAME; 36 hints.ai_family = PF_UNSPEC; 37 38 if (getaddrinfo(hostname, NULL, &hints, &result) == 0) { 39 if (result->ai_family == AF_INET) 40 addr = ((void *)&((struct sockaddr_in *)result->ai_addr)->sin_addr); 41 else if (result->ai_family == AF_INET6) 42 addr = ((void *)&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr); 43 if (addr) 44 str = (char *)inet_ntop_native(result->ai_family, addr, abuf, 45 sizeof(abuf)); 46 freeaddrinfo(result); 47 return str; 48 } 49 #else 50 struct hostent *hp; 51 struct in_addr in; 52 53 if ((hp = gethostbyname(hostname)) != NULL) { 54 memcpy(&in, hp->h_addr, sizeof(in)); 55 return inet_ntoa(in); 56 } 57 #endif 58 return NULL; 59 } 60 61 /* 62 * Converts a socket structures IP address into presentation form. 63 * Note: returns a pointer to a buffer which is overwritten on each call. 64 */ 65 char *inet_stop(struct SOCKSTORAGE *ss) 66 { 67 #ifdef INET6 68 static char abuf[INET6_ADDRSTRLEN]; 69 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; 70 71 if (ss->ss_family == AF_INET6) 72 return (char *)inet_ntop_native(AF_INET6, &sin6->sin6_addr, abuf, sizeof (abuf)); 73 #endif 74 return inet_ntoa(((struct sockaddr_in *)ss)->sin_addr); 75 } 76 77 char *wu_gethostbyname(const char *hostname) 78 { 79 #ifdef INET6 80 static char hostbuf[MAXHOSTNAMELEN]; 81 struct addrinfo hints, *result; 82 83 memset(&hints, 0, sizeof(hints)); 84 hints.ai_flags = AI_CANONNAME; 85 hints.ai_family = PF_UNSPEC; 86 87 if (getaddrinfo(hostname, NULL, &hints, &result) == 0) { 88 strncpy(hostbuf, result->ai_canonname, sizeof(hostbuf)); 89 hostbuf[sizeof(hostbuf) - 1] = '\0'; 90 freeaddrinfo(result); 91 return hostbuf; 92 } 93 #else 94 struct hostent *hp = gethostbyname(hostname); 95 96 if (hp) 97 return hp->h_name; 98 #endif 99 return NULL; 100 } 101 102 int wu_gethostbyaddr(struct SOCKSTORAGE *ss, char *hostname, int hostlen) 103 { 104 #ifdef INET6 105 char hostbuf[NI_MAXHOST]; 106 #else 107 struct hostent *hp; 108 #endif 109 110 if ((ss == NULL) || (hostname == NULL) || (hostlen < 1)) 111 return 0; 112 113 #ifdef INET6 114 if (getnameinfo((struct sockaddr *)ss, SOCK_LEN(*ss), hostbuf, 115 sizeof(hostbuf), NULL, 0, NI_NAMEREQD) == 0) { 116 strncpy(hostname, hostbuf, hostlen); 117 hostname[hostlen - 1] = '\0'; 118 return 1; 119 } 120 #else 121 hp = gethostbyaddr((char *)&ss->sin_addr, sizeof(struct in_addr), AF_INET); 122 if (hp) { 123 strncpy(hostname, hp->h_name, hostlen); 124 hostname[hostlen - 1] = '\0'; 125 return 1; 126 } 127 #endif 128 return 0; 129 } 130 131 /* Compares a socket structures IP address with addr, returning 0 on a match */ 132 int sock_cmp_inaddr(struct SOCKSTORAGE *ss, struct in_addr addr) { 133 #ifdef INET6 134 if (ss->ss_family == AF_INET6) { 135 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; 136 137 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 138 u_char *a = (u_char *)&sin6->sin6_addr; 139 140 /* compare the IPv4 part of an IPv4-mapped IPv6 address */ 141 return memcmp(&addr, a + sizeof(struct in6_addr) - sizeof(struct in_addr), sizeof(struct in_addr)); 142 } 143 return 1; 144 } 145 #endif 146 return ((struct sockaddr_in *)ss)->sin_addr.s_addr != addr.s_addr; 147 } 148 149 #ifdef INET6 150 /* Sets a socket structures IP address to addr */ 151 void sock_set_inaddr(struct SOCKSTORAGE *ss, struct in_addr addr) { 152 if (ss->ss_family == AF_INET6) { 153 struct in6_addr *in6; 154 155 in6 = &((struct sockaddr_in6 *)ss)->sin6_addr; 156 memset(&in6->s6_addr[0], 0, 10); 157 memset(&in6->s6_addr[10], 0xff, 2); 158 memcpy(&in6->s6_addr[12], &addr, sizeof(struct in_addr)); 159 return; 160 } 161 ((struct sockaddr_in *)ss)->sin_addr = addr; 162 } 163 164 /* Compares two socket structure IP addresses, returning 0 if they match */ 165 int sock_cmp_addr(struct SOCKSTORAGE *ss1, struct SOCKSTORAGE *ss2) { 166 if (ss1->ss_family == AF_INET6) { 167 if (ss2->ss_family == AF_INET6) 168 return memcmp(&((struct sockaddr_in6 *)ss1)->sin6_addr, 169 &((struct sockaddr_in6 *)ss2)->sin6_addr, 170 sizeof(struct in6_addr)); 171 return sock_cmp_inaddr(ss1, ((struct sockaddr_in *)ss2)->sin_addr); 172 } 173 return sock_cmp_inaddr(ss2, ((struct sockaddr_in *)ss1)->sin_addr); 174 } 175 176 void sock_set_scope(struct SOCKSTORAGE *dst, struct SOCKSTORAGE *src) { 177 #ifdef HAVE_SIN6_SCOPE_ID 178 struct sockaddr_in6 *src_in6 = (struct sockaddr_in6 *)src; 179 struct sockaddr_in6 *dst_in6 = (struct sockaddr_in6 *)dst; 180 181 if (dst->ss_family == AF_INET6) { 182 if ((src->ss_family == AF_INET6) && 183 (memcmp(&src_in6->sin6_addr, &dst_in6->sin6_addr, 184 sizeof(struct in6_addr)) == 0)) 185 dst_in6->sin6_scope_id = src_in6->sin6_scope_id; 186 else 187 dst_in6->sin6_scope_id = 0; 188 } 189 #endif 190 } 191 192 /* 193 * Similar to inet_pton(), str can be an IPv4 or IPv6 address, but an IPv6 194 * address is returned in addr. 195 */ 196 int inet_pton6(char *str, struct in6_addr *addr) 197 { 198 struct in_addr v4addr; 199 200 /* Try v6 first */ 201 if (inet_pton(AF_INET6, str, addr) != 1) { 202 /* If that fails, try v4 and map it */ 203 if (inet_pton(AF_INET, str, &v4addr) == 1) { 204 memset(&addr->s6_addr[0], 0, 10); 205 memset(&addr->s6_addr[10], 0xff, 2); 206 memcpy(&addr->s6_addr[12], &v4addr, sizeof(struct in_addr)); 207 } 208 else 209 return 0; 210 } 211 return 1; 212 } 213 214 /* 215 * Similar to inet_ntop(), except when addr is an IPv4-mapped IPv6 address 216 * returns a printable IPv4 address (not an IPv4-mapped IPv6 address). 217 */ 218 const char *inet_ntop_native(int af, const void *addr, char *dst, size_t size) 219 { 220 const char *result; 221 222 if (af == AF_INET6) { 223 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) 224 result = inet_ntop(AF_INET, (char *)addr + sizeof(struct in6_addr) 225 - sizeof(struct in_addr), dst, size); 226 else 227 result = inet_ntop(AF_INET6, addr, dst, size); 228 } 229 else 230 result = inet_ntop(af, addr, dst, size); 231 return result; 232 } 233 #endif /* INET6 */