~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/roken/getaddrinfo.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
 
3
 * (Royal Institute of Technology, Stockholm, Sweden).
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 *
 
10
 * 1. Redistributions of source code must retain the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer.
 
12
 *
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 *
 
17
 * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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
#ifdef HAVE_CONFIG_H
 
35
#include <config.h>
 
36
RCSID("$Id$");
 
37
#endif
 
38
 
 
39
#include "roken.h"
 
40
 
 
41
/*
 
42
 * uses hints->ai_socktype and hints->ai_protocol
 
43
 */
 
44
 
 
45
static int
 
46
get_port_protocol_socktype (const char *servname,
 
47
                            const struct addrinfo *hints,
 
48
                            int *port,
 
49
                            int *protocol,
 
50
                            int *socktype)
 
51
{
 
52
    struct servent *se;
 
53
    const char *proto_str = NULL;
 
54
 
 
55
    *socktype = 0;
 
56
 
 
57
    if (hints != NULL && hints->ai_protocol != 0) {
 
58
        struct protoent *protoent = getprotobynumber (hints->ai_protocol);
 
59
 
 
60
        if (protoent == NULL)
 
61
            return EAI_SOCKTYPE; /* XXX */
 
62
 
 
63
        proto_str = protoent->p_name;
 
64
        *protocol = protoent->p_proto;
 
65
    }
 
66
 
 
67
    if (hints != NULL)
 
68
        *socktype = hints->ai_socktype;
 
69
 
 
70
    if (*socktype == SOCK_STREAM) {
 
71
        se = getservbyname (servname, proto_str ? proto_str : "tcp");
 
72
        if (proto_str == NULL)
 
73
            *protocol = IPPROTO_TCP;
 
74
    } else if (*socktype == SOCK_DGRAM) {
 
75
        se = getservbyname (servname, proto_str ? proto_str : "udp");
 
76
        if (proto_str == NULL)
 
77
            *protocol = IPPROTO_UDP;
 
78
    } else if (*socktype == 0) {
 
79
        if (proto_str != NULL) {
 
80
            se = getservbyname (servname, proto_str);
 
81
        } else {
 
82
            se = getservbyname (servname, "tcp");
 
83
            *protocol = IPPROTO_TCP;
 
84
            *socktype = SOCK_STREAM;
 
85
            if (se == NULL) {
 
86
                se = getservbyname (servname, "udp");
 
87
                *protocol = IPPROTO_UDP;
 
88
                *socktype = SOCK_DGRAM;
 
89
            }
 
90
        }
 
91
    } else
 
92
        return EAI_SOCKTYPE;
 
93
 
 
94
    if (se == NULL) {
 
95
        char *endstr;
 
96
 
 
97
        *port = htons(strtol (servname, &endstr, 10));
 
98
        if (servname == endstr)
 
99
            return EAI_NONAME;
 
100
    } else {
 
101
        *port = se->s_port;
 
102
    }
 
103
    return 0;
 
104
}
 
105
 
 
106
static int
 
107
add_one (int port, int protocol, int socktype,
 
108
         struct addrinfo ***ptr,
 
109
         int (*func)(struct addrinfo *, void *data, int port),
 
110
         void *data,
 
111
         char *canonname)
 
112
{
 
113
    struct addrinfo *a;
 
114
    int ret;
 
115
 
 
116
    a = malloc (sizeof (*a));
 
117
    if (a == NULL)
 
118
        return EAI_MEMORY;
 
119
    memset (a, 0, sizeof(*a));
 
120
    a->ai_flags     = 0;
 
121
    a->ai_next      = NULL;
 
122
    a->ai_protocol  = protocol;
 
123
    a->ai_socktype  = socktype;
 
124
    a->ai_canonname = canonname;
 
125
    ret = (*func)(a, data, port);
 
126
    if (ret) {
 
127
        free (a);
 
128
        return ret;
 
129
    }
 
130
    **ptr = a;
 
131
    *ptr = &a->ai_next;
 
132
    return 0;
 
133
}
 
134
 
 
135
static int
 
136
const_v4 (struct addrinfo *a, void *data, int port)
 
137
{
 
138
    struct sockaddr_in *sin4;
 
139
    struct in_addr *addr = (struct in_addr *)data;
 
140
 
 
141
    a->ai_family  = PF_INET;
 
142
    a->ai_addrlen = sizeof(*sin4);
 
143
    a->ai_addr    = malloc (sizeof(*sin4));
 
144
    if (a->ai_addr == NULL)
 
145
        return EAI_MEMORY;
 
146
    sin4 = (struct sockaddr_in *)a->ai_addr;
 
147
    memset (sin4, 0, sizeof(*sin4));
 
148
    sin4->sin_family = AF_INET;
 
149
    sin4->sin_port   = port;
 
150
    sin4->sin_addr   = *addr;
 
151
    return 0;
 
152
}
 
153
 
 
154
#ifdef HAVE_IPV6
 
155
static int
 
156
const_v6 (struct addrinfo *a, void *data, int port)
 
157
{
 
158
    struct sockaddr_in6 *sin6;
 
159
    struct in6_addr *addr = (struct in6_addr *)data;
 
160
 
 
161
    a->ai_family  = PF_INET6;
 
162
    a->ai_addrlen = sizeof(*sin6);
 
163
    a->ai_addr    = malloc (sizeof(*sin6));
 
164
    if (a->ai_addr == NULL)
 
165
        return EAI_MEMORY;
 
166
    sin6 = (struct sockaddr_in6 *)a->ai_addr;
 
167
    memset (sin6, 0, sizeof(*sin6));
 
168
    sin6->sin6_family = AF_INET6;
 
169
    sin6->sin6_port   = port;
 
170
    sin6->sin6_addr   = *addr;
 
171
    return 0;
 
172
}
 
173
#endif
 
174
 
 
175
/* this is mostly a hack for some versions of AIX that has a prototype
 
176
   for in6addr_loopback but no actual symbol in libc */
 
177
#if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
 
178
#define in6addr_loopback _roken_in6addr_loopback
 
179
struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 
180
#endif
 
181
 
 
182
static int
 
183
get_null (const struct addrinfo *hints,
 
184
          int port, int protocol, int socktype,
 
185
          struct addrinfo **res)
 
186
{
 
187
    struct in_addr v4_addr;
 
188
#ifdef HAVE_IPV6
 
189
    struct in6_addr v6_addr;
 
190
#endif
 
191
    struct addrinfo *first = NULL;
 
192
    struct addrinfo **current = &first;
 
193
    int family = PF_UNSPEC;
 
194
    int ret;
 
195
 
 
196
    if (hints != NULL)
 
197
        family = hints->ai_family;
 
198
 
 
199
    if (hints && hints->ai_flags & AI_PASSIVE) {
 
200
        v4_addr.s_addr = INADDR_ANY;
 
201
#ifdef HAVE_IPV6
 
202
        v6_addr        = in6addr_any;
 
203
#endif
 
204
    } else {
 
205
        v4_addr.s_addr = htonl(INADDR_LOOPBACK);
 
206
#ifdef HAVE_IPV6
 
207
        v6_addr        = in6addr_loopback;
 
208
#endif
 
209
    }
 
210
 
 
211
#ifdef HAVE_IPV6
 
212
    if (family == PF_INET6 || family == PF_UNSPEC) {
 
213
        ret = add_one (port, protocol, socktype,
 
214
                       &current, const_v6, &v6_addr, NULL);
 
215
    }
 
216
#endif
 
217
    if (family == PF_INET || family == PF_UNSPEC) {
 
218
        ret = add_one (port, protocol, socktype,
 
219
                       &current, const_v4, &v4_addr, NULL);
 
220
    }
 
221
    *res = first;
 
222
    return 0;
 
223
}
 
224
 
 
225
static int
 
226
add_hostent (int port, int protocol, int socktype,
 
227
             struct addrinfo ***current,
 
228
             int (*func)(struct addrinfo *, void *data, int port),
 
229
             struct hostent *he, int *flags)
 
230
{
 
231
    int ret;
 
232
    char *canonname = NULL;
 
233
    char **h;
 
234
 
 
235
    if (*flags & AI_CANONNAME) {
 
236
        struct hostent *he2 = NULL;
 
237
        const char *tmp_canon;
 
238
 
 
239
        tmp_canon = hostent_find_fqdn (he);
 
240
        if (strchr (tmp_canon, '.') == NULL) {
 
241
            int error;
 
242
 
 
243
            he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length,
 
244
                                   he->h_addrtype, &error);
 
245
            if (he2 != NULL) {
 
246
                const char *tmp = hostent_find_fqdn (he2);
 
247
 
 
248
                if (strchr (tmp, '.') != NULL)
 
249
                    tmp_canon = tmp;
 
250
            }
 
251
        }
 
252
 
 
253
        canonname = strdup (tmp_canon);
 
254
        if (he2 != NULL)
 
255
            freehostent (he2);
 
256
        if (canonname == NULL)
 
257
            return EAI_MEMORY;
 
258
    }
 
259
 
 
260
    for (h = he->h_addr_list; *h != NULL; ++h) {
 
261
        ret = add_one (port, protocol, socktype,
 
262
                       current, func, *h, canonname);
 
263
        if (ret)
 
264
            return ret;
 
265
        if (*flags & AI_CANONNAME) {
 
266
            *flags &= ~AI_CANONNAME;
 
267
            canonname = NULL;
 
268
        }
 
269
    }
 
270
    return 0;
 
271
}
 
272
 
 
273
static int
 
274
get_number (const char *nodename,
 
275
            const struct addrinfo *hints,
 
276
            int port, int protocol, int socktype,
 
277
            struct addrinfo **res)
 
278
{
 
279
    struct addrinfo *first = NULL;
 
280
    struct addrinfo **current = &first;
 
281
    int family = PF_UNSPEC;
 
282
    int ret;
 
283
 
 
284
    if (hints != NULL) {
 
285
        family = hints->ai_family;
 
286
    }
 
287
 
 
288
#ifdef HAVE_IPV6
 
289
    if (family == PF_INET6 || family == PF_UNSPEC) {
 
290
        struct in6_addr v6_addr;
 
291
 
 
292
        if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) {
 
293
            ret = add_one (port, protocol, socktype,
 
294
                           &current, const_v6, &v6_addr, NULL);
 
295
            *res = first;
 
296
            return ret;
 
297
        }
 
298
    }
 
299
#endif
 
300
    if (family == PF_INET || family == PF_UNSPEC) {
 
301
        struct in_addr v4_addr;
 
302
 
 
303
        if (inet_pton (PF_INET, nodename, &v4_addr) == 1) {
 
304
            ret = add_one (port, protocol, socktype,
 
305
                           &current, const_v4, &v4_addr, NULL);
 
306
            *res = first;
 
307
            return ret;
 
308
        }
 
309
    }
 
310
    return EAI_NONAME;
 
311
}
 
312
 
 
313
static int
 
314
get_nodes (const char *nodename,
 
315
           const struct addrinfo *hints,
 
316
           int port, int protocol, int socktype,
 
317
           struct addrinfo **res)
 
318
{
 
319
    struct addrinfo *first = NULL;
 
320
    struct addrinfo **current = &first;
 
321
    int family = PF_UNSPEC;
 
322
    int flags  = 0;
 
323
    int ret = EAI_NONAME;
 
324
    int error;
 
325
 
 
326
    if (hints != NULL) {
 
327
        family = hints->ai_family;
 
328
        flags  = hints->ai_flags;
 
329
    }
 
330
 
 
331
#ifdef HAVE_IPV6
 
332
    if (family == PF_INET6 || family == PF_UNSPEC) {
 
333
        struct hostent *he;
 
334
 
 
335
        he = getipnodebyname (nodename, PF_INET6, 0, &error);
 
336
 
 
337
        if (he != NULL) {
 
338
            ret = add_hostent (port, protocol, socktype,
 
339
                               &current, const_v6, he, &flags);
 
340
            freehostent (he);
 
341
        }
 
342
    }
 
343
#endif
 
344
    if (family == PF_INET || family == PF_UNSPEC) {
 
345
        struct hostent *he;
 
346
 
 
347
        he = getipnodebyname (nodename, PF_INET, 0, &error);
 
348
 
 
349
        if (he != NULL) {
 
350
            ret = add_hostent (port, protocol, socktype,
 
351
                               &current, const_v4, he, &flags);
 
352
            freehostent (he);
 
353
        }
 
354
    }
 
355
    *res = first;
 
356
    return ret;
 
357
}
 
358
 
 
359
/*
 
360
 * hints:
 
361
 *
 
362
 * struct addrinfo {
 
363
 *     int    ai_flags;
 
364
 *     int    ai_family;
 
365
 *     int    ai_socktype;
 
366
 *     int    ai_protocol;
 
367
 * ...
 
368
 * };
 
369
 */
 
370
 
 
371
int ROKEN_LIB_FUNCTION
 
372
getaddrinfo(const char *nodename,
 
373
            const char *servname,
 
374
            const struct addrinfo *hints,
 
375
            struct addrinfo **res)
 
376
{
 
377
    int ret;
 
378
    int port     = 0;
 
379
    int protocol = 0;
 
380
    int socktype = 0;
 
381
 
 
382
    *res = NULL;
 
383
 
 
384
    if (servname == NULL && nodename == NULL)
 
385
        return EAI_NONAME;
 
386
 
 
387
    if (hints != NULL
 
388
        && hints->ai_family != PF_UNSPEC
 
389
        && hints->ai_family != PF_INET
 
390
#ifdef HAVE_IPV6
 
391
        && hints->ai_family != PF_INET6
 
392
#endif
 
393
        )
 
394
        return EAI_FAMILY;
 
395
 
 
396
    if (servname != NULL) {
 
397
        ret = get_port_protocol_socktype (servname, hints,
 
398
                                          &port, &protocol, &socktype);
 
399
        if (ret)
 
400
            return ret;
 
401
    }
 
402
    if (nodename != NULL) {
 
403
        ret = get_number (nodename, hints, port, protocol, socktype, res);
 
404
        if (ret) {
 
405
            if(hints && hints->ai_flags & AI_NUMERICHOST)
 
406
                ret = EAI_NONAME;
 
407
            else
 
408
                ret = get_nodes (nodename, hints, port, protocol, socktype,
 
409
                                 res);
 
410
        }
 
411
    } else {
 
412
        ret = get_null (hints, port, protocol, socktype, res);
 
413
    }
 
414
    if (ret)
 
415
        freeaddrinfo (*res);
 
416
    return ret;
 
417
}