entered into RCS
[kopensolaris-gnu/glibc.git] / resolv / res_mkquery.c
1 /*
2  * ++Copyright++ 1985
3  * -
4  * Copyright (c) 1985 Regents of the University of California.
5  * All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by the University of
18  *      California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  * -
35  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36  * 
37  * Permission to use, copy, modify, and distribute this software for any
38  * purpose with or without fee is hereby granted, provided that the above
39  * copyright notice and this permission notice appear in all copies, and that
40  * the name of Digital Equipment Corporation not be used in advertising or
41  * publicity pertaining to distribution of the document or software without
42  * specific, written prior permission.
43  * 
44  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51  * SOFTWARE.
52  * -
53  * --Copyright--
54  */
55
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)res_mkquery.c       6.16 (Berkeley) 3/6/91";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
60
61 #include <sys/param.h>
62 #include <netinet/in.h>
63 #include <arpa/nameser.h>
64 #include <resolv.h>
65 #include <stdio.h>
66 #include "../conf/portability.h"
67
68 /*
69  * Form all types of queries.
70  * Returns the size of the result or -1.
71  */
72 res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen)
73         int op;                 /* opcode of query */
74         const char *dname;              /* domain name */
75         int class, type;        /* class and type of query */
76         const char *data;               /* resource record data */
77         int datalen;            /* length of data */
78         const char *newrr_in;   /* new rr for modify or append */
79         char *buf;              /* buffer to put query */
80         int buflen;             /* size of buffer */
81 {
82         register HEADER *hp;
83         register char *cp;
84         register int n;
85         struct rrec *newrr = (struct rrec *) newrr_in;
86         char *dnptrs[10], **dpp, **lastdnptr;
87
88 #ifdef DEBUG
89         if (_res.options & RES_DEBUG)
90                 printf(";; res_mkquery(%d, %s, %d, %d)\n",
91                        op, dname, class, type);
92 #endif
93         /*
94          * Initialize header fields.
95          */
96         if ((buf == NULL) || (buflen < sizeof(HEADER)))
97                 return(-1);
98         bzero(buf, sizeof(HEADER));
99         hp = (HEADER *) buf;
100         hp->id = htons(++_res.id);
101         hp->opcode = op;
102         hp->pr = (_res.options & RES_PRIMARY) != 0;
103         hp->rd = (_res.options & RES_RECURSE) != 0;
104         hp->rcode = NOERROR;
105         cp = buf + sizeof(HEADER);
106         buflen -= sizeof(HEADER);
107         dpp = dnptrs;
108         *dpp++ = buf;
109         *dpp++ = NULL;
110         lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
111         /*
112          * perform opcode specific processing
113          */
114         switch (op) {
115         case QUERY:
116                 if ((buflen -= QFIXEDSZ) < 0)
117                         return(-1);
118                 if ((n = dn_comp((u_char *)dname, (u_char *)cp, buflen,
119                     (u_char **)dnptrs, (u_char **)lastdnptr)) < 0)
120                         return (-1);
121                 cp += n;
122                 buflen -= n;
123                 __putshort(type, (u_char *)cp);
124                 cp += sizeof(u_short);
125                 __putshort(class, (u_char *)cp);
126                 cp += sizeof(u_short);
127                 hp->qdcount = htons(1);
128                 if (op == QUERY || data == NULL)
129                         break;
130                 /*
131                  * Make an additional record for completion domain.
132                  */
133                 buflen -= RRFIXEDSZ;
134                 if ((n = dn_comp((u_char *)data, (u_char *)cp, buflen,
135                     (u_char **)dnptrs, (u_char **)lastdnptr)) < 0)
136                         return (-1);
137                 cp += n;
138                 buflen -= n;
139                 __putshort(T_NULL, (u_char *)cp);
140                 cp += sizeof(u_short);
141                 __putshort(class, (u_char *)cp);
142                 cp += sizeof(u_short);
143                 __putlong(0, (u_char *)cp);
144                 cp += sizeof(u_int32_t);
145                 __putshort(0, (u_char *)cp);
146                 cp += sizeof(u_short);
147                 hp->arcount = htons(1);
148                 break;
149
150         case IQUERY:
151                 /*
152                  * Initialize answer section
153                  */
154                 if (buflen < 1 + RRFIXEDSZ + datalen)
155                         return (-1);
156                 *cp++ = '\0';   /* no domain name */
157                 __putshort(type, (u_char *)cp);
158                 cp += sizeof(u_short);
159                 __putshort(class, (u_char *)cp);
160                 cp += sizeof(u_short);
161                 __putlong(0, (u_char *)cp);
162                 cp += sizeof(u_int32_t);
163                 __putshort(datalen, (u_char *)cp);
164                 cp += sizeof(u_short);
165                 if (datalen) {
166                         bcopy(data, cp, datalen);
167                         cp += datalen;
168                 }
169                 hp->ancount = htons(1);
170                 break;
171
172 #ifdef ALLOW_UPDATES
173         /*
174          * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
175          * (Record to be modified is followed by its replacement in msg.)
176          */
177         case UPDATEM:
178         case UPDATEMA:
179
180         case UPDATED:
181                 /*
182                  * The res code for UPDATED and UPDATEDA is the same; user
183                  * calls them differently: specifies data for UPDATED; server
184                  * ignores data if specified for UPDATEDA.
185                  */
186         case UPDATEDA:
187                 buflen -= RRFIXEDSZ + datalen;
188                 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
189                         return (-1);
190                 cp += n;
191                 __putshort(type, cp);
192                 cp += sizeof(u_short);
193                 __putshort(class, cp);
194                 cp += sizeof(u_short);
195                 __putlong(0, cp);
196                 cp += sizeof(u_int32_t);
197                 __putshort(datalen, cp);
198                 cp += sizeof(u_short);
199                 if (datalen) {
200                         bcopy(data, cp, datalen);
201                         cp += datalen;
202                 }
203                 if ( (op == UPDATED) || (op == UPDATEDA) ) {
204                         hp->ancount = htons(0);
205                         break;
206                 }
207                 /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
208
209         case UPDATEA:   /* Add new resource record */
210                 buflen -= RRFIXEDSZ + datalen;
211                 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
212                         return (-1);
213                 cp += n;
214                 __putshort(newrr->r_type, cp);
215                 cp += sizeof(u_short);
216                 __putshort(newrr->r_class, cp);
217                 cp += sizeof(u_short);
218                 __putlong(0, cp);
219                 cp += sizeof(u_int32_t);
220                 __putshort(newrr->r_size, cp);
221                 cp += sizeof(u_short);
222                 if (newrr->r_size) {
223                         bcopy(newrr->r_data, cp, newrr->r_size);
224                         cp += newrr->r_size;
225                 }
226                 hp->ancount = htons(0);
227                 break;
228
229 #endif /* ALLOW_UPDATES */
230         }
231         return (cp - buf);
232 }