Sigh, back out the last bright idea I had here about compiling the res_*
routines from contrib/bind directly. There were too many problems, including having to add -DUSE_OPTIONS_H to the entire libc source in order for the contrib code to pick up it's options, and so on. Instead, I've merged the changes, libc is now self contained again.
This commit is contained in:
parent
93ae833698
commit
f991bb5181
@ -2,7 +2,6 @@
|
||||
|
||||
# machine-independent net sources
|
||||
.PATH: ${.CURDIR}/${MACHINE}/net ${.CURDIR}/net
|
||||
.PATH: ${.CURDIR}/../../contrib/bind/res
|
||||
|
||||
SRCS+= addr2ascii.c ascii2addr.c \
|
||||
gethostbydns.c gethostbyht.c gethostbynis.c gethostnamadr.c \
|
||||
|
486
lib/libc/net/res_comp.c
Normal file
486
lib/libc/net/res_comp.c
Normal file
@ -0,0 +1,486 @@
|
||||
/*
|
||||
* ++Copyright++ 1985, 1993
|
||||
* -
|
||||
* Copyright (c) 1985, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
|
||||
static char rcsid[] = "$Id: res_comp.c,v 8.8 1996/08/05 08:31:35 vixie Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <resolv.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
static int dn_find __P((u_char *exp_dn, u_char *msg,
|
||||
u_char **dnptrs, u_char **lastdnptr));
|
||||
|
||||
/*
|
||||
* Expand compressed domain name 'comp_dn' to full domain name.
|
||||
* 'msg' is a pointer to the begining of the message,
|
||||
* 'eomorig' points to the first location after the message,
|
||||
* 'exp_dn' is a pointer to a buffer of size 'length' for the result.
|
||||
* Return size of compressed name or -1 if there was an error.
|
||||
*/
|
||||
int
|
||||
dn_expand(msg, eomorig, comp_dn, exp_dn, length)
|
||||
const u_char *msg, *eomorig, *comp_dn;
|
||||
char *exp_dn;
|
||||
int length;
|
||||
{
|
||||
register const u_char *cp;
|
||||
register char *dn;
|
||||
register int n, c;
|
||||
char *eom;
|
||||
int len = -1, checked = 0;
|
||||
|
||||
dn = exp_dn;
|
||||
cp = comp_dn;
|
||||
eom = exp_dn + length;
|
||||
/*
|
||||
* fetch next label in domain name
|
||||
*/
|
||||
while ( (n = *cp++) ) {
|
||||
/*
|
||||
* Check for indirection
|
||||
*/
|
||||
switch (n & INDIR_MASK) {
|
||||
case 0:
|
||||
if (dn != exp_dn) {
|
||||
if (dn >= eom)
|
||||
return (-1);
|
||||
*dn++ = '.';
|
||||
}
|
||||
if (dn+n >= eom)
|
||||
return (-1);
|
||||
checked += n + 1;
|
||||
while (--n >= 0) {
|
||||
if (((c = *cp++) == '.') || (c == '\\')) {
|
||||
if (dn + n + 2 >= eom)
|
||||
return (-1);
|
||||
*dn++ = '\\';
|
||||
}
|
||||
*dn++ = c;
|
||||
if (cp >= eomorig) /* out of range */
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case INDIR_MASK:
|
||||
if (len < 0)
|
||||
len = cp - comp_dn + 1;
|
||||
cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
|
||||
if (cp < msg || cp >= eomorig) /* out of range */
|
||||
return (-1);
|
||||
checked += 2;
|
||||
/*
|
||||
* Check for loops in the compressed name;
|
||||
* if we've looked at the whole message,
|
||||
* there must be a loop.
|
||||
*/
|
||||
if (checked >= eomorig - msg)
|
||||
return (-1);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1); /* flag error */
|
||||
}
|
||||
}
|
||||
*dn = '\0';
|
||||
if (len < 0)
|
||||
len = cp - comp_dn;
|
||||
return (len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compress domain name 'exp_dn' into 'comp_dn'.
|
||||
* Return the size of the compressed name or -1.
|
||||
* 'length' is the size of the array pointed to by 'comp_dn'.
|
||||
* 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
|
||||
* is a pointer to the beginning of the message. The list ends with NULL.
|
||||
* 'lastdnptr' is a pointer to the end of the arrary pointed to
|
||||
* by 'dnptrs'. Side effect is to update the list of pointers for
|
||||
* labels inserted into the message as we compress the name.
|
||||
* If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
|
||||
* is NULL, we don't update the list.
|
||||
*/
|
||||
int
|
||||
dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
|
||||
const char *exp_dn;
|
||||
u_char *comp_dn, **dnptrs, **lastdnptr;
|
||||
int length;
|
||||
{
|
||||
register u_char *cp, *dn;
|
||||
register int c, l;
|
||||
u_char **cpp, **lpp, *sp, *eob;
|
||||
u_char *msg;
|
||||
|
||||
dn = (u_char *)exp_dn;
|
||||
cp = comp_dn;
|
||||
eob = cp + length;
|
||||
lpp = cpp = NULL;
|
||||
if (dnptrs != NULL) {
|
||||
if ((msg = *dnptrs++) != NULL) {
|
||||
for (cpp = dnptrs; *cpp != NULL; cpp++)
|
||||
;
|
||||
lpp = cpp; /* end of list to search */
|
||||
}
|
||||
} else
|
||||
msg = NULL;
|
||||
for (c = *dn++; c != '\0'; ) {
|
||||
/* look to see if we can use pointers */
|
||||
if (msg != NULL) {
|
||||
if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
|
||||
if (cp+1 >= eob)
|
||||
return (-1);
|
||||
*cp++ = (l >> 8) | INDIR_MASK;
|
||||
*cp++ = l % 256;
|
||||
return (cp - comp_dn);
|
||||
}
|
||||
/* not found, save it */
|
||||
if (lastdnptr != NULL && cpp < lastdnptr-1) {
|
||||
*cpp++ = cp;
|
||||
*cpp = NULL;
|
||||
}
|
||||
}
|
||||
sp = cp++; /* save ptr to length byte */
|
||||
do {
|
||||
if (c == '.') {
|
||||
c = *dn++;
|
||||
break;
|
||||
}
|
||||
if (c == '\\') {
|
||||
if ((c = *dn++) == '\0')
|
||||
break;
|
||||
}
|
||||
if (cp >= eob) {
|
||||
if (msg != NULL)
|
||||
*lpp = NULL;
|
||||
return (-1);
|
||||
}
|
||||
*cp++ = c;
|
||||
} while ((c = *dn++) != '\0');
|
||||
/* catch trailing '.'s but not '..' */
|
||||
if ((l = cp - sp - 1) == 0 && c == '\0') {
|
||||
cp--;
|
||||
break;
|
||||
}
|
||||
if (l <= 0 || l > MAXLABEL) {
|
||||
if (msg != NULL)
|
||||
*lpp = NULL;
|
||||
return (-1);
|
||||
}
|
||||
*sp = l;
|
||||
}
|
||||
if (cp >= eob) {
|
||||
if (msg != NULL)
|
||||
*lpp = NULL;
|
||||
return (-1);
|
||||
}
|
||||
*cp++ = '\0';
|
||||
return (cp - comp_dn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip over a compressed domain name. Return the size or -1.
|
||||
*/
|
||||
int
|
||||
__dn_skipname(comp_dn, eom)
|
||||
const u_char *comp_dn, *eom;
|
||||
{
|
||||
register const u_char *cp;
|
||||
register int n;
|
||||
|
||||
cp = comp_dn;
|
||||
while (cp < eom && (n = *cp++)) {
|
||||
/*
|
||||
* check for indirection
|
||||
*/
|
||||
switch (n & INDIR_MASK) {
|
||||
case 0: /* normal case, n == len */
|
||||
cp += n;
|
||||
continue;
|
||||
case INDIR_MASK: /* indirection */
|
||||
cp++;
|
||||
break;
|
||||
default: /* illegal type */
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cp > eom)
|
||||
return (-1);
|
||||
return (cp - comp_dn);
|
||||
}
|
||||
|
||||
static int
|
||||
mklower(ch)
|
||||
register int ch;
|
||||
{
|
||||
if (isascii(ch) && isupper(ch))
|
||||
return (tolower(ch));
|
||||
return (ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for expanded name from a list of previously compressed names.
|
||||
* Return the offset from msg if found or -1.
|
||||
* dnptrs is the pointer to the first name on the list,
|
||||
* not the pointer to the start of the message.
|
||||
*/
|
||||
static int
|
||||
dn_find(exp_dn, msg, dnptrs, lastdnptr)
|
||||
u_char *exp_dn, *msg;
|
||||
u_char **dnptrs, **lastdnptr;
|
||||
{
|
||||
register u_char *dn, *cp, **cpp;
|
||||
register int n;
|
||||
u_char *sp;
|
||||
|
||||
for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
|
||||
dn = exp_dn;
|
||||
sp = cp = *cpp;
|
||||
while ( (n = *cp++) ) {
|
||||
/*
|
||||
* check for indirection
|
||||
*/
|
||||
switch (n & INDIR_MASK) {
|
||||
case 0: /* normal case, n == len */
|
||||
while (--n >= 0) {
|
||||
if (*dn == '.')
|
||||
goto next;
|
||||
if (*dn == '\\')
|
||||
dn++;
|
||||
if (mklower(*dn++) != mklower(*cp++))
|
||||
goto next;
|
||||
}
|
||||
if ((n = *dn++) == '\0' && *cp == '\0')
|
||||
return (sp - msg);
|
||||
if (n == '.')
|
||||
continue;
|
||||
goto next;
|
||||
|
||||
case INDIR_MASK: /* indirection */
|
||||
cp = msg + (((n & 0x3f) << 8) | *cp);
|
||||
break;
|
||||
|
||||
default: /* illegal type */
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (*dn == '\0')
|
||||
return (sp - msg);
|
||||
next: ;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that a domain name uses an acceptable character set.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note the conspicuous absence of ctype macros in these definitions. On
|
||||
* non-ASCII hosts, we can't depend on string literals or ctype macros to
|
||||
* tell us anything about network-format data. The rest of the BIND system
|
||||
* is not careful about this, but for some reason, we're doing it right here.
|
||||
*/
|
||||
#define PERIOD 0x2e
|
||||
#define hyphenchar(c) ((c) == 0x2d)
|
||||
#define bslashchar(c) ((c) == 0x5c)
|
||||
#define periodchar(c) ((c) == PERIOD)
|
||||
#define asterchar(c) ((c) == 0x2a)
|
||||
#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
|
||||
|| ((c) >= 0x61 && (c) <= 0x7a))
|
||||
#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
|
||||
|
||||
#define borderchar(c) (alphachar(c) || digitchar(c))
|
||||
#define middlechar(c) (borderchar(c) || hyphenchar(c))
|
||||
#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
|
||||
|
||||
int
|
||||
res_hnok(dn)
|
||||
const char *dn;
|
||||
{
|
||||
int ppch = '\0', pch = PERIOD, ch = *dn++;
|
||||
|
||||
while (ch != '\0') {
|
||||
int nch = *dn++;
|
||||
|
||||
if (periodchar(ch)) {
|
||||
NULL;
|
||||
} else if (periodchar(pch)) {
|
||||
if (!borderchar(ch))
|
||||
return (0);
|
||||
} else if (periodchar(nch) || nch == '\0') {
|
||||
if (!borderchar(ch))
|
||||
return (0);
|
||||
} else {
|
||||
if (!middlechar(ch))
|
||||
return (0);
|
||||
}
|
||||
ppch = pch, pch = ch, ch = nch;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* hostname-like (A, MX, WKS) owners can have "*" as their first label
|
||||
* but must otherwise be as a host name.
|
||||
*/
|
||||
int
|
||||
res_ownok(dn)
|
||||
const char *dn;
|
||||
{
|
||||
if (asterchar(dn[0]) && periodchar(dn[1]))
|
||||
dn += 2;
|
||||
return (res_hnok(dn));
|
||||
}
|
||||
|
||||
/*
|
||||
* SOA RNAMEs and RP RNAMEs can have any printable character in their first
|
||||
* label, but the rest of the name has to look like a host name.
|
||||
*/
|
||||
int
|
||||
res_mailok(dn)
|
||||
const char *dn;
|
||||
{
|
||||
int ch, escaped = 0;
|
||||
|
||||
/* "." is a valid missing representation */
|
||||
if (*dn == '\0')
|
||||
return(1);
|
||||
|
||||
/* otherwise <label>.<hostname> */
|
||||
while ((ch = *dn++) != '\0') {
|
||||
if (!domainchar(ch))
|
||||
return (0);
|
||||
if (!escaped && periodchar(ch))
|
||||
break;
|
||||
if (escaped)
|
||||
escaped = 0;
|
||||
else if (bslashchar(ch))
|
||||
escaped = 1;
|
||||
}
|
||||
if (periodchar(ch))
|
||||
return (res_hnok(dn));
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is quite liberal, since RFC 1034's character sets are only
|
||||
* recommendations.
|
||||
*/
|
||||
int
|
||||
res_dnok(dn)
|
||||
const char *dn;
|
||||
{
|
||||
int ch;
|
||||
|
||||
while ((ch = *dn++) != '\0')
|
||||
if (!domainchar(ch))
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines to insert/extract short/long's.
|
||||
*/
|
||||
|
||||
u_int16_t
|
||||
_getshort(msgp)
|
||||
register const u_char *msgp;
|
||||
{
|
||||
register u_int16_t u;
|
||||
|
||||
GETSHORT(u, msgp);
|
||||
return (u);
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
_getlong(msgp)
|
||||
register const u_char *msgp;
|
||||
{
|
||||
register u_int32_t u;
|
||||
|
||||
GETLONG(u, msgp);
|
||||
return (u);
|
||||
}
|
||||
|
||||
void
|
||||
#if defined(__STDC__) || defined(__cplusplus)
|
||||
__putshort(register u_int16_t s, register u_char *msgp) /* must match proto */
|
||||
#else
|
||||
__putshort(s, msgp)
|
||||
register u_int16_t s;
|
||||
register u_char *msgp;
|
||||
#endif
|
||||
{
|
||||
PUTSHORT(s, msgp);
|
||||
}
|
||||
|
||||
void
|
||||
__putlong(l, msgp)
|
||||
register u_int32_t l;
|
||||
register u_char *msgp;
|
||||
{
|
||||
PUTLONG(l, msgp);
|
||||
}
|
@ -4,5 +4,6 @@
|
||||
#define RFC1535 /* comply with RFC1535 (STRONGLY reccomended by vixie)*/
|
||||
#undef USELOOPBACK /* res_init() bind to localhost */
|
||||
#undef SUNSECURITY /* verify gethostbyaddr() calls - WE DONT NEED IT */
|
||||
#undef ALLOW_UPDATES /* compile support for update REQUESTS - harmless */
|
||||
#define ALLOW_UPDATES /* compile recognition for update REQUESTS - harmless */
|
||||
#define MULTI_PTRS_ARE_ALIASES 1 /* fold multiple PTR records into aliases */
|
||||
#define CHECK_SRVR_ADDR 1 /* confirm that the server requested sent the reply */
|
||||
|
111
lib/libc/net/res_data.c
Normal file
111
lib/libc/net/res_data.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* ++Copyright++ 1995
|
||||
* -
|
||||
* Copyright (c) 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char rcsid[] = "$Id: res_data.c,v 8.2 1996/08/05 08:31:35 vixie Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <resolv.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *_res_opcodes[] = {
|
||||
"QUERY",
|
||||
"IQUERY",
|
||||
"CQUERYM",
|
||||
"CQUERYU", /* experimental */
|
||||
"NOTIFY", /* experimental */
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"UPDATEA",
|
||||
"UPDATED",
|
||||
"UPDATEDA",
|
||||
"UPDATEM",
|
||||
"UPDATEMA",
|
||||
"ZONEINIT",
|
||||
"ZONEREF",
|
||||
};
|
||||
|
||||
const char *_res_resultcodes[] = {
|
||||
"NOERROR",
|
||||
"FORMERR",
|
||||
"SERVFAIL",
|
||||
"NXDOMAIN",
|
||||
"NOTIMP",
|
||||
"REFUSED",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"10",
|
||||
"11",
|
||||
"12",
|
||||
"13",
|
||||
"14",
|
||||
"NOCHANGE",
|
||||
};
|
1208
lib/libc/net/res_debug.c
Normal file
1208
lib/libc/net/res_debug.c
Normal file
File diff suppressed because it is too large
Load Diff
454
lib/libc/net/res_init.c
Normal file
454
lib/libc/net/res_init.c
Normal file
@ -0,0 +1,454 @@
|
||||
/*
|
||||
* ++Copyright++ 1985, 1989, 1993
|
||||
* -
|
||||
* Copyright (c) 1985, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
|
||||
static char rcsid[] = "$Id: res_init.c,v 8.5 1996/08/05 08:31:35 vixie Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "res_config.h"
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <resolv.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void res_setoptions __P((char *, char *));
|
||||
|
||||
#ifdef RESOLVSORT
|
||||
static const char sort_mask[] = "/&";
|
||||
#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
|
||||
static u_int32_t net_mask __P((struct in_addr));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Resolver state default settings.
|
||||
*/
|
||||
|
||||
struct __res_state _res;
|
||||
|
||||
/*
|
||||
* Set up default settings. If the configuration file exist, the values
|
||||
* there will have precedence. Otherwise, the server address is set to
|
||||
* INADDR_ANY and the default domain name comes from the gethostname().
|
||||
*
|
||||
* An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
|
||||
* rather than INADDR_ANY ("0.0.0.0") as the default name server address
|
||||
* since it was noted that INADDR_ANY actually meant ``the first interface
|
||||
* you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
|
||||
* it had to be "up" in order for you to reach your own name server. It
|
||||
* was later decided that since the recommended practice is to always
|
||||
* install local static routes through 127.0.0.1 for all your network
|
||||
* interfaces, that we could solve this problem without a code change.
|
||||
*
|
||||
* The configuration file should always be used, since it is the only way
|
||||
* to specify a default domain. If you are running a server on your local
|
||||
* machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
|
||||
* in the configuration file.
|
||||
*
|
||||
* Return 0 if completes successfully, -1 on error
|
||||
*/
|
||||
int
|
||||
res_init()
|
||||
{
|
||||
register FILE *fp;
|
||||
register char *cp, **pp;
|
||||
register int n;
|
||||
char buf[BUFSIZ];
|
||||
int nserv = 0; /* number of nameserver records read from file */
|
||||
int haveenv = 0;
|
||||
int havesearch = 0;
|
||||
#ifdef RESOLVSORT
|
||||
int nsort = 0;
|
||||
char *net;
|
||||
#endif
|
||||
#ifndef RFC1535
|
||||
int dots;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These three fields used to be statically initialized. This made
|
||||
* it hard to use this code in a shared library. It is necessary,
|
||||
* now that we're doing dynamic initialization here, that we preserve
|
||||
* the old semantics: if an application modifies one of these three
|
||||
* fields of _res before res_init() is called, res_init() will not
|
||||
* alter them. Of course, if an application is setting them to
|
||||
* _zero_ before calling res_init(), hoping to override what used
|
||||
* to be the static default, we can't detect it and unexpected results
|
||||
* will follow. Zero for any of these fields would make no sense,
|
||||
* so one can safely assume that the applications were already getting
|
||||
* unexpected results.
|
||||
*
|
||||
* _res.options is tricky since some apps were known to diddle the bits
|
||||
* before res_init() was first called. We can't replicate that semantic
|
||||
* with dynamic initialization (they may have turned bits off that are
|
||||
* set in RES_DEFAULT). Our solution is to declare such applications
|
||||
* "broken". They could fool us by setting RES_INIT but none do (yet).
|
||||
*/
|
||||
if (!_res.retrans)
|
||||
_res.retrans = RES_TIMEOUT;
|
||||
if (!_res.retry)
|
||||
_res.retry = 4;
|
||||
if (!(_res.options & RES_INIT))
|
||||
_res.options = RES_DEFAULT;
|
||||
|
||||
/*
|
||||
* This one used to initialize implicitly to zero, so unless the app
|
||||
* has set it to something in particular, we can randomize it now.
|
||||
*/
|
||||
if (!_res.id)
|
||||
_res.id = res_randomid();
|
||||
|
||||
#ifdef USELOOPBACK
|
||||
_res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
|
||||
#else
|
||||
_res.nsaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
#endif
|
||||
_res.nsaddr.sin_family = AF_INET;
|
||||
_res.nsaddr.sin_port = htons(NAMESERVER_PORT);
|
||||
_res.nscount = 1;
|
||||
_res.ndots = 1;
|
||||
_res.pfcode = 0;
|
||||
|
||||
/* Allow user to override the local domain definition */
|
||||
if ((cp = getenv("LOCALDOMAIN")) != NULL) {
|
||||
(void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
|
||||
haveenv++;
|
||||
|
||||
/*
|
||||
* Set search list to be blank-separated strings
|
||||
* from rest of env value. Permits users of LOCALDOMAIN
|
||||
* to still have a search list, and anyone to set the
|
||||
* one that they want to use as an individual (even more
|
||||
* important now that the rfc1535 stuff restricts searches)
|
||||
*/
|
||||
cp = _res.defdname;
|
||||
pp = _res.dnsrch;
|
||||
*pp++ = cp;
|
||||
for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
|
||||
if (*cp == '\n') /* silly backwards compat */
|
||||
break;
|
||||
else if (*cp == ' ' || *cp == '\t') {
|
||||
*cp = 0;
|
||||
n = 1;
|
||||
} else if (n) {
|
||||
*pp++ = cp;
|
||||
n = 0;
|
||||
havesearch = 1;
|
||||
}
|
||||
}
|
||||
/* null terminate last domain if there are excess */
|
||||
while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
|
||||
cp++;
|
||||
*cp = '\0';
|
||||
*pp++ = 0;
|
||||
}
|
||||
|
||||
#define MATCH(line, name) \
|
||||
(!strncmp(line, name, sizeof(name) - 1) && \
|
||||
(line[sizeof(name) - 1] == ' ' || \
|
||||
line[sizeof(name) - 1] == '\t'))
|
||||
|
||||
if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
|
||||
/* read the config file */
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
/* skip comments */
|
||||
if (*buf == ';' || *buf == '#')
|
||||
continue;
|
||||
/* read default domain name */
|
||||
if (MATCH(buf, "domain")) {
|
||||
if (haveenv) /* skip if have from environ */
|
||||
continue;
|
||||
cp = buf + sizeof("domain") - 1;
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
if ((*cp == '\0') || (*cp == '\n'))
|
||||
continue;
|
||||
strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
|
||||
if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL)
|
||||
*cp = '\0';
|
||||
havesearch = 0;
|
||||
continue;
|
||||
}
|
||||
/* set search list */
|
||||
if (MATCH(buf, "search")) {
|
||||
if (haveenv) /* skip if have from environ */
|
||||
continue;
|
||||
cp = buf + sizeof("search") - 1;
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
if ((*cp == '\0') || (*cp == '\n'))
|
||||
continue;
|
||||
strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
|
||||
if ((cp = strchr(_res.defdname, '\n')) != NULL)
|
||||
*cp = '\0';
|
||||
/*
|
||||
* Set search list to be blank-separated strings
|
||||
* on rest of line.
|
||||
*/
|
||||
cp = _res.defdname;
|
||||
pp = _res.dnsrch;
|
||||
*pp++ = cp;
|
||||
for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
|
||||
if (*cp == ' ' || *cp == '\t') {
|
||||
*cp = 0;
|
||||
n = 1;
|
||||
} else if (n) {
|
||||
*pp++ = cp;
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
/* null terminate last domain if there are excess */
|
||||
while (*cp != '\0' && *cp != ' ' && *cp != '\t')
|
||||
cp++;
|
||||
*cp = '\0';
|
||||
*pp++ = 0;
|
||||
havesearch = 1;
|
||||
continue;
|
||||
}
|
||||
/* read nameservers to query */
|
||||
if (MATCH(buf, "nameserver") && nserv < MAXNS) {
|
||||
struct in_addr a;
|
||||
|
||||
cp = buf + sizeof("nameserver") - 1;
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) {
|
||||
_res.nsaddr_list[nserv].sin_addr = a;
|
||||
_res.nsaddr_list[nserv].sin_family = AF_INET;
|
||||
_res.nsaddr_list[nserv].sin_port =
|
||||
htons(NAMESERVER_PORT);
|
||||
nserv++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#ifdef RESOLVSORT
|
||||
if (MATCH(buf, "sortlist")) {
|
||||
struct in_addr a;
|
||||
|
||||
cp = buf + sizeof("sortlist") - 1;
|
||||
while (nsort < MAXRESOLVSORT) {
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
if (*cp == '\0' || *cp == '\n' || *cp == ';')
|
||||
break;
|
||||
net = cp;
|
||||
while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
|
||||
isascii(*cp) && !isspace(*cp))
|
||||
cp++;
|
||||
n = *cp;
|
||||
*cp = 0;
|
||||
if (inet_aton(net, &a)) {
|
||||
_res.sort_list[nsort].addr = a;
|
||||
if (ISSORTMASK(n)) {
|
||||
*cp++ = n;
|
||||
net = cp;
|
||||
while (*cp && *cp != ';' &&
|
||||
isascii(*cp) && !isspace(*cp))
|
||||
cp++;
|
||||
n = *cp;
|
||||
*cp = 0;
|
||||
if (inet_aton(net, &a)) {
|
||||
_res.sort_list[nsort].mask = a.s_addr;
|
||||
} else {
|
||||
_res.sort_list[nsort].mask =
|
||||
net_mask(_res.sort_list[nsort].addr);
|
||||
}
|
||||
} else {
|
||||
_res.sort_list[nsort].mask =
|
||||
net_mask(_res.sort_list[nsort].addr);
|
||||
}
|
||||
nsort++;
|
||||
}
|
||||
*cp = n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (MATCH(buf, "options")) {
|
||||
res_setoptions(buf + sizeof("options") - 1, "conf");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (nserv > 1)
|
||||
_res.nscount = nserv;
|
||||
#ifdef RESOLVSORT
|
||||
_res.nsort = nsort;
|
||||
#endif
|
||||
(void) fclose(fp);
|
||||
}
|
||||
if (_res.defdname[0] == 0 &&
|
||||
gethostname(buf, sizeof(_res.defdname) - 1) == 0 &&
|
||||
(cp = strchr(buf, '.')) != NULL)
|
||||
strcpy(_res.defdname, cp + 1);
|
||||
|
||||
/* find components of local domain that might be searched */
|
||||
if (havesearch == 0) {
|
||||
pp = _res.dnsrch;
|
||||
*pp++ = _res.defdname;
|
||||
*pp = NULL;
|
||||
|
||||
#ifndef RFC1535
|
||||
dots = 0;
|
||||
for (cp = _res.defdname; *cp; cp++)
|
||||
dots += (*cp == '.');
|
||||
|
||||
cp = _res.defdname;
|
||||
while (pp < _res.dnsrch + MAXDFLSRCH) {
|
||||
if (dots < LOCALDOMAINPARTS)
|
||||
break;
|
||||
cp = strchr(cp, '.') + 1; /* we know there is one */
|
||||
*pp++ = cp;
|
||||
dots--;
|
||||
}
|
||||
*pp = NULL;
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG) {
|
||||
printf(";; res_init()... default dnsrch list:\n");
|
||||
for (pp = _res.dnsrch; *pp; pp++)
|
||||
printf(";;\t%s\n", *pp);
|
||||
printf(";;\t..END..\n");
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
#endif /* !RFC1535 */
|
||||
}
|
||||
|
||||
if ((cp = getenv("RES_OPTIONS")) != NULL)
|
||||
res_setoptions(cp, "env");
|
||||
_res.options |= RES_INIT;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
res_setoptions(options, source)
|
||||
char *options, *source;
|
||||
{
|
||||
char *cp = options;
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG)
|
||||
printf(";; res_setoptions(\"%s\", \"%s\")...\n",
|
||||
options, source);
|
||||
#endif
|
||||
while (*cp) {
|
||||
/* skip leading and inner runs of spaces */
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
/* search for and process individual options */
|
||||
if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
|
||||
i = atoi(cp + sizeof("ndots:") - 1);
|
||||
if (i <= RES_MAXNDOTS)
|
||||
_res.ndots = i;
|
||||
else
|
||||
_res.ndots = RES_MAXNDOTS;
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG)
|
||||
printf(";;\tndots=%d\n", _res.ndots);
|
||||
#endif
|
||||
} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
|
||||
#ifdef DEBUG
|
||||
if (!(_res.options & RES_DEBUG)) {
|
||||
printf(";; res_setoptions(\"%s\", \"%s\")..\n",
|
||||
options, source);
|
||||
_res.options |= RES_DEBUG;
|
||||
}
|
||||
printf(";;\tdebug\n");
|
||||
#endif
|
||||
} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
|
||||
_res.options |= RES_USE_INET6;
|
||||
} else {
|
||||
/* XXX - print a warning here? */
|
||||
}
|
||||
/* skip to next run of spaces */
|
||||
while (*cp && *cp != ' ' && *cp != '\t')
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RESOLVSORT
|
||||
/* XXX - should really support CIDR which means explicit masks always. */
|
||||
static u_int32_t
|
||||
net_mask(in) /* XXX - should really use system's version of this */
|
||||
struct in_addr in;
|
||||
{
|
||||
register u_int32_t i = ntohl(in.s_addr);
|
||||
|
||||
if (IN_CLASSA(i))
|
||||
return (htonl(IN_CLASSA_NET));
|
||||
else if (IN_CLASSB(i))
|
||||
return (htonl(IN_CLASSB_NET));
|
||||
return (htonl(IN_CLASSC_NET));
|
||||
}
|
||||
#endif
|
||||
|
||||
u_int16_t
|
||||
res_randomid()
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
|
||||
}
|
245
lib/libc/net/res_mkquery.c
Normal file
245
lib/libc/net/res_mkquery.c
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* ++Copyright++ 1985, 1993
|
||||
* -
|
||||
* Copyright (c) 1985, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
|
||||
static char rcsid[] = "$Id: res_mkquery.c,v 8.4 1996/08/05 08:31:35 vixie Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "res_config.h"
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
* Form all types of queries.
|
||||
* Returns the size of the result or -1.
|
||||
*/
|
||||
int
|
||||
res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen)
|
||||
int op; /* opcode of query */
|
||||
const char *dname; /* domain name */
|
||||
int class, type; /* class and type of query */
|
||||
const u_char *data; /* resource record data */
|
||||
int datalen; /* length of data */
|
||||
const u_char *newrr_in; /* new rr for modify or append */
|
||||
u_char *buf; /* buffer to put query */
|
||||
int buflen; /* size of buffer */
|
||||
{
|
||||
register HEADER *hp;
|
||||
register u_char *cp;
|
||||
register int n;
|
||||
#ifdef ALLOW_UPDATES
|
||||
struct rrec *newrr = (struct rrec *) newrr_in;
|
||||
#endif
|
||||
u_char *dnptrs[20], **dpp, **lastdnptr;
|
||||
|
||||
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return (-1);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG)
|
||||
printf(";; res_mkquery(%d, %s, %d, %d)\n",
|
||||
op, dname, class, type);
|
||||
#endif
|
||||
/*
|
||||
* Initialize header fields.
|
||||
*/
|
||||
if ((buf == NULL) || (buflen < HFIXEDSZ))
|
||||
return (-1);
|
||||
bzero(buf, HFIXEDSZ);
|
||||
hp = (HEADER *) buf;
|
||||
hp->id = htons(++_res.id);
|
||||
hp->opcode = op;
|
||||
hp->rd = (_res.options & RES_RECURSE) != 0;
|
||||
hp->rcode = NOERROR;
|
||||
cp = buf + HFIXEDSZ;
|
||||
buflen -= HFIXEDSZ;
|
||||
dpp = dnptrs;
|
||||
*dpp++ = buf;
|
||||
*dpp++ = NULL;
|
||||
lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
|
||||
/*
|
||||
* perform opcode specific processing
|
||||
*/
|
||||
switch (op) {
|
||||
case QUERY: /*FALLTHROUGH*/
|
||||
case NS_NOTIFY_OP:
|
||||
if ((buflen -= QFIXEDSZ) < 0)
|
||||
return (-1);
|
||||
if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
|
||||
return (-1);
|
||||
cp += n;
|
||||
buflen -= n;
|
||||
__putshort(type, cp);
|
||||
cp += INT16SZ;
|
||||
__putshort(class, cp);
|
||||
cp += INT16SZ;
|
||||
hp->qdcount = htons(1);
|
||||
if (op == QUERY || data == NULL)
|
||||
break;
|
||||
/*
|
||||
* Make an additional record for completion domain.
|
||||
*/
|
||||
buflen -= RRFIXEDSZ;
|
||||
n = dn_comp((char *)data, cp, buflen, dnptrs, lastdnptr);
|
||||
if (n < 0)
|
||||
return (-1);
|
||||
cp += n;
|
||||
buflen -= n;
|
||||
__putshort(T_NULL, cp);
|
||||
cp += INT16SZ;
|
||||
__putshort(class, cp);
|
||||
cp += INT16SZ;
|
||||
__putlong(0, cp);
|
||||
cp += INT32SZ;
|
||||
__putshort(0, cp);
|
||||
cp += INT16SZ;
|
||||
hp->arcount = htons(1);
|
||||
break;
|
||||
|
||||
case IQUERY:
|
||||
/*
|
||||
* Initialize answer section
|
||||
*/
|
||||
if (buflen < 1 + RRFIXEDSZ + datalen)
|
||||
return (-1);
|
||||
*cp++ = '\0'; /* no domain name */
|
||||
__putshort(type, cp);
|
||||
cp += INT16SZ;
|
||||
__putshort(class, cp);
|
||||
cp += INT16SZ;
|
||||
__putlong(0, cp);
|
||||
cp += INT32SZ;
|
||||
__putshort(datalen, cp);
|
||||
cp += INT16SZ;
|
||||
if (datalen) {
|
||||
bcopy(data, cp, datalen);
|
||||
cp += datalen;
|
||||
}
|
||||
hp->ancount = htons(1);
|
||||
break;
|
||||
|
||||
#ifdef ALLOW_UPDATES
|
||||
/*
|
||||
* For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
|
||||
* (Record to be modified is followed by its replacement in msg.)
|
||||
*/
|
||||
case UPDATEM:
|
||||
case UPDATEMA:
|
||||
|
||||
case UPDATED:
|
||||
/*
|
||||
* The res code for UPDATED and UPDATEDA is the same; user
|
||||
* calls them differently: specifies data for UPDATED; server
|
||||
* ignores data if specified for UPDATEDA.
|
||||
*/
|
||||
case UPDATEDA:
|
||||
buflen -= RRFIXEDSZ + datalen;
|
||||
if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
|
||||
return (-1);
|
||||
cp += n;
|
||||
__putshort(type, cp);
|
||||
cp += INT16SZ;
|
||||
__putshort(class, cp);
|
||||
cp += INT16SZ;
|
||||
__putlong(0, cp);
|
||||
cp += INT32SZ;
|
||||
__putshort(datalen, cp);
|
||||
cp += INT16SZ;
|
||||
if (datalen) {
|
||||
bcopy(data, cp, datalen);
|
||||
cp += datalen;
|
||||
}
|
||||
if ( (op == UPDATED) || (op == UPDATEDA) ) {
|
||||
hp->ancount = htons(0);
|
||||
break;
|
||||
}
|
||||
/* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
|
||||
|
||||
case UPDATEA: /* Add new resource record */
|
||||
buflen -= RRFIXEDSZ + datalen;
|
||||
if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
|
||||
return (-1);
|
||||
cp += n;
|
||||
__putshort(newrr->r_type, cp);
|
||||
cp += INT16SZ;
|
||||
__putshort(newrr->r_class, cp);
|
||||
cp += INT16SZ;
|
||||
__putlong(0, cp);
|
||||
cp += INT32SZ;
|
||||
__putshort(newrr->r_size, cp);
|
||||
cp += INT16SZ;
|
||||
if (newrr->r_size) {
|
||||
bcopy(newrr->r_data, cp, newrr->r_size);
|
||||
cp += newrr->r_size;
|
||||
}
|
||||
hp->ancount = htons(0);
|
||||
break;
|
||||
#endif /* ALLOW_UPDATES */
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
return (cp - buf);
|
||||
}
|
386
lib/libc/net/res_query.c
Normal file
386
lib/libc/net/res_query.c
Normal file
@ -0,0 +1,386 @@
|
||||
/*
|
||||
* ++Copyright++ 1988, 1993
|
||||
* -
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
|
||||
static char rcsid[] = "$Id: res_query.c,v 8.7 1996/08/05 08:31:35 vixie Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "res_config.h"
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if PACKETSZ > 1024
|
||||
#define MAXPACKET PACKETSZ
|
||||
#else
|
||||
#define MAXPACKET 1024
|
||||
#endif
|
||||
|
||||
char *__hostalias __P((const char *));
|
||||
int h_errno;
|
||||
|
||||
/*
|
||||
* Formulate a normal query, send, and await answer.
|
||||
* Returned answer is placed in supplied buffer "answer".
|
||||
* Perform preliminary check of answer, returning success only
|
||||
* if no error is indicated and the answer count is nonzero.
|
||||
* Return the size of the response on success, -1 on error.
|
||||
* Error number is left in h_errno.
|
||||
*
|
||||
* Caller must parse answer and determine whether it answers the question.
|
||||
*/
|
||||
int
|
||||
res_query(name, class, type, answer, anslen)
|
||||
const char *name; /* domain name */
|
||||
int class, type; /* class and type of query */
|
||||
u_char *answer; /* buffer to put answer */
|
||||
int anslen; /* size of answer buffer */
|
||||
{
|
||||
u_char buf[MAXPACKET];
|
||||
register HEADER *hp = (HEADER *) answer;
|
||||
int n;
|
||||
|
||||
hp->rcode = NOERROR; /* default */
|
||||
|
||||
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return (-1);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG)
|
||||
printf(";; res_query(%s, %d, %d)\n", name, class, type);
|
||||
#endif
|
||||
|
||||
n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
|
||||
buf, sizeof(buf));
|
||||
if (n <= 0) {
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG)
|
||||
printf(";; res_query: mkquery failed\n");
|
||||
#endif
|
||||
h_errno = NO_RECOVERY;
|
||||
return (n);
|
||||
}
|
||||
n = res_send(buf, n, answer, anslen);
|
||||
if (n < 0) {
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG)
|
||||
printf(";; res_query: send error\n");
|
||||
#endif
|
||||
h_errno = TRY_AGAIN;
|
||||
return (n);
|
||||
}
|
||||
|
||||
if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG)
|
||||
printf(";; rcode = %d, ancount=%d\n", hp->rcode,
|
||||
ntohs(hp->ancount));
|
||||
#endif
|
||||
switch (hp->rcode) {
|
||||
case NXDOMAIN:
|
||||
h_errno = HOST_NOT_FOUND;
|
||||
break;
|
||||
case SERVFAIL:
|
||||
h_errno = TRY_AGAIN;
|
||||
break;
|
||||
case NOERROR:
|
||||
h_errno = NO_DATA;
|
||||
break;
|
||||
case FORMERR:
|
||||
case NOTIMP:
|
||||
case REFUSED:
|
||||
default:
|
||||
h_errno = NO_RECOVERY;
|
||||
break;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
return (n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Formulate a normal query, send, and retrieve answer in supplied buffer.
|
||||
* Return the size of the response on success, -1 on error.
|
||||
* If enabled, implement search rules until answer or unrecoverable failure
|
||||
* is detected. Error code, if any, is left in h_errno.
|
||||
*/
|
||||
int
|
||||
res_search(name, class, type, answer, anslen)
|
||||
const char *name; /* domain name */
|
||||
int class, type; /* class and type of query */
|
||||
u_char *answer; /* buffer to put answer */
|
||||
int anslen; /* size of answer */
|
||||
{
|
||||
register const char *cp, * const *domain;
|
||||
HEADER *hp = (HEADER *) answer;
|
||||
u_int dots;
|
||||
int trailing_dot, ret, saved_herrno;
|
||||
int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
|
||||
|
||||
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return (-1);
|
||||
}
|
||||
errno = 0;
|
||||
h_errno = HOST_NOT_FOUND; /* default, if we never query */
|
||||
dots = 0;
|
||||
for (cp = name; *cp; cp++)
|
||||
dots += (*cp == '.');
|
||||
trailing_dot = 0;
|
||||
if (cp > name && *--cp == '.')
|
||||
trailing_dot++;
|
||||
|
||||
/*
|
||||
* if there aren't any dots, it could be a user-level alias
|
||||
*/
|
||||
if (!dots && (cp = __hostalias(name)) != NULL)
|
||||
return (res_query(cp, class, type, answer, anslen));
|
||||
|
||||
/*
|
||||
* If there are dots in the name already, let's just give it a try
|
||||
* 'as is'. The threshold can be set with the "ndots" option.
|
||||
*/
|
||||
saved_herrno = -1;
|
||||
if (dots >= _res.ndots) {
|
||||
ret = res_querydomain(name, NULL, class, type, answer, anslen);
|
||||
if (ret > 0)
|
||||
return (ret);
|
||||
saved_herrno = h_errno;
|
||||
tried_as_is++;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do at least one level of search if
|
||||
* - there is no dot and RES_DEFNAME is set, or
|
||||
* - there is at least one dot, there is no trailing dot,
|
||||
* and RES_DNSRCH is set.
|
||||
*/
|
||||
if ((!dots && (_res.options & RES_DEFNAMES)) ||
|
||||
(dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
|
||||
int done = 0;
|
||||
|
||||
for (domain = (const char * const *)_res.dnsrch;
|
||||
*domain && !done;
|
||||
domain++) {
|
||||
|
||||
ret = res_querydomain(name, *domain, class, type,
|
||||
answer, anslen);
|
||||
if (ret > 0)
|
||||
return (ret);
|
||||
|
||||
/*
|
||||
* If no server present, give up.
|
||||
* If name isn't found in this domain,
|
||||
* keep trying higher domains in the search list
|
||||
* (if that's enabled).
|
||||
* On a NO_DATA error, keep trying, otherwise
|
||||
* a wildcard entry of another type could keep us
|
||||
* from finding this entry higher in the domain.
|
||||
* If we get some other error (negative answer or
|
||||
* server failure), then stop searching up,
|
||||
* but try the input name below in case it's
|
||||
* fully-qualified.
|
||||
*/
|
||||
if (errno == ECONNREFUSED) {
|
||||
h_errno = TRY_AGAIN;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (h_errno) {
|
||||
case NO_DATA:
|
||||
got_nodata++;
|
||||
/* FALLTHROUGH */
|
||||
case HOST_NOT_FOUND:
|
||||
/* keep trying */
|
||||
break;
|
||||
case TRY_AGAIN:
|
||||
if (hp->rcode == SERVFAIL) {
|
||||
/* try next search element, if any */
|
||||
got_servfail++;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
/* anything else implies that we're done */
|
||||
done++;
|
||||
}
|
||||
|
||||
/* if we got here for some reason other than DNSRCH,
|
||||
* we only wanted one iteration of the loop, so stop.
|
||||
*/
|
||||
if (!(_res.options & RES_DNSRCH))
|
||||
done++;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we have not already tried the name "as is", do that now.
|
||||
* note that we do this regardless of how many dots were in the
|
||||
* name or whether it ends with a dot.
|
||||
*/
|
||||
if (!tried_as_is) {
|
||||
ret = res_querydomain(name, NULL, class, type, answer, anslen);
|
||||
if (ret > 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* if we got here, we didn't satisfy the search.
|
||||
* if we did an initial full query, return that query's h_errno
|
||||
* (note that we wouldn't be here if that query had succeeded).
|
||||
* else if we ever got a nodata, send that back as the reason.
|
||||
* else send back meaningless h_errno, that being the one from
|
||||
* the last DNSRCH we did.
|
||||
*/
|
||||
if (saved_herrno != -1)
|
||||
h_errno = saved_herrno;
|
||||
else if (got_nodata)
|
||||
h_errno = NO_DATA;
|
||||
else if (got_servfail)
|
||||
h_errno = TRY_AGAIN;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a call on res_query on the concatenation of name and domain,
|
||||
* removing a trailing dot from name if domain is NULL.
|
||||
*/
|
||||
int
|
||||
res_querydomain(name, domain, class, type, answer, anslen)
|
||||
const char *name, *domain;
|
||||
int class, type; /* class and type of query */
|
||||
u_char *answer; /* buffer to put answer */
|
||||
int anslen; /* size of answer */
|
||||
{
|
||||
char nbuf[2*MAXDNAME+2];
|
||||
const char *longname = nbuf;
|
||||
int n;
|
||||
|
||||
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return (-1);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (_res.options & RES_DEBUG)
|
||||
printf(";; res_querydomain(%s, %s, %d, %d)\n",
|
||||
name, domain?domain:"<Nil>", class, type);
|
||||
#endif
|
||||
if (domain == NULL) {
|
||||
/*
|
||||
* Check for trailing '.';
|
||||
* copy without '.' if present.
|
||||
*/
|
||||
n = strlen(name) - 1;
|
||||
if (n != (0 - 1) && name[n] == '.' && n < sizeof(nbuf) - 1) {
|
||||
bcopy(name, nbuf, n);
|
||||
nbuf[n] = '\0';
|
||||
} else
|
||||
longname = name;
|
||||
} else
|
||||
sprintf(nbuf, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
|
||||
|
||||
return (res_query(longname, class, type, answer, anslen));
|
||||
}
|
||||
|
||||
char *
|
||||
__hostalias(name)
|
||||
register const char *name;
|
||||
{
|
||||
register char *cp1, *cp2;
|
||||
FILE *fp;
|
||||
char *file;
|
||||
char buf[BUFSIZ];
|
||||
static char abuf[MAXDNAME];
|
||||
|
||||
if (_res.options & RES_NOALIASES)
|
||||
return (NULL);
|
||||
file = getenv("HOSTALIASES");
|
||||
if (file == NULL || (fp = fopen(file, "r")) == NULL)
|
||||
return (NULL);
|
||||
setbuf(fp, NULL);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
|
||||
;
|
||||
if (!*cp1)
|
||||
break;
|
||||
*cp1 = '\0';
|
||||
if (!strcasecmp(buf, name)) {
|
||||
while (isspace(*++cp1))
|
||||
;
|
||||
if (!*cp1)
|
||||
break;
|
||||
for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
|
||||
;
|
||||
abuf[sizeof(abuf) - 1] = *cp2 = '\0';
|
||||
strncpy(abuf, cp1, sizeof(abuf) - 1);
|
||||
fclose(fp);
|
||||
return (abuf);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return (NULL);
|
||||
}
|
741
lib/libc/net/res_send.c
Normal file
741
lib/libc/net/res_send.c
Normal file
@ -0,0 +1,741 @@
|
||||
/*
|
||||
* ++Copyright++ 1985, 1989, 1993
|
||||
* -
|
||||
* Copyright (c) 1985, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
|
||||
static char rcsid[] = "$Id: res_send.c,v 8.9 1996/08/05 08:31:35 vixie Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
/*
|
||||
* Send query to name server and wait for reply.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "res_config.h"
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <resolv.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
void _res_close __P((void));
|
||||
|
||||
static int s = -1; /* socket used for communications */
|
||||
static int connected = 0; /* is the socket connected */
|
||||
static int vc = 0; /* is the socket a virtual ciruit? */
|
||||
|
||||
#ifndef DEBUG
|
||||
# define Dprint(cond, args) /*empty*/
|
||||
# define DprintQ(cond, args, query, size) /*empty*/
|
||||
# define Aerror(file, string, error, address) /*empty*/
|
||||
# define Perror(file, string, error) /*empty*/
|
||||
#else
|
||||
# define Dprint(cond, args) if (cond) {fprintf args;} else {}
|
||||
# define DprintQ(cond, args, query, size) if (cond) {\
|
||||
fprintf args;\
|
||||
__fp_nquery(query, size, stdout);\
|
||||
} else {}
|
||||
static void
|
||||
Aerror(file, string, error, address)
|
||||
FILE *file;
|
||||
char *string;
|
||||
int error;
|
||||
struct sockaddr_in address;
|
||||
{
|
||||
int save = errno;
|
||||
|
||||
if (_res.options & RES_DEBUG) {
|
||||
fprintf(file, "res_send: %s ([%s].%u): %s\n",
|
||||
string,
|
||||
inet_ntoa(address.sin_addr),
|
||||
ntohs(address.sin_port),
|
||||
strerror(error));
|
||||
}
|
||||
errno = save;
|
||||
}
|
||||
static void
|
||||
Perror(file, string, error)
|
||||
FILE *file;
|
||||
char *string;
|
||||
int error;
|
||||
{
|
||||
int save = errno;
|
||||
|
||||
if (_res.options & RES_DEBUG) {
|
||||
fprintf(file, "res_send: %s: %s\n",
|
||||
string, strerror(error));
|
||||
}
|
||||
errno = save;
|
||||
}
|
||||
#endif
|
||||
|
||||
static res_send_qhook Qhook = NULL;
|
||||
static res_send_rhook Rhook = NULL;
|
||||
|
||||
void
|
||||
res_send_setqhook(hook)
|
||||
res_send_qhook hook;
|
||||
{
|
||||
|
||||
Qhook = hook;
|
||||
}
|
||||
|
||||
void
|
||||
res_send_setrhook(hook)
|
||||
res_send_rhook hook;
|
||||
{
|
||||
|
||||
Rhook = hook;
|
||||
}
|
||||
|
||||
/* int
|
||||
* res_isourserver(ina)
|
||||
* looks up "ina" in _res.ns_addr_list[]
|
||||
* returns:
|
||||
* 0 : not found
|
||||
* >0 : found
|
||||
* author:
|
||||
* paul vixie, 29may94
|
||||
*/
|
||||
int
|
||||
res_isourserver(inp)
|
||||
const struct sockaddr_in *inp;
|
||||
{
|
||||
struct sockaddr_in ina;
|
||||
register int ns, ret;
|
||||
|
||||
ina = *inp;
|
||||
ret = 0;
|
||||
for (ns = 0; ns < _res.nscount; ns++) {
|
||||
register const struct sockaddr_in *srv = &_res.nsaddr_list[ns];
|
||||
|
||||
if (srv->sin_family == ina.sin_family &&
|
||||
srv->sin_port == ina.sin_port &&
|
||||
(srv->sin_addr.s_addr == INADDR_ANY ||
|
||||
srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* int
|
||||
* res_nameinquery(name, type, class, buf, eom)
|
||||
* look for (name,type,class) in the query section of packet (buf,eom)
|
||||
* returns:
|
||||
* -1 : format error
|
||||
* 0 : not found
|
||||
* >0 : found
|
||||
* author:
|
||||
* paul vixie, 29may94
|
||||
*/
|
||||
int
|
||||
res_nameinquery(name, type, class, buf, eom)
|
||||
const char *name;
|
||||
register int type, class;
|
||||
const u_char *buf, *eom;
|
||||
{
|
||||
register const u_char *cp = buf + HFIXEDSZ;
|
||||
int qdcount = ntohs(((HEADER*)buf)->qdcount);
|
||||
|
||||
while (qdcount-- > 0) {
|
||||
char tname[MAXDNAME+1];
|
||||
register int n, ttype, tclass;
|
||||
|
||||
n = dn_expand(buf, eom, cp, tname, sizeof tname);
|
||||
if (n < 0)
|
||||
return (-1);
|
||||
cp += n;
|
||||
ttype = _getshort(cp); cp += INT16SZ;
|
||||
tclass = _getshort(cp); cp += INT16SZ;
|
||||
if (ttype == type &&
|
||||
tclass == class &&
|
||||
strcasecmp(tname, name) == 0)
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* int
|
||||
* res_queriesmatch(buf1, eom1, buf2, eom2)
|
||||
* is there a 1:1 mapping of (name,type,class)
|
||||
* in (buf1,eom1) and (buf2,eom2)?
|
||||
* returns:
|
||||
* -1 : format error
|
||||
* 0 : not a 1:1 mapping
|
||||
* >0 : is a 1:1 mapping
|
||||
* author:
|
||||
* paul vixie, 29may94
|
||||
*/
|
||||
int
|
||||
res_queriesmatch(buf1, eom1, buf2, eom2)
|
||||
const u_char *buf1, *eom1;
|
||||
const u_char *buf2, *eom2;
|
||||
{
|
||||
register const u_char *cp = buf1 + HFIXEDSZ;
|
||||
int qdcount = ntohs(((HEADER*)buf1)->qdcount);
|
||||
|
||||
if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
|
||||
return (0);
|
||||
while (qdcount-- > 0) {
|
||||
char tname[MAXDNAME+1];
|
||||
register int n, ttype, tclass;
|
||||
|
||||
n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
|
||||
if (n < 0)
|
||||
return (-1);
|
||||
cp += n;
|
||||
ttype = _getshort(cp); cp += INT16SZ;
|
||||
tclass = _getshort(cp); cp += INT16SZ;
|
||||
if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
res_send(buf, buflen, ans, anssiz)
|
||||
const u_char *buf;
|
||||
int buflen;
|
||||
u_char *ans;
|
||||
int anssiz;
|
||||
{
|
||||
HEADER *hp = (HEADER *) buf;
|
||||
HEADER *anhp = (HEADER *) ans;
|
||||
int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
|
||||
register int n;
|
||||
u_int badns; /* XXX NSMAX can't exceed #/bits in this var */
|
||||
|
||||
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
||||
/* errno should have been set by res_init() in this case. */
|
||||
return (-1);
|
||||
}
|
||||
DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
|
||||
(stdout, ";; res_send()\n"), buf, buflen);
|
||||
v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
|
||||
gotsomewhere = 0;
|
||||
connreset = 0;
|
||||
terrno = ETIMEDOUT;
|
||||
badns = 0;
|
||||
|
||||
/*
|
||||
* Send request, RETRY times, or until successful
|
||||
*/
|
||||
for (try = 0; try < _res.retry; try++) {
|
||||
for (ns = 0; ns < _res.nscount; ns++) {
|
||||
struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
|
||||
same_ns:
|
||||
if (badns & (1 << ns)) {
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
|
||||
if (Qhook) {
|
||||
int done = 0, loops = 0;
|
||||
|
||||
do {
|
||||
res_sendhookact act;
|
||||
|
||||
act = (*Qhook)(&nsap, &buf, &buflen,
|
||||
ans, anssiz, &resplen);
|
||||
switch (act) {
|
||||
case res_goahead:
|
||||
done = 1;
|
||||
break;
|
||||
case res_nextns:
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
case res_done:
|
||||
return (resplen);
|
||||
case res_modified:
|
||||
/* give the hook another try */
|
||||
if (++loops < 42) /*doug adams*/
|
||||
break;
|
||||
/*FALLTHROUGH*/
|
||||
case res_error:
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
Dprint(_res.options & RES_DEBUG,
|
||||
(stdout, ";; Querying server (# %d) address = %s\n",
|
||||
ns + 1, inet_ntoa(nsap->sin_addr)));
|
||||
|
||||
if (v_circuit) {
|
||||
int truncated;
|
||||
struct iovec iov[2];
|
||||
u_short len;
|
||||
u_char *cp;
|
||||
|
||||
/*
|
||||
* Use virtual circuit;
|
||||
* at most one attempt per server.
|
||||
*/
|
||||
try = _res.retry;
|
||||
truncated = 0;
|
||||
if ((s < 0) || (!vc)) {
|
||||
if (s >= 0)
|
||||
_res_close();
|
||||
|
||||
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
terrno = errno;
|
||||
Perror(stderr, "socket(vc)", errno);
|
||||
return (-1);
|
||||
}
|
||||
errno = 0;
|
||||
if (connect(s, (struct sockaddr *)nsap,
|
||||
sizeof(struct sockaddr)) < 0) {
|
||||
terrno = errno;
|
||||
Aerror(stderr, "connect/vc",
|
||||
errno, *nsap);
|
||||
badns |= (1 << ns);
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
vc = 1;
|
||||
}
|
||||
/*
|
||||
* Send length & message
|
||||
*/
|
||||
putshort((u_short)buflen, (u_char*)&len);
|
||||
iov[0].iov_base = (caddr_t)&len;
|
||||
iov[0].iov_len = INT16SZ;
|
||||
iov[1].iov_base = (caddr_t)buf;
|
||||
iov[1].iov_len = buflen;
|
||||
if (writev(s, iov, 2) != (INT16SZ + buflen)) {
|
||||
terrno = errno;
|
||||
Perror(stderr, "write failed", errno);
|
||||
badns |= (1 << ns);
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
/*
|
||||
* Receive length & response
|
||||
*/
|
||||
read_len:
|
||||
cp = ans;
|
||||
len = INT16SZ;
|
||||
while ((n = read(s, (char *)cp, (int)len)) > 0) {
|
||||
cp += n;
|
||||
if ((len -= n) <= 0)
|
||||
break;
|
||||
}
|
||||
if (n <= 0) {
|
||||
terrno = errno;
|
||||
Perror(stderr, "read failed", errno);
|
||||
_res_close();
|
||||
/*
|
||||
* A long running process might get its TCP
|
||||
* connection reset if the remote server was
|
||||
* restarted. Requery the server instead of
|
||||
* trying a new one. When there is only one
|
||||
* server, this means that a query might work
|
||||
* instead of failing. We only allow one reset
|
||||
* per query to prevent looping.
|
||||
*/
|
||||
if (terrno == ECONNRESET && !connreset) {
|
||||
connreset = 1;
|
||||
_res_close();
|
||||
goto same_ns;
|
||||
}
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
resplen = _getshort(ans);
|
||||
if (resplen > anssiz) {
|
||||
Dprint(_res.options & RES_DEBUG,
|
||||
(stdout, ";; response truncated\n")
|
||||
);
|
||||
truncated = 1;
|
||||
len = anssiz;
|
||||
} else
|
||||
len = resplen;
|
||||
cp = ans;
|
||||
while (len != 0 &&
|
||||
(n = read(s, (char *)cp, (int)len)) > 0) {
|
||||
cp += n;
|
||||
len -= n;
|
||||
}
|
||||
if (n <= 0) {
|
||||
terrno = errno;
|
||||
Perror(stderr, "read(vc)", errno);
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
if (truncated) {
|
||||
/*
|
||||
* Flush rest of answer
|
||||
* so connection stays in synch.
|
||||
*/
|
||||
anhp->tc = 1;
|
||||
len = resplen - anssiz;
|
||||
while (len != 0) {
|
||||
char junk[PACKETSZ];
|
||||
|
||||
n = (len > sizeof(junk)
|
||||
? sizeof(junk)
|
||||
: len);
|
||||
if ((n = read(s, junk, n)) > 0)
|
||||
len -= n;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The calling applicating has bailed out of
|
||||
* a previous call and failed to arrange to have
|
||||
* the circuit closed or the server has got
|
||||
* itself confused. Anyway drop the packet and
|
||||
* wait for the correct one.
|
||||
*/
|
||||
if (hp->id != anhp->id) {
|
||||
DprintQ((_res.options & RES_DEBUG) ||
|
||||
(_res.pfcode & RES_PRF_REPLY),
|
||||
(stdout, ";; old answer (unexpected):\n"),
|
||||
ans, (resplen>anssiz)?anssiz:resplen);
|
||||
goto read_len;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Use datagrams.
|
||||
*/
|
||||
struct timeval timeout;
|
||||
fd_set dsmask;
|
||||
struct sockaddr_in from;
|
||||
int fromlen;
|
||||
|
||||
if ((s < 0) || vc) {
|
||||
if (vc)
|
||||
_res_close();
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
terrno = errno;
|
||||
Perror(stderr, "socket(dg)", errno);
|
||||
return (-1);
|
||||
}
|
||||
connected = 0;
|
||||
}
|
||||
/*
|
||||
* On a 4.3BSD+ machine (client and server,
|
||||
* actually), sending to a nameserver datagram
|
||||
* port with no nameserver will cause an
|
||||
* ICMP port unreachable message to be returned.
|
||||
* If our datagram socket is "connected" to the
|
||||
* server, we get an ECONNREFUSED error on the next
|
||||
* socket operation, and select returns if the
|
||||
* error message is received. We can thus detect
|
||||
* the absence of a nameserver without timing out.
|
||||
* If we have sent queries to at least two servers,
|
||||
* however, we don't want to remain connected,
|
||||
* as we wish to receive answers from the first
|
||||
* server to respond.
|
||||
*/
|
||||
if (_res.nscount == 1 || (try == 0 && ns == 0)) {
|
||||
/*
|
||||
* Connect only if we are sure we won't
|
||||
* receive a response from another server.
|
||||
*/
|
||||
if (!connected) {
|
||||
if (connect(s, (struct sockaddr *)nsap,
|
||||
sizeof(struct sockaddr)
|
||||
) < 0) {
|
||||
Aerror(stderr,
|
||||
"connect(dg)",
|
||||
errno, *nsap);
|
||||
badns |= (1 << ns);
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
connected = 1;
|
||||
}
|
||||
if (send(s, (char*)buf, buflen, 0) != buflen) {
|
||||
Perror(stderr, "send", errno);
|
||||
badns |= (1 << ns);
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Disconnect if we want to listen
|
||||
* for responses from more than one server.
|
||||
*/
|
||||
if (connected) {
|
||||
struct sockaddr_in no_addr;
|
||||
|
||||
no_addr.sin_family = AF_INET;
|
||||
no_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
no_addr.sin_port = 0;
|
||||
(void) connect(s,
|
||||
(struct sockaddr *)
|
||||
&no_addr,
|
||||
sizeof(no_addr));
|
||||
connected = 0;
|
||||
errno = 0;
|
||||
}
|
||||
if (sendto(s, (char*)buf, buflen, 0,
|
||||
(struct sockaddr *)nsap,
|
||||
sizeof(struct sockaddr))
|
||||
!= buflen) {
|
||||
Aerror(stderr, "sendto", errno, *nsap);
|
||||
badns |= (1 << ns);
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for reply
|
||||
*/
|
||||
timeout.tv_sec = (_res.retrans << try);
|
||||
if (try > 0)
|
||||
timeout.tv_sec /= _res.nscount;
|
||||
if ((long) timeout.tv_sec <= 0)
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
wait:
|
||||
FD_ZERO(&dsmask);
|
||||
FD_SET(s, &dsmask);
|
||||
n = select(s+1, &dsmask, (fd_set *)NULL,
|
||||
(fd_set *)NULL, &timeout);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
goto wait;
|
||||
Perror(stderr, "select", errno);
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
if (n == 0) {
|
||||
/*
|
||||
* timeout
|
||||
*/
|
||||
Dprint(_res.options & RES_DEBUG,
|
||||
(stdout, ";; timeout\n"));
|
||||
gotsomewhere = 1;
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
errno = 0;
|
||||
fromlen = sizeof(struct sockaddr_in);
|
||||
resplen = recvfrom(s, (char*)ans, anssiz, 0,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
if (resplen <= 0) {
|
||||
Perror(stderr, "recvfrom", errno);
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
gotsomewhere = 1;
|
||||
if (hp->id != anhp->id) {
|
||||
/*
|
||||
* response from old query, ignore it.
|
||||
* XXX - potential security hazard could
|
||||
* be detected here.
|
||||
*/
|
||||
DprintQ((_res.options & RES_DEBUG) ||
|
||||
(_res.pfcode & RES_PRF_REPLY),
|
||||
(stdout, ";; old answer:\n"),
|
||||
ans, (resplen>anssiz)?anssiz:resplen);
|
||||
goto wait;
|
||||
}
|
||||
#if CHECK_SRVR_ADDR
|
||||
if (!(_res.options & RES_INSECURE1) &&
|
||||
!res_isourserver(&from)) {
|
||||
/*
|
||||
* response from wrong server? ignore it.
|
||||
* XXX - potential security hazard could
|
||||
* be detected here.
|
||||
*/
|
||||
DprintQ((_res.options & RES_DEBUG) ||
|
||||
(_res.pfcode & RES_PRF_REPLY),
|
||||
(stdout, ";; not our server:\n"),
|
||||
ans, (resplen>anssiz)?anssiz:resplen);
|
||||
goto wait;
|
||||
}
|
||||
#endif
|
||||
if (!(_res.options & RES_INSECURE2) &&
|
||||
!res_queriesmatch(buf, buf + buflen,
|
||||
ans, ans + anssiz)) {
|
||||
/*
|
||||
* response contains wrong query? ignore it.
|
||||
* XXX - potential security hazard could
|
||||
* be detected here.
|
||||
*/
|
||||
DprintQ((_res.options & RES_DEBUG) ||
|
||||
(_res.pfcode & RES_PRF_REPLY),
|
||||
(stdout, ";; wrong query name:\n"),
|
||||
ans, (resplen>anssiz)?anssiz:resplen);
|
||||
goto wait;
|
||||
}
|
||||
if (anhp->rcode == SERVFAIL ||
|
||||
anhp->rcode == NOTIMP ||
|
||||
anhp->rcode == REFUSED) {
|
||||
DprintQ(_res.options & RES_DEBUG,
|
||||
(stdout, "server rejected query:\n"),
|
||||
ans, (resplen>anssiz)?anssiz:resplen);
|
||||
badns |= (1 << ns);
|
||||
_res_close();
|
||||
/* don't retry if called from dig */
|
||||
if (!_res.pfcode)
|
||||
goto next_ns;
|
||||
}
|
||||
if (!(_res.options & RES_IGNTC) && anhp->tc) {
|
||||
/*
|
||||
* get rest of answer;
|
||||
* use TCP with same server.
|
||||
*/
|
||||
Dprint(_res.options & RES_DEBUG,
|
||||
(stdout, ";; truncated answer\n"));
|
||||
v_circuit = 1;
|
||||
_res_close();
|
||||
goto same_ns;
|
||||
}
|
||||
} /*if vc/dg*/
|
||||
Dprint((_res.options & RES_DEBUG) ||
|
||||
((_res.pfcode & RES_PRF_REPLY) &&
|
||||
(_res.pfcode & RES_PRF_HEAD1)),
|
||||
(stdout, ";; got answer:\n"));
|
||||
DprintQ((_res.options & RES_DEBUG) ||
|
||||
(_res.pfcode & RES_PRF_REPLY),
|
||||
(stdout, ""),
|
||||
ans, (resplen>anssiz)?anssiz:resplen);
|
||||
/*
|
||||
* If using virtual circuits, we assume that the first server
|
||||
* is preferred over the rest (i.e. it is on the local
|
||||
* machine) and only keep that one open.
|
||||
* If we have temporarily opened a virtual circuit,
|
||||
* or if we haven't been asked to keep a socket open,
|
||||
* close the socket.
|
||||
*/
|
||||
if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
|
||||
!(_res.options & RES_STAYOPEN)) {
|
||||
_res_close();
|
||||
}
|
||||
if (Rhook) {
|
||||
int done = 0, loops = 0;
|
||||
|
||||
do {
|
||||
res_sendhookact act;
|
||||
|
||||
act = (*Rhook)(nsap, buf, buflen,
|
||||
ans, anssiz, &resplen);
|
||||
switch (act) {
|
||||
case res_goahead:
|
||||
case res_done:
|
||||
done = 1;
|
||||
break;
|
||||
case res_nextns:
|
||||
_res_close();
|
||||
goto next_ns;
|
||||
case res_modified:
|
||||
/* give the hook another try */
|
||||
if (++loops < 42) /*doug adams*/
|
||||
break;
|
||||
/*FALLTHROUGH*/
|
||||
case res_error:
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
}
|
||||
return (resplen);
|
||||
next_ns: ;
|
||||
} /*foreach ns*/
|
||||
} /*foreach retry*/
|
||||
_res_close();
|
||||
if (!v_circuit)
|
||||
if (!gotsomewhere)
|
||||
errno = ECONNREFUSED; /* no nameservers found */
|
||||
else
|
||||
errno = ETIMEDOUT; /* no answer obtained */
|
||||
else
|
||||
errno = terrno;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is for closing the socket if a virtual circuit is used and
|
||||
* the program wants to close it. This provides support for endhostent()
|
||||
* which expects to close the socket.
|
||||
*
|
||||
* This routine is not expected to be user visible.
|
||||
*/
|
||||
void
|
||||
_res_close()
|
||||
{
|
||||
if (s >= 0) {
|
||||
(void) close(s);
|
||||
s = -1;
|
||||
connected = 0;
|
||||
vc = 0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user