📄 ns_resp.c
字号:
goto formerr; } if ((n = dovalidate((caddr_t)msg, msglen, tempcp, 0, dbflags, server, &VCode)) < 0) { dprintf(1, (ddt, "resp: leaving, dovalidate failed\n")); /* return code filled in by dovalidate */ goto return_msg; } validatelist[i] = VCode; if (VCode == INVALID) lesscount++; tempcp += n; } /* need to delete INVALID records from the message * and change fields appropriately */ n = update_msg(msg, &msglen, validatelist, count); free((char *)validatelist); if (n < 0) goto formerr; count -= lesscount; if (old_ancount && !hp->ancount) { /* We lost all the answers */ dprintf(1, (ddt, "validate count -> 0")); return; } ancount <- ntohs(hp->ancount);#endif for (i = 0; i < count; i++) { struct databuf *ns3;#ifdef CRED u_char cred;#endif if (cp >= msg + msglen) { formerrmsg = outofDataFinal; goto formerr; }#ifdef CRED if (i < ancount) { cred = hp->aa ?DB_C_AUTH :DB_C_ANSWER; } else { cred = DB_C_ADDITIONAL; }#endif ns3 = 0; if ((n = doupdate((caddr_t)msg, msglen, cp, 0, &ns3, dbflags#ifdef CRED , cred#endif )) < 0) { dprintf(1, (ddt, "resp: leaving, doupdate failed\n"));#ifdef DATUMREFCNT free_nsp(nsp);#endif /* return code filled in by doupdate */ goto return_msg; } /* * Remember nameservers from the authority section * for referrals. * (This is usually overwritten by findns below(?). XXX */ if (ns3 && i >= ancount && i < ancount + aucount && nspp < &nsp[NSMAX-1]) { *nspp++ = ns3;#ifdef DATUMREFCNT ns3->d_rcnt++; *nspp = NULL;#endif } cp += n; } if ((qp->q_flags & Q_SYSTEM) && ancount) { if (qp->q_flags & Q_PRIMING) check_root(); dprintf(3, (ddt, "resp: leaving, SYSQUERY ancount %d\n", ancount)); qremove(qp);#ifdef DATUMREFCNT free_nsp(nsp);#endif return; } if (cp > msg + msglen) { formerrmsg = outofDataAFinal; goto formerr; } /* * If there are addresses and this is a local query, * sort them appropriately for the local context. */ if (ancount > 1 && (lp = local(&qp->q_from)) != NULL) sort_response((caddr_t)tp, ancount, lp, msg + msglen); /* * An answer to a T_ANY query or a successful answer to a * regular query with no indirection, then just return answer. */ if ((hp->qdcount && type == T_ANY && ancount) || (!cname && !qp->q_cmsglen && ancount)) { dprintf(3, (ddt, "resp: got as much answer as there is\n")); goto return_msg; } /* * Eventually we will want to cache this negative answer. */ if (ancount == 0 && nscount == 0 && (hp->aa || fwd || class == C_ANY)) { /* We have an authoritative NO */ dprintf(3, (ddt, "resp: leaving auth NO\n")); if (qp->q_cmsglen) { msg = (u_char *)qp->q_cmsg; msglen = qp->q_cmsglen; hp = (HEADER *)msg; }#ifdef NCACHE /*answer was an authoritative NO,*/ if ((ancount == 0) && (hp->aa) && ((hp->rcode == NXDOMAIN) || (hp->rcode == NOERROR))) { cache_n_resp(msg, msglen); }#endif /*NCACHE*/ goto return_msg; } /* * All messages in here need further processing. i.e. they * are either CNAMEs or we got referred again. */ count = 0; founddata = 0; foundname = 0; dname = name; if (!cname && qp->q_cmsglen && ancount) { dprintf(1, (ddt, "Cname second pass\n")); newmsglen = qp->q_cmsglen; bcopy(qp->q_cmsg, newmsg, newmsglen); } else { newmsglen = msglen; bcopy(msg, newmsg, newmsglen); } hp = (HEADER *) newmsg; hp->ancount = 0; hp->nscount = 0; hp->arcount = 0; dnptrs[0] = newmsg; dnptrs[1] = NULL; cp = newmsg + sizeof(HEADER); if (cname) cp += dn_skipname(cp, newmsg + newmsglen) + QFIXEDSZ; if ((n = dn_expand(newmsg, newmsg + newmsglen, cp, (u_char *)dname, sizeof(name))) < 0) { dprintf(1, (ddt, "dn_expand failed\n")); goto servfail; } if (!cname) cp += n + QFIXEDSZ; buflen = sizeof(newmsg) - (cp - newmsg);try_again: dprintf(1, (ddt, "resp: nlookup(%s) type=%d\n", dname, type)); fname = ""; htp = hashtab; /* lookup relative to root */ np = nlookup(dname, &htp, &fname, 0); dprintf(1, (ddt, "resp: %s '%s' as '%s' (cname=%d)\n", np == NULL ? "missed" : "found", dname, fname, cname)); if (np == NULL || fname != dname) goto fetch_ns; foundname++; count = cp - newmsg; n = finddata(np, class, type, hp, &dname, &buflen, &count); if (n == 0) goto fetch_ns; /* NO data available */ cp += n; buflen -= n; hp->ancount += count; if (fname != dname && type != T_CNAME && type != T_ANY) { cname++; goto try_again; } founddata = 1; dprintf(3, (ddt, "resp: foundname=%d, count=%d, founddata=%d, cname=%d\n", foundname, count, founddata, cname));fetch_ns: hp->ancount = htons(hp->ancount); /* * Look for name servers to refer to and fill in the authority * section or record the address for forwarding the query * (recursion desired). */#ifdef DATUMREFCNT free_nsp(nsp);#endif switch (findns(&np, class, nsp, &count, 0)) { case NXDOMAIN: /* shouldn't happen */ dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n", dname, hp->rcode)); if (!foundname) hp->rcode = NXDOMAIN; if (class != C_ANY) { hp->aa = 1; /* * should return SOA if founddata == 0, * but old named's are confused by an SOA * in the auth. section if there's no error. */ if (foundname == 0 && np) { n = doaddauth(hp, cp, buflen, np, nsp[0]); cp += n; buflen -= n; } } goto return_newmsg; case SERVFAIL: goto servfail; } if (founddata) { hp = (HEADER *)newmsg; n = add_data(np, nsp, cp, buflen); if (n < 0) { hp->tc = 1; n = (-n); } cp += n; buflen -= n; hp->nscount = htons((u_int16_t)count); goto return_newmsg; } /* * If we get here, we don't have the answer yet and are about * to iterate to try and get it. First, infinite loop avoidance. */ if (qp->q_nqueries++ > MAXQUERIES) { dprintf(1, (ddt, "resp: MAXQUERIES exceeded (%s, class %d, type %d)\n", dname, class, type ) ); syslog(LOG_NOTICE, "MAXQUERIES exceeded, possible data loop in resolving (%s)", dname); goto servfail; } /* Reset the query control structure */#ifdef DATUMREFCNT for (i = 0 ; i < qp->q_naddr ; i++) { if ((--(qp->q_addr[i].ns->d_rcnt))) { dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d\n", qp->q_addr[i].ns->d_data, qp->q_addr[i].ns->d_rcnt)); } else { dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d delayed\n", qp->q_addr[i].ns->d_data, qp->q_addr[i].ns->d_rcnt)); free((char*)qp->q_addr[i].ns); } if ((--(qp->q_addr[i].nsdata->d_rcnt))) { dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d\n", *(int32_t *)(qp->q_addr[i].nsdata->d_data), qp->q_addr[i].nsdata->d_rcnt)); } else { dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d delayed\n", *(int32_t *)(qp->q_addr[i].nsdata->d_data), qp->q_addr[i].nsdata->d_rcnt)); free((char*)qp->q_addr[i].nsdata); } }#endif qp->q_naddr = 0; qp->q_curaddr = 0; qp->q_fwd = fwdtab; if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) { if (n < 0) { dprintf(3, (ddt, "resp: nslookup reports danger\n")); } else { dprintf(3, (ddt, "resp: no addrs found for NS's\n")); } if (cname) /* a remote CNAME that does not have data */ goto return_newmsg; goto servfail; } for (n = 0; n < qp->q_naddr; n++) qp->q_addr[n].stime.tv_sec = 0; if (!qp->q_fwd) qp->q_addr[0].stime = tt; if (cname) { if (qp->q_cname++ == MAXCNAMES) { dprintf(3, (ddt, "resp: leaving, MAXCNAMES exceeded\n")); goto servfail; } dprintf(1, (ddt, "q_cname = %d\n",qp->q_cname)); dprintf(3, (ddt, "resp: building recursive query; nslookup\n")); if (qp->q_msg) (void) free(qp->q_msg); if ((qp->q_msg = malloc(BUFSIZ)) == NULL) { dprintf(1, (ddt, "resp: malloc error\n")); goto servfail; } qp->q_msglen = res_mkquery(QUERY, dname, class, type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ); hp = (HEADER *) qp->q_msg; hp->rd = 0; } else hp = (HEADER *)qp->q_msg; hp->id = qp->q_nsid = htons((u_int16_t)++nsid); if (qp->q_fwd) hp->rd = 1; unsched(qp); schedretry(qp, retrytime(qp)); dprintf(1, (ddt, "resp: forw -> [%s].%d ds=%d nsid=%d id=%d %dms\n", inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr), ntohs(Q_NEXTADDR(qp,0)->sin_port), ds, ntohs(qp->q_nsid), ntohs(qp->q_id), (qp->q_addr[0].nsdata != NULL) ? qp->q_addr[0].nsdata->d_nstime : (-1)));#ifdef DEBUG if (debug >= 10) fp_query((char *)msg, ddt);#endif if (sendto(ds, qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)Q_NEXTADDR(qp,0), sizeof(struct sockaddr_in)) < 0) { dprintf(5, (ddt, "sendto error = %d\n", errno)); } hp->rd = 0; /* leave set to 0 for dup detection */ stats[S_OUTPKTS].cnt++; dprintf(3, (ddt, "resp: Query sent.\n"));#ifdef DATUMREFCNT free_nsp(nsp);#endif return;formerr: dprintf(3, (ddt, "FORMERR resp() from [%s].%d size err %d, msglen %d\n", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port), cp-msg, msglen)); if (!haveComplained((char*)from_addr.sin_addr.s_addr, (char*)dhash((u_char *)formerrmsg, strlen(formerrmsg) ) ) ) { syslog(LOG_INFO, "Malformed response from [%s].%d (%s)\n", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port), formerrmsg); } stats[S_RESPFORMERR].cnt++;#ifdef DATUMREFCNT free_nsp(nsp);#endif return;return_msg: stats[S_RESPOK].cnt++; /* The "standard" return code */ hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; hp->ra = 1; (void) send_msg((caddr_t)msg, msglen, qp); qremove(qp);#ifdef DATUMREFCNT free_nsp(nsp);#endif return;return_newmsg: stats[S_RESPOK].cnt++; if (addcount) { n = doaddinfo(hp, cp, buflen); cp += n; buflen -= n; } hp->id = qp->q_id; hp->rd = 1; hp->ra = 1; hp->qr = 1; (void) send_msg((caddr_t)newmsg, cp - newmsg, qp); qremove(qp);#ifdef DATUMREFCNT free_nsp(nsp);#endif return;servfail: stats[S_RESPFAIL].cnt++; hp = (HEADER *)(cname ? qp->q_cmsg : qp->q_msg); hp->rcode = SERVFAIL; hp->id = qp->q_id; hp->rd = 1; hp->ra = 1; hp->qr = 1; (void) send_msg((char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen), qp); qremove(qp);#ifdef DATUMREFCNT free_nsp(nsp);#endif return;}/* * Decode the resource record 'rrp' and update the database. * If savens is non-nil, record pointer for forwarding queries a second time. */intdoupdate(msg, msglen, rrp, zone, savens, flags#ifdef CRED , cred#endif ) char *msg; u_char *rrp; struct databuf **savens; int msglen, zone, flags;#ifdef CRED u_int cred;#endif{ register u_char *cp; register int n; int class, type, dlen, n1; u_int32_t ttl; struct databuf *dp; char dname[MAXDNAME]; u_char *cp1; u_char data[BUFSIZ]; register HEADER *hp = (HEADER *) msg;#ifdef ALLOW_UPDATES int zonenum;#endif dprintf(3, (ddt, "doupdate(zone %d, savens %x, flags %x)\n", zone, savens, flags)); cp = rrp; if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, cp, (u_char *)dname, sizeof(dname))) < 0) { hp->rcode = FORMERR; return (-1); } cp += n; GETSHORT(type, cp); GETSHORT(class, cp); GETLONG(ttl, cp); GETSHORT(dlen, cp); dprintf(3, (ddt, "doupdate: dname %s type %d class %d ttl %d\n", dname, type, class, ttl)); /* * Convert the resource record data into the internal * database format. */ switch (type) { case T_A: case T_WKS: case T_HINFO: case T_UINFO: case T_UID: case T_GID: case T_TXT:#ifdef ALLOW_T_UNSPEC case T_UNSPEC:#endif cp1 = cp; n = dlen; cp += n; break; case T_CNAME: case T_MB: case T_MG: case T_MR: case T_NS: case T_PTR: if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, cp, data, sizeof(data))) < 0) { hp->rcode = FORMERR; return (-1); } cp += n; cp1 = data; n = strlen((char *)data) + 1; break; case T_MINFO: case T_SOA: case T_RP: if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, cp, data, sizeof(data))) < 0) { hp->rcode = FORMERR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -