static char sccsid
[] = "@(#)ns_req.c 4.3 (Berkeley) 5/30/86";
* Copyright (c) 1986 Regents of the University of California
#include <arpa/nameser.h>
char *a_dname
; /* domain name */
u_short a_class
; /* class for address */
struct addinfo addinfo
[NADDRECS
]; /* additional info records */
int addcount
; /* number of names in addinfo */
char *dnptrs
[20]; /* ptrs to dnames in message for dn_comp */
* Process request using database; assemble and send response.
ns_req(msg
, msglen
, buflen
, qsp
, from
)
struct sockaddr_in
*from
;
register struct namebuf
*np
;
register struct databuf
*dp
;
char dnbuf
[MAXDNAME
], *dname
;
int n
, class, type
, count
, foundname
, founddata
, cname
= 0;
struct databuf
*nsp
[MAXNS
], **nspp
;
extern struct qinfo
*qhead
;
fprintf(ddt
,"ns_req()\n");
cp
= msg
+ sizeof(HEADER
);
if (ntohs(hp
->qdcount
) != 1 ||
hp
->ancount
|| hp
->nscount
|| hp
->arcount
) {
fprintf(ddt
,"FORMERR Query header counts wrong\n");
* Get domain name, class, and type.
if ((*cp
& INDIR_MASK
) == 0)
*dpp
++ = cp
; /* remember name for compression */
if ((n
= dn_expand(msg
, msg
+ msglen
, cp
, dnbuf
,
fprintf(ddt
,"FORMERR Query expand name failed\n");
fprintf(ddt
,"FORMERR Query message length off\n");
fprintf(ddt
,"message length > recived message\n");
if (!check_class(quest
.qtype
->class)) {
fprintf(ddt
,"FORMERR Query class is wrong\n");
if (!check_type(quest
.qtype
->type
)) {
fprintf(ddt
,"proc_query FORMERR Query type wrong\n");
/* refuse request if not a TCP connection */
if (qsp
== QSTREAM_NULL
) {
/* don't compress names */
fprintf(ddt
,"nlookup(%s)\n", dname
);
htp
= hashtab
; /* lookup relative to root */
np
= nlookup(dname
, &htp
, &fname
, 0);
* if nlookup failed to find address then
* see if there are any '.''s in the name
* if not then add local domain name to the
dnp
= &dname
[strlen(dname
)];
if ( index(dname
, '.') == NULL
)
for (zp
= zones
; zp
< &zones
[nzones
]; zp
++) {
if ( zp
->z_type
== Z_DOMAIN
){
fprintf(ddt
,"domain = %s\n",
(void) strcat(dname
,".");
(void) strcat(dname
,zp
->z_origin
);
fprintf(ddt
,"nlookup(%s)\n", dname
);
np
= nlookup(dname
, &htp
, &fname
, 0);
fprintf(ddt
,"CNAME with data\n");
fprintf(ddt
,"CNAME without data %s\n", dname
);
fprintf(ddt
,"found '%s'\n", dname
);
if (!wanted(dp
, class, type
)) {
if ((n
= make_rr(dname
, dp
, cp
, buflen
, 1)) < 0) {
/* delete old cache entry */
fprintf(ddt
,"deleting cache entry\n");
if (dp
->d_type
== T_CNAME
) {
fprintf(ddt
,"foundname = %d count = %d ", foundname
, count
);
fprintf(ddt
,"founddata = %d cname = %d\n",founddata
, cname
);
hp
->ancount
= htons((u_short
)count
);
if (type
== T_AXFR
&& founddata
) {
fprintf(ddt
,"doing axfr()\n");
* child does the work while
rfp
= fdopen(qsp
->s_rfd
, "w");
setproctitle("zone XFR to", qsp
->s_rfd
);
fdstat
= fcntl(qsp
->s_rfd
, F_GETFL
, 0);
(void) fcntl(qsp
->s_rfd
, F_SETFL
,
fwritemsg(rfp
, msg
, cp
- msg
);
fwritemsg(rfp
, msg
, cp
- msg
);
* Look for name servers to refer to and
* fill in the authority section or record the address
* for forwarding the query (recursion desired).
for (count
= 0; ; np
= np
->n_parent
) {
fprintf(ddt
,"fname = '%s'\n", fname
);
for (np
= hashtab
->h_tab
[0]; np
!= NULL
;
if ( np
->n_dname
[0] == '\0')
fprintf(ddt
,"No root nameserver?\n");
syslog(LOG_ERR
,"No root Nameserver\n");
nspp
= nsp
; /* record ns records if forwarding */
curtime
=(u_long
) tt
.tv_sec
;
if (dp
->d_zone
&& match(dp
, class, T_SOA
)) {
if (!match(dp
, class, T_NS
)) {
/* delete old cache entry */
fprintf(ddt
,"deleting cache entry\n");
if (hp
->rd
&& !founddata
) {
if (nspp
< &nsp
[MAXNS
-1])
if ((n
= make_rr(fname
, dp
, cp
, buflen
, 1)) < 0) {
/* delete old cache entry */
fprintf(ddt
,"deleting cache entry\n");
if (count
&& founddata
) {
hp
->nscount
= htons((u_short
)count
);
for (qp
= qhead
; qp
!=QINFO_NULL
;
qp
->q_cmsglen
== msglen
&&
bcmp((char *)qp
->q_cmsg
+2,
/* build new qinfo struct */
if (nslookup(nsp
, qp
) == 0) {
fprintf(ddt
,"none found in nsp\n");
if ((qp
->q_cmsg
= malloc((unsigned)msglen
))
fprintf(ddt
,"ns_req: malloc fail\n");
syslog(LOG_ERR
, "ns_req: Out Of Memory");
bcopy(msg
, qp
->q_cmsg
, qp
->q_cmsglen
= msglen
);
if ((newmsg
= malloc(BUFSIZ
)) == NULL
) {
fprintf(ddt
,"ns_req: malloc error\n");
syslog(LOG_ERR
, "ns_req: Out Of Memory");
newmsglen
= res_mkquery(QUERY
, dname
, class,
type
, (char *)NULL
, 0, NULL
,
qp
->q_msglen
= newmsglen
;
hp
->id
= qp
->q_nsid
= htons((u_short
)++nsid
);
schedretry(qp
, (time_t)RETRYTIME
);
fprintf(ddt
,"forw -> %s (%d)\n",
inet_ntoa(qp
->q_addr
[0].sin_addr
),
ntohs(qp
->q_addr
[0].sin_port
));
if (sendto(ds
, newmsg
, newmsglen
, 0,
&qp
->q_addr
[0], sizeof(qp
->q_addr
[0])) < 0){
fprintf(ddt
,"sendto error \n");
if ((n
= ns_forw(nsp
, msg
, msglen
, from
, qsp
)) == 0)
if ((fname
= index(fname
, '.')) == NULL
)
register struct invbuf
*ip
;
char anbuf
[PACKETSZ
], *data
;
if (ntohs(hp
->ancount
) != 1 ||
hp
->qdcount
|| hp
->nscount
|| hp
->arcount
) {
fprintf(ddt
,"FORMERR IQuery header counts wrong\n");
* Skip domain name, get class, and type.
if ((n
= dn_skip(cp
)) < 0) {
fprintf(ddt
,"FORMERR IQuery packet name problem\n");
cp
+= sizeof(u_short
) + sizeof(u_long
);
cp
+= sizeof(u_short
) + dlen
;
if (cp
!= msg
+ msglen
) {
fprintf(ddt
,"FORMERR IQuery message length off\n");
/* not all inverse queries are handled. */
fname
= msg
+ sizeof(HEADER
);
bcopy(fname
, anbuf
, alen
= cp
- fname
);
data
= anbuf
+ alen
- dlen
;
buflen
-= sizeof(HEADER
);
for (ip
= invtab
[dhash(data
, dlen
)]; ip
!= NULL
;
for (i
= 0; i
< INVBLKSZ
; i
++) {
if ((np
= ip
->i_dname
[i
]) == NULL
)
fprintf(ddt
,"dname = %d\n", np
->n_dname
);
for (dp
= np
->n_data
; dp
!= NULL
; dp
= dp
->d_next
) {
if (!match(dp
, class, type
))
if (dp
->d_size
!= dlen
||
bcmp(dp
->d_data
, data
, dlen
))
getname(np
, dnbuf
, sizeof(dnbuf
));
dn_comp(dnbuf
, cp
, buflen
, (char **)NULL
,
putshort((u_short
)dp
->d_type
, cp
);
putshort((u_short
)dp
->d_class
, cp
);
hp
->qdcount
= htons((u_short
)count
);
dn_expand(msg
, msg
+ msglen
, cp
, dnbuf
, sizeof(dnbuf
))) < 0)
fprintf(ddt
,"FORMERR UpdateA expand name failed\n");
if (cp
+ n
!= msg
+ msglen
) {
fprintf(ddt
,"FORMERR UpdateA expand name failed\n");
dp
= savedata(class, type
, ttl
, cp
, n
);
dp
->d_zone
= findzone(dnbuf
, class);
if ((n
= updatedb(dnbuf
, NULL
, dp
, DB_NODATA
)) != NOERROR
) {
fprintf(ddt
,"update failed\n");
dn_expand(msg
, msg
+ msglen
, cp
, dnbuf
, sizeof(dnbuf
))) < 0)
fprintf(ddt
,"FORMERR UpdateD expand name failed\n");
rrec
.r_type
= getshort(cp
);
rrec
.r_class
= getshort(cp
);
cp
+= sizeof(u_short
) + sizeof(u_long
);
rrec
.r_size
= getshort(cp
);
rrec
.r_data
= cp
+= sizeof(u_short
);
if (cp
+ rrec
.r_size
!= msg
+ msglen
) {
fprintf(ddt
,"FORMERR UpdateD message length off\n");
if (updatedb(dnbuf
, &rrec
, NULL
, DB_DELETE
) < 0) {
fprintf(ddt
,"update failed\n");
if ((n
= dn_expand(msg
, msg
+ msglen
, cp
, addbuf
,
fprintf(ddt
,"FORMERR UpdateM expand name 1 failed\n");
rrec
.r_type
= getshort(cp
);
rrec
.r_class
= getshort(cp
);
cp
+= sizeof(u_short
) + sizeof(u_long
);
rrec
.r_size
= getshort(cp
);
rrec
.r_data
= cp
+= sizeof(u_short
);
dn_expand(msg
, msg
+ msglen
, cp
, dnbuf
, sizeof(dnbuf
))) < 0)
fprintf(ddt
,"FORMERR UpdateM expand name 2 failed\n");
if (cistrcmp(dnbuf
, addbuf
) != 0) {
fprintf(ddt
,"FORMERR UpdateM string compair failed\n");
if (cp
+ n
!= msg
+ msglen
) {
fprintf(ddt
,"FORMERR UpdateM message length off\n");
dp
= savedata(class, type
, ttl
, cp
, n
);
dp
->d_zone
= findzone(dnbuf
, class);
updatedb(dnbuf
, &rrec
, dp
, DB_MEXIST
|DB_DELETE
)) != NOERROR
)
fprintf(ddt
,"update failed\n");
fprintf(ddt
,"Refresh Zone\n");
hp
->qr
= 1; /* set Response flag */
hp
->ra
= 1; /* Recursion is Available */
cp
+= doaddinfo(hp
, cp
, buflen
- (cp
- msg
));
if (qsp
== QSTREAM_NULL
) {
if (sendto(ds
, msg
, cp
-msg
, 0, from
, sizeof(*from
)) < 0) {
fprintf(ddt
,"error returning msg\n");
(void) writemsg(qsp
->s_rfd
, msg
, cp
- msg
);
fwritemsg(rfp
, msg
, msglen
)
u_short len
= htons((u_short
)msglen
);
if (fwrite((char *)&len
, sizeof(len
), 1, rfp
) != 1 ||
fwrite(msg
, msglen
, 1, rfp
) != 1) {
fprintf(ddt
,"fwrite failed %d\n", errno
);
syslog(LOG_ERR, "fwritemsg: write failed: %m");
writemsg(rfd
, msg
, msglen
)
u_short len
= htons((u_short
)msglen
);
iov
[0].iov_base
= (caddr_t
)&len
;
iov
[0].iov_len
= sizeof(len
);
if (writev(rfd
, iov
, 2) != sizeof(len
) + msglen
) {
fprintf(ddt
,"write failed %d\n", errno
);
syslog(LOG_ERR, "writemsg: write failed: %m");
* Copy databuf into a resource record for replies.
* Return size of RR if OK, -1 if buffer is full and
* -2 if its an outdated cache entry.
make_rr(name
, dp
, buf
, buflen
, doadd
)
register struct databuf
*dp
;
register struct addinfo
*ap
;
char **edp
= dnptrs
+ sizeof(dnptrs
)/sizeof(dnptrs
[0]);
fprintf(ddt
,"make_rr(%s, %x, %x, %d, %d) %d\n", name
, dp
, buf
,
buflen
, doadd
, dp
->d_size
);
/* check for outdated RR before updating dnptrs by dn_comp() */
ttl
= dp
->d_ttl
- (u_long
) tt
.tv_sec
;
if (dp
->d_ttl
< (u_long
)tt
.tv_sec
)
ttl
= zones
[dp
->d_zone
].z_minimum
;
if ((n
= dn_comp(name
, buf
, buflen
, (char **)dnptrs
, (char **)edp
)) < 0)
putshort((u_short
)dp
->d_type
, cp
);
putshort((u_short
)dp
->d_class
, cp
);
if ((n
= dn_comp(dp
->d_data
, cp
, buflen
, (char **)dnptrs
,
putshort((u_short
)n
, sp
);
/* Store domain name in answer */
if ((n
= dn_comp(dp
->d_data
, cp
, buflen
, (char **)dnptrs
,
putshort((u_short
)n
, sp
);
for (ap
= addinfo
, n
= addcount
; --n
>= 0; ap
++)
if (cistrcmp(ap
->a_dname
, dp
->d_data
) == 0)
/* add domain name to additional section */
if (addcount
>= NADDRECS
)
ap
->a_dname
= dp
->d_data
;
ap
->a_class
= dp
->d_class
;
if ((n
= dn_comp(cp1
, cp
, buflen
, (char **)dnptrs
,
buflen
-= dp
->d_type
== T_MINFO
? n
: n
+ 5 * sizeof(u_long
);
if ((n
= dn_comp(cp1
, cp
, buflen
, (char **)dnptrs
,
if (dp
->d_type
== T_SOA
) {
(int)(n
= dp
->d_size
- (cp1
- dp
->d_data
)));
putshort((u_short
)(cp
- sp
) - sizeof(u_short
), sp
);
/* cp1 == our data/ cp == data of RR */
bcopy(cp1
,cp
,sizeof(u_short
));
buflen
-= sizeof(u_short
);
if ((n
= dn_comp(cp1
, cp
, buflen
, (char **)dnptrs
,
putshort((u_short
)(cp
-sp
)-sizeof(u_short
),sp
);
bcopy(dp
->d_data
, cp
, dp
->d_size
);
putshort((u_short
)dp
->d_size
, sp
);
* Lookup addresses for names in addinfo and put into the message's
doaddinfo(hp
, msg
, msglen
)
register struct namebuf
*np
;
register struct databuf
*dp
;
register struct databuf
*tmp
;
fprintf(ddt
,"doaddinfo() addcount = %d\n", addcount
);
for (ap
= addinfo
; --addcount
>= 0; ap
++) {
fprintf(ddt
,"do additional '%s'\n", ap
->a_dname
);
htp
= hashtab
; /* lookup relative to root */
np
= nlookup(ap
->a_dname
, &htp
, &fname
, 0);
if (np
== NULL
|| fname
!= ap
->a_dname
)
fprintf(ddt
,"found it\n");
if (!match(dp
, (int)ap
->a_class
, T_A
)) {
if ((n
= make_rr(ap
->a_dname
, dp
, cp
, msglen
, 0)) < 0)
/* delete old cache entry */
fprintf(ddt
,"deleting cache entry\n");
fprintf(ddt
,"n = %d\n", n
);
hp
->arcount
= htons((u_short
)count
);
* Do we want this data record based on the class and type?
fprintf(ddt
,"wanted(%x, %d, %d) %d, %d\n", dp
, class, type
,
dp
->d_class
, dp
->d_type
);
if (dp
->d_class
!= class && class != C_ANY
)
* Get the domain name of 'np' and put in 'buf'.
(void) strcpy(cp
, np
->n_dname
);
* Do a zone transfer. SOA record already sent.
register struct namebuf
*np
;
register struct databuf
*dp
;
struct namebuf
**npp
, **nppend
;
HEADER
*hp
= (HEADER
*) msg
;
fprintf(ddt
,"doaxfr()\n");
hp
->qr
= hp
->aa
= hp
->tc
= hp
->ra
= hp
->pr
= hp
->rd
= 0;
cp
= msg
+ sizeof(HEADER
);
getname(np
, dname
, sizeof(dname
));
/* first do data records */
for (dp
= np
->n_data
; dp
!= NULL
; dp
= dp
->d_next
) {
/* skip the root SOA record (marks end of data) */
} else if (dp
->d_type
== T_NS
)
if ((n
= make_rr(dname
, dp
, cp
,
sizeof(msg
)-sizeof(HEADER
), 0)) < 0)
fwritemsg(rfp
, msg
, n
+ sizeof(HEADER
));
if (fndns
|| np
->n_hash
== NULL
)
nppend
= npp
+ np
->n_hash
->h_size
;
for (np
= *npp
++; np
!= NULL
; np
= np
->n_next
) {
fprintf(ddt
,"exit doaxfr()\n");