1: /* 2: * Copyright (c) 1985 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: */ 12: 13: #if defined(LIBC_SCCS) && !defined(lint) 14: static char sccsid[] = "@(#)res_mkquery.c 6.7 (Berkeley) 3/7/88"; 15: #endif /* LIBC_SCCS and not lint */ 16: 17: #include <stdio.h> 18: #include <sys/types.h> 19: #include <netinet/in.h> 20: #include <arpa/nameser.h> 21: #include <resolv.h> 22: 23: /* 24: * Form all types of queries. 25: * Returns the size of the result or -1. 26: */ 27: res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen) 28: int op; /* opcode of query */ 29: char *dname; /* domain name */ 30: int class, type; /* class and type of query */ 31: char *data; /* resource record data */ 32: int datalen; /* length of data */ 33: struct rrec *newrr; /* new rr for modify or append */ 34: char *buf; /* buffer to put query */ 35: int buflen; /* size of buffer */ 36: { 37: register HEADER *hp; 38: register char *cp; 39: register int n; 40: char dnbuf[MAXDNAME]; 41: char *dnptrs[10], **dpp, **lastdnptr; 42: extern char *index(); 43: 44: #ifdef DEBUG 45: if (_res.options & RES_DEBUG) 46: printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type); 47: #endif DEBUG 48: /* 49: * Initialize header fields. 50: */ 51: hp = (HEADER *) buf; 52: hp->id = htons(++_res.id); 53: hp->opcode = op; 54: hp->qr = hp->aa = hp->tc = hp->ra = 0; 55: hp->pr = (_res.options & RES_PRIMARY) != 0; 56: hp->rd = (_res.options & RES_RECURSE) != 0; 57: hp->rcode = NOERROR; 58: hp->qdcount = 0; 59: hp->ancount = 0; 60: hp->nscount = 0; 61: hp->arcount = 0; 62: cp = buf + sizeof(HEADER); 63: buflen -= sizeof(HEADER); 64: dpp = dnptrs; 65: *dpp++ = buf; 66: *dpp++ = NULL; 67: lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); 68: /* 69: * If the domain name contains no dots (single label), then 70: * append the default domain name to the one given. 71: */ 72: if ((_res.options & RES_DEFNAMES) && dname != 0 && dname[0] != '\0' && 73: index(dname, '.') == NULL) { 74: if (!(_res.options & RES_INIT)) 75: if (res_init() == -1) 76: return(-1); 77: if (_res.defdname[0] != '\0') { 78: (void)sprintf(dnbuf, "%s.%s", dname, _res.defdname); 79: dname = dnbuf; 80: } 81: } 82: /* 83: * perform opcode specific processing 84: */ 85: switch (op) { 86: case QUERY: 87: buflen -= QFIXEDSZ; 88: if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 89: return (-1); 90: cp += n; 91: buflen -= n; 92: putshort(type, cp); 93: cp += sizeof(u_short); 94: putshort(class, cp); 95: cp += sizeof(u_short); 96: hp->qdcount = htons(1); 97: if (op == QUERY || data == NULL) 98: break; 99: /* 100: * Make an additional record for completion domain. 101: */ 102: buflen -= RRFIXEDSZ; 103: if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0) 104: return (-1); 105: cp += n; 106: buflen -= n; 107: putshort(T_NULL, cp); 108: cp += sizeof(u_short); 109: putshort(class, cp); 110: cp += sizeof(u_short); 111: putlong((long)0, cp); 112: cp += sizeof(u_long); 113: putshort(0, cp); 114: cp += sizeof(u_short); 115: hp->arcount = htons(1); 116: break; 117: 118: case IQUERY: 119: /* 120: * Initialize answer section 121: */ 122: if (buflen < 1 + RRFIXEDSZ + datalen) 123: return (-1); 124: *cp++ = '\0'; /* no domain name */ 125: putshort(type, cp); 126: cp += sizeof(u_short); 127: putshort(class, cp); 128: cp += sizeof(u_short); 129: putlong((long)0, cp); 130: cp += sizeof(u_long); 131: putshort(datalen, cp); 132: cp += sizeof(u_short); 133: if (datalen) { 134: bcopy(data, cp, datalen); 135: cp += datalen; 136: } 137: hp->ancount = htons(1); 138: break; 139: 140: #ifdef ALLOW_UPDATES 141: /* 142: * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA 143: * (Record to be modified is followed by its replacement in msg.) 144: */ 145: case UPDATEM: 146: case UPDATEMA: 147: 148: case UPDATED: 149: /* 150: * The res code for UPDATED and UPDATEDA is the same; user 151: * calls them differently: specifies data for UPDATED; server 152: * ignores data if specified for UPDATEDA. 153: */ 154: case UPDATEDA: 155: buflen -= RRFIXEDSZ + datalen; 156: if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 157: return (-1); 158: cp += n; 159: putshort(type, cp); 160: cp += sizeof(u_short); 161: putshort(class, cp); 162: cp += sizeof(u_short); 163: putlong((long)0, cp); 164: cp += sizeof(u_long); 165: putshort(datalen, cp); 166: cp += sizeof(u_short); 167: if (datalen) { 168: bcopy(data, cp, datalen); 169: cp += datalen; 170: } 171: if ( (op == UPDATED) || (op == UPDATEDA) ) { 172: hp->ancount = htons(0); 173: break; 174: } 175: /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */ 176: 177: case UPDATEA: /* Add new resource record */ 178: buflen -= RRFIXEDSZ + datalen; 179: if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 180: return (-1); 181: cp += n; 182: putshort(newrr->r_type, cp); 183: cp += sizeof(u_short); 184: putshort(newrr->r_class, cp); 185: cp += sizeof(u_short); 186: putlong((long)0, cp); 187: cp += sizeof(u_long); 188: putshort(newrr->r_size, cp); 189: cp += sizeof(u_short); 190: if (newrr->r_size) { 191: bcopy(newrr->r_data, cp, newrr->r_size); 192: cp += newrr->r_size; 193: } 194: hp->ancount = htons(0); 195: break; 196: 197: #endif ALLOW_UPDATES 198: } 199: return (cp - buf); 200: }