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
convert2ascii(char * buf,const in6_addr_t * addr)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 *
strchr_w(const char * sp,int c)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
str2inet_addr(char * cp,ipaddr_t * addrp)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 *
__inet_ntop(int af,const void * addr,char * buf,int addrlen,int compat)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 *
_inet_ntop(int af,const void * addr,char * buf,int addrlen)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 *
inet_ntop(int af,const void * addr,char * buf,int addrlen)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
__inet_pton(int af,char * inp,void * outp,int compat)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
_inet_pton(int af,char * inp,void * outp)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
inet_pton(int af,char * inp,void * outp)422 inet_pton(int af, char *inp, void *outp)
423 {
424 return (__inet_pton(af, inp, outp, 1));
425 }
426