]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/getnameinfo.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / StdLib / BsdSocketLib / getnameinfo.c
1 /* $NetBSD: getnameinfo.c,v 1.45 2006/10/15 16:14:46 christos Exp $ */
2 /* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */
3
4 /*
5 * Copyright (c) 2000 Ben Harris.
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * Issues to be discussed:
36 * - Thread safe-ness must be checked
37 * - RFC2553 says that we should raise error on short buffer. X/Open says
38 * we need to truncate the result. We obey RFC2553 (and X/Open should be
39 * modified). ipngwg rough consensus seems to follow RFC2553.
40 * - What is "local" in NI_FQDN?
41 * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
42 * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
43 * sin6_scope_id is filled - standardization status?
44 * XXX breaks backward compat for code that expects no scopeid.
45 * beware on merge.
46 */
47
48 #define INET6 1
49
50 #include <sys/cdefs.h>
51 #if defined(LIBC_SCCS) && !defined(lint)
52 __RCSID("$NetBSD: getnameinfo.c,v 1.45 2006/10/15 16:14:46 christos Exp $");
53 #endif /* LIBC_SCCS and not lint */
54
55 #include "namespace.h"
56 #include <sys/types.h>
57 #include <sys/socket.h>
58 #include <net/if.h>
59 #include <net/if_dl.h>
60 //#include <net/if_ieee1394.h>
61 //#include <net/if_types.h>
62 #include <netinet/in.h>
63 #include <arpa/inet.h>
64 #include <arpa/nameser.h>
65 #include <assert.h>
66 #include <limits.h>
67 #include <netdb.h>
68 #include <resolv.h>
69 #include <stddef.h>
70 #include <string.h>
71
72 #include <net/servent.h>
73
74 #define CLLADDR(x) ( LLADDR(x) )
75 #define endservent_r(svd) endservent()
76 #define getservbyport_r(Port,pProto,pSv,pSvd) getservbyport(Port,pProto)
77
78 #ifdef __weak_alias
79 __weak_alias(getnameinfo,_getnameinfo)
80 #endif
81
82 static
83 int
84 hexname(
85 const u_int8_t * cp,
86 size_t len,
87 char * host,
88 socklen_t hostlen
89 );
90
91 static const struct afd {
92 int a_af;
93 socklen_t a_addrlen;
94 socklen_t a_socklen;
95 int a_off;
96 } afdl [] = {
97 #ifdef INET6
98 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
99 offsetof(struct sockaddr_in6, sin6_addr)},
100 #endif
101 {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
102 offsetof(struct sockaddr_in, sin_addr)},
103 {0, 0, 0, 0},
104 };
105
106 struct sockinet {
107 u_char si_len;
108 u_char si_family;
109 u_short si_port;
110 };
111
112 static int getnameinfo_inet __P((const struct sockaddr *, socklen_t, char *,
113 socklen_t, char *, socklen_t, int));
114 #ifdef INET6
115 static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
116 socklen_t, int));
117 static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t,
118 int));
119 #endif
120 static int getnameinfo_link __P((const struct sockaddr *, socklen_t, char *,
121 socklen_t, char *, socklen_t, int));
122 static int hexname __P((const u_int8_t *, size_t, char *, socklen_t));
123
124 /*
125 * Top-level getnameinfo() code. Look at the address family, and pick an
126 * appropriate function to call.
127 */
128 int
129 getnameinfo(
130 const struct sockaddr * sa,
131 socklen_t salen,
132 char * host,
133 socklen_t hostlen,
134 char * serv,
135 socklen_t servlen,
136 int flags
137 )
138 {
139
140 switch (sa->sa_family) {
141 case AF_INET:
142 case AF_INET6:
143 return getnameinfo_inet(sa, salen, host, hostlen,
144 serv, servlen, flags);
145 case AF_LINK:
146 return getnameinfo_link(sa, salen, host, hostlen,
147 serv, servlen, flags);
148 default:
149 return EAI_FAMILY;
150 }
151 }
152
153
154 /*
155 * getnameinfo_inet():
156 * Format an IPv4 or IPv6 sockaddr into a printable string.
157 */
158 static
159 int
160 getnameinfo_inet(
161 const struct sockaddr * sa,
162 socklen_t salen,
163 char * host,
164 socklen_t hostlen,
165 char * serv,
166 socklen_t servlen,
167 int flags
168 )
169 {
170 const struct afd *afd;
171 struct servent *sp;
172 struct hostent *hp;
173 u_short port;
174 int family, i;
175 const char *addr;
176 u_int32_t v4a;
177 char numserv[512];
178 char numaddr[512];
179
180 /* sa is checked below */
181 /* host may be NULL */
182 /* serv may be NULL */
183
184 if (sa == NULL)
185 return EAI_FAIL;
186
187 #ifdef BSD4_4
188 if (sa->sa_len != salen)
189 return EAI_FAIL;
190 #endif
191
192 family = sa->sa_family;
193 for (i = 0; afdl[i].a_af; i++)
194 if (afdl[i].a_af == family) {
195 afd = &afdl[i];
196 goto found;
197 }
198 return EAI_FAMILY;
199
200 found:
201 if (salen != afd->a_socklen)
202 return EAI_FAIL;
203
204 /* network byte order */
205 port = ((const struct sockinet *)(const void *)sa)->si_port;
206 addr = (const char *)(const void *)sa + afd->a_off;
207
208 if (serv == NULL || servlen == 0) {
209 /*
210 * do nothing in this case.
211 * in case you are wondering if "&&" is more correct than
212 * "||" here: rfc2553bis-03 says that serv == NULL OR
213 * servlen == 0 means that the caller does not want the result.
214 */
215 } else {
216 if (flags & NI_NUMERICSERV)
217 sp = NULL;
218 else {
219 struct servent_data svd;
220 // struct servent sv;
221
222 (void)memset(&svd, 0, sizeof(svd));
223 sp = getservbyport_r(port,
224 (flags & NI_DGRAM) ? "udp" : "tcp", &sv, &svd);
225 endservent_r(&svd);
226 }
227 if (sp) {
228 if (strlen(sp->s_name) + 1 > servlen)
229 return EAI_MEMORY;
230 strlcpy(serv, sp->s_name, servlen);
231 } else {
232 snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
233 if (strlen(numserv) + 1 > servlen)
234 return EAI_MEMORY;
235 strlcpy(serv, numserv, servlen);
236 }
237 }
238
239 switch (sa->sa_family) {
240 case AF_INET:
241 v4a = (u_int32_t)
242 ntohl(((const struct sockaddr_in *)
243 (const void *)sa)->sin_addr.s_addr);
244 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
245 flags |= NI_NUMERICHOST;
246 v4a >>= IN_CLASSA_NSHIFT;
247 if (v4a == 0)
248 flags |= NI_NUMERICHOST;
249 break;
250 #ifdef INET6
251 case AF_INET6:
252 {
253 const struct sockaddr_in6 *sin6;
254 sin6 = (const struct sockaddr_in6 *)(const void *)sa;
255 switch (sin6->sin6_addr.s6_addr[0]) {
256 case 0x00:
257 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
258 ;
259 else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
260 ;
261 else
262 flags |= NI_NUMERICHOST;
263 break;
264 default:
265 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
266 flags |= NI_NUMERICHOST;
267 }
268 else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
269 flags |= NI_NUMERICHOST;
270 break;
271 }
272 }
273 break;
274 #endif
275 }
276 if (host == NULL || hostlen == 0) {
277 /*
278 * do nothing in this case.
279 * in case you are wondering if "&&" is more correct than
280 * "||" here: rfc2553bis-03 says that host == NULL or
281 * hostlen == 0 means that the caller does not want the result.
282 */
283 } else if (flags & NI_NUMERICHOST) {
284 size_t numaddrlen;
285
286 /* NUMERICHOST and NAMEREQD conflicts with each other */
287 if (flags & NI_NAMEREQD)
288 return EAI_NONAME;
289
290 switch(afd->a_af) {
291 #ifdef INET6
292 case AF_INET6:
293 {
294 int error;
295
296 if ((error = ip6_parsenumeric(sa, addr, host,
297 hostlen, flags)) != 0)
298 return(error);
299 break;
300 }
301 #endif
302 default:
303 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
304 == NULL)
305 return EAI_SYSTEM;
306 numaddrlen = strlen(numaddr);
307 if (numaddrlen + 1 > hostlen) /* don't forget terminator */
308 return EAI_MEMORY;
309 strlcpy(host, numaddr, hostlen);
310 break;
311 }
312 } else {
313 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
314
315 if (hp) {
316 #if 0
317 /*
318 * commented out, since "for local host" is not
319 * implemented here - see RFC2553 p30
320 */
321 if (flags & NI_NOFQDN) {
322 char *p;
323 p = strchr(hp->h_name, '.');
324 if (p)
325 *p = '\0';
326 }
327 #endif
328 if (strlen(hp->h_name) + 1 > hostlen) {
329 return EAI_MEMORY;
330 }
331 strlcpy(host, hp->h_name, hostlen);
332 } else {
333 if (flags & NI_NAMEREQD)
334 return EAI_NONAME;
335 switch(afd->a_af) {
336 #ifdef INET6
337 case AF_INET6:
338 {
339 int error;
340
341 if ((error = ip6_parsenumeric(sa, addr, host,
342 hostlen,
343 flags)) != 0)
344 return(error);
345 break;
346 }
347 #endif
348 default:
349 if (inet_ntop(afd->a_af, addr, host,
350 hostlen) == NULL)
351 return EAI_SYSTEM;
352 break;
353 }
354 }
355 }
356 return(0);
357 }
358
359 #ifdef INET6
360 static int
361 ip6_parsenumeric(
362 const struct sockaddr *sa,
363 const char *addr,
364 char *host,
365 socklen_t hostlen,
366 int flags
367 )
368 {
369 size_t numaddrlen;
370 char numaddr[512];
371
372 _DIAGASSERT(sa != NULL);
373 _DIAGASSERT(addr != NULL);
374 _DIAGASSERT(host != NULL);
375
376 if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL)
377 return EAI_SYSTEM;
378
379 numaddrlen = strlen(numaddr);
380 if (numaddrlen + 1 > hostlen) /* don't forget terminator */
381 return EAI_OVERFLOW;
382 strlcpy(host, numaddr, hostlen);
383
384 if (((const struct sockaddr_in6 *)(const void *)sa)->sin6_scope_id) {
385 char zonebuf[MAXHOSTNAMELEN];
386 int zonelen;
387
388 zonelen = ip6_sa2str(
389 (const struct sockaddr_in6 *)(const void *)sa,
390 zonebuf, sizeof(zonebuf), flags);
391 if (zonelen < 0)
392 return EAI_OVERFLOW;
393 if ((size_t) zonelen + 1 + numaddrlen + 1 > hostlen)
394 return EAI_OVERFLOW;
395 /* construct <numeric-addr><delim><zoneid> */
396 memcpy(host + numaddrlen + 1, zonebuf,
397 (size_t)zonelen);
398 host[numaddrlen] = SCOPE_DELIMITER;
399 host[numaddrlen + 1 + zonelen] = '\0';
400 }
401
402 return 0;
403 }
404
405 /* ARGSUSED */
406 static int
407 ip6_sa2str(
408 const struct sockaddr_in6 *sa6,
409 char *buf,
410 size_t bufsiz,
411 int flags
412 )
413 {
414 unsigned int ifindex;
415 const struct in6_addr *a6;
416 int n;
417
418 _DIAGASSERT(sa6 != NULL);
419 _DIAGASSERT(buf != NULL);
420
421 ifindex = (unsigned int)sa6->sin6_scope_id;
422 a6 = &sa6->sin6_addr;
423
424 #ifdef NI_NUMERICSCOPE
425 if ((flags & NI_NUMERICSCOPE) != 0) {
426 n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
427 if ((n < 0) || ((size_t)n >= bufsiz))
428 return -1;
429 else
430 return n;
431 }
432 #endif
433
434 #if 0
435 /* if_indextoname() does not take buffer size. not a good api... */
436 if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
437 bufsiz >= IF_NAMESIZE) {
438 char *p = if_indextoname(ifindex, buf);
439 if (p) {
440 return(strlen(p));
441 }
442 }
443 #endif // 0
444
445 /* last resort */
446 n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
447 if (n < 0 || (size_t) n >= bufsiz)
448 return -1;
449 else
450 return n;
451 }
452 #endif /* INET6 */
453
454
455 /*
456 * getnameinfo_link():
457 * Format a link-layer address into a printable format, paying attention to
458 * the interface type.
459 */
460 /* ARGSUSED */
461 static
462 int
463 getnameinfo_link (
464 const struct sockaddr * sa,
465 socklen_t salen,
466 char * host,
467 socklen_t hostlen,
468 char * serv,
469 socklen_t servlen,
470 int flags
471 )
472 {
473 const struct sockaddr_dl *sdl =
474 (const struct sockaddr_dl *)(const void *)sa;
475 // const struct ieee1394_hwaddr *iha;
476 int n;
477
478 if (serv != NULL && servlen > 0)
479 *serv = '\0';
480
481 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) {
482 n = snprintf(host, hostlen, "link#%u", sdl->sdl_index);
483 if (n < 0 || (socklen_t) n > hostlen) {
484 *host = '\0';
485 return EAI_MEMORY;
486 }
487 return 0;
488 }
489
490 #if 0
491 switch (sdl->sdl_type) {
492 #ifdef IFT_ECONET
493 case IFT_ECONET:
494 if (sdl->sdl_alen < 2)
495 return EAI_FAMILY;
496 if (CLLADDR(sdl)[1] == 0)
497 n = snprintf(host, hostlen, "%u", CLLADDR(sdl)[0]);
498 else
499 n = snprintf(host, hostlen, "%u.%u",
500 CLLADDR(sdl)[1], CLLADDR(sdl)[0]);
501 if (n < 0 || (socklen_t) n >= hostlen) {
502 *host = '\0';
503 return EAI_MEMORY;
504 } else
505 return 0;
506 #endif
507 case IFT_IEEE1394:
508 if (sdl->sdl_alen < sizeof(iha->iha_uid))
509 return EAI_FAMILY;
510 iha =
511 (const struct ieee1394_hwaddr *)(const void *)CLLADDR(sdl);
512 return hexname(iha->iha_uid, sizeof(iha->iha_uid),
513 host, hostlen);
514 /*
515 * The following have zero-length addresses.
516 * IFT_ATM (net/if_atmsubr.c)
517 * IFT_FAITH (net/if_faith.c)
518 * IFT_GIF (net/if_gif.c)
519 * IFT_LOOP (net/if_loop.c)
520 * IFT_PPP (net/if_ppp.c, net/if_spppsubr.c)
521 * IFT_SLIP (net/if_sl.c, net/if_strip.c)
522 * IFT_STF (net/if_stf.c)
523 * IFT_L2VLAN (net/if_vlan.c)
524 * IFT_PROPVIRTUAL (net/if_bridge.h>
525 */
526 /*
527 * The following use IPv4 addresses as link-layer addresses:
528 * IFT_OTHER (net/if_gre.c)
529 */
530 case IFT_ARCNET: /* default below is believed correct for all these. */
531 case IFT_ETHER:
532 case IFT_FDDI:
533 case IFT_HIPPI:
534 case IFT_ISO88025:
535 default:
536 #endif // 0
537 return hexname((const u_int8_t *)CLLADDR(sdl),
538 (size_t)sdl->sdl_alen, host, hostlen);
539 // }
540 }
541
542 static
543 int
544 hexname(
545 const u_int8_t * cp,
546 size_t len,
547 char * host,
548 socklen_t hostlen
549 )
550 {
551 int n;
552 size_t i;
553 char *outp = host;
554
555 *outp = '\0';
556 for (i = 0; i < len; i++) {
557 n = snprintf(outp, hostlen, "%s%02x",
558 i ? ":" : "", cp[i]);
559 if (n < 0 || (socklen_t) n >= hostlen) {
560 *host = '\0';
561 return EAI_MEMORY;
562 }
563 outp += n;
564 hostlen -= n;
565 }
566 return 0;
567 }