1 /*-
2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 * -
7 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies, and that
12 * the name of Digital Equipment Corporation not be used in advertising or
13 * publicity pertaining to distribution of the document or software without
14 * specific, written prior permission.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
17 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
19 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
20 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
21 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
22 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 * SOFTWARE.
24 * -
25 * --Copyright--
26 */
27
28 #if defined(LIBC_SCCS) && !defined(lint)
29 static char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 06/04/93";
30 static char rcsid[] = "$Id: res_mkquery.c,v 4.9.1.2 1993/05/17 10:00:01 vixie Exp $";
31 #endif /* LIBC_SCCS and not lint */
32
33 #include <sys/param.h>
34 #include <netinet/in.h>
35 #include <arpa/nameser.h>
36 #include <resolv.h>
37 #include <stdio.h>
38 #include <string.h>
39
40 /*
41 * Form all types of queries.
42 * Returns the size of the result or -1.
43 */
res_mkquery(op,dname,class,type,data,datalen,newrr_in,buf,buflen)44 res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen)
45 int op; /* opcode of query */
46 const char *dname; /* domain name */
47 int class, type; /* class and type of query */
48 const char *data; /* resource record data */
49 int datalen; /* length of data */
50 const char *newrr_in; /* new rr for modify or append */
51 char *buf; /* buffer to put query */
52 int buflen; /* size of buffer */
53 {
54 register HEADER *hp;
55 register char *cp;
56 register int n;
57 struct rrec *newrr = (struct rrec *) newrr_in;
58 char *dnptrs[10], **dpp, **lastdnptr;
59
60 #ifdef DEBUG
61 if (_res.options & RES_DEBUG)
62 printf(";; res_mkquery(%d, %s, %d, %d)\n",
63 op, dname, class, type);
64 #endif
65 /*
66 * Initialize header fields.
67 */
68 if ((buf == NULL) || (buflen < sizeof(HEADER)))
69 return(-1);
70 bzero(buf, sizeof(HEADER));
71 hp = (HEADER *) buf;
72 hp->id = htons(++_res.id);
73 hp->opcode = op;
74 hp->pr = (_res.options & RES_PRIMARY) != 0;
75 hp->rd = (_res.options & RES_RECURSE) != 0;
76 hp->rcode = NOERROR;
77 cp = buf + sizeof(HEADER);
78 buflen -= sizeof(HEADER);
79 dpp = dnptrs;
80 *dpp++ = buf;
81 *dpp++ = NULL;
82 lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
83 /*
84 * perform opcode specific processing
85 */
86 switch (op) {
87 case QUERY:
88 if ((buflen -= QFIXEDSZ) < 0)
89 return(-1);
90 if ((n = dn_comp((u_char *)dname, (u_char *)cp, buflen,
91 (u_char **)dnptrs, (u_char **)lastdnptr)) < 0)
92 return (-1);
93 cp += n;
94 buflen -= n;
95 __putshort(type, (u_char *)cp);
96 cp += sizeof(u_int16_t);
97 __putshort(class, (u_char *)cp);
98 cp += sizeof(u_int16_t);
99 hp->qdcount = htons(1);
100 if (op == QUERY || data == NULL)
101 break;
102 /*
103 * Make an additional record for completion domain.
104 */
105 buflen -= RRFIXEDSZ;
106 if ((n = dn_comp((u_char *)data, (u_char *)cp, buflen,
107 (u_char **)dnptrs, (u_char **)lastdnptr)) < 0)
108 return (-1);
109 cp += n;
110 buflen -= n;
111 __putshort(T_NULL, (u_char *)cp);
112 cp += sizeof(u_int16_t);
113 __putshort(class, (u_char *)cp);
114 cp += sizeof(u_int16_t);
115 __putlong(0, (u_char *)cp);
116 cp += sizeof(u_int32_t);
117 __putshort(0, (u_char *)cp);
118 cp += sizeof(u_int16_t);
119 hp->arcount = htons(1);
120 break;
121
122 case IQUERY:
123 /*
124 * Initialize answer section
125 */
126 if (buflen < 1 + RRFIXEDSZ + datalen)
127 return (-1);
128 *cp++ = '\0'; /* no domain name */
129 __putshort(type, (u_char *)cp);
130 cp += sizeof(u_int16_t);
131 __putshort(class, (u_char *)cp);
132 cp += sizeof(u_int16_t);
133 __putlong(0, (u_char *)cp);
134 cp += sizeof(u_int32_t);
135 __putshort(datalen, (u_char *)cp);
136 cp += sizeof(u_int16_t);
137 if (datalen) {
138 bcopy(data, cp, datalen);
139 cp += datalen;
140 }
141 hp->ancount = htons(1);
142 break;
143
144 #ifdef ALLOW_UPDATES
145 /*
146 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
147 * (Record to be modified is followed by its replacement in msg.)
148 */
149 case UPDATEM:
150 case UPDATEMA:
151
152 case UPDATED:
153 /*
154 * The res code for UPDATED and UPDATEDA is the same; user
155 * calls them differently: specifies data for UPDATED; server
156 * ignores data if specified for UPDATEDA.
157 */
158 case UPDATEDA:
159 buflen -= RRFIXEDSZ + datalen;
160 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
161 return (-1);
162 cp += n;
163 __putshort(type, cp);
164 cp += sizeof(u_int16_t);
165 __putshort(class, cp);
166 cp += sizeof(u_int16_t);
167 __putlong(0, cp);
168 cp += sizeof(u_int32_t);
169 __putshort(datalen, cp);
170 cp += sizeof(u_int16_t);
171 if (datalen) {
172 bcopy(data, cp, datalen);
173 cp += datalen;
174 }
175 if ( (op == UPDATED) || (op == UPDATEDA) ) {
176 hp->ancount = htons(0);
177 break;
178 }
179 /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
180
181 case UPDATEA: /* Add new resource record */
182 buflen -= RRFIXEDSZ + datalen;
183 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
184 return (-1);
185 cp += n;
186 __putshort(newrr->r_type, cp);
187 cp += sizeof(u_int16_t);
188 __putshort(newrr->r_class, cp);
189 cp += sizeof(u_int16_t);
190 __putlong(0, cp);
191 cp += sizeof(u_int32_t);
192 __putshort(newrr->r_size, cp);
193 cp += sizeof(u_int16_t);
194 if (newrr->r_size) {
195 bcopy(newrr->r_data, cp, newrr->r_size);
196 cp += newrr->r_size;
197 }
198 hp->ancount = htons(0);
199 break;
200
201 #endif /* ALLOW_UPDATES */
202 }
203 return (cp - buf);
204 }
205