* Copyright (c) 1985,1989 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
static char sccsid
[] = "@(#)getinfo.c 5.22 (Berkeley) 6/1/90";
*******************************************************************************
* Routines to create requests to name servers
* and interpret the answers.
* Adapted from 4.3BSD BIND gethostnamadr.c
*******************************************************************************
#include <arpa/nameser.h>
extern char *_res_resultcodes
[];
static char *addr_list
[MAXADDRS
+ 1];
static char *host_aliases
[MAXALIASES
];
static int host_aliases_len
[MAXALIASES
];
static char hostbuf
[BUFSIZ
+1];
char *domain
[MAXDOMAINS
];
ServerTable server
[MAXSERVERS
];
#define GetShort(cp) _getshort(cp); cp += sizeof(unsigned short);
*******************************************************************************
* Interprets an answer packet and retrieves the following
* SUCCESS the info was retrieved.
* NO_INFO the packet did not contain an answer.
* NONAUTH non-authoritative information was found.
* ERROR the answer was malformed.
* Other errors returned in the packet header.
*******************************************************************************
GetAnswer(nsAddrPtr
, queryType
, msg
, msglen
, iquery
, hostPtr
, isServer
)
struct in_addr
*nsAddrPtr
;
register HostInfo
*hostPtr
;
register HEADER
*headerPtr
;
char *eom
, *bp
, **aliasPtr
;
int qdcount
, ancount
, arcount
, nscount
, buflen
;
Boolean printedAnswers
= FALSE
;
* If the hostPtr was used before, free up the calloc'd areas.
FreeHostInfoPtr(hostPtr
);
status
= SendRequest(nsAddrPtr
, msg
, msglen
, (char *) &answer
,
if (_res
.options
& RES_DEBUG2
)
printf("SendRequest failed\n");
eom
= (char *) &answer
+ n
;
headerPtr
= (HEADER
*) &answer
;
if (headerPtr
->rcode
!= NOERROR
) {
return (headerPtr
->rcode
);
qdcount
= ntohs(headerPtr
->qdcount
);
ancount
= ntohs(headerPtr
->ancount
);
arcount
= ntohs(headerPtr
->arcount
);
nscount
= ntohs(headerPtr
->nscount
);
* If there are no answer, n.s. or additional records
* then return with an error.
if (ancount
== 0 && nscount
== 0 && arcount
== 0) {
buflen
= sizeof(hostbuf
);
cp
= (char *) &answer
+ sizeof(HEADER
);
/* Skip over question section. */
cp
+= dn_skipname(cp
, eom
) + QFIXEDSZ
;
* Scan through the answer resource records.
* Answers for address query types are saved.
* Other query type answers are just printed.
if (!isServer
&& !headerPtr
->aa
) {
printf("Non-authoritative answer:\n");
if (queryType
!= T_A
&& !(iquery
&& queryType
== T_PTR
)) {
while (--ancount
>= 0 && cp
< eom
) {
if ((cp
= Print_rr(cp
, (char *)&answer
, eom
, stdout
)) == NULL
) {
while (--ancount
>= 0 && cp
< eom
) {
if ((n
= dn_expand((char *)&answer
, eom
, cp
, bp
, buflen
)) < 0) {
cp
+= sizeof(u_long
); /* skip TTL */
if (aliasPtr
>= &host_aliases
[MAXALIASES
-1]) {
host_aliases_len
[numAliases
] = n
;
} else if (type
== T_PTR
) {
* Found a "pointer" to the real name.
if((n
=dn_expand((char *)&answer
, eom
, cp
, bp
,buflen
)) < 0) {
hostPtr
->name
= Calloc(1, len
);
bcopy(bp
, hostPtr
->name
, len
);
} else if (type
!= T_A
) {
* If we've already got 1 address, we aren't interested
* in addresses with a different length or class.
if (dlen
!= hostPtr
->addrLen
) {
if (class != origClass
) {
* First address: record its length and class so we
* only save additonal ones with the same attributes.
hostPtr
->addrType
= (class == C_IN
) ? AF_INET
: AF_UNSPEC
;
hostPtr
->name
= Calloc(1, len
);
bcopy(bp
, hostPtr
->name
, len
);
bp
+= (((u_long
)bp
) % sizeof(align
));
if (bp
+ dlen
>= &hostbuf
[sizeof(hostbuf
)]) {
if (_res
.options
& RES_DEBUG
) {
printf("Size (%d) too big\n", dlen
);
bcopy(cp
, *addrPtr
++ = bp
, dlen
);
if ((queryType
== T_A
|| queryType
== T_PTR
) && haveAnswer
) {
* Go through the alias and address lists and return them
* in the hostPtr variable.
hostPtr
->aliases
= (char **) Calloc(1 + numAliases
, sizeof(char *));
for (i
= 0; i
< numAliases
; i
++) {
hostPtr
->aliases
[i
] = Calloc(1, host_aliases_len
[i
]);
bcopy(host_aliases
[i
], hostPtr
->aliases
[i
],host_aliases_len
[i
]);
hostPtr
->aliases
[i
] = NULL
;
hostPtr
->addrList
= (char **)Calloc(1+numAddresses
, sizeof(char *));
for (i
= 0; i
< numAddresses
; i
++) {
hostPtr
->addrList
[i
] = Calloc(1, hostPtr
->addrLen
);
bcopy(addr_list
[i
], hostPtr
->addrList
[i
], hostPtr
->addrLen
);
hostPtr
->addrList
[i
] = NULL
;
if (headerPtr
->aa
|| nscount
== 0) {
* At this point, for the T_A query type, only empty answers remain.
* For other query types, additional information might be found
* in the additional resource records part.
if (!headerPtr
->aa
&& (queryType
!= T_A
) && (nscount
> 0 || arcount
> 0)) {
printf("Authoritative answers can be found from:\n");
cp
= res_skip((char *) &answer
, 2, eom
);
* If we don't need to save the record, just print it.
while (--nscount
>= 0 && cp
< eom
) {
if ((cp
= Print_rr(cp
, (char *) &answer
, eom
, stdout
)) == NULL
) {
while (--nscount
>= 0 && cp
< eom
) {
* Go through the NS records and retrieve the names of hosts
* that serve the requested domain.
if ((n
= dn_expand((char *) &answer
, eom
, cp
, bp
, buflen
)) < 0) {
dnamePtr
= Calloc(1, len
); /* domain name */
bcopy(bp
, dnamePtr
, len
);
cp
+= sizeof(u_long
); /* skip TTL */
if ((n
= dn_expand((char *) &answer
, eom
, cp
, bp
, buflen
)) < 0){
namePtr
= Calloc(1, len
); /* server host name */
* Store the information keyed by the server host name.
for (j
= 0; j
< numServers
; j
++) {
if (strcmp(namePtr
, server
[j
].name
) == 0) {
if (server
[j
].numDomains
<= MAXDOMAINS
) {
server
[j
].domain
[server
[j
].numDomains
-1] = dnamePtr
;
if (numServers
>= MAXSERVERS
) {
server
[numServers
].name
= namePtr
;
server
[numServers
].domain
[0] = dnamePtr
;
server
[numServers
].numDomains
= 1;
server
[numServers
].numAddresses
= 0;
* Additional resource records contain addresses of servers.
cp
= res_skip((char *) &answer
, 3, eom
);
* If we don't need to save the record, just print it.
while (--arcount
>= 0 && cp
< eom
) {
if ((cp
= Print_rr(cp
, (char *) &answer
, eom
, stdout
)) == NULL
) {
while (--arcount
>= 0 && cp
< eom
) {
if ((n
= dn_expand((char *) &answer
, eom
, cp
, bp
, buflen
)) < 0) {
cp
+= sizeof(u_long
); /* skip TTL */
for (j
= 0; j
< numServers
; j
++) {
if (strcmp(bp
, server
[j
].name
) == 0) {
server
[j
].numAddresses
++;
if (server
[j
].numAddresses
<= MAXADDRS
) {
server
[j
].address
[server
[j
].numAddresses
-1] =
server
[j
].address
[server
[j
].numAddresses
-1],dlen
);
* If we are returning name server info, transfer it to the hostPtr.
hostPtr
->servers
= (ServerInfo
**)
Calloc(numServers
+1, sizeof(ServerInfo
*));
for (i
= 0; i
< numServers
; i
++) {
hostPtr
->servers
[i
] = (ServerInfo
*) Calloc(1, sizeof(ServerInfo
));
hostPtr
->servers
[i
]->name
= server
[i
].name
;
hostPtr
->servers
[i
]->domains
= (char **)
Calloc(server
[i
].numDomains
+1,sizeof(char *));
for (j
= 0; j
< server
[i
].numDomains
; j
++) {
hostPtr
->servers
[i
]->domains
[j
] = server
[i
].domain
[j
];
hostPtr
->servers
[i
]->domains
[j
] = NULL
;
hostPtr
->servers
[i
]->addrList
= (char **)
Calloc(server
[i
].numAddresses
+1,sizeof(char *));
for (j
= 0; j
< server
[i
].numAddresses
; j
++) {
hostPtr
->servers
[i
]->addrList
[j
] = server
[i
].address
[j
];
hostPtr
->servers
[i
]->addrList
[j
] = NULL
;
hostPtr
->servers
[i
] = NULL
;
*******************************************************************************
* Retrieves host name, address and alias information
* Algorithm from res_search().
* ERROR - res_mkquery failed.
* + return values from GetAnswer()
*******************************************************************************
GetHostInfoByName(nsAddrPtr
, queryClass
, queryType
, name
, hostPtr
, isServer
)
struct in_addr
*nsAddrPtr
;
register char *cp
, **domain
;
extern char *hostalias();
Boolean got_nodata
= FALSE
;
/* Catch explicit addresses */
if ((queryType
== T_A
) && IsAddr(name
, &ina
)) {
hostPtr
->name
= Calloc(strlen(name
)+3, 1);
(void)sprintf(hostPtr
->name
,"[%s]",name
);
hostPtr
->addrType
= AF_INET
;
hostPtr
->addrLen
= sizeof(struct in_addr
);
hostPtr
->addrList
= (char **)Calloc(2, sizeof(char *));
hostPtr
->addrList
[0] = Calloc(sizeof(long), sizeof(char));
bcopy((char *)&ina
, hostPtr
->addrList
[0], sizeof(ina
));
hostPtr
->addrList
[1] = NULL
;
for (cp
= name
, n
= 0; *cp
; cp
++)
if (n
== 0 && (cp
= hostalias(name
))) {
printf("Aliased to \"%s\"\n\n", cp
);
return (GetHostDomain(nsAddrPtr
, queryClass
, queryType
,
cp
, (char *)NULL
, hostPtr
, isServer
));
* 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,
if ((n
== 0 && _res
.options
& RES_DEFNAMES
) ||
(n
!= 0 && *--cp
!= '.' && _res
.options
& RES_DNSRCH
))
for (domain
= _res
.dnsrch
; *domain
; domain
++) {
result
= GetHostDomain(nsAddrPtr
, queryClass
, queryType
,
name
, *domain
, hostPtr
, isServer
);
* If no server present, give up.
* If name isn't found in this domain,
* keep trying higher domains in the search list
* On a NO_INFO 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 (result
== SUCCESS
|| result
== NO_RESPONSE
)
if ((result
!= NXDOMAIN
&& result
!= NO_INFO
) ||
(_res
.options
& RES_DNSRCH
) == 0)
* If the search/default failed, try the name as fully-qualified,
* but only if it contained at least one dot (even trailing).
* This is purely a heuristic; we assume that any reasonable query
* about a top-level domain (for servers, SOA, etc) will not use
if (n
&& (result
= GetHostDomain(nsAddrPtr
, queryClass
, queryType
,
name
, (char *)NULL
, hostPtr
, isServer
)) == SUCCESS
)
* Perform a query on the concatenation of name and domain,
* removing a trailing dot from name if domain is NULL.
GetHostDomain(nsAddrPtr
, queryClass
, queryType
, name
, domain
, hostPtr
, isServer
)
struct in_addr
*nsAddrPtr
;
* Check for trailing '.';
* copy without '.' if present.
if (name
[n
] == '.' && n
< sizeof(nbuf
) - 1) {
(void)sprintf(nbuf
, "%.*s.%.*s",
MAXDNAME
, name
, MAXDNAME
, domain
);
n
= res_mkquery(QUERY
, longname
, queryClass
, queryType
,
(char *)0, 0, (char *)0, (char *) &buf
, sizeof(buf
));
if (_res
.options
& RES_DEBUG
) {
printf("Res_mkquery failed\n");
n
= GetAnswer(nsAddrPtr
, queryType
, (char *)&buf
, n
, 0, hostPtr
, isServer
);
* GetAnswer didn't find a name, so set it to the specified one.
if (hostPtr
->name
== NULL
) {
int len
= strlen(longname
) + 1;
hostPtr
->name
= Calloc(len
, sizeof(char));
bcopy(longname
, hostPtr
->name
, len
);
*******************************************************************************
* Performs an inverse query to find the host name
* that corresponds to the given address.
* ERROR - res_mkquery failed.
* + return values from GetAnswer()
*******************************************************************************
GetHostInfoByAddr(nsAddrPtr
, address
, hostPtr
)
struct in_addr
*nsAddrPtr
;
char *p
= (char *) &address
->s_addr
;
(void)sprintf(qbuf
, "%u.%u.%u.%u.in-addr.arpa",
((unsigned)p
[0] & 0xff));
n
= res_mkquery(QUERY
, qbuf
, C_IN
, T_PTR
,
NULL
, 0, NULL
, (char *) &buf
, sizeof(buf
));
if (_res
.options
& RES_DEBUG
) {
printf("res_mkquery() failed\n");
n
= GetAnswer(nsAddrPtr
, T_PTR
, (char *) &buf
, n
, 1, hostPtr
, 1);
hostPtr
->addrType
= AF_INET
;
hostPtr
->addrList
= (char **)Calloc(2, sizeof(char *));
hostPtr
->addrList
[0] = Calloc(sizeof(long), sizeof(char));
bcopy((char *)p
, hostPtr
->addrList
[0], sizeof(struct in_addr
));
hostPtr
->addrList
[1] = NULL
;
*******************************************************************************
* Deallocates all the calloc'd areas for a HostInfo variable.
*******************************************************************************
register HostInfo
*hostPtr
;
if (hostPtr
->name
!= NULL
) {
if (hostPtr
->aliases
!= NULL
) {
while (hostPtr
->aliases
[i
] != NULL
) {
free(hostPtr
->aliases
[i
]);
free((char *)hostPtr
->aliases
);
if (hostPtr
->addrList
!= NULL
) {
while (hostPtr
->addrList
[i
] != NULL
) {
free(hostPtr
->addrList
[i
]);
free((char *)hostPtr
->addrList
);
hostPtr
->addrList
= NULL
;
if (hostPtr
->servers
!= NULL
) {
while (hostPtr
->servers
[i
] != NULL
) {
if (hostPtr
->servers
[i
]->name
!= NULL
) {
free(hostPtr
->servers
[i
]->name
);
if (hostPtr
->servers
[i
]->domains
!= NULL
) {
while (hostPtr
->servers
[i
]->domains
[j
] != NULL
) {
free(hostPtr
->servers
[i
]->domains
[j
]);
free((char *)hostPtr
->servers
[i
]->domains
);
if (hostPtr
->servers
[i
]->addrList
!= NULL
) {
while (hostPtr
->servers
[i
]->addrList
[j
] != NULL
) {
free(hostPtr
->servers
[i
]->addrList
[j
]);
free((char *)hostPtr
->servers
[i
]->addrList
);
free((char *)hostPtr
->servers
[i
]);
free((char *)hostPtr
->servers
);