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.8 (Berkeley) 09/20/88"; 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 hp = (HEADER *) buf; 57 hp->id = htons(++_res.id); 58 hp->opcode = op; 59 hp->qr = hp->aa = hp->tc = hp->ra = 0; 60 hp->pr = (_res.options & RES_PRIMARY) != 0; 61 hp->rd = (_res.options & RES_RECURSE) != 0; 62 hp->rcode = NOERROR; 63 hp->qdcount = 0; 64 hp->ancount = 0; 65 hp->nscount = 0; 66 hp->arcount = 0; 67 cp = buf + sizeof(HEADER); 68 buflen -= sizeof(HEADER); 69 dpp = dnptrs; 70 *dpp++ = buf; 71 *dpp++ = NULL; 72 lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); 73 /* 74 * perform opcode specific processing 75 */ 76 switch (op) { 77 case QUERY: 78 buflen -= QFIXEDSZ; 79 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 80 return (-1); 81 cp += n; 82 buflen -= n; 83 putshort(type, cp); 84 cp += sizeof(u_short); 85 putshort(class, cp); 86 cp += sizeof(u_short); 87 hp->qdcount = htons(1); 88 if (op == QUERY || data == NULL) 89 break; 90 /* 91 * Make an additional record for completion domain. 92 */ 93 buflen -= RRFIXEDSZ; 94 if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0) 95 return (-1); 96 cp += n; 97 buflen -= n; 98 putshort(T_NULL, cp); 99 cp += sizeof(u_short); 100 putshort(class, cp); 101 cp += sizeof(u_short); 102 putlong(0, cp); 103 cp += sizeof(u_long); 104 putshort(0, cp); 105 cp += sizeof(u_short); 106 hp->arcount = htons(1); 107 break; 108 109 case IQUERY: 110 /* 111 * Initialize answer section 112 */ 113 if (buflen < 1 + RRFIXEDSZ + datalen) 114 return (-1); 115 *cp++ = '\0'; /* no domain name */ 116 putshort(type, cp); 117 cp += sizeof(u_short); 118 putshort(class, cp); 119 cp += sizeof(u_short); 120 putlong(0, cp); 121 cp += sizeof(u_long); 122 putshort(datalen, cp); 123 cp += sizeof(u_short); 124 if (datalen) { 125 bcopy(data, cp, datalen); 126 cp += datalen; 127 } 128 hp->ancount = htons(1); 129 break; 130 131 #ifdef ALLOW_UPDATES 132 /* 133 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA 134 * (Record to be modified is followed by its replacement in msg.) 135 */ 136 case UPDATEM: 137 case UPDATEMA: 138 139 case UPDATED: 140 /* 141 * The res code for UPDATED and UPDATEDA is the same; user 142 * calls them differently: specifies data for UPDATED; server 143 * ignores data if specified for UPDATEDA. 144 */ 145 case UPDATEDA: 146 buflen -= RRFIXEDSZ + datalen; 147 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 148 return (-1); 149 cp += n; 150 putshort(type, cp); 151 cp += sizeof(u_short); 152 putshort(class, cp); 153 cp += sizeof(u_short); 154 putlong(0, cp); 155 cp += sizeof(u_long); 156 putshort(datalen, cp); 157 cp += sizeof(u_short); 158 if (datalen) { 159 bcopy(data, cp, datalen); 160 cp += datalen; 161 } 162 if ( (op == UPDATED) || (op == UPDATEDA) ) { 163 hp->ancount = htons(0); 164 break; 165 } 166 /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */ 167 168 case UPDATEA: /* Add new resource record */ 169 buflen -= RRFIXEDSZ + datalen; 170 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 171 return (-1); 172 cp += n; 173 putshort(newrr->r_type, cp); 174 cp += sizeof(u_short); 175 putshort(newrr->r_class, cp); 176 cp += sizeof(u_short); 177 putlong(0, cp); 178 cp += sizeof(u_long); 179 putshort(newrr->r_size, cp); 180 cp += sizeof(u_short); 181 if (newrr->r_size) { 182 bcopy(newrr->r_data, cp, newrr->r_size); 183 cp += newrr->r_size; 184 } 185 hp->ancount = htons(0); 186 break; 187 188 #endif ALLOW_UPDATES 189 } 190 return (cp - buf); 191 } 192