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