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