diff options
Diffstat (limited to 'contrib/bind/named/ns_validate.c')
-rw-r--r-- | contrib/bind/named/ns_validate.c | 1234 |
1 files changed, 0 insertions, 1234 deletions
diff --git a/contrib/bind/named/ns_validate.c b/contrib/bind/named/ns_validate.c deleted file mode 100644 index b7e774cadf896..0000000000000 --- a/contrib/bind/named/ns_validate.c +++ /dev/null @@ -1,1234 +0,0 @@ -/************************************************************************** - * ns_validate.c (was security.c in original ISI contribution) - * author: anant kumar - * contributed: March 17, 1993 - * - * implements validation procedure for RR's received from a server as a - * response to a query. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/file.h> - -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <arpa/inet.h> - -#include <syslog.h> -#include <errno.h> -#include <stdio.h> -#include <resolv.h> - -#include "named.h" - -#ifdef VALIDATE - -static int isvalid __P((struct namebuf *, int, int, char *, int)), - check_addr_ns __P((struct databuf **, - struct sockaddr_in *, - char *)), - check_in_tables __P((struct databuf **, - struct sockaddr_in *, - char *)); -#if 0 -static void stick_in_queue __P((char *, int, int, char *)); -#endif - -static NAMEADDR nameaddrlist[MAXNAMECACHE]; -static int firstNA = 0, - lastNA = 0; - -static TO_Validate *validateQ, *currentVQ; -static int VQcount; - -/***************************************************************** - * validate() is called from dovalidate(). it takes as parameters, - * the domain name sought, the class, type etc. of record, the server - * that gave us the answer and the data it gave us - * - * it returns VALID if it is able to validate the record, INVALID if it cannot. - * furtehr VALID is split into VALID_CACHE if we need to cache this record - * since the domainname is not something we are authoritative for and - * VALID_NO_CACHE if the name is something we are authoritative for. - * - * pseudocode for function validate is as follows: - * validate(domain, qdomain, server, type, class, data, dlen, rcode) { - * - * if (dname or a higher level name not found in cache) - * return INVALID; - * if (NS records for "domain" found in cache){ - * - * if (we are authoritative) /findns() returned NXDOMAIN;/ - * if (we did not have an exact match on names) - * =>the name does not exist in our database - * => data is bad: return INVALID - * if (data agrees with what we have) - * return VALID_NO_CACHE; - * else return INVALID; - * - * if (we are not authoritative) /findns() returned OK;/ - * if (domain lives below the qdomain) - * return VALID_CACHE; - * if (address records for NS's found in cache){ - * if ("server" = one of the addresses){ - * return VALID_CACHE; - * }else{ - * stick in queue of "to_validate" data; - * return (INVALID); - * } - * else return INVALID; - * - * This performs the validation procedure described above. Checks - * for the longest component of the dname that has a NS record - * associated with it. At any stage, if no data is found, it implies - * that the name is bad (has an unknown domain identifier) thus, we - * return INVALID. - * If address of one of these servers matches the address of the server - * that returned us this data, we are happy! - * - * since findns will set needs_prime_cache if np = NULL is passed, we always - * reset it. will let ns_req do it when we are searching for ns records to - * query someone. hence in all the three cases of switch(findns()) - * we have needs_prime_cache = 0; - *****************************************************************************/ -int -validate(dname, qdomain, server, type, class, data, dlen -#ifdef NCACHE - ,rcode -#endif - ) - char *dname, *qdomain; - struct sockaddr_in *server; - int type, class; - char *data; - int dlen; -#ifdef NCACHE - int rcode; -#endif -{ - struct namebuf *np, *dnamep; - struct hashbuf *htp; - struct databuf *nsp[NSMAX]; - int count; - const char *fname; - int exactmatch = 0; - struct fwdinfo *fwd; - - nsp[0] = NULL; - dprintf(3, (ddt, - "validate(), d:%s, s:[%s], t:%d, c:%d\n", - dname, inet_ntoa(server->sin_addr), type, class)); - - /* everything from forwarders is the GOSPEL */ - for (fwd = fwdtab; fwd != NULL; fwd = fwd->next) { - if (server->sin_addr.s_addr == fwd->fwdaddr.sin_addr.s_addr) - return (VALID_CACHE); - } - - htp = hashtab; - if (priming && (dname[0] == '\0')) - np = NULL; - else - np = nlookup(dname, &htp, &fname, 0); - - /* we were able to locate namebufs for this domain, or a parent domain, - * or ??? */ - - if (np == NULL) - fname = ""; - dprintf(5, (ddt, - "validate:namebuf found np:%#lx, d:\"%s\", f:\"%s\"\n", - (u_long)np, dname, fname)); - /* save the namebuf if we were able to locate the exact dname */ - if (!strcasecmp(dname, fname)) { - dnamep = np; - exactmatch = 1; - } - switch (findns(&np, class, nsp, &count, 0)) { - case NXDOMAIN: - /** we are authoritative for this domain, lookup name - * in our zone data, if it matches, return valid. - * in either case, do not cache - **/ - dprintf(5, (ddt, "validate: auth data found\n")); - free_nsp(nsp); - if (needs_prime_cache) - needs_prime_cache = 0; - -#ifdef NCACHE - if (rcode == NXDOMAIN) { - /* If we had an exactmatch on the name, we found the - * name in our authority database, so this couldn't - * have been a bad name. INVALID data, say so - */ - if (exactmatch) - return (INVALID); - else - /* we did not have an exactmatch, the data is - * good, we do not NCACHE stuff we are - * authoritative for, though. - */ - return (VALID_NO_CACHE); - } -#endif - if (!strcasecmp(dname, NAME(*np))) { - - /* if the name we seek is the same as that we have ns - * records for, compare the data we have to see if it - * matches. if it does, return valid_no_cache, if it - * doesn't, invalid. - */ - if (isvalid(np, type, class, data, dlen)) - return (VALID_NO_CACHE); - else - return (INVALID); - } - - /* we found ns records in a higher level, if we were unable to - * locate the exact name earlier, it means we are - * authoritative for this domain but do not have records for - * this name. this name is obviously invalid - */ - if (!exactmatch) - return (INVALID); - - /* we found the exact name earlier and we are obviously - * authoritative so check for data records and see if any - * match. - */ - if (isvalid(dnamep, type, class, data, dlen)) - return (VALID_NO_CACHE); - else - return (INVALID); - - case SERVFAIL:/* could not find name server records*/ - /* stick_in_queue(dname, type, class, data); */ - if (needs_prime_cache) - needs_prime_cache = 0; - free_nsp(nsp); - return (INVALID); - - case OK: /*proceed */ - dprintf(5, (ddt, "validate:found ns records\n")); - if (needs_prime_cache) - needs_prime_cache = 0; - if (samedomain(dname, qdomain) || - check_addr_ns(nsp, server, dname)) { - free_nsp(nsp); - return (VALID_CACHE); - } - /* server is not one of those we know of */ - /* stick_in_queue(dname, type, class, data); */ - free_nsp(nsp); - return (INVALID); - default: - free_nsp(nsp); - return (INVALID); - } /*switch*/ - -} /*validate*/ - -/*********************************************************************** - * validate rr returned by somebody against your own database, if you are - * authoritative for the information. if you have a record that matches, - * return 1, else return 0. validate() above will use this and determine - * if the record should be returned/discarded. - ***********************************************************************/ -static int -isvalid(np, type, class, data, dlen) - struct namebuf *np; - int type, class; - char *data; - int dlen; -{ - register struct databuf *dp; - - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (!wanted(dp, class, type)) { - if ((type == T_CNAME) && (class == dp->d_class)) { - /* if a cname exists, any other will not */ - return (0); - /* we come here only for zone info, - * so -ve $ed info can't be - */ - } - continue; - } - /* type and class match, if i get here - * let's now compare the data section, per RR type - */ - - /* unless, of course, the data was negative, in which case - * we should return FAILURE since we should not have found - * data here. - */ - if ((data == NULL) || (dlen == 0)) - return (0); - - /* XXX: why aren't we just calling db_cmp()? */ - - switch (type) { - char *td; - u_char *tdp; - int x; - - case T_A: - case T_WKS: - case T_HINFO: - case T_UINFO: - case T_UID: - case T_GID: - case T_TXT: - case T_X25: - case T_ISDN: - case T_LOC: -#ifdef ALLOW_T_UNSPEC - case T_UNSPEC: -#endif - x = memcmp(dp->d_data, data, dlen); - dprintf(3, (ddt, "type = %d, GOOD = %d\n", - type, x)); - if (x == 0) - return (1); - else - break; - - case T_CNAME: - case T_MB: - case T_MG: - case T_MR: - case T_NS: - case T_PTR: - x = strncasecmp((char *)dp->d_data, data, dlen); - dprintf(3, (ddt, "type = %d, GOOD = %d\n", - type, x)); - if (x == 0) - return (1); - else - break; - - case T_MINFO: - case T_SOA: - case T_RP: - /* compare first string */ - x = strncasecmp((char *)dp->d_data, data, - strlen(data) + 1); - if (x != 0) - break; - - /* move to second string */ - td = data + (strlen(data) + 1); - tdp = dp->d_data + - (strlen((char *)dp->d_data)+1); - - /* compare second string */ - x = strncasecmp(td, (char *)tdp, - strlen((char *)td+1)); - if (x != 0) - break; - - /* move beyond second string, to - * set of words in SOA. - * RP and MINFO stuff really - * ends here - */ - - td = td + strlen((char *)td) + 1; - tdp = tdp + strlen((char *)tdp) + 1; - if (type == T_SOA) { - x = memcmp(td, (char *)tdp, - 5*INT32SZ); - if (x != 0) - break; - } - - /* everything was equal, wow! - * so return a success - */ - return (1); - - case T_MX: - case T_AFSDB: - case T_RT: - x = memcmp(dp->d_data, data, - INT16SZ); - if (x != 0) - break; - td = data + INT16SZ; - tdp = dp->d_data + INT16SZ; - x = strncasecmp(td, (char *)tdp, - strlen((char *)td) + 1); - if (x != 0) - break; - return (1); - - case T_PX: - x = memcmp(dp->d_data, data, - INT16SZ); - if (x != 0) - break; - td = data + INT16SZ; - tdp = dp->d_data + INT16SZ; - - /* compare first string */ - x = strncasecmp(td, (char *)tdp, - strlen((char *)td) + 1); - if (x != 0) - break; - td += (strlen(td) + 1); - tdp += (strlen((char *)tdp) + 1); - - /* compare second string */ - x = strncasecmp(td, (char *)tdp, - strlen((char *)td+1)); - if (x != 0) - break; - return (1); - - default: - dprintf(3, (ddt, "unknown type %d\n", type)); - return (0); - } - /* continue in loop if record did not match */ - } - /* saw no record of interest in whole chain - * If the data we were trying to validate was negative, we succeeded! - * else we failed - */ - if ((data == NULL) || (dlen == 0)) { - /* negative data, report success */ - return (1); - } - /* positive data, no such RR, validation failed */ - return (0); -} - -/****************************************************************** - * get a list of databufs that have ns addresses for the closest domain - * you know about, get their addresses and confirm that server indeed - * is one of them. if yes return 1 else 0. - * first checks the cache that we build in nslookup() earlier - * when we ns_forw(). if unableto find it there, it checks the entire - * hash table to do address translations. - *******************************************************************/ -static int -check_addr_ns(nsp, server, dname) - struct databuf **nsp; - struct sockaddr_in *server; - char *dname; -{ - int i, found=0; - char sname[MAXDNAME]; - struct in_addr *saddr = &(server->sin_addr); - struct databuf **nsdp; - - dprintf(5, (ddt, "check_addr_ns: s:[%s], db:0x%lx, d:\"%s\"\n", - inet_ntoa(*saddr), (u_long)nsp, dname)); - - for(i = lastNA; i != firstNA; i = (i+1) % MAXNAMECACHE) { - if (!bcmp((char *)saddr, - (char *)&(nameaddrlist[i].ns_addr), - INADDRSZ)) { - strcpy(sname, nameaddrlist[i].nsname); - found = 1; - break; - } - } - if (found) { - dprintf(3, (ddt, - "check_addr_ns: found address:[%s]\n", - inet_ntoa(*saddr))); - for (nsdp = nsp; *nsdp != NULL;nsdp++) { - dprintf(5, (ddt, - "check_addr_ns:names are:%s, %s\n", - sname,(*nsdp)->d_data)); - if (!strcasecmp(sname,(char *)((*nsdp)->d_data))) { - return (1); - } - } - } - /* could not find name in my cache of servers, must go through the - * whole grind - */ - - dprintf(2, (ddt, "check_addr_ns:calling check_in_tables()\n")); - return (check_in_tables(nsp, server, dname)); -} - -/************************************************************************* - * checks in hash tables for the address of servers whose name is in the - * data section of nsp records. borrows code from nslookup()/ns_forw.c - * largely. - *************************************************************************/ -static int -check_in_tables(nsp, server, syslogdname) - struct databuf *nsp[]; - struct sockaddr_in *server; - char *syslogdname; -{ - register struct namebuf *np; - register struct databuf *dp, *nsdp; - struct hashbuf *tmphtp; - const char *dname, *fname; - int class; - int qcomp(); - - dprintf(3, (ddt, "check_in_tables(nsp=x%lx, qp=x%x, '%s')\n", - (u_long)nsp, server, syslogdname)); - - while ((nsdp = *nsp++) != NULL) { - class = nsdp->d_class; - dname = (char *)nsdp->d_data; - dprintf(3, (ddt, "check_in_tables: NS %s c%d t%d (x%x)\n", - dname, class, nsdp->d_type, nsdp->d_flags)); - tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab); - np = nlookup(dname, &tmphtp, &fname, 1); - if (np == NULL || fname != dname) { - dprintf(3, (ddt, "%s: not found %s %x\n", - dname, fname, np)); - continue; - } - /* look for name server addresses */ - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (stale(dp)) - continue; - if (dp->d_type != T_A || dp->d_class != class) - continue; -#ifdef NCACHE - if (dp->d_rcode) - continue; -#endif - if (!bcmp((char *)dp->d_data, - (char *)&(server->sin_addr), - INADDRSZ)) { - return (1); - } - } - } - return (0); /* haven't been able to locate the right address */ -} - -/************************************************************************ - * is called in nslookup() and stores the name vs address of a name server - * --& check_in_tables above-- - * we contact, in a list of a maximum MAXNAMECACHE entries. we later refer - * -- NAMEADDR nameaddrlist[MAXNAMECACHE]; -- - * to this list when we are trying to resolve the name in check_addr_ns(). - *************************************************************************/ -void -store_name_addr(servername, serveraddr, syslogdname, sysloginfo) - const char *servername; - struct in_addr serveraddr; - const char *syslogdname; - const char *sysloginfo; -{ - int i; - - dprintf(3, (ddt, - "store_name_addr:s:%s, a:[%s]\n", - servername, inet_ntoa(serveraddr))); - - /* if we already have the name address pair in cache, return */ - for (i = lastNA; i != firstNA; i = (i+1) % MAXNAMECACHE) { - if (strcasecmp(servername, nameaddrlist[i].nsname) == 0) { - if (serveraddr.s_addr - == - nameaddrlist[i].ns_addr.s_addr) { - dprintf(5, (ddt, - "store_name_addr:found n and a [%s] [%s] in our $\n", - inet_ntoa(nameaddrlist[i].ns_addr), - inet_ntoa(serveraddr))); - return; - } /* if */ - } else if (serveraddr.s_addr - == - nameaddrlist[i].ns_addr.s_addr) { -#ifdef BAD_IDEA - /* - * log this as it needs to be fixed. - * replace old name by new, next query likely to have - * NS record matching new - */ - if (!haveComplained((char*) - nhash(nameaddrlist[i].nsname), - (char*)nhash(servername))) - syslog(LOG_INFO, - "%s: server name mismatch for [%s]: (%s != %s) (server for %s)", - sysloginfo, - inet_ntoa(serveraddr), - nameaddrlist[i].nsname, servername, - syslogdname); -#endif - free(nameaddrlist[i].nsname); - nameaddrlist[i].nsname = savestr(servername); - return; - } - } - /* we have to add this one to our cache */ - - nameaddrlist[firstNA].nsname = savestr(servername); - bcopy((char *)&serveraddr, - (char *)&(nameaddrlist[firstNA].ns_addr), - INADDRSZ); - - dprintf(2, (ddt, "store_name_addr:added entry #:%d n:%s a:[%s]\n", - firstNA, nameaddrlist[firstNA].nsname, - inet_ntoa(nameaddrlist[firstNA].ns_addr))); - - firstNA = (firstNA+1) % MAXNAMECACHE; - if (firstNA == lastNA) { - free(nameaddrlist[firstNA].nsname); - nameaddrlist[firstNA].nsname = 0; - lastNA = (lastNA+1) % MAXNAMECACHE; - } - return; -} - -/* - * Decode the resource record 'rrp' and validate the RR. - * Borrows code almost entirely from doupdate(). is a rather - * non-invasive routine since it just goes thru the same motions - * as doupdate but just marks the array validatelist entry as - * the return code from validate(). This is later used in doupdate - * to cache/not cache the entry. also used in update_msg() to - * delete/keep the record from the outgoing message. - */ -int -dovalidate(msg, msglen, rrp, zone, flags, qdomain, server, VCode) - u_char *msg, *rrp; - int msglen, zone, flags; - char *qdomain; - struct sockaddr_in *server; - int *VCode; -{ - register u_char *cp; - register int n; - int class, type, dlen, n1; - u_int32_t ttl; - char dname[MAXDNAME]; - u_char *cp1; - u_char data[MAXDNAME*2 + INT32SZ*5]; - register HEADER *hp = (HEADER *) msg; - - dprintf(2, (ddt, "dovalidate(zone %d, flags %x)\n", - zone, flags)); -#ifdef DEBUG - if (debug >= 10) - fp_nquery(msg, msglen, ddt); -#endif - - cp = rrp; - n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname); - if (n < 0) { - hp->rcode = FORMERR; - return (-1); - } - cp += n; - GETSHORT(type, cp); - GETSHORT(class, cp); - GETLONG(ttl, cp); - GETSHORT(dlen, cp); - dprintf(2, (ddt, "dovalidate: 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: - case T_X25: - case T_ISDN: - case T_LOC: -#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: - n = dn_expand(msg, msg + msglen, cp, - (char *)data, sizeof data); - if (n < 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: - n = dn_expand(msg, msg + msglen, cp, - (char *)data, sizeof data); - if (n < 0) { - hp->rcode = FORMERR; - return (-1); - } - cp += n; - cp1 = data + (n = strlen((char *)data) + 1); - n1 = sizeof(data) - n; - if (type == T_SOA) - n1 -= 5 * INT32SZ; - n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1); - if (n < 0) { - hp->rcode = FORMERR; - return (-1); - } - cp += n; - cp1 += strlen((char *)cp1) + 1; - if (type == T_SOA) { - bcopy((char *)cp, (char *)cp1, n = 5 * INT32SZ); - cp += n; - cp1 += n; - } - n = cp1 - data; - cp1 = data; - break; - - case T_MX: - case T_AFSDB: - case T_RT: - /* grab preference */ - bcopy((char *)cp, data, INT16SZ); - cp1 = data + INT16SZ; - cp += INT16SZ; - - /* get name */ - n = dn_expand(msg, msg + msglen, cp, - (char *)cp1, sizeof(data) - INT16SZ); - if (n < 0) { - hp->rcode = FORMERR; - return (-1); - } - cp += n; - - /* compute end of data */ - cp1 += strlen((char *)cp1) + 1; - /* compute size of data */ - n = cp1 - data; - cp1 = data; - break; - - case T_PX: - /* grab preference */ - bcopy((char *)cp, data, INT16SZ); - cp1 = data + INT16SZ; - cp += INT16SZ; - - /* get first name */ - n = dn_expand(msg, msg + msglen, cp, - (char *)cp1, sizeof(data) - INT16SZ); - if (n < 0) { - hp->rcode = FORMERR; - return (-1); - } - cp += n; - cp1 += (n = strlen((char *)cp1) + 1); - n1 = sizeof(data) - n; - - /* get second name */ - n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1); - if (n < 0) { - hp->rcode = FORMERR; - return (-1); - } - cp += n; - cp1 += strlen((char *)cp1) + 1; - n = cp1 - data; - cp1 = data; - break; - - default: - dprintf(3, (ddt, "unknown type %d\n", type)); - return ((cp - rrp) + dlen); - } - if (n > MAXDATA) { - dprintf(2, (ddt, - "update type %d: %d bytes is too much data\n", - type, n)); - hp->rcode = FORMERR; - return (-1); - } - - *VCode = validate(dname, qdomain, server, type, class,(char *)cp1, n -#ifdef NCACHE - ,NOERROR -#endif - ); - if (*VCode == INVALID) { - dprintf(2, (ddt, - "validation failed d:%s, t:%d, c:%d\n", - dname, type, class)); - } else { - dprintf(2, (ddt, - "validation succeeded d:%s, t:%d, c:%d\n", - dname, type, class)); - } - return (cp - rrp); -} - -#if 0 -/****************************************************************** - * This manages a data structure that stores all RRs that we were - * unable to validate. Am not sure exactly what purpose this might - * serve but until such time as we are sure it will not help, let - * me do it anyway. - *****************************************************************/ -static void -stick_in_queue(dname, type, class, data) - char *dname; - int type; - int class; - char *data; -{ - struct timeval tp; - struct _TIMEZONE tzp; - TO_Validate *tempVQ; - u_long leasttime; - - if (validateQ == NULL) { - validateQ = (TO_Validate *)malloc(sizeof(TO_Validate)); - if (!validateQ) - panic(errno, "malloc(validateQ)"); - validateQ->type = type; - validateQ->class = class; - validateQ->dname = savestr(dname); - validateQ->data = savestr(data); /* XXX no \0 */ - gettimeofday(&tp, &tzp); - validateQ->time = tp.tv_sec; - VQcount = 1; - validateQ->next = validateQ->prev = NULL; - currentVQ = validateQ; - return; - } - if (VQcount < MAXVQ) { - tempVQ =(TO_Validate *)malloc(sizeof(TO_Validate)); - if (!tempVQ) - panic(errno, "malloc(tempVQ)"); - tempVQ->type = type; - tempVQ->class = class; - tempVQ->dname = savestr(dname); - tempVQ->data = savestr(data); /* XXX no \0 */ - gettimeofday(&tp,&tzp); - tempVQ->time = tp.tv_sec; - tempVQ->next = currentVQ->next; - tempVQ->prev = currentVQ; - if (currentVQ->next != NULL) - currentVQ->next->prev = tempVQ; - currentVQ->next = tempVQ; - currentVQ = tempVQ; - VQcount++; - return; - } - gettimeofday(&tp, &tzp); - leasttime = validateQ->time; - currentVQ = validateQ; - for (tempVQ = validateQ; tempVQ != NULL; tempVQ = tempVQ->next) { - if (tp.tv_sec >= tempVQ->time +VQEXPIRY) { - tempVQ->type = type; - tempVQ->class = class; - strcpy(tempVQ->dname, dname); - strcpy(tempVQ->data, data); - tempVQ->time = tp.tv_sec; - currentVQ = tempVQ; - return; - } - if (tempVQ->time < leasttime) { - leasttime = tempVQ->time; - currentVQ = tempVQ; - } - } - currentVQ->type = type; - currentVQ->class = class; - strcpy(currentVQ->dname, dname); - strcpy(currentVQ->data, data); - currentVQ->time = tp.tv_sec; - return; -} -#endif - -#ifdef BAD_IDEA -/* removes any INVALID RR's from the msg being returned, updates msglen to - * reflect the new message length. - */ -int -update_msg(msg, msglen, Vlist, c) - u_char *msg; - int *msglen; - int Vlist[]; - int c; -{ - register HEADER *hp; - register u_char *cp; - int i; - int n = 0; - u_char *tempcp, *newcp; - int *RRlen; - int qlen; /* the length of the query section*/ - u_int16_t rdlength; - u_int16_t ancount, nscount; - u_int16_t new_ancount, new_nscount, new_arcount; - char dname[MAXDNAME], qname[MAXDNAME]; - u_char data[MAXDNAME]; - u_char **dpp; - u_char *dnptrs[40]; - u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); - u_char *eom = msg + *msglen; - int n_new; - int rembuflen, newlen; - u_char *newmsg; - u_int16_t type, class, dlen; - u_int32_t ttl; - int inv = 0; - -#ifdef DEBUG - if (debug) { - fprintf(ddt, "update_msg: msglen:%d, c:%d\n", *msglen, c); - if (debug >= 10) - fp_nquery(msg, *msglen, ddt); - } -#endif - /* just making sure we do not do all the work for nothing */ - for (i=0; i<c; i++) { - if (Vlist[i] == INVALID) { - inv = 1; - break; - } - } - if (inv != 1) { - /* no invalid records, go about your job */ - return (0); - } - - dprintf(2, (ddt, "update_msg: NEEDS updating:\n")); - - RRlen = (int *)malloc((unsigned)c*sizeof(int)); - if (!RRlen) - panic(errno, "malloc(RRlen)"); - hp = (HEADER *)msg; - new_ancount = ancount = ntohs(hp->ancount); - new_nscount = nscount = ntohs(hp->nscount); - new_arcount = ntohs(hp->arcount); - - cp = msg + HFIXEDSZ; - newlen = HFIXEDSZ; - /* skip the query section */ - qlen = dn_expand(msg, eom, cp, qname, sizeof qname); - if (qlen <= 0) { - dprintf(2, (ddt, "dn_expand() failed, bad record\n")); - goto badend; - } - cp +=qlen; - GETSHORT(type,cp); - GETSHORT(class,cp); - qlen += 2 * INT16SZ; - newlen += qlen; - - for (i = 0; i < c; i++) { - if (Vlist[i] == INVALID) { - if (i < ancount) - new_ancount--; - else if (i < ancount+nscount) - new_nscount--; - else - new_arcount--; - } - - RRlen[i] = dn_skipname(cp, msg + *msglen); - if (RRlen[i] <= 0) { - dprintf(2, (ddt, - "dn_skipname() failed, bad record\n")); - goto badend; - } - RRlen[i] += 2 * INT16SZ + INT32SZ; - /*type+class+TTL*/ - cp += RRlen[i]; - GETSHORT(rdlength, cp); - RRlen[i] += INT16SZ; /*rdlength*/ - RRlen[i] += rdlength; /*rdata field*/ - dprintf(3, (ddt, "RRlen[%d]=%d\n", i, RRlen[i])); - if (Vlist[i] != INVALID) - newlen += RRlen[i]; - cp += rdlength; /*increment pointer to next RR*/ - } - hp->ancount = htons(new_ancount); - hp->nscount = htons(new_nscount); - hp->arcount = htons(new_arcount); - /* get new buffer */ - dprintf(3, (ddt, - "newlen:%d, if no RR is INVALID == msglen\n", newlen)); - newmsg = (u_char *)calloc(1,newlen + MAXDNAME); - if (newmsg == NULL) - goto badend; - dpp = dnptrs; - *dpp++ = newmsg; - *dpp = NULL; - /* bcopy the header, with all the length fields correctly put in */ - bcopy((char *)msg, (char*)newmsg, HFIXEDSZ); /*header copied */ - newcp = newmsg +HFIXEDSZ; /*need a pointer in the new buffer */ - rembuflen = newlen +MAXDNAME - HFIXEDSZ; /*buflen we can workin*/ - newlen = HFIXEDSZ; /* this will now contain the length of msg */ - n_new = dn_comp(qname, newcp, rembuflen, dnptrs, edp); - if (n_new < 0) - goto badend; - newcp += n_new; - PUTSHORT(type, newcp); - PUTSHORT(class, newcp); /*query section complete*/ - newlen += (n_new+2*INT16SZ); - rembuflen -= (n_new+2*INT16SZ); - /* have to decode and copy every Valid RR from here */ - - cp = msg +HFIXEDSZ +qlen; /*skip header and query section*/ - for (i = 0; i < c; i++) { - if (Vlist[i] == INVALID) { - /* go to next RR if this one is not INVALID */ - cp += RRlen[i]; - continue; - } - /* we have a valid record, must put it in the newmsg */ - n = dn_expand(msg, eom, cp, dname, sizeof dname); - if (n < 0) { - hp->rcode = FORMERR; - goto badend; - } - n_new = dn_comp(dname, newcp, rembuflen, dnptrs, edp); - if (n_new < 0) - goto badend; - cp += n; - newcp += n_new; - dprintf(5, (ddt, - "cp:0x%x newcp:0x%x after getting name\n", - cp, newcp)); - GETSHORT(type, cp); - PUTSHORT(type, newcp); - dprintf(5, (ddt, - "cp:0x%x newcp:0x%x after getting type\n", - cp, newcp)); - GETSHORT(class, cp); - PUTSHORT(class, newcp); - dprintf(5, (ddt, - "cp:0x%x newcp:0x%x after getting class\n", - cp, newcp)); - GETLONG(ttl, cp); - PUTLONG(ttl, newcp); - dprintf(5, (ddt, - "cp:0x%x newcp:0x%x after getting ttl\n", - cp, newcp)); - /* this will probably be modified for newmsg, - * will put this in later, after compression - */ - GETSHORT(dlen, cp); - newlen += (n_new+3*INT16SZ + INT32SZ); - rembuflen -= (n_new+3*INT16SZ+ INT32SZ); - tempcp = newcp; - newcp += INT16SZ; /*advance to rdata field*/ - dprintf(5, (ddt, "tempcp:0x%x newcp:0x%x\n", - tempcp, newcp)); - dprintf(3, (ddt, - "update_msg: dname %s type %d class %d ttl %d\n", - dname, type, class, ttl)); - /* read off the data section */ - switch (type) { - case T_A: - case T_WKS: - case T_HINFO: - case T_UINFO: - case T_UID: - case T_GID: - case T_TXT: - case T_X25: - case T_ISDN: - case T_LOC: -#ifdef ALLOW_T_UNSPEC - case T_UNSPEC: -#endif - n = dlen; - PUTSHORT(n, tempcp); /*time to put in the dlen*/ - bcopy(cp, newcp,n); /*done here*/ - cp +=n; - newcp +=n; - newlen += n; - rembuflen -= n; - dprintf(3, (ddt, "\tcp:0x%x newcp:0x%x dlen:%d\n", - cp, newcp, dlen)); - break; - - case T_CNAME: - case T_MB: - case T_MG: - case T_MR: - case T_NS: - case T_PTR: - /*read off name from data section */ - n = dn_expand(msg, eom, cp, - (char *)data, sizeof data); - if (n < 0) { - hp->rcode = FORMERR; - goto badend; - } - cp += n; /*advance pointer*/ - /* fill in new packet */ - n_new = dn_comp((char *)data, newcp, rembuflen, - dnptrs, edp); - if (n_new < 0) - goto badend; - PUTSHORT(n_new,tempcp); /*put in dlen field*/ - newcp += n_new; /*advance new pointer*/ - newlen += n_new; - rembuflen -= n_new; - break; - - case T_MINFO: - case T_SOA: - case T_RP: - n = dn_expand(msg, eom, cp, (char *)data, sizeof data); - if (n < 0) { - hp->rcode = FORMERR; - goto badend; - } - cp += n; - n_new = dn_comp((char *)data, newcp, rembuflen, - dnptrs, edp); - if (n_new < 0) - goto badend; - newcp += n_new; - newlen += n_new; - rembuflen -= n_new; - dlen = n_new; - n = dn_expand(msg, eom, cp, (char *)data, sizeof data); - if (n < 0) { - hp->rcode = FORMERR; - goto badend; - } - cp += n; - n_new = dn_comp((char *)data, newcp, rembuflen, - dnptrs, edp); - if (n_new < 0) - goto badend; - newcp += n_new; - newlen += n_new; - rembuflen -= n_new; - dlen += n_new; - if (type == T_SOA) { - bcopy(cp, newcp, n = 5*INT32SZ); - cp += n; - newcp += n; - newlen +=n; - rembuflen -= n; - dlen +=n; - } - PUTSHORT(dlen, tempcp); - break; - - case T_MX: - case T_AFSDB: - case T_RT: - /* grab preference */ - bcopy(cp,newcp,INT16SZ); - cp += INT16SZ; - newcp += INT16SZ; - - /* get name */ - n = dn_expand(msg, eom, cp, (char *)data, sizeof data); - if (n < 0) { - hp->rcode = FORMERR; - goto badend; - } - cp += n; - n_new = dn_comp((char *)data, newcp, rembuflen, - dnptrs, edp); - if (n_new < 0) - goto badend; - PUTSHORT(n_new+INT16SZ, tempcp); - newcp += n_new; - newlen += n_new+INT16SZ; - rembuflen -= n_new+INT16SZ; - break; - - case T_PX: - /* grab preference */ - bcopy(cp, newcp, INT16SZ); - cp += INT16SZ; - newcp += INT16SZ; - - /* get first name */ - n = dn_expand(msg, eom, cp, (char *)data, sizeof data); - if (n < 0) { - hp->rcode = FORMERR; - goto badend; - } - cp += n; - n_new = dn_comp((char *)data, newcp, rembuflen, - dnptrs, edp); - if (n_new < 0) - goto badend; - newcp += n_new; - newlen += n_new+INT16SZ; - rembuflen -= n_new+INT16SZ; - dlen = n_new+INT16SZ; - n = dn_expand(msg, eom, cp, (char *)data, sizeof data); - if (n < 0) { - hp->rcode = FORMERR; - goto badend; - } - cp += n; - n_new = dn_comp((char *)data, newcp, rembuflen, - dnptrs, edp); - if (n_new < 0) - goto badend; - newcp += n_new; - newlen += n_new; - rembuflen -= n_new; - dlen += n_new; - PUTSHORT(dlen, tempcp); - break; - - default: - dprintf(3, (ddt, "unknown type %d\n", type)); - goto badend; - } - dprintf(2, (ddt, - "newlen:%d, i:%d newcp:0x%x cp:0x%x\n\n", - newlen, i, newcp, cp)); - } - bcopy(newmsg, msg, newlen); - n = *msglen - newlen; - if (n < 0) { - dprintf(2, (ddt, - "update_msg():newmsg longer than old: n:%d o:%d ???\n", - newlen, *msglen)); - } - *msglen = newlen; - free((char *)newmsg); - -#ifdef DEBUG - if (debug >= 10) - fp_nquery(msg, *msglen, ddt); -#endif - free((char *)RRlen); - return (n); -badend: - dprintf(2, (ddt, "encountered problems: UPDATE_MSG\n")); - free((char *)RRlen); - return (-1); -} -#endif /*BAD_IDEA*/ - -#endif /*VALIDATE*/ |