OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / bionic / libc / netbsd / net / getnameinfo.c
1 /*      $NetBSD: getnameinfo.c,v 1.43 2006/02/17 15:58:26 ginsbach 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 #include <sys/cdefs.h>
49 #if defined(LIBC_SCCS) && !defined(lint)
50 __RCSID("$NetBSD: getnameinfo.c,v 1.43 2006/02/17 15:58:26 ginsbach Exp $");
51 #endif /* LIBC_SCCS and not lint */
52
53 #include <sys/types.h>
54 #include <sys/socket.h>
55 #include <net/if.h>
56 #include <net/if_dl.h>
57 #include <net/if_ieee1394.h>
58 #include <net/if_types.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
61 #include "arpa_nameser.h"
62 #include <assert.h>
63 #include <limits.h>
64 #include <netdb.h>
65 #ifdef ANDROID_CHANGES
66 #include "resolv_private.h"
67 #else
68 #include <resolv.h>
69 #endif
70 #include <stddef.h>
71 #include <string.h>
72
73 static const struct afd {
74         int             a_af;
75         socklen_t       a_addrlen;
76         socklen_t       a_socklen;
77         int             a_off;
78 } afdl [] = {
79 #ifdef INET6
80         {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
81                 offsetof(struct sockaddr_in6, sin6_addr)},
82 #endif
83         {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
84                 offsetof(struct sockaddr_in, sin_addr)},
85         {0, 0, 0, 0},
86 };
87
88 struct sockinet {
89         u_char  si_len;
90         u_char  si_family;
91         u_short si_port;
92 };
93
94 static int getnameinfo_inet __P((const struct sockaddr *, socklen_t, char *,
95     socklen_t, char *, socklen_t, int));
96 #ifdef INET6
97 static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
98                                  socklen_t, int));
99 static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t,
100                                  int));
101 #endif
102 static int getnameinfo_link __P((const struct sockaddr *, socklen_t, char *,
103     socklen_t, char *, socklen_t, int));
104 static int hexname __P((const u_int8_t *, size_t, char *, socklen_t));
105
106 /*
107  * Top-level getnameinfo() code.  Look at the address family, and pick an
108  * appropriate function to call.
109  */
110 int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags)
111 {
112         switch (sa->sa_family) {
113         case AF_INET:
114         case AF_INET6:
115                 return getnameinfo_inet(sa, salen, host, hostlen,
116                     serv, servlen, flags);
117 #if 0
118         case AF_LINK:
119                 return getnameinfo_link(sa, salen, host, hostlen,
120                     serv, servlen, flags);
121 #endif
122         default:
123                 return EAI_FAMILY;
124         }
125 }
126
127
128 /*
129  * getnameinfo_inet():
130  * Format an IPv4 or IPv6 sockaddr into a printable string.
131  */
132 static int
133 getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags)
134         const struct sockaddr *sa;
135         socklen_t salen;
136         char *host;
137         socklen_t hostlen;
138         char *serv;
139         socklen_t servlen;
140         int flags;
141 {
142         const struct afd *afd;
143         struct servent *sp;
144         struct hostent *hp;
145         u_short port;
146         int family, i;
147         const char *addr;
148         u_int32_t v4a;
149         char numserv[512];
150         char numaddr[512];
151
152         /* sa is checked below */
153         /* host may be NULL */
154         /* serv may be NULL */
155
156         if (sa == NULL)
157                 return EAI_FAIL;
158
159 #ifdef BSD4_4
160         if (sa->sa_len != salen)
161                 return EAI_FAIL;
162 #endif
163
164         family = sa->sa_family;
165         for (i = 0; afdl[i].a_af; i++)
166                 if (afdl[i].a_af == family) {
167                         afd = &afdl[i];
168                         goto found;
169                 }
170         return EAI_FAMILY;
171
172  found:
173         if (salen != afd->a_socklen)
174                 return EAI_FAIL;
175
176         /* network byte order */
177         port = ((const struct sockinet *)(const void *)sa)->si_port;
178         addr = (const char *)(const void *)sa + afd->a_off;
179
180         if (serv == NULL || servlen == 0) {
181                 /*
182                  * do nothing in this case.
183                  * in case you are wondering if "&&" is more correct than
184                  * "||" here: rfc2553bis-03 says that serv == NULL OR
185                  * servlen == 0 means that the caller does not want the result.
186                  */
187         } else {
188                 if (flags & NI_NUMERICSERV)
189                         sp = NULL;
190                 else {
191                         sp = getservbyport(port,
192                                 (flags & NI_DGRAM) ? "udp" : "tcp");
193                 }
194                 if (sp) {
195                         if (strlen(sp->s_name) + 1 > (size_t)servlen)
196                                 return EAI_MEMORY;
197                         strlcpy(serv, sp->s_name, servlen);
198                 } else {
199                         snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
200                         if (strlen(numserv) + 1 > (size_t)servlen)
201                                 return EAI_MEMORY;
202                         strlcpy(serv, numserv, servlen);
203                 }
204         }
205
206         switch (sa->sa_family) {
207         case AF_INET:
208                 v4a = (u_int32_t)
209                     ntohl(((const struct sockaddr_in *)
210                     (const void *)sa)->sin_addr.s_addr);
211                 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
212                         flags |= NI_NUMERICHOST;
213                 v4a >>= IN_CLASSA_NSHIFT;
214                 if (v4a == 0)
215                         flags |= NI_NUMERICHOST;
216                 break;
217 #ifdef INET6
218         case AF_INET6:
219             {
220                 const struct sockaddr_in6 *sin6;
221                 sin6 = (const struct sockaddr_in6 *)(const void *)sa;
222                 switch (sin6->sin6_addr.s6_addr[0]) {
223                 case 0x00:
224                         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
225                                 ;
226                         else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
227                                 ;
228                         else
229                                 flags |= NI_NUMERICHOST;
230                         break;
231                 default:
232                         if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
233                                 flags |= NI_NUMERICHOST;
234                         }
235                         else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
236                                 flags |= NI_NUMERICHOST;
237                         break;
238                 }
239             }
240                 break;
241 #endif
242         }
243         if (host == NULL || hostlen == 0) {
244                 /*
245                  * do nothing in this case.
246                  * in case you are wondering if "&&" is more correct than
247                  * "||" here: rfc2553bis-03 says that host == NULL or
248                  * hostlen == 0 means that the caller does not want the result.
249                  */
250         } else if (flags & NI_NUMERICHOST) {
251                 size_t numaddrlen;
252
253                 /* NUMERICHOST and NAMEREQD conflicts with each other */
254                 if (flags & NI_NAMEREQD)
255                         return EAI_NONAME;
256
257                 switch(afd->a_af) {
258 #ifdef INET6
259                 case AF_INET6:
260                 {
261                         int error;
262
263                         if ((error = ip6_parsenumeric(sa, addr, host,
264                                                       hostlen, flags)) != 0)
265                                 return(error);
266                         break;
267                 }
268 #endif
269                 default:
270                         if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
271                             == NULL)
272                                 return EAI_SYSTEM;
273                         numaddrlen = strlen(numaddr);
274                         if (numaddrlen + 1 > (size_t)hostlen) /* don't forget terminator */
275                                 return EAI_MEMORY;
276                         strlcpy(host, numaddr, hostlen);
277                         break;
278                 }
279         } else {
280                 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
281
282                 if (hp) {
283 #if 0
284                         /*
285                          * commented out, since "for local host" is not
286                          * implemented here - see RFC2553 p30
287                          */
288                         if (flags & NI_NOFQDN) {
289                                 char *p;
290                                 p = strchr(hp->h_name, '.');
291                                 if (p)
292                                         *p = '\0';
293                         }
294 #endif
295                         if (strlen(hp->h_name) + 1 > (size_t)hostlen) {
296                                 return EAI_MEMORY;
297                         }
298                         strlcpy(host, hp->h_name, hostlen);
299                 } else {
300                         if (flags & NI_NAMEREQD)
301                                 return EAI_NONAME;
302                         switch(afd->a_af) {
303 #ifdef INET6
304                         case AF_INET6:
305                         {
306                                 int error;
307
308                                 if ((error = ip6_parsenumeric(sa, addr, host,
309                                                               hostlen,
310                                                               flags)) != 0)
311                                         return(error);
312                                 break;
313                         }
314 #endif
315                         default:
316                                 if (inet_ntop(afd->a_af, addr, host,
317                                     hostlen) == NULL)
318                                         return EAI_SYSTEM;
319                                 break;
320                         }
321                 }
322         }
323         return(0);
324 }
325
326 #ifdef INET6
327 static int
328 ip6_parsenumeric(sa, addr, host, hostlen, flags)
329         const struct sockaddr *sa;
330         const char *addr;
331         char *host;
332         socklen_t hostlen;
333         int flags;
334 {
335         size_t numaddrlen;
336         char numaddr[512];
337
338         assert(sa != NULL);
339         assert(addr != NULL);
340         assert(host != NULL);
341
342         if (hostlen < 0)
343                 return EAI_OVERFLOW;
344
345         if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL)
346                 return EAI_SYSTEM;
347
348         numaddrlen = strlen(numaddr);
349         if (numaddrlen + 1 > (size_t)hostlen) /* don't forget terminator */
350                 return EAI_OVERFLOW;
351         strlcpy(host, numaddr, hostlen);
352
353         if (((const struct sockaddr_in6 *)(const void *)sa)->sin6_scope_id) {
354                 char zonebuf[MAXHOSTNAMELEN];
355                 int zonelen;
356
357                 zonelen = ip6_sa2str(
358                     (const struct sockaddr_in6 *)(const void *)sa,
359                     zonebuf, sizeof(zonebuf), flags);
360                 if (zonelen < 0)
361                         return EAI_OVERFLOW;
362                 if ((size_t) zonelen + 1 + numaddrlen + 1 > (size_t)hostlen)
363                         return EAI_OVERFLOW;
364                 /* construct <numeric-addr><delim><zoneid> */
365                 memcpy(host + numaddrlen + 1, zonebuf,
366                     (size_t)zonelen);
367                 host[numaddrlen] = SCOPE_DELIMITER;
368                 host[numaddrlen + 1 + zonelen] = '\0';
369         }
370
371         return 0;
372 }
373
374 /* ARGSUSED */
375 static int
376 ip6_sa2str(sa6, buf, bufsiz, flags)
377         const struct sockaddr_in6 *sa6;
378         char *buf;
379         size_t bufsiz;
380         int flags;
381 {
382         unsigned int ifindex;
383         const struct in6_addr *a6;
384         int n;
385
386         assert(sa6 != NULL);
387         assert(buf != NULL);
388
389         ifindex = (unsigned int)sa6->sin6_scope_id;
390         a6 = &sa6->sin6_addr;
391
392 #ifdef NI_NUMERICSCOPE
393         if ((flags & NI_NUMERICSCOPE) != 0) {
394                 n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
395                 if (n < 0 || n >= bufsiz)
396                         return -1;
397                 else
398                         return n;
399         }
400 #endif
401
402         /* if_indextoname() does not take buffer size.  not a good api... */
403         if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
404             bufsiz >= IF_NAMESIZE) {
405                 char *p = if_indextoname(ifindex, buf);
406                 if (p) {
407                         return(strlen(p));
408                 }
409         }
410
411         /* last resort */
412         n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
413         if (n < 0 || (size_t) n >= bufsiz)
414                 return -1;
415         else
416                 return n;
417 }
418 #endif /* INET6 */
419
420
421 /*
422  * getnameinfo_link():
423  * Format a link-layer address into a printable format, paying attention to
424  * the interface type.
425  */
426 /* ARGSUSED */
427 static int
428 getnameinfo_link(const struct sockaddr *sa, socklen_t salen,
429     char *host, socklen_t hostlen, char *serv, socklen_t servlen,
430     int flags)
431 {
432         const struct sockaddr_dl *sdl =
433             (const struct sockaddr_dl *)(const void *)sa;
434         const struct ieee1394_hwaddr *iha;
435         int n;
436
437         if (serv != NULL && servlen > 0)
438                 *serv = '\0';
439
440         if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) {
441                 n = snprintf(host, hostlen, "link#%u", sdl->sdl_index);
442                 if (n < 0 || (socklen_t) n > hostlen) {
443                         *host = '\0';
444                         return EAI_MEMORY;
445                 }
446                 return 0;
447         }
448
449         switch (sdl->sdl_type) {
450 #ifdef IFT_ECONET
451         case IFT_ECONET:
452                 if (sdl->sdl_alen < 2)
453                         return EAI_FAMILY;
454                 if (CLLADDR(sdl)[1] == 0)
455                         n = snprintf(host, hostlen, "%u", CLLADDR(sdl)[0]);
456                 else
457                         n = snprintf(host, hostlen, "%u.%u",
458                             CLLADDR(sdl)[1], CLLADDR(sdl)[0]);
459                 if (n < 0 || (socklen_t) n >= hostlen) {
460                         *host = '\0';
461                         return EAI_MEMORY;
462                 } else
463                         return 0;
464 #endif
465         case IFT_IEEE1394:
466                 if (sdl->sdl_alen < sizeof(iha->iha_uid))
467                         return EAI_FAMILY;
468                 iha =
469                     (const struct ieee1394_hwaddr *)(const void *)CLLADDR(sdl);
470                 return hexname(iha->iha_uid, sizeof(iha->iha_uid),
471                     host, hostlen);
472         /*
473          * The following have zero-length addresses.
474          * IFT_ATM      (net/if_atmsubr.c)
475          * IFT_FAITH    (net/if_faith.c)
476          * IFT_GIF      (net/if_gif.c)
477          * IFT_LOOP     (net/if_loop.c)
478          * IFT_PPP      (net/if_ppp.c, net/if_spppsubr.c)
479          * IFT_SLIP     (net/if_sl.c, net/if_strip.c)
480          * IFT_STF      (net/if_stf.c)
481          * IFT_L2VLAN   (net/if_vlan.c)
482          * IFT_PROPVIRTUAL (net/if_bridge.h>
483          */
484         /*
485          * The following use IPv4 addresses as link-layer addresses:
486          * IFT_OTHER    (net/if_gre.c)
487          */
488         case IFT_ARCNET: /* default below is believed correct for all these. */
489         case IFT_ETHER:
490         case IFT_FDDI:
491         case IFT_HIPPI:
492         case IFT_ISO88025:
493         default:
494                 return hexname((const u_int8_t *)CLLADDR(sdl),
495                     (size_t)sdl->sdl_alen, host, hostlen);
496         }
497 }
498
499 static int
500 hexname(cp, len, host, hostlen)
501         const u_int8_t *cp;
502         char *host;
503         size_t len;
504         socklen_t hostlen;
505 {
506         int n;
507         size_t i;
508         char *outp = host;
509
510         *outp = '\0';
511         for (i = 0; i < len; i++) {
512                 n = snprintf(outp, hostlen, "%s%02x",
513                     i ? ":" : "", cp[i]);
514                 if (n < 0 || (socklen_t) n >= hostlen) {
515                         *host = '\0';
516                         return EAI_MEMORY;
517                 }
518                 outp += n;
519                 hostlen -= n;
520         }
521         return 0;
522 }