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