📄 arlib.c
字号:
/* * arlib.c (C)opyright 1993 Darren Reed. All rights reserved. * This file may not be distributed without the author's permission in any * shape or form. The author takes no responsibility for any damage or loss * of property which results from the use of this software. */#ifndef lintstatic char sccsid[] = "@(#)arlib.c 1.9 6/5/93 (C)opyright 1992 Darren \Reed. ASYNC DNS";#endif#include <stdio.h>#include <fcntl.h>#include <signal.h>#include <sys/types.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include "netdb.h"#include "arpa/nameser.h"#include <resolv.h>#include "arlib.h"#include "arplib.h"extern int errno, h_errno;static char ar_hostbuf[65], ar_domainname[65];static char ar_dot[] = ".";static int ar_resfd = -1, ar_vc = 0;static struct reslist *ar_last, *ar_first;/* * Statistics structure. */static struct resstats { int re_errors; int re_nu_look; int re_na_look; int re_replies; int re_requests; int re_resends; int re_sent; int re_timeouts;} ar_reinfo;static int do_query_name(/* struct resinfo *, char *, struct reslist * */);static int do_query_number(/* struct resinfo *, char *, struct reslist * */);static int ar_resend_query(/* struct reslist * */);/* * ar_init * * Initializes the various ARLIB internal varilables and related DNS * options for res_init(). * * Returns 0 or the socket opened for use with talking to name servers * if 0 is passed or ARES_INITSOCK is set. */int ar_init(op)int op;{ int ret = 0; if (op & ARES_INITLIST) { bzero(&ar_reinfo, sizeof(ar_reinfo)); ar_first = ar_last = NULL; } if (op & ARES_CALLINIT && !(_res.options & RES_INIT)) { ret = res_init(); (void)strcpy(ar_domainname, ar_dot); (void)strncat(ar_domainname, _res.defdname, sizeof(ar_domainname)-2); } if (op & ARES_INITSOCK) ret = ar_resfd = ar_open(); if (op & ARES_INITDEBG) _res.options |= RES_DEBUG; if (op == 0) ret = ar_resfd; return ret;}/* * ar_open * * Open a socket to talk to a name server with. * Check _res.options to see if we use a TCP or UDP socket. */int ar_open(){ if (ar_resfd == -1) { if (_res.options & RES_USEVC) { struct sockaddr_in *sip; int i; sip = _res.NS_ADDR_LIST; /* was _res.nsaddr_list */ ar_vc = 1; ar_resfd = socket(AF_INET, SOCK_STREAM, 0); /* * Try each name server listed in sequence until we * succeed or run out. */ while (connect(ar_resfd, (struct sockaddr *)sip++, sizeof(struct sockaddr))) { (void)close(ar_resfd); ar_resfd = -1; if (i >= _res.nscount) break; ar_resfd = socket(AF_INET, SOCK_STREAM, 0); } } else ar_resfd = socket(AF_INET, SOCK_DGRAM, 0); } if (ar_resfd >= 0) { /* Need one of these two here - and it MUST work!! */ int flags; if ((flags = fcntl(ar_resfd, F_GETFL, 0)) != -1)#ifdef O_NONBLOCK if (fcntl(ar_resfd, F_SETFL, flags|O_NONBLOCK) == -1)#else# ifdef O_NDELAY if (fcntl(ar_resfd, F_SETFL, flags|O_NDELAY) == -1)# else# ifdef FNDELAY if (fcntl(ar_resfd, F_SETFL, flags|FNDELAY) == -1)# endif# endif#endif { (void)close(ar_resfd); ar_resfd = -1; } } return ar_resfd;}/* * ar_close * * Closes and flags the ARLIB socket as closed. */void ar_close(){ (void)close(ar_resfd); ar_resfd = -1; return;}/* * ar_add_request * * Add a new DNS query to the end of the query list. */static int ar_add_request(new)struct reslist *new;{ if (!new) return -1; if (!ar_first) ar_first = ar_last = new; else { ar_last->re_next = new; ar_last = new; } new->re_next = NULL; ar_reinfo.re_requests++; return 0;}/* * ar_remrequest * * Remove a request from the list. This must also free any memory that has * been allocated for temporary storage of DNS results. * * Returns -1 if there are anyy problems removing the requested structure * or 0 if the remove is successful. */static int ar_remrequest(old)struct reslist *old;{ register struct reslist *rptr, *r2ptr; register char **s; if (!old) return -1; for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next) { if (rptr == old) break; r2ptr = rptr; } if (!rptr) return -1; if (rptr == ar_first) ar_first = ar_first->re_next; else if (rptr == ar_last) { if (ar_last = r2ptr) ar_last->re_next = NULL; } else r2ptr->re_next = rptr->re_next; if (!ar_first) ar_last = ar_first;#ifdef ARLIB_DEBUG ar_dump_hostent("ar_remrequest:", rptr->re_he);#endif if (rptr->re_he.h_name) (void)free(rptr->re_he.h_name); if (s = rptr->re_he.h_aliases) for (; *s; s++) (void)free(*s); if (rptr->re_rinfo.ri_ptr) (void)free(rptr->re_rinfo.ri_ptr); (void)free(rptr); return 0;}/* * ar_make_request * * Create a DNS query recorded for the request being made and place it on the * current list awaiting replies. Initialization of the record with set * values should also be done. */static struct reslist *ar_make_request(resi)register struct resinfo *resi;{ register struct reslist *rptr; register struct resinfo *rp; rptr = (struct reslist *)calloc(1, sizeof(struct reslist)); rp = &rptr->re_rinfo; rptr->re_next = NULL; /* where NULL is non-zero ;) */ rptr->re_sentat = time(NULL); rptr->re_retries = _res.retry; rptr->re_sends = 1; rptr->re_resend = 1; rptr->re_timeout = rptr->re_sentat + _res.retrans; rptr->re_he.h_name = NULL; rptr->re_he.h_addrtype = AF_INET; rptr->re_he.h_aliases[0] = NULL; rp->ri_ptr = resi->ri_ptr; rp->ri_size = resi->ri_size; (void)ar_add_request(rptr); return rptr;}/* * ar_timeout * * Remove queries from the list which have been there too long without * being resolved. */long ar_timeout(now, info, size)time_t now;char *info;int size;{ register struct reslist *rptr, *r2ptr; register long next = 0; for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr) { r2ptr = rptr->re_next; if (now >= rptr->re_timeout) { /* * If the timeout for the query has been exceeded, * then resend the query if we still have some * 'retry credit' and reset the timeout. If we have * used it all up, then remove the request. */ if (--rptr->re_retries <= 0) { ar_reinfo.re_timeouts++; if (info && rptr->re_rinfo.ri_ptr) bcopy(rptr->re_rinfo.ri_ptr, info, MIN(rptr->re_rinfo.ri_size, size)); (void)ar_remrequest(rptr); return now; } else { rptr->re_sends++; rptr->re_sentat = now; rptr->re_timeout = now + _res.retrans; (void)ar_resend_query(rptr); } } if (!next || rptr->re_timeout < next) next = rptr->re_timeout; } return next;}/* * ar_send_res_msg * * When sending queries to nameservers listed in the resolv.conf file, * don't send a query to every one, but increase the number sent linearly * to match the number of resends. This increase only occurs if there are * multiple nameserver entries in the resolv.conf file. * The return value is the number of messages successfully sent to * nameservers or -1 if no successful sends. */static int ar_send_res_msg(msg, len, rcount)char *msg;int len, rcount;{ register int i; int sent = 0; if (!msg) return -1; rcount = (_res.nscount > rcount) ? rcount : _res.nscount; if (_res.options & RES_PRIMARY) rcount = 1; if (ar_vc) { ar_reinfo.re_sent++; sent++; if (write(ar_resfd, msg, len) == -1) { int errtmp = errno; (void)close(ar_resfd); errno = errtmp; ar_resfd = -1; } } else for (i = 0; i < rcount; i++) { if (sendto(ar_resfd, msg, len, 0, (struct sockaddr *)&(_res.NS_ADDR_LIST[i]), sizeof(struct sockaddr_in)) == len) { ar_reinfo.re_sent++; sent++; } } return (sent) ? sent : -1;}/* * ar_find_id * * find a dns query record by the id (id is determined by dn_mkquery) */static struct reslist *ar_find_id(id)int id;{ register struct reslist *rptr; for (rptr = ar_first; rptr; rptr = rptr->re_next) if (rptr->re_id == id) return rptr; return NULL;}/* * ar_delete * * Delete a request from the waiting list if it has a data pointer which * matches the one passed. */int ar_delete(ptr, size)char *ptr;int size;{ register struct reslist *rptr; register struct reslist *r2ptr; int removed = 0; for (rptr = ar_first; rptr; rptr = r2ptr) { r2ptr = rptr->re_next; if (rptr->re_rinfo.ri_ptr && ptr && size && bcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0) { (void)ar_remrequest(rptr); removed++; } } return removed;}/* * ar_query_name * * generate a query based on class, type and name. */static int ar_query_name(name, class, type, rptr)char *name;int class, type;struct reslist *rptr;{ static char buf[MAXPACKET]; int r,s,a; HEADER *hptr; bzero(buf, sizeof(buf)); r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, buf, sizeof(buf)); if (r <= 0) { h_errno = NO_RECOVERY; return r; } hptr = (HEADER *)buf; rptr->re_id = ntohs(hptr->id); s = ar_send_res_msg(buf, r, rptr->re_sends); if (s == -1) { h_errno = TRY_AGAIN; return -1; } else rptr->re_sent += s; return 0;}/* * ar_gethostbyname * * Replacement library function call to gethostbyname(). This one, however, * doesn't return the record being looked up but just places the query in the * queue to await answers. */int ar_gethostbyname(name, info, size)char *name;char *info;int size;{ char host[65]; struct resinfo resi; register struct resinfo *rp = &resi; if (size && info) { rp->ri_ptr = (char *)malloc(size); bcopy(info, rp->ri_ptr, size); rp->ri_size = size; } else bzero((char *)rp, sizeof(resi)); ar_reinfo.re_na_look++; (void)strncpy(host, name, 64); host[64] = '\0'; return (do_query_name(rp, host, NULL));}static int do_query_name(resi, name, rptr)struct resinfo *resi;char *name;register struct reslist *rptr;{ char hname[65]; int len; len = strlen((char *)strncpy(hname, name, sizeof(hname)-1)); if (rptr && (hname[len-1] != '.')) { (void)strncat(hname, ar_dot, sizeof(hname)-len-1); /* * NOTE: The logical relationship between DNSRCH and DEFNAMES * is implies. ie no DEFNAES, no DNSRCH. */ if (_res.options & (RES_DEFNAMES|RES_DNSRCH) == (RES_DEFNAMES|RES_DNSRCH)) { if (_res.dnsrch[rptr->re_srch]) (void)strncat(hname, _res.dnsrch[rptr->re_srch], sizeof(hname) - ++len -1); } else if (_res.options & RES_DEFNAMES) (void)strncat(hname, ar_domainname, sizeof(hname) - len -1); } /* * Store the name passed as the one to lookup and generate other host * names to pass onto the nameserver(s) for lookups. */ if (!rptr) { rptr = ar_make_request(resi); rptr->re_type = T_A; (void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -