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) 03/07/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(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(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(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(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 } 201