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