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