1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/cmn_err.h> 32 #include <sys/systm.h> 33 #include <sys/socket.h> 34 #include <sys/sunddi.h> 35 #include <netinet/in.h> 36 #include <inet/led.h> 37 38 static void convert2ascii(char *, const in6_addr_t *); 39 static char *strchr_w(const char *, int); 40 static int str2inet_addr(char *, ipaddr_t *); 41 42 /* 43 * inet_ntop -- Convert an IPv4 or IPv6 address in binary form into 44 * printable form, and return a pointer to that string. Caller should 45 * provide a buffer of correct length to store string into. 46 * Note: this routine is kernel version of inet_ntop. It has similar 47 * format as inet_ntop() defined in rfc2553. But it does not do 48 * error handling operations exactly as rfc2553 defines. This function 49 * is used by kernel inet directory routines only for debugging. 50 * This inet_ntop() function, does not return NULL if third argument 51 * is NULL. The reason is simple that we don't want kernel to panic 52 * as the output of this function is directly fed to ip<n>dbg macro. 53 * Instead it uses a local buffer for destination address for 54 * those calls which purposely pass NULL ptr for the destination 55 * buffer. This function is thread-safe when the caller passes a non- 56 * null buffer with the third argument. 57 */ 58 /* ARGSUSED */ 59 char * 60 inet_ntop(int af, const void *addr, char *buf, int addrlen) 61 { 62 static char local_buf[INET6_ADDRSTRLEN]; 63 static char *err_buf1 = "<badaddr>"; 64 static char *err_buf2 = "<badfamily>"; 65 in6_addr_t *v6addr; 66 uchar_t *v4addr; 67 char *caddr; 68 69 /* 70 * We don't allow thread unsafe inet_ntop calls, they 71 * must pass a non-null buffer pointer. For DEBUG mode 72 * we use the ASSERT() and for non-debug kernel it will 73 * silently allow it for now. Someday we should remove 74 * the static buffer from this function. 75 */ 76 77 ASSERT(buf != NULL); 78 if (buf == NULL) 79 buf = local_buf; 80 buf[0] = '\0'; 81 82 /* Let user know politely not to send NULL or unaligned addr */ 83 if (addr == NULL || !(OK_32PTR(addr))) { 84 #ifdef DEBUG 85 cmn_err(CE_WARN, "inet_ntop: addr is <null> or unaligned"); 86 #endif 87 return (err_buf1); 88 } 89 90 91 #define UC(b) (((int)b) & 0xff) 92 switch (af) { 93 case AF_INET: 94 ASSERT(addrlen >= INET_ADDRSTRLEN); 95 v4addr = (uchar_t *)addr; 96 (void) sprintf(buf, "%03d.%03d.%03d.%03d", 97 UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3])); 98 return (buf); 99 100 case AF_INET6: 101 ASSERT(addrlen >= INET6_ADDRSTRLEN); 102 v6addr = (in6_addr_t *)addr; 103 if (IN6_IS_ADDR_V4MAPPED(v6addr)) { 104 caddr = (char *)addr; 105 (void) sprintf(buf, "::ffff:%d.%d.%d.%d", 106 UC(caddr[12]), UC(caddr[13]), 107 UC(caddr[14]), UC(caddr[15])); 108 } else if (IN6_IS_ADDR_V4COMPAT(v6addr)) { 109 caddr = (char *)addr; 110 (void) sprintf(buf, "::%d.%d.%d.%d", 111 UC(caddr[12]), UC(caddr[13]), UC(caddr[14]), 112 UC(caddr[15])); 113 } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) { 114 (void) sprintf(buf, "::"); 115 } else { 116 convert2ascii(buf, v6addr); 117 } 118 return (buf); 119 120 default: 121 return (err_buf2); 122 } 123 #undef UC 124 } 125 126 /* 127 * 128 * v6 formats supported 129 * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx 130 * The short hand notation :: is used for COMPAT addr 131 * Other forms : fe80::xxxx:xxxx:xxxx:xxxx 132 */ 133 static void 134 convert2ascii(char *buf, const in6_addr_t *addr) 135 { 136 int hexdigits; 137 int head_zero = 0; 138 int tail_zero = 0; 139 /* tempbuf must be big enough to hold ffff:\0 */ 140 char tempbuf[6]; 141 char *ptr; 142 uint16_t *addr_component; 143 size_t len; 144 boolean_t first = B_FALSE; 145 boolean_t med_zero = B_FALSE; 146 boolean_t end_zero = B_FALSE; 147 148 addr_component = (uint16_t *)addr; 149 ptr = buf; 150 151 /* First count if trailing zeroes higher in number */ 152 for (hexdigits = 0; hexdigits < 8; hexdigits++) { 153 if (*addr_component == 0) { 154 if (hexdigits < 4) 155 head_zero++; 156 else 157 tail_zero++; 158 } 159 addr_component++; 160 } 161 addr_component = (uint16_t *)addr; 162 if (tail_zero > head_zero && (head_zero + tail_zero) != 7) 163 end_zero = B_TRUE; 164 165 for (hexdigits = 0; hexdigits < 8; hexdigits++) { 166 167 /* if entry is a 0 */ 168 169 if (*addr_component == 0) { 170 if (!first && *(addr_component + 1) == 0) { 171 if (end_zero && (hexdigits < 4)) { 172 *ptr++ = '0'; 173 *ptr++ = ':'; 174 } else { 175 /* 176 * address starts with 0s .. 177 * stick in leading ':' of pair 178 */ 179 if (hexdigits == 0) 180 *ptr++ = ':'; 181 /* add another */ 182 *ptr++ = ':'; 183 first = B_TRUE; 184 med_zero = B_TRUE; 185 } 186 } else if (first && med_zero) { 187 if (hexdigits == 7) 188 *ptr++ = ':'; 189 addr_component++; 190 continue; 191 } else { 192 *ptr++ = '0'; 193 *ptr++ = ':'; 194 } 195 addr_component++; 196 continue; 197 } 198 if (med_zero) 199 med_zero = B_FALSE; 200 201 tempbuf[0] = '\0'; 202 (void) sprintf(tempbuf, "%x:", ntohs(*addr_component) & 0xffff); 203 len = strlen(tempbuf); 204 bcopy(tempbuf, ptr, len); 205 ptr = ptr + len; 206 addr_component++; 207 } 208 *--ptr = '\0'; 209 } 210 211 /* 212 * search for char c, terminate on trailing white space 213 */ 214 static char * 215 strchr_w(const char *sp, int c) 216 { 217 /* skip leading white space */ 218 while (*sp && (*sp == ' ' || *sp == '\t')) { 219 sp++; 220 } 221 222 do { 223 if (*sp == (char)c) 224 return ((char *)sp); 225 if (*sp == ' ' || *sp == '\t') 226 return (NULL); 227 } while (*sp++); 228 return (NULL); 229 } 230 231 static int 232 str2inet_addr(char *cp, ipaddr_t *addrp) 233 { 234 char *end; 235 long byte; 236 int i; 237 uint8_t *addr = (uint8_t *)addrp; 238 239 *addrp = 0; 240 241 for (i = 0; i < 4; i++) { 242 if (ddi_strtol(cp, &end, 10, &byte) != 0 || byte < 0 || 243 byte > 255) { 244 return (0); 245 } 246 addr[i] = (uint8_t)byte; 247 if (i < 3) { 248 if (*end != '.') { 249 return (0); 250 } else { 251 cp = end + 1; 252 } 253 } else { 254 cp = end; 255 } 256 } 257 258 return (1); 259 } 260 261 /* 262 * inet_pton: This function takes string format IPv4 or IPv6 address and 263 * converts it to binary form. The format of this function corresponds to 264 * inet_pton() in the socket library. 265 * It returns 0 for invalid IPv4 and IPv6 address 266 * 1 when successfully converts ascii to binary 267 * -1 when af is not AF_INET or AF_INET6 268 */ 269 int 270 m_inet_pton(int af, char *inp, void *outp, int revert) 271 { 272 int i; 273 long byte; 274 char *end; 275 276 switch (af) { 277 case AF_INET: 278 if (str2inet_addr(inp, (ipaddr_t *)outp)) { 279 if (! revert) 280 *(uint32_t *)outp = ntohl(*(uint32_t *)outp); 281 return (1); 282 } else { 283 return (0); 284 } 285 case AF_INET6: { 286 union v6buf_u { 287 uint16_t v6words_u[8]; 288 in6_addr_t v6addr_u; 289 } v6buf, *v6outp; 290 uint16_t *dbl_col = NULL; 291 char lastbyte = NULL; 292 293 v6outp = (union v6buf_u *)outp; 294 295 if (strchr_w(inp, '.') != NULL) { 296 /* v4 mapped or v4 compatable */ 297 if (strncmp(inp, "::ffff:", 7) == 0) { 298 ipaddr_t ipv4_all_zeroes = 0; 299 /* mapped - first init prefix and then fill */ 300 IN6_IPADDR_TO_V4MAPPED(ipv4_all_zeroes, 301 &v6outp->v6addr_u); 302 return (str2inet_addr(inp + 7, 303 &(v6outp->v6addr_u.s6_addr32[3]))); 304 } else if (strncmp(inp, "::", 2) == 0) { 305 /* v4 compatable - prefix all zeroes */ 306 bzero(&v6outp->v6addr_u, sizeof (in6_addr_t)); 307 return (str2inet_addr(inp + 2, 308 &(v6outp->v6addr_u.s6_addr32[3]))); 309 } 310 return (0); 311 } 312 for (i = 0; i < 8; i++) { 313 int error; 314 /* 315 * if ddi_strtol() fails it could be because 316 * the string is "::". That is valid and 317 * checked for below so just set the value to 318 * 0 and continue. 319 */ 320 if ((error = ddi_strtol(inp, &end, 16, &byte)) != 0) { 321 if (error == ERANGE) 322 return (0); 323 byte = 0; 324 } 325 if (byte < 0 || byte > 0x0ffff) { 326 return (0); 327 } 328 if (revert) { 329 v6buf.v6words_u[i] = htons((uint16_t)byte); 330 } else { 331 v6buf.v6words_u[i] = (uint16_t)byte; 332 } 333 if (*end == NULL || i == 7) { 334 inp = end; 335 break; 336 } 337 if (inp == end) { /* not a number must be */ 338 if (*inp == ':' && 339 ((i == 0 && *(inp + 1) == ':') || 340 lastbyte == ':')) { 341 if (dbl_col) { 342 return (0); 343 } 344 if (byte != 0) 345 i++; 346 dbl_col = &v6buf.v6words_u[i]; 347 if (i == 0) 348 inp++; 349 } else if (*inp == NULL || *inp == ' ' || 350 *inp == '\t') { 351 break; 352 } else { 353 return (0); 354 } 355 } else { 356 inp = end; 357 } 358 if (*inp != ':') { 359 return (0); 360 } 361 inp++; 362 if (*inp == NULL || *inp == ' ' || *inp == '\t') { 363 break; 364 } 365 lastbyte = *inp; 366 } 367 if (*inp != NULL && *inp != ' ' && *inp != '\t') { 368 return (0); 369 } 370 /* 371 * v6words now contains the bytes we could translate 372 * dbl_col points to the word (should be 0) where 373 * a double colon was found 374 */ 375 if (i == 7) { 376 v6outp->v6addr_u = v6buf.v6addr_u; 377 } else { 378 int rem; 379 int word; 380 int next; 381 if (dbl_col == NULL) { 382 return (0); 383 } 384 bzero(&v6outp->v6addr_u, sizeof (in6_addr_t)); 385 rem = dbl_col - &v6buf.v6words_u[0]; 386 for (next = 0; next < rem; next++) { 387 v6outp->v6words_u[next] = v6buf.v6words_u[next]; 388 } 389 next++; /* skip dbl_col 0 */ 390 rem = i - rem; 391 word = 8 - rem; 392 while (rem > 0) { 393 v6outp->v6words_u[word] = v6buf.v6words_u[next]; 394 word++; 395 rem--; 396 next++; 397 } 398 } 399 return (1); /* Success */ 400 } 401 } /* switch */ 402 return (-1); /* return -1 for default case */ 403 } 404 405 406 int 407 _inet_pton(int af, char *inp, void *outp) 408 { 409 return (m_inet_pton(af, inp, outp, 1)); 410 } 411 412 /* 413 * We need this inet_pton to preserve compatibility with old closed binaries. 414 * Earlier, inet_pton returned address in hardware native order, 415 * not in network one. (See http://www.illumos.org/issue/3105). 416 * Having fixed that, we still need to support binaries, that use bad inet_pton 417 * and reverse returned address manually. All new inet_pton calls will be 418 * redirected to _inet_pton with #define in the header file. 419 */ 420 int 421 inet_pton(int af, char *inp, void *outp) 422 { 423 return (m_inet_pton(af, inp, outp, 0)); 424 }