~ubuntu-branches/debian/squeeze/ntp/squeeze-201010051545

« back to all changes in this revision

Viewing changes to arlib/arlib.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Zimmerman
  • Date: 2004-10-11 16:10:27 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20041011161027-icyjbji8ujym633o
Tags: 1:4.2.0a-10ubuntu2
Use ntp.ubuntulinux.org instead of pool.ntp.org

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * arlib.c (C)opyright 1993 Darren Reed. All rights reserved.
 
3
 * This file may not be distributed without the author's permission in any
 
4
 * shape or form. The author takes no responsibility for any damage or loss
 
5
 * of property which results from the use of this software.
 
6
 */
 
7
#ifndef lint
 
8
static  char    sccsid[] = "@(#)arlib.c 1.9 6/5/93 (C)opyright 1992 Darren \
 
9
Reed. ASYNC DNS";
 
10
#endif
 
11
 
 
12
#include <stdio.h>
 
13
#include <fcntl.h>
 
14
#include <signal.h>
 
15
#include <sys/types.h>
 
16
#include <sys/time.h>
 
17
#include <sys/socket.h>
 
18
#include <netinet/in.h>
 
19
#include "netdb.h"
 
20
#include "arpa/nameser.h"
 
21
#include <resolv.h>
 
22
#include "arlib.h"
 
23
#include "arplib.h"
 
24
 
 
25
extern  int     errno, h_errno;
 
26
static  char    ar_hostbuf[65], ar_domainname[65];
 
27
static  char    ar_dot[] = ".";
 
28
static  int     ar_resfd = -1, ar_vc = 0;
 
29
static  struct  reslist *ar_last, *ar_first;
 
30
 
 
31
/*
 
32
 * Statistics structure.
 
33
 */
 
34
static  struct  resstats {
 
35
        int     re_errors;
 
36
        int     re_nu_look;
 
37
        int     re_na_look;
 
38
        int     re_replies;
 
39
        int     re_requests;
 
40
        int     re_resends;
 
41
        int     re_sent;
 
42
        int     re_timeouts;
 
43
} ar_reinfo;
 
44
 
 
45
static int do_query_name(/* struct resinfo *, char *, struct reslist * */);
 
46
static int do_query_number(/* struct resinfo *, char *, struct reslist * */);
 
47
static int ar_resend_query(/* struct reslist * */);
 
48
 
 
49
/*
 
50
 * ar_init
 
51
 *
 
52
 * Initializes the various ARLIB internal varilables and related DNS
 
53
 * options for res_init().
 
54
 *
 
55
 * Returns 0 or the socket opened for use with talking to name servers
 
56
 * if 0 is passed or ARES_INITSOCK is set.
 
57
 */
 
58
int     ar_init(op)
 
59
int     op;
 
60
{
 
61
        int     ret = 0;
 
62
 
 
63
        if (op & ARES_INITLIST)
 
64
            {
 
65
                bzero(&ar_reinfo, sizeof(ar_reinfo));
 
66
                ar_first = ar_last = NULL;
 
67
            }
 
68
 
 
69
        if (op & ARES_CALLINIT && !(_res.options & RES_INIT))
 
70
            {
 
71
                ret = res_init();
 
72
                (void)strcpy(ar_domainname, ar_dot);
 
73
                (void)strncat(ar_domainname, _res.defdname,
 
74
                                sizeof(ar_domainname)-2);
 
75
            }
 
76
 
 
77
        if (op & ARES_INITSOCK)
 
78
                ret = ar_resfd = ar_open();
 
79
 
 
80
        if (op & ARES_INITDEBG)
 
81
                _res.options |= RES_DEBUG;
 
82
 
 
83
        if (op == 0)
 
84
                ret = ar_resfd;
 
85
 
 
86
        return ret;
 
87
}
 
88
 
 
89
 
 
90
/*
 
91
 * ar_open
 
92
 *
 
93
 * Open a socket to talk to a name server with.
 
94
 * Check _res.options to see if we use a TCP or UDP socket.
 
95
 */
 
96
int     ar_open()
 
97
{
 
98
        if (ar_resfd == -1)
 
99
            {
 
100
                if (_res.options & RES_USEVC)
 
101
                    {
 
102
                        struct  sockaddr_in     *sip;
 
103
                        int     i;
 
104
 
 
105
                        sip = _res.NS_ADDR_LIST;        /* was _res.nsaddr_list */
 
106
                        ar_vc = 1;
 
107
                        ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
 
108
 
 
109
                        /*
 
110
                         * Try each name server listed in sequence until we
 
111
                         * succeed or run out.
 
112
                         */
 
113
                        while (connect(ar_resfd, (struct sockaddr *)sip++,
 
114
                                        sizeof(struct sockaddr)))
 
115
                            {
 
116
                                (void)close(ar_resfd);
 
117
                                ar_resfd = -1;
 
118
                                if (i >= _res.nscount)
 
119
                                        break;
 
120
                                ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
 
121
                            }
 
122
                    }
 
123
                else
 
124
                        ar_resfd = socket(AF_INET, SOCK_DGRAM, 0);
 
125
            }
 
126
        if (ar_resfd >= 0)
 
127
            {   /* Need one of these two here - and it MUST work!! */
 
128
                int flags;
 
129
 
 
130
                if ((flags = fcntl(ar_resfd, F_GETFL, 0)) != -1)
 
131
#ifdef  O_NONBLOCK
 
132
                         if (fcntl(ar_resfd, F_SETFL, flags|O_NONBLOCK) == -1)
 
133
#else
 
134
# ifdef O_NDELAY
 
135
                         if (fcntl(ar_resfd, F_SETFL, flags|O_NDELAY) == -1)
 
136
# else
 
137
#  ifdef        FNDELAY
 
138
                         if (fcntl(ar_resfd, F_SETFL, flags|FNDELAY) == -1)
 
139
#  endif
 
140
# endif
 
141
#endif
 
142
                    {
 
143
                        (void)close(ar_resfd);
 
144
                        ar_resfd = -1;
 
145
                    }
 
146
            }
 
147
        return ar_resfd;
 
148
}
 
149
 
 
150
 
 
151
/*
 
152
 * ar_close
 
153
 *
 
154
 * Closes and flags the ARLIB socket as closed.
 
155
 */
 
156
void    ar_close()
 
157
{
 
158
        (void)close(ar_resfd);
 
159
        ar_resfd = -1;
 
160
        return;
 
161
}
 
162
 
 
163
 
 
164
/*
 
165
 * ar_add_request
 
166
 *
 
167
 * Add a new DNS query to the end of the query list.
 
168
 */
 
169
static  int     ar_add_request(new)
 
170
struct  reslist *new;
 
171
{
 
172
        if (!new)
 
173
                return -1;
 
174
        if (!ar_first)
 
175
                ar_first = ar_last = new;
 
176
        else {
 
177
                ar_last->re_next = new;
 
178
                ar_last = new;
 
179
        }
 
180
        new->re_next = NULL;
 
181
        ar_reinfo.re_requests++;
 
182
        return 0;
 
183
}
 
184
 
 
185
 
 
186
/*
 
187
 * ar_remrequest
 
188
 *
 
189
 * Remove a request from the list. This must also free any memory that has
 
190
 * been allocated for temporary storage of DNS results.
 
191
 *
 
192
 * Returns -1 if there are anyy problems removing the requested structure
 
193
 * or 0 if the remove is successful.
 
194
 */
 
195
static  int     ar_remrequest(old)
 
196
struct  reslist *old;
 
197
{
 
198
        register struct reslist *rptr, *r2ptr;
 
199
        register char   **s;
 
200
 
 
201
        if (!old)
 
202
                return -1;
 
203
        for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next)
 
204
            {
 
205
                if (rptr == old)
 
206
                        break;
 
207
                r2ptr = rptr;
 
208
            }
 
209
 
 
210
        if (!rptr)
 
211
                return -1;
 
212
        if (rptr == ar_first)
 
213
                ar_first = ar_first->re_next;
 
214
        else if (rptr == ar_last)
 
215
            {
 
216
                if (ar_last = r2ptr)
 
217
                        ar_last->re_next = NULL;
 
218
            }
 
219
        else
 
220
                r2ptr->re_next = rptr->re_next;
 
221
 
 
222
        if (!ar_first)
 
223
                ar_last = ar_first;
 
224
 
 
225
#ifdef  ARLIB_DEBUG
 
226
        ar_dump_hostent("ar_remrequest:", rptr->re_he);
 
227
#endif
 
228
 
 
229
        if (rptr->re_he.h_name)
 
230
                (void)free(rptr->re_he.h_name);
 
231
        if (s = rptr->re_he.h_aliases)
 
232
                for (; *s; s++)
 
233
                        (void)free(*s);
 
234
        if (rptr->re_rinfo.ri_ptr)
 
235
                (void)free(rptr->re_rinfo.ri_ptr);
 
236
        (void)free(rptr);
 
237
 
 
238
        return 0;
 
239
}
 
240
 
 
241
 
 
242
/*
 
243
 * ar_make_request
 
244
 *
 
245
 * Create a DNS query recorded for the request being made and place it on the
 
246
 * current list awaiting replies.  Initialization of the record with set
 
247
 * values should also be done.
 
248
 */
 
249
static  struct  reslist *ar_make_request(resi)
 
250
register struct resinfo *resi;
 
251
{
 
252
        register struct reslist *rptr;
 
253
        register struct resinfo *rp;
 
254
 
 
255
        rptr = (struct reslist *)calloc(1, sizeof(struct reslist));
 
256
        rp = &rptr->re_rinfo;
 
257
 
 
258
        rptr->re_next    = NULL; /* where NULL is non-zero ;) */
 
259
        rptr->re_sentat  = time(NULL);
 
260
        rptr->re_retries = _res.retry;
 
261
        rptr->re_sends = 1;
 
262
        rptr->re_resend  = 1;
 
263
        rptr->re_timeout = rptr->re_sentat + _res.retrans;
 
264
        rptr->re_he.h_name = NULL;
 
265
        rptr->re_he.h_addrtype   = AF_INET;
 
266
        rptr->re_he.h_aliases[0] = NULL;
 
267
        rp->ri_ptr = resi->ri_ptr;
 
268
        rp->ri_size = resi->ri_size;
 
269
 
 
270
        (void)ar_add_request(rptr);
 
271
 
 
272
        return rptr;
 
273
}
 
274
 
 
275
 
 
276
/*
 
277
 * ar_timeout
 
278
 *
 
279
 * Remove queries from the list which have been there too long without
 
280
 * being resolved.
 
281
 */
 
282
long    ar_timeout(now, info, size)
 
283
time_t  now;
 
284
char    *info;
 
285
int     size;
 
286
{
 
287
        register struct reslist *rptr, *r2ptr;
 
288
        register long   next = 0;
 
289
 
 
290
        for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr)
 
291
            {
 
292
                r2ptr = rptr->re_next;
 
293
                if (now >= rptr->re_timeout)
 
294
                    {
 
295
                        /*
 
296
                         * If the timeout for the query has been exceeded,
 
297
                         * then resend the query if we still have some
 
298
                         * 'retry credit' and reset the timeout. If we have
 
299
                         * used it all up, then remove the request.
 
300
                         */
 
301
                        if (--rptr->re_retries <= 0)
 
302
                            {
 
303
                                ar_reinfo.re_timeouts++;
 
304
                                if (info && rptr->re_rinfo.ri_ptr)
 
305
                                        bcopy(rptr->re_rinfo.ri_ptr, info,
 
306
                                                MIN(rptr->re_rinfo.ri_size,
 
307
                                                    size));
 
308
                                (void)ar_remrequest(rptr);
 
309
                                return now;
 
310
                            }
 
311
                        else
 
312
                            {
 
313
                                rptr->re_sends++;
 
314
                                rptr->re_sentat = now;
 
315
                                rptr->re_timeout = now + _res.retrans;
 
316
                                (void)ar_resend_query(rptr);
 
317
                            }
 
318
                    }
 
319
                if (!next || rptr->re_timeout < next)
 
320
                        next = rptr->re_timeout;
 
321
            }
 
322
        return next;
 
323
}
 
324
 
 
325
 
 
326
/*
 
327
 * ar_send_res_msg
 
328
 *
 
329
 * When sending queries to nameservers listed in the resolv.conf file,
 
330
 * don't send a query to every one, but increase the number sent linearly
 
331
 * to match the number of resends. This increase only occurs if there are
 
332
 * multiple nameserver entries in the resolv.conf file.
 
333
 * The return value is the number of messages successfully sent to 
 
334
 * nameservers or -1 if no successful sends.
 
335
 */
 
336
static  int     ar_send_res_msg(msg, len, rcount)
 
337
char    *msg;
 
338
int     len, rcount;
 
339
{
 
340
        register int    i;
 
341
        int     sent = 0;
 
342
 
 
343
        if (!msg)
 
344
                return -1;
 
345
 
 
346
        rcount = (_res.nscount > rcount) ? rcount : _res.nscount;
 
347
        if (_res.options & RES_PRIMARY)
 
348
                rcount = 1;
 
349
 
 
350
        if (ar_vc)
 
351
            {
 
352
                ar_reinfo.re_sent++;
 
353
                sent++;
 
354
                if (write(ar_resfd, msg, len) == -1)
 
355
                    {
 
356
                        int errtmp = errno;
 
357
                        (void)close(ar_resfd);
 
358
                        errno = errtmp;
 
359
                        ar_resfd = -1;
 
360
                    }
 
361
            }
 
362
        else
 
363
                for (i = 0; i < rcount; i++)
 
364
                    {
 
365
                        if (sendto(ar_resfd, msg, len, 0,
 
366
                                   (struct sockaddr *)&(_res.NS_ADDR_LIST[i]),
 
367
                                sizeof(struct sockaddr_in)) == len)
 
368
                            {
 
369
                                ar_reinfo.re_sent++;
 
370
                                sent++;
 
371
                            }
 
372
                    }
 
373
        return (sent) ? sent : -1;
 
374
}
 
375
 
 
376
 
 
377
/*
 
378
 * ar_find_id
 
379
 *
 
380
 * find a dns query record by the id (id is determined by dn_mkquery)
 
381
 */
 
382
static  struct  reslist *ar_find_id(id)
 
383
int     id;
 
384
{
 
385
        register struct reslist *rptr;
 
386
 
 
387
        for (rptr = ar_first; rptr; rptr = rptr->re_next)
 
388
                if (rptr->re_id == id)
 
389
                        return rptr;
 
390
        return NULL;
 
391
}
 
392
 
 
393
 
 
394
/*
 
395
 * ar_delete
 
396
 *
 
397
 * Delete a request from the waiting list if it has a data pointer which
 
398
 * matches the one passed.
 
399
 */
 
400
int     ar_delete(ptr, size)
 
401
char    *ptr;
 
402
int     size;
 
403
{
 
404
        register struct reslist *rptr;
 
405
        register struct reslist *r2ptr;
 
406
        int     removed = 0;
 
407
 
 
408
        for (rptr = ar_first; rptr; rptr = r2ptr)
 
409
            {
 
410
                r2ptr = rptr->re_next;
 
411
                if (rptr->re_rinfo.ri_ptr && ptr && size &&
 
412
                    bcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0)
 
413
                    {
 
414
                        (void)ar_remrequest(rptr);
 
415
                        removed++;
 
416
                    }
 
417
            }
 
418
        return removed;
 
419
}
 
420
 
 
421
 
 
422
/*
 
423
 * ar_query_name
 
424
 *
 
425
 * generate a query based on class, type and name.
 
426
 */
 
427
static  int     ar_query_name(name, class, type, rptr)
 
428
char    *name;
 
429
int     class, type;
 
430
struct  reslist *rptr;
 
431
{
 
432
        static  char buf[MAXPACKET];
 
433
        int     r,s,a;
 
434
        HEADER  *hptr;
 
435
 
 
436
        bzero(buf, sizeof(buf));
 
437
        r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
 
438
                        buf, sizeof(buf));
 
439
        if (r <= 0)
 
440
            {
 
441
                h_errno = NO_RECOVERY;
 
442
                return r;
 
443
            }
 
444
        hptr = (HEADER *)buf;
 
445
        rptr->re_id = ntohs(hptr->id);
 
446
 
 
447
        s = ar_send_res_msg(buf, r, rptr->re_sends);
 
448
 
 
449
        if (s == -1)
 
450
            {
 
451
                h_errno = TRY_AGAIN;
 
452
                return -1;
 
453
            }
 
454
        else
 
455
                rptr->re_sent += s;
 
456
        return 0;
 
457
}
 
458
 
 
459
 
 
460
/*
 
461
 * ar_gethostbyname
 
462
 *
 
463
 * Replacement library function call to gethostbyname().  This one, however,
 
464
 * doesn't return the record being looked up but just places the query in the
 
465
 * queue to await answers.
 
466
 */
 
467
int     ar_gethostbyname(name, info, size)
 
468
char    *name;
 
469
char    *info;
 
470
int     size;
 
471
{
 
472
        char    host[65];
 
473
        struct  resinfo resi;
 
474
        register struct resinfo *rp = &resi;
 
475
 
 
476
        if (size && info)
 
477
            {
 
478
                rp->ri_ptr = (char *)malloc(size);
 
479
                bcopy(info, rp->ri_ptr, size);
 
480
                rp->ri_size = size;
 
481
            }
 
482
        else
 
483
                bzero((char *)rp, sizeof(resi));
 
484
        ar_reinfo.re_na_look++;
 
485
        (void)strncpy(host, name, 64);
 
486
        host[64] = '\0';
 
487
 
 
488
        return (do_query_name(rp, host, NULL));
 
489
}
 
490
 
 
491
 
 
492
static  int     do_query_name(resi, name, rptr)
 
493
struct  resinfo *resi;
 
494
char    *name;
 
495
register struct reslist *rptr;
 
496
{
 
497
        char    hname[65];
 
498
        int     len;
 
499
 
 
500
        len = strlen((char *)strncpy(hname, name, sizeof(hname)-1));
 
501
 
 
502
        if (rptr && (hname[len-1] != '.'))
 
503
            {
 
504
                (void)strncat(hname, ar_dot, sizeof(hname)-len-1);
 
505
                /*
 
506
                 * NOTE: The logical relationship between DNSRCH and DEFNAMES
 
507
                 * is implies. ie no DEFNAES, no DNSRCH.
 
508
                 */
 
509
                if (_res.options & (RES_DEFNAMES|RES_DNSRCH) ==
 
510
                    (RES_DEFNAMES|RES_DNSRCH))
 
511
                    {
 
512
                        if (_res.dnsrch[rptr->re_srch])
 
513
                                (void)strncat(hname, _res.dnsrch[rptr->re_srch],
 
514
                                        sizeof(hname) - ++len -1);
 
515
                    }
 
516
                else if (_res.options & RES_DEFNAMES)
 
517
                        (void)strncat(hname, ar_domainname, sizeof(hname) - len -1);
 
518
            }
 
519
 
 
520
        /*
 
521
         * Store the name passed as the one to lookup and generate other host
 
522
         * names to pass onto the nameserver(s) for lookups.
 
523
         */
 
524
        if (!rptr)
 
525
            {
 
526
                rptr = ar_make_request(resi);
 
527
                rptr->re_type = T_A;
 
528
                (void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1);
 
529
            }
 
530
        return (ar_query_name(hname, C_IN, T_A, rptr));
 
531
}
 
532
 
 
533
 
 
534
/*
 
535
 * ar_gethostbyaddr
 
536
 *
 
537
 * Generates a query for a given IP address.
 
538
 */
 
539
int     ar_gethostbyaddr(addr, info, size)
 
540
char    *addr;
 
541
char    *info;
 
542
int     size;
 
543
{
 
544
        struct  resinfo resi;
 
545
        register struct resinfo *rp = &resi;
 
546
 
 
547
        if (size && info)
 
548
            {
 
549
                rp->ri_ptr = (char *)malloc(size);
 
550
                bcopy(info, rp->ri_ptr, size);
 
551
                rp->ri_size = size;
 
552
            }
 
553
        else
 
554
                bzero((char *)rp, sizeof(resi));
 
555
        ar_reinfo.re_nu_look++;
 
556
        return (do_query_number(rp, addr, NULL));
 
557
}
 
558
 
 
559
 
 
560
/*
 
561
 * do_query_number
 
562
 *
 
563
 * Use this to do reverse IP# lookups.
 
564
 */
 
565
static  int     do_query_number(resi, numb, rptr)
 
566
struct  resinfo *resi;
 
567
char    *numb;
 
568
register struct reslist *rptr;
 
569
{
 
570
        register unsigned char  *cp;
 
571
        static  char    ipbuf[32];
 
572
 
 
573
        /*
 
574
         * Generate name in the "in-addr.arpa" domain.  No addings bits to this
 
575
         * name to get more names to query!.
 
576
         */
 
577
        cp = (unsigned char *)numb;
 
578
        (void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.",
 
579
                        (unsigned int)(cp[3]), (unsigned int)(cp[2]),
 
580
                        (unsigned int)(cp[1]), (unsigned int)(cp[0]));
 
581
 
 
582
        if (!rptr)
 
583
            {
 
584
                rptr = ar_make_request(resi);
 
585
                rptr->re_type = T_PTR;
 
586
                rptr->re_he.h_length = sizeof(struct in_addr);
 
587
                bcopy(numb, (char *)&rptr->re_addr, rptr->re_he.h_length);
 
588
                bcopy(numb, (char *)&rptr->re_he.h_addr_list[0].s_addr,
 
589
                        rptr->re_he.h_length);
 
590
            }
 
591
        return (ar_query_name(ipbuf, C_IN, T_PTR, rptr));
 
592
}
 
593
 
 
594
 
 
595
/*
 
596
 * ar_resent_query
 
597
 *
 
598
 * resends a query.
 
599
 */
 
600
static  int     ar_resend_query(rptr)
 
601
struct  reslist *rptr;
 
602
{
 
603
        if (!rptr->re_resend)
 
604
                return -1;
 
605
 
 
606
        switch(rptr->re_type)
 
607
        {
 
608
        case T_PTR:
 
609
                ar_reinfo.re_resends++;
 
610
                return do_query_number(NULL, &rptr->re_addr, rptr);
 
611
        case T_A:
 
612
                ar_reinfo.re_resends++;
 
613
                return do_query_name(NULL, rptr->re_name, rptr);
 
614
        default:
 
615
                break;
 
616
        }
 
617
 
 
618
        return -1;
 
619
}
 
620
 
 
621
 
 
622
/*
 
623
 * ar_procanswer
 
624
 *
 
625
 * process an answer received from a nameserver.
 
626
 */
 
627
static  int     ar_procanswer(rptr, hptr, buf, eob)
 
628
struct  reslist *rptr;
 
629
char    *buf, *eob;
 
630
HEADER  *hptr;
 
631
{
 
632
        char    *cp, **alias, *s;
 
633
        int     class, type, dlen, len, ans = 0, n, i;
 
634
        u_int32_t ttl, dr, *adr;
 
635
        struct  hent    *hp;
 
636
 
 
637
        cp = buf + sizeof(HEADER);
 
638
        adr = (u_int32_t *)rptr->re_he.h_addr_list;
 
639
 
 
640
        while (*adr)
 
641
                adr++;
 
642
 
 
643
        alias = rptr->re_he.h_aliases;
 
644
        while (*alias)
 
645
                alias++;
 
646
 
 
647
        hp = &rptr->re_he;
 
648
 
 
649
 
 
650
        /*
 
651
         * Skip over the original question.
 
652
         */
 
653
        while (hptr->qdcount-- > 0)
 
654
                cp += dn_skipname(cp, eob) + QFIXEDSZ;
 
655
        /*
 
656
         * proccess each answer sent to us. blech.
 
657
         */
 
658
        while (hptr->ancount-- > 0 && cp < eob) {
 
659
                n = dn_expand(buf, eob, cp, ar_hostbuf, sizeof(ar_hostbuf));
 
660
                cp += n;
 
661
                if (n <= 0)
 
662
                        return ans;
 
663
 
 
664
                ans++;
 
665
                /*
 
666
                 * 'skip' past the general dns crap (ttl, class, etc) to get
 
667
                 * the pointer to the right spot.  Some of thse are actually
 
668
                 * useful so its not a good idea to skip past in one big jump.
 
669
                 */
 
670
                type = (int)_getshort(cp);
 
671
                cp += sizeof(short);
 
672
                class = (int)_getshort(cp);
 
673
                cp += sizeof(short);
 
674
                ttl = (u_int32_t)_getlong(cp);
 
675
                cp += sizeof(u_int32_t);
 
676
                dlen =  (int)_getshort(cp);
 
677
                cp += sizeof(short);
 
678
                rptr->re_type = type;
 
679
 
 
680
                switch(type)
 
681
                {
 
682
                case T_A :
 
683
                        rptr->re_he.h_length = dlen;
 
684
                        if (ans == 1)
 
685
                                rptr->re_he.h_addrtype=(class == C_IN) ?
 
686
                                                        AF_INET : AF_UNSPEC;
 
687
                        if (dlen != sizeof(dr))
 
688
                            {
 
689
                                h_errno = TRY_AGAIN;
 
690
                                continue;
 
691
                            }
 
692
                        bcopy(cp, &dr, dlen);
 
693
                        *adr++ = dr;
 
694
                        *adr = 0;
 
695
                        cp += dlen;
 
696
                        len = strlen(ar_hostbuf);
 
697
                        if (!rptr->re_he.h_name)
 
698
                            {
 
699
                                rptr->re_he.h_name = (char *)malloc(len+1);
 
700
                                if (!rptr->re_he.h_name)
 
701
                                        break;
 
702
                                (void)strcpy(rptr->re_he.h_name, ar_hostbuf);
 
703
                            }
 
704
                        break;
 
705
                case T_PTR :
 
706
                        if ((n = dn_expand(buf, eob, cp, ar_hostbuf,
 
707
                                           sizeof(ar_hostbuf) )) < 0)
 
708
                            {
 
709
                                cp += n;
 
710
                                continue;
 
711
                            }
 
712
                        cp += n;
 
713
                        len = strlen(ar_hostbuf)+1;
 
714
                        /*
 
715
                         * copy the returned hostname into the host name
 
716
                         * or alias field if there is a known hostname
 
717
                         * already.
 
718
                         */
 
719
                        if (!rptr->re_he.h_name)
 
720
                            {
 
721
                                rptr->re_he.h_name = (char *)malloc(len);
 
722
                                if (!rptr->re_he.h_name)
 
723
                                        break;
 
724
                                (void)strcpy(rptr->re_he.h_name, ar_hostbuf);
 
725
                            }
 
726
                        else
 
727
                            {
 
728
                                *alias = (char *)malloc(len);
 
729
                                if (!*alias)
 
730
                                        return -1;
 
731
                                (void)strcpy(*alias++, ar_hostbuf);
 
732
                                *alias = NULL;
 
733
                            }
 
734
                        break;
 
735
                case T_CNAME :
 
736
                        cp += dlen;
 
737
                        if (alias >= &(rptr->re_he.h_aliases[MAXALIASES-1]))
 
738
                                continue;
 
739
                        n = strlen(ar_hostbuf)+1;
 
740
                        *alias = (char *)malloc(n);
 
741
                        if (!*alias)
 
742
                                return -1;
 
743
                        (void)strcpy(*alias++, ar_hostbuf);
 
744
                        *alias = NULL;
 
745
                        break;
 
746
                default :
 
747
                        break;
 
748
                }
 
749
        }
 
750
 
 
751
        return ans;
 
752
}
 
753
 
 
754
 
 
755
/*
 
756
 * ar_answer
 
757
 *
 
758
 * Get an answer from a DNS server and process it.  If a query is found to
 
759
 * which no answer has been given to yet, copy its 'info' structure back
 
760
 * to where "reip" points and return a pointer to the hostent structure.
 
761
 */
 
762
struct  hostent *ar_answer(reip, size)
 
763
char    *reip;
 
764
int     size;
 
765
{
 
766
        static  char    ar_rcvbuf[sizeof(HEADER) + MAXPACKET];
 
767
        static  struct  hostent ar_host;
 
768
 
 
769
        register HEADER *hptr;
 
770
        register struct reslist *rptr = NULL;
 
771
        register struct hostent *hp;
 
772
        register char **s;
 
773
        unsigned long   *adr;
 
774
        int     rc, i, n, a;
 
775
 
 
776
        rc = recv(ar_resfd, ar_rcvbuf, sizeof(ar_rcvbuf), 0);
 
777
        if (rc <= 0)
 
778
                goto getres_err;
 
779
 
 
780
        ar_reinfo.re_replies++;
 
781
        hptr = (HEADER *)ar_rcvbuf;
 
782
        /*
 
783
         * convert things to be in the right order.
 
784
         */
 
785
        hptr->id = ntohs(hptr->id);
 
786
        hptr->ancount = ntohs(hptr->ancount);
 
787
        hptr->arcount = ntohs(hptr->arcount);
 
788
        hptr->nscount = ntohs(hptr->nscount);
 
789
        hptr->qdcount = ntohs(hptr->qdcount);
 
790
        /*
 
791
         * response for an id which we have already received an answer for
 
792
         * just ignore this response.
 
793
         */
 
794
        rptr = ar_find_id(hptr->id);
 
795
        if (!rptr)
 
796
                goto getres_err;
 
797
 
 
798
        if ((hptr->rcode != NOERROR) || (hptr->ancount == 0))
 
799
            {
 
800
                switch (hptr->rcode)
 
801
                {
 
802
                case NXDOMAIN:
 
803
                        h_errno = HOST_NOT_FOUND;
 
804
                        break;
 
805
                case SERVFAIL:
 
806
                        h_errno = TRY_AGAIN;
 
807
                        break;
 
808
                case NOERROR:
 
809
                        h_errno = NO_DATA;
 
810
                        break;
 
811
                case FORMERR:
 
812
                case NOTIMP:
 
813
                case REFUSED:
 
814
                default:
 
815
                        h_errno = NO_RECOVERY;
 
816
                        break;
 
817
                }
 
818
                ar_reinfo.re_errors++;
 
819
                /*
 
820
                ** If a bad error was returned, we stop here and dont send
 
821
                ** send any more (no retries granted).
 
822
                */
 
823
                if (h_errno != TRY_AGAIN)
 
824
                    {
 
825
                        rptr->re_resend = 0;
 
826
                        rptr->re_retries = 0;
 
827
                    }
 
828
                goto getres_err;
 
829
            }
 
830
 
 
831
        a = ar_procanswer(rptr, hptr, ar_rcvbuf, ar_rcvbuf+rc);
 
832
 
 
833
        if ((rptr->re_type == T_PTR) && (_res.options & RES_CHECKPTR))
 
834
            {
 
835
                /*
 
836
                 * For reverse lookups on IP#'s, lookup the name that is given
 
837
                 * for the ip# and return with that as the official result.
 
838
                 * -avalon
 
839
                 */
 
840
                rptr->re_type = T_A;
 
841
                /*
 
842
                 * Clean out the list of addresses already set, even though
 
843
                 * there should only be one :)
 
844
                 */
 
845
                adr = (unsigned long *)rptr->re_he.h_addr_list;
 
846
                while (*adr)
 
847
                        *adr++ = 0L;
 
848
                /*
 
849
                 * Lookup the name that we were given for the ip#
 
850
                 */
 
851
                ar_reinfo.re_na_look++;
 
852
                (void)strncpy(rptr->re_name, rptr->re_he.h_name,
 
853
                        sizeof(rptr->re_name)-1);
 
854
                rptr->re_he.h_name = NULL;
 
855
                rptr->re_retries = _res.retry;
 
856
                rptr->re_sends = 1;
 
857
                rptr->re_resend = 1;
 
858
                rptr->re_he.h_name = NULL;
 
859
                ar_reinfo.re_na_look++;
 
860
                (void)ar_query_name(rptr->re_name, C_IN, T_A, rptr);
 
861
                return NULL;
 
862
            }
 
863
 
 
864
        if (reip && rptr->re_rinfo.ri_ptr && size)
 
865
                bcopy(rptr->re_rinfo.ri_ptr, reip,
 
866
                        MIN(rptr->re_rinfo.ri_size, size));
 
867
        /*
 
868
         * Clean up structure from previous usage.
 
869
         */
 
870
        hp = &ar_host;
 
871
#ifdef  ARLIB_DEBUG
 
872
        ar_dump_hostent("ar_answer: previous usage", hp);
 
873
#endif
 
874
 
 
875
        if (hp->h_name)
 
876
                (void)free(hp->h_name);
 
877
        if (s = hp->h_aliases)
 
878
            {
 
879
                while (*s)
 
880
                        (void)free(*s++);
 
881
                (void)free(hp->h_aliases);
 
882
            }
 
883
        if (s = hp->h_addr_list)
 
884
            {
 
885
                /*
 
886
                 * Only free once since we allocated space for
 
887
                 * address in one big chunk.
 
888
                 */
 
889
                (void)free(*s);
 
890
                (void)free(hp->h_addr_list);
 
891
            }
 
892
        bzero((char *)hp, sizeof(*hp));
 
893
 
 
894
        /*
 
895
         * Setup and copy details for the structure we return a pointer to.
 
896
         */
 
897
        hp->h_addrtype = AF_INET;
 
898
        hp->h_length = sizeof(struct in_addr);
 
899
        if(rptr->re_he.h_name)
 
900
            {
 
901
                hp->h_name = (char *)malloc(strlen(rptr->re_he.h_name)+1);
 
902
                if(!hp->h_name)
 
903
                    {
 
904
#ifdef  ARLIB_DEBUG
 
905
                        fprintf(stderr, "no memory for hostname\n");
 
906
#endif
 
907
                        h_errno = TRY_AGAIN;
 
908
                        goto getres_err;
 
909
                    }
 
910
                (void)strcpy(hp->h_name, rptr->re_he.h_name);
 
911
            }
 
912
#ifdef  ARLIB_DEBUG
 
913
        ar_dump_hostent("ar_answer: (snap) store name", hp);
 
914
#endif
 
915
 
 
916
        /*
 
917
         * Count IP#'s.
 
918
         */
 
919
        for (i = 0, n = 0; i < MAXADDRS; i++, n++)
 
920
                if (!rptr->re_he.h_addr_list[i].s_addr)
 
921
                        break;
 
922
        s = hp->h_addr_list = (char **)malloc((n + 1) * sizeof(char *));
 
923
        if (n)
 
924
            {
 
925
                *s = (char *)malloc(n * sizeof(struct in_addr));
 
926
                if(!*s)
 
927
                    {
 
928
#ifdef  ARLIB_DEBUG
 
929
                        fprintf(stderr, "no memory for IP#'s (%d)\n", n);
 
930
#endif
 
931
                        h_errno = TRY_AGAIN;
 
932
                        goto getres_err;
 
933
                    }
 
934
                bcopy((char *)&rptr->re_he.h_addr_list[0].s_addr, *s,
 
935
                        sizeof(struct in_addr));
 
936
                s++;
 
937
                for (i = 1; i < n; i++, s++)
 
938
                    {
 
939
                        *s = hp->h_addr + i * sizeof(struct in_addr);
 
940
                        bcopy((char *)&rptr->re_he.h_addr_list[i].s_addr, *s,
 
941
                                sizeof(struct in_addr));
 
942
                    }
 
943
            }
 
944
        *s = NULL;
 
945
#ifdef  ARLIB_DEBUG
 
946
        ar_dump_hostent("ar_answer: (snap) store IP#'s", hp);
 
947
#endif
 
948
 
 
949
        /*
 
950
         * Count CNAMEs
 
951
         */
 
952
        for (i = 0, n = 0; i < MAXADDRS; i++, n++)
 
953
                if (!rptr->re_he.h_aliases[i])
 
954
                        break;
 
955
        s = hp->h_aliases = (char **)malloc((n + 1) * sizeof(char *));
 
956
        if (!s)
 
957
            {
 
958
#ifdef  ARLIB_DEBUG
 
959
                fprintf(stderr, "no memory for aliases (%d)\n", n);
 
960
#endif
 
961
                h_errno = TRY_AGAIN;
 
962
                goto getres_err;
 
963
            }
 
964
        for (i = 0; i < n; i++)
 
965
            {
 
966
                *s++ = rptr->re_he.h_aliases[i];
 
967
                rptr->re_he.h_aliases[i] = NULL;
 
968
            }
 
969
        *s = NULL;
 
970
#ifdef  ARLIB_DEBUG
 
971
        ar_dump_hostent("ar_answer: (snap) store CNAMEs", hp);
 
972
        ar_dump_hostent("ar_answer: new one", hp);
 
973
#endif
 
974
 
 
975
        if (a > 0)
 
976
                (void)ar_remrequest(rptr);
 
977
        else
 
978
                if (!rptr->re_sent)
 
979
                        (void)ar_remrequest(rptr);
 
980
        return hp;
 
981
 
 
982
getres_err:
 
983
        if (rptr)
 
984
            {
 
985
                if (reip && rptr->re_rinfo.ri_ptr && size)
 
986
                        bcopy(rptr->re_rinfo.ri_ptr, reip,
 
987
                                MIN(rptr->re_rinfo.ri_size, size));
 
988
                if ((h_errno != TRY_AGAIN) &&
 
989
                    (_res.options & (RES_DNSRCH|RES_DEFNAMES) ==
 
990
                     (RES_DNSRCH|RES_DEFNAMES) ))
 
991
                        if (_res.dnsrch[rptr->re_srch])
 
992
                            {
 
993
                                rptr->re_retries = _res.retry;
 
994
                                rptr->re_sends = 1;
 
995
                                rptr->re_resend = 1;
 
996
                                (void)ar_resend_query(rptr);
 
997
                                rptr->re_srch++;
 
998
                            }
 
999
                return NULL;
 
1000
            }
 
1001
        return NULL;
 
1002
}
 
1003
 
 
1004
 
 
1005
#ifdef  ARLIB_DEBUG
 
1006
void ar_dump_hostent(prefix, hp)
 
1007
char *prefix;
 
1008
struct hostent *hp;
 
1009
{
 
1010
        register char **s;
 
1011
 
 
1012
        fflush(stdout);
 
1013
 
 
1014
        fprintf(stderr, "%s\n", prefix);
 
1015
        fprintf(stderr, "  hp %p\n", hp);
 
1016
        fprintf(stderr, "    h_name %p '%s'\n",
 
1017
        hp->h_name, hp->h_name);
 
1018
        if (s = hp->h_aliases)
 
1019
            {
 
1020
                fprintf(stderr, "    h_aliases %p\n",
 
1021
                hp->h_aliases);
 
1022
                while (*s)
 
1023
                    {
 
1024
                        fprintf(stderr, "      element %p\n", *s);
 
1025
                        s++;
 
1026
                    }
 
1027
            }
 
1028
        if (s = hp->h_addr_list)
 
1029
            {
 
1030
                fprintf(stderr, "    h_addr_list %p\n",
 
1031
                hp->h_addr_list);
 
1032
                while (*s)
 
1033
                    {
 
1034
                        fprintf(stderr, "      element %p\n", *s);
 
1035
                        s++;
 
1036
                    }
 
1037
            }
 
1038
 
 
1039
        fflush(stderr);
 
1040
}
 
1041
 
 
1042
 
 
1043
void ar_dump_reslist(FILE* fp)
 
1044
{
 
1045
        register struct reslist *rptr;
 
1046
        int c;
 
1047
 
 
1048
        c = 0;
 
1049
        for (rptr = ar_first; rptr; rptr = rptr->re_next)
 
1050
            {
 
1051
                fprintf(fp, "%4d [%p] %4d [%p]: %s\n", rptr->re_id, rptr,
 
1052
                        *(rptr->re_rinfo.ri_ptr), rptr->re_rinfo.ri_ptr,
 
1053
                        rptr->re_name);
 
1054
            }
 
1055
}
 
1056
#endif