source: rtems-libbsd/freebsd/lib/libc/net/getnameinfo.c @ 3d1e767

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 3d1e767 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

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