Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / bind-9.3 / lib / bind / resolv / res_mkupdate.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1996-1999 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /*
19  * Based on the Dynamic DNS reference implementation by Viraj Bais
20  * <viraj_bais@ccm.fm.intel.com>
21  */
22
23 #if !defined(lint) && !defined(SABER)
24 static const char rcsid[] = "$Id: res_mkupdate.c,v 1.1.2.1.4.5 2005/10/14 05:43:47 marka Exp $";
25 #endif /* not lint */
26
27 #include "port_before.h"
28
29 #include <sys/types.h>
30 #include <sys/param.h>
31
32 #include <netinet/in.h>
33 #include <arpa/nameser.h>
34 #include <arpa/inet.h>
35
36 #include <errno.h>
37 #include <limits.h>
38 #include <netdb.h>
39 #include <resolv.h>
40 #include <res_update.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <ctype.h>
46
47 #include "port_after.h"
48
49 /* Options.  Leave them on. */
50 #define DEBUG
51 #define MAXPORT 1024
52
53 static int getnum_str(u_char **, u_char *);
54 static int gethexnum_str(u_char **, u_char *);
55 static int getword_str(char *, int, u_char **, u_char *);
56 static int getstr_str(char *, int, u_char **, u_char *);
57
58 #define ShrinkBuffer(x)  if ((buflen -= x) < 0) return (-2);
59
60 /* Forward. */
61
62 int res_protocolnumber(const char *);
63 int res_servicenumber(const char *);
64
65 /*
66  * Form update packets.
67  * Returns the size of the resulting packet if no error
68  * On error,
69  *      returns -1 if error in reading a word/number in rdata
70  *                 portion for update packets
71  *              -2 if length of buffer passed is insufficient
72  *              -3 if zone section is not the first section in
73  *                 the linked list, or section order has a problem
74  *              -4 on a number overflow
75  *              -5 unknown operation or no records
76  */
77 int
78 res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
79         ns_updrec *rrecp_start = rrecp_in;
80         HEADER *hp;
81         u_char *cp, *sp2, *startp, *endp;
82         int n, i, soanum, multiline;
83         ns_updrec *rrecp;
84         struct in_addr ina;
85         struct in6_addr in6a;
86         char buf2[MAXDNAME];
87         u_char buf3[MAXDNAME];
88         int section, numrrs = 0, counts[ns_s_max];
89         u_int16_t rtype, rclass;
90         u_int32_t n1, rttl;
91         u_char *dnptrs[20], **dpp, **lastdnptr;
92         int siglen, keylen, certlen;
93
94         /*
95          * Initialize header fields.
96          */
97         if ((buf == NULL) || (buflen < HFIXEDSZ))
98                 return (-1);
99         memset(buf, 0, HFIXEDSZ);
100         hp = (HEADER *) buf;
101         hp->id = htons(++statp->id);
102         hp->opcode = ns_o_update;
103         hp->rcode = NOERROR;
104         cp = buf + HFIXEDSZ;
105         buflen -= HFIXEDSZ;
106         dpp = dnptrs;
107         *dpp++ = buf;
108         *dpp++ = NULL;
109         lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
110
111         if (rrecp_start == NULL)
112                 return (-5);
113         else if (rrecp_start->r_section != S_ZONE)
114                 return (-3);
115
116         memset(counts, 0, sizeof counts);
117         for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
118                 numrrs++;
119                 section = rrecp->r_section;
120                 if (section < 0 || section >= ns_s_max)
121                         return (-1);
122                 counts[section]++;
123                 for (i = section + 1; i < ns_s_max; i++)
124                         if (counts[i])
125                                 return (-3);
126                 rtype = rrecp->r_type;
127                 rclass = rrecp->r_class;
128                 rttl = rrecp->r_ttl;
129                 /* overload class and type */
130                 if (section == S_PREREQ) {
131                         rttl = 0;
132                         switch (rrecp->r_opcode) {
133                         case YXDOMAIN:
134                                 rclass = C_ANY;
135                                 rtype = T_ANY;
136                                 rrecp->r_size = 0;
137                                 break;
138                         case NXDOMAIN:
139                                 rclass = C_NONE;
140                                 rtype = T_ANY;
141                                 rrecp->r_size = 0;
142                                 break;
143                         case NXRRSET:
144                                 rclass = C_NONE;
145                                 rrecp->r_size = 0;
146                                 break;
147                         case YXRRSET:
148                                 if (rrecp->r_size == 0)
149                                         rclass = C_ANY;
150                                 break;
151                         default:
152                                 fprintf(stderr,
153                                         "res_mkupdate: incorrect opcode: %d\n",
154                                         rrecp->r_opcode);
155                                 fflush(stderr);
156                                 return (-1);
157                         }
158                 } else if (section == S_UPDATE) {
159                         switch (rrecp->r_opcode) {
160                         case DELETE:
161                                 rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
162                                 break;
163                         case ADD:
164                                 break;
165                         default:
166                                 fprintf(stderr,
167                                         "res_mkupdate: incorrect opcode: %d\n",
168                                         rrecp->r_opcode);
169                                 fflush(stderr);
170                                 return (-1);
171                         }
172                 }
173
174                 /*
175                  * XXX  appending default domain to owner name is omitted,
176                  *      fqdn must be provided
177                  */
178                 if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
179                                  lastdnptr)) < 0)
180                         return (-1);
181                 cp += n;
182                 ShrinkBuffer(n + 2*INT16SZ);
183                 PUTSHORT(rtype, cp);
184                 PUTSHORT(rclass, cp);
185                 if (section == S_ZONE) {
186                         if (numrrs != 1 || rrecp->r_type != T_SOA)
187                                 return (-3);
188                         continue;
189                 }
190                 ShrinkBuffer(INT32SZ + INT16SZ);
191                 PUTLONG(rttl, cp);
192                 sp2 = cp;  /* save pointer to length byte */
193                 cp += INT16SZ;
194                 if (rrecp->r_size == 0) {
195                         if (section == S_UPDATE && rclass != C_ANY)
196                                 return (-1);
197                         else {
198                                 PUTSHORT(0, sp2);
199                                 continue;
200                         }
201                 }
202                 startp = rrecp->r_data;
203                 endp = startp + rrecp->r_size - 1;
204                 /* XXX this should be done centrally. */
205                 switch (rrecp->r_type) {
206                 case T_A:
207                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
208                                 return (-1);
209                         if (!inet_aton(buf2, &ina))
210                                 return (-1);
211                         n1 = ntohl(ina.s_addr);
212                         ShrinkBuffer(INT32SZ);
213                         PUTLONG(n1, cp);
214                         break;
215                 case T_CNAME:
216                 case T_MB:
217                 case T_MG:
218                 case T_MR:
219                 case T_NS:
220                 case T_PTR:
221                 case ns_t_dname:
222                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
223                                 return (-1);
224                         n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
225                         if (n < 0)
226                                 return (-1);
227                         cp += n;
228                         ShrinkBuffer(n);
229                         break;
230                 case T_MINFO:
231                 case T_SOA:
232                 case T_RP:
233                         for (i = 0; i < 2; i++) {
234                                 if (!getword_str(buf2, sizeof buf2, &startp,
235                                                  endp))
236                                 return (-1);
237                                 n = dn_comp(buf2, cp, buflen,
238                                             dnptrs, lastdnptr);
239                                 if (n < 0)
240                                         return (-1);
241                                 cp += n;
242                                 ShrinkBuffer(n);
243                         }
244                         if (rrecp->r_type == T_SOA) {
245                                 ShrinkBuffer(5 * INT32SZ);
246                                 while (isspace(*startp) || !*startp)
247                                         startp++;
248                                 if (*startp == '(') {
249                                         multiline = 1;
250                                         startp++;
251                                 } else
252                                         multiline = 0;
253                                 /* serial, refresh, retry, expire, minimum */
254                                 for (i = 0; i < 5; i++) {
255                                         soanum = getnum_str(&startp, endp);
256                                         if (soanum < 0)
257                                                 return (-1);
258                                         PUTLONG(soanum, cp);
259                                 }
260                                 if (multiline) {
261                                         while (isspace(*startp) || !*startp)
262                                                 startp++;
263                                         if (*startp != ')')
264                                                 return (-1);
265                                 }
266                         }
267                         break;
268                 case T_MX:
269                 case T_AFSDB:
270                 case T_RT:
271                         n = getnum_str(&startp, endp);
272                         if (n < 0)
273                                 return (-1);
274                         ShrinkBuffer(INT16SZ);
275                         PUTSHORT(n, cp);
276                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
277                                 return (-1);
278                         n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
279                         if (n < 0)
280                                 return (-1);
281                         cp += n;
282                         ShrinkBuffer(n);
283                         break;
284                 case T_SRV:
285                         n = getnum_str(&startp, endp);
286                         if (n < 0)
287                                 return (-1);
288                         ShrinkBuffer(INT16SZ);
289                         PUTSHORT(n, cp);
290
291                         n = getnum_str(&startp, endp);
292                         if (n < 0)
293                                 return (-1);
294                         ShrinkBuffer(INT16SZ);
295                         PUTSHORT(n, cp);
296
297                         n = getnum_str(&startp, endp);
298                         if (n < 0)
299                                 return (-1);
300                         ShrinkBuffer(INT16SZ);
301                         PUTSHORT(n, cp);
302
303                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
304                                 return (-1);
305                         n = dn_comp(buf2, cp, buflen, NULL, NULL);
306                         if (n < 0)
307                                 return (-1);
308                         cp += n;
309                         ShrinkBuffer(n);
310                         break;
311                 case T_PX:
312                         n = getnum_str(&startp, endp);
313                         if (n < 0)
314                                 return (-1);
315                         PUTSHORT(n, cp);
316                         ShrinkBuffer(INT16SZ);
317                         for (i = 0; i < 2; i++) {
318                                 if (!getword_str(buf2, sizeof buf2, &startp,
319                                                  endp))
320                                         return (-1);
321                                 n = dn_comp(buf2, cp, buflen, dnptrs,
322                                             lastdnptr);
323                                 if (n < 0)
324                                         return (-1);
325                                 cp += n;
326                                 ShrinkBuffer(n);
327                         }
328                         break;
329                 case T_WKS: {
330                         char bm[MAXPORT/8];
331                         unsigned int maxbm = 0;
332
333                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
334                                 return (-1);
335                         if (!inet_aton(buf2, &ina))
336                                 return (-1);
337                         n1 = ntohl(ina.s_addr);
338                         ShrinkBuffer(INT32SZ);
339                         PUTLONG(n1, cp);
340
341                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
342                                 return (-1);
343                         if ((i = res_protocolnumber(buf2)) < 0)
344                                 return (-1);
345                         ShrinkBuffer(1);
346                         *cp++ = i & 0xff;
347                          
348                         for (i = 0; i < MAXPORT/8 ; i++)
349                                 bm[i] = 0;
350
351                         while (getword_str(buf2, sizeof buf2, &startp, endp)) {
352                                 if ((n = res_servicenumber(buf2)) <= 0)
353                                         return (-1);
354
355                                 if (n < MAXPORT) {
356                                         bm[n/8] |= (0x80>>(n%8));
357                                         if ((unsigned)n > maxbm)
358                                                 maxbm = n;
359                                 } else
360                                         return (-1);
361                         }
362                         maxbm = maxbm/8 + 1;
363                         ShrinkBuffer(maxbm);
364                         memcpy(cp, bm, maxbm);
365                         cp += maxbm;
366                         break;
367                 }
368                 case T_HINFO:
369                         for (i = 0; i < 2; i++) {
370                                 if ((n = getstr_str(buf2, sizeof buf2,
371                                                 &startp, endp)) < 0)
372                                         return (-1);
373                                 if (n > 255)
374                                         return (-1);
375                                 ShrinkBuffer(n+1);
376                                 *cp++ = n;
377                                 memcpy(cp, buf2, n);
378                                 cp += n;
379                         }
380                         break;
381                 case T_TXT:
382                         for (;;) {
383                                 if ((n = getstr_str(buf2, sizeof buf2,
384                                                 &startp, endp)) < 0) {
385                                         if (cp != (sp2 + INT16SZ))
386                                                 break;
387                                         return (-1);
388                                 }
389                                 if (n > 255)
390                                         return (-1);
391                                 ShrinkBuffer(n+1);
392                                 *cp++ = n;
393                                 memcpy(cp, buf2, n);
394                                 cp += n;
395                         }
396                         break;
397                 case T_X25:
398                         /* RFC 1183 */
399                         if ((n = getstr_str(buf2, sizeof buf2, &startp,
400                                          endp)) < 0)
401                                 return (-1);
402                         if (n > 255)
403                                 return (-1);
404                         ShrinkBuffer(n+1);
405                         *cp++ = n;
406                         memcpy(cp, buf2, n);
407                         cp += n;
408                         break;
409                 case T_ISDN:
410                         /* RFC 1183 */
411                         if ((n = getstr_str(buf2, sizeof buf2, &startp,
412                                          endp)) < 0)
413                                 return (-1);
414                         if ((n > 255) || (n == 0))
415                                 return (-1);
416                         ShrinkBuffer(n+1);
417                         *cp++ = n;
418                         memcpy(cp, buf2, n);
419                         cp += n;
420                         if ((n = getstr_str(buf2, sizeof buf2, &startp,
421                                          endp)) < 0)
422                                 n = 0;
423                         if (n > 255)
424                                 return (-1);
425                         ShrinkBuffer(n+1);
426                         *cp++ = n;
427                         memcpy(cp, buf2, n);
428                         cp += n;
429                         break;
430                 case T_NSAP:
431                         if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
432                                 ShrinkBuffer(n);
433                                 memcpy(cp, buf2, n);
434                                 cp += n;
435                         } else {
436                                 return (-1);
437                         }
438                         break;
439                 case T_LOC:
440                         if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
441                                 ShrinkBuffer(n);
442                                 memcpy(cp, buf2, n);
443                                 cp += n;
444                         } else
445                                 return (-1);
446                         break;
447                 case ns_t_sig:
448                     {
449                         int sig_type, success, dateerror;
450                         u_int32_t exptime, timesigned;
451
452                         /* type */
453                         if ((n = getword_str(buf2, sizeof buf2,
454                                              &startp, endp)) < 0)
455                                 return (-1);
456                         sig_type = sym_ston(__p_type_syms, buf2, &success);
457                         if (!success || sig_type == ns_t_any)
458                                 return (-1);
459                         ShrinkBuffer(INT16SZ);
460                         PUTSHORT(sig_type, cp);
461                         /* alg */
462                         n = getnum_str(&startp, endp);
463                         if (n < 0)
464                                 return (-1);
465                         ShrinkBuffer(1);
466                         *cp++ = n;
467                         /* labels */
468                         n = getnum_str(&startp, endp);
469                         if (n <= 0 || n > 255)
470                                 return (-1);
471                         ShrinkBuffer(1);
472                         *cp++ = n;
473                         /* ottl  & expire */
474                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
475                                 return (-1);
476                         exptime = ns_datetosecs(buf2, &dateerror);
477                         if (!dateerror) {
478                                 ShrinkBuffer(INT32SZ);
479                                 PUTLONG(rttl, cp);
480                         }
481                         else {
482                                 char *ulendp;
483                                 u_int32_t ottl;
484
485                                 errno = 0;
486                                 ottl = strtoul(buf2, &ulendp, 10);
487                                 if (errno != 0 ||
488                                     (ulendp != NULL && *ulendp != '\0'))
489                                         return (-1);
490                                 ShrinkBuffer(INT32SZ);
491                                 PUTLONG(ottl, cp);
492                                 if (!getword_str(buf2, sizeof buf2, &startp,
493                                                  endp))
494                                         return (-1);
495                                 exptime = ns_datetosecs(buf2, &dateerror);
496                                 if (dateerror)
497                                         return (-1);
498                         }
499                         /* expire */
500                         ShrinkBuffer(INT32SZ);
501                         PUTLONG(exptime, cp);
502                         /* timesigned */
503                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
504                                 return (-1);
505                         timesigned = ns_datetosecs(buf2, &dateerror);
506                         if (!dateerror) {
507                                 ShrinkBuffer(INT32SZ);
508                                 PUTLONG(timesigned, cp);
509                         }
510                         else
511                                 return (-1);
512                         /* footprint */
513                         n = getnum_str(&startp, endp);
514                         if (n < 0)
515                                 return (-1);
516                         ShrinkBuffer(INT16SZ);
517                         PUTSHORT(n, cp);
518                         /* signer name */
519                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
520                                 return (-1);
521                         n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
522                         if (n < 0)
523                                 return (-1);
524                         cp += n;
525                         ShrinkBuffer(n);
526                         /* sig */
527                         if ((n = getword_str(buf2, sizeof buf2,
528                                              &startp, endp)) < 0)
529                                 return (-1);
530                         siglen = b64_pton(buf2, buf3, sizeof(buf3));
531                         if (siglen < 0)
532                                 return (-1);
533                         ShrinkBuffer(siglen);
534                         memcpy(cp, buf3, siglen);
535                         cp += siglen;
536                         break;
537                     }
538                 case ns_t_key:
539                         /* flags */
540                         n = gethexnum_str(&startp, endp);
541                         if (n < 0)
542                                 return (-1);
543                         ShrinkBuffer(INT16SZ);
544                         PUTSHORT(n, cp);
545                         /* proto */
546                         n = getnum_str(&startp, endp);
547                         if (n < 0)
548                                 return (-1);
549                         ShrinkBuffer(1);
550                         *cp++ = n;
551                         /* alg */
552                         n = getnum_str(&startp, endp);
553                         if (n < 0)
554                                 return (-1);
555                         ShrinkBuffer(1);
556                         *cp++ = n;
557                         /* key */
558                         if ((n = getword_str(buf2, sizeof buf2,
559                                              &startp, endp)) < 0)
560                                 return (-1);
561                         keylen = b64_pton(buf2, buf3, sizeof(buf3));
562                         if (keylen < 0)
563                                 return (-1);
564                         ShrinkBuffer(keylen);
565                         memcpy(cp, buf3, keylen);
566                         cp += keylen;
567                         break;
568                 case ns_t_nxt:
569                     {
570                         int success, nxt_type;
571                         u_char data[32];
572                         int maxtype;
573
574                         /* next name */
575                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
576                                 return (-1);
577                         n = dn_comp(buf2, cp, buflen, NULL, NULL);
578                         if (n < 0)
579                                 return (-1);
580                         cp += n;
581                         ShrinkBuffer(n);
582                         maxtype = 0;
583                         memset(data, 0, sizeof data);
584                         for (;;) {
585                                 if (!getword_str(buf2, sizeof buf2, &startp,
586                                                  endp))
587                                         break;
588                                 nxt_type = sym_ston(__p_type_syms, buf2,
589                                                     &success);
590                                 if (!success || !ns_t_rr_p(nxt_type))
591                                         return (-1);
592                                 NS_NXT_BIT_SET(nxt_type, data);
593                                 if (nxt_type > maxtype)
594                                         maxtype = nxt_type;
595                         }
596                         n = maxtype/NS_NXT_BITS+1;
597                         ShrinkBuffer(n);
598                         memcpy(cp, data, n);
599                         cp += n;
600                         break;
601                     }
602                 case ns_t_cert:
603                         /* type */
604                         n = getnum_str(&startp, endp);
605                         if (n < 0)
606                                 return (-1);
607                         ShrinkBuffer(INT16SZ);
608                         PUTSHORT(n, cp);
609                         /* key tag */
610                         n = getnum_str(&startp, endp);
611                         if (n < 0)
612                                 return (-1);
613                         ShrinkBuffer(INT16SZ);
614                         PUTSHORT(n, cp);
615                         /* alg */
616                         n = getnum_str(&startp, endp);
617                         if (n < 0)
618                                 return (-1);
619                         ShrinkBuffer(1);
620                         *cp++ = n;
621                         /* cert */
622                         if ((n = getword_str(buf2, sizeof buf2,
623                                              &startp, endp)) < 0)
624                                 return (-1);
625                         certlen = b64_pton(buf2, buf3, sizeof(buf3));
626                         if (certlen < 0)
627                                 return (-1);
628                         ShrinkBuffer(certlen);
629                         memcpy(cp, buf3, certlen);
630                         cp += certlen;
631                         break;
632                 case ns_t_aaaa:
633                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
634                                 return (-1);
635                         if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
636                                 return (-1);
637                         ShrinkBuffer(NS_IN6ADDRSZ);
638                         memcpy(cp, &in6a, NS_IN6ADDRSZ);
639                         cp += NS_IN6ADDRSZ;
640                         break;
641                 case ns_t_naptr:
642                         /* Order Preference Flags Service Replacement Regexp */
643                         /* Order */
644                         n = getnum_str(&startp, endp);
645                         if (n < 0 || n > 65535)
646                                 return (-1);
647                         ShrinkBuffer(INT16SZ);
648                         PUTSHORT(n, cp);
649                         /* Preference */
650                         n = getnum_str(&startp, endp);
651                         if (n < 0 || n > 65535)
652                                 return (-1);
653                         ShrinkBuffer(INT16SZ);
654                         PUTSHORT(n, cp);
655                         /* Flags */
656                         if ((n = getstr_str(buf2, sizeof buf2,
657                                         &startp, endp)) < 0) {
658                                 return (-1);
659                         }
660                         if (n > 255)
661                                 return (-1);
662                         ShrinkBuffer(n+1);
663                         *cp++ = n;
664                         memcpy(cp, buf2, n);
665                         cp += n;
666                         /* Service Classes */
667                         if ((n = getstr_str(buf2, sizeof buf2,
668                                         &startp, endp)) < 0) {
669                                 return (-1);
670                         }
671                         if (n > 255)
672                                 return (-1);
673                         ShrinkBuffer(n+1);
674                         *cp++ = n;
675                         memcpy(cp, buf2, n);
676                         cp += n;
677                         /* Pattern */
678                         if ((n = getstr_str(buf2, sizeof buf2,
679                                         &startp, endp)) < 0) {
680                                 return (-1);
681                         }
682                         if (n > 255)
683                                 return (-1);
684                         ShrinkBuffer(n+1);
685                         *cp++ = n;
686                         memcpy(cp, buf2, n);
687                         cp += n;
688                         /* Replacement */
689                         if (!getword_str(buf2, sizeof buf2, &startp, endp))
690                                 return (-1);
691                         n = dn_comp(buf2, cp, buflen, NULL, NULL);
692                         if (n < 0)
693                                 return (-1);
694                         cp += n;
695                         ShrinkBuffer(n);
696                         break;
697                 default:
698                         return (-1);
699                 } /*switch*/
700                 n = (u_int16_t)((cp - sp2) - INT16SZ);
701                 PUTSHORT(n, sp2);
702         } /*for*/
703                 
704         hp->qdcount = htons(counts[0]);
705         hp->ancount = htons(counts[1]);
706         hp->nscount = htons(counts[2]);
707         hp->arcount = htons(counts[3]);
708         return (cp - buf);
709 }
710
711 /*
712  * Get a whitespace delimited word from a string (not file)
713  * into buf. modify the start pointer to point after the
714  * word in the string.
715  */
716 static int
717 getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
718         char *cp;
719         int c;
720  
721         for (cp = buf; *startpp <= endp; ) {
722                 c = **startpp;
723                 if (isspace(c) || c == '\0') {
724                         if (cp != buf) /* trailing whitespace */
725                                 break;
726                         else { /* leading whitespace */
727                                 (*startpp)++;
728                                 continue;
729                         }
730                 }
731                 (*startpp)++;
732                 if (cp >= buf+size-1)
733                         break;
734                 *cp++ = (u_char)c;
735         }
736         *cp = '\0';
737         return (cp != buf);
738 }
739
740 /*
741  * get a white spae delimited string from memory.  Process quoted strings
742  * and \DDD escapes.  Return length or -1 on error.  Returned string may
743  * contain nulls.
744  */
745 static char digits[] = "0123456789";
746 static int
747 getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
748         char *cp;
749         int c, c1 = 0;
750         int inquote = 0;
751         int seen_quote = 0;
752         int escape = 0;
753         int dig = 0;
754  
755         for (cp = buf; *startpp <= endp; ) {
756                 if ((c = **startpp) == '\0')
757                         break;
758                 /* leading white space */
759                 if ((cp == buf) && !seen_quote && isspace(c)) {
760                         (*startpp)++;
761                         continue;
762                 }
763
764                 switch (c) {
765                 case '\\':
766                         if (!escape)  {
767                                 escape = 1;
768                                 dig = 0;
769                                 c1 = 0;
770                                 (*startpp)++;
771                                 continue;
772                         } 
773                         goto do_escape;
774                 case '"':
775                         if (!escape) {
776                                 inquote = !inquote;
777                                 seen_quote = 1;
778                                 (*startpp)++;
779                                 continue;
780                         }
781                         /* fall through */
782                 default:
783                 do_escape:
784                         if (escape) {
785                                 switch (c) {
786                                 case '0':
787                                 case '1':
788                                 case '2':
789                                 case '3':
790                                 case '4':
791                                 case '5':
792                                 case '6':
793                                 case '7':
794                                 case '8':
795                                 case '9':
796                                         c1 = c1 * 10 + 
797                                                 (strchr(digits, c) - digits);
798
799                                         if (++dig == 3) {
800                                                 c = c1 &0xff;
801                                                 break;
802                                         }
803                                         (*startpp)++;
804                                         continue;
805                                 }
806                                 escape = 0;
807                         } else if (!inquote && isspace(c))
808                                 goto done;
809                         if (cp >= buf+size-1)
810                                 goto done;
811                         *cp++ = (u_char)c;
812                         (*startpp)++;
813                 }
814         }
815  done:
816         *cp = '\0';
817         return ((cp == buf)?  (seen_quote? 0: -1): (cp - buf));
818 }
819 /*
820  * Get a whitespace delimited base 16 number from a string (not file) into buf
821  * update the start pointer to point after the number in the string.
822  */
823 static int
824 gethexnum_str(u_char **startpp, u_char *endp) {
825         int c, n;
826         int seendigit = 0;
827         int m = 0;
828
829         if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
830                 return getnum_str(startpp, endp);
831         (*startpp)+=2;
832         for (n = 0; *startpp <= endp; ) {
833                 c = **startpp;
834                 if (isspace(c) || c == '\0') {
835                         if (seendigit) /* trailing whitespace */
836                                 break;
837                         else { /* leading whitespace */
838                                 (*startpp)++;
839                                 continue;
840                         }
841                 }
842                 if (c == ';') {
843                         while ((*startpp <= endp) &&
844                                ((c = **startpp) != '\n'))
845                                         (*startpp)++;
846                         if (seendigit)
847                                 break;
848                         continue;
849                 }
850                 if (!isxdigit(c)) {
851                         if (c == ')' && seendigit) {
852                                 (*startpp)--;
853                                 break;
854                         }
855                         return (-1);
856                 }        
857                 (*startpp)++;
858                 if (isdigit(c))
859                         n = n * 16 + (c - '0');
860                 else
861                         n = n * 16 + (tolower(c) - 'a' + 10);
862                 seendigit = 1;
863         }
864         return (n + m);
865 }
866
867 /*
868  * Get a whitespace delimited base 10 number from a string (not file) into buf
869  * update the start pointer to point after the number in the string.
870  */
871 static int
872 getnum_str(u_char **startpp, u_char *endp) {
873         int c, n;
874         int seendigit = 0;
875         int m = 0;
876
877         for (n = 0; *startpp <= endp; ) {
878                 c = **startpp;
879                 if (isspace(c) || c == '\0') {
880                         if (seendigit) /* trailing whitespace */
881                                 break;
882                         else { /* leading whitespace */
883                                 (*startpp)++;
884                                 continue;
885                         }
886                 }
887                 if (c == ';') {
888                         while ((*startpp <= endp) &&
889                                ((c = **startpp) != '\n'))
890                                         (*startpp)++;
891                         if (seendigit)
892                                 break;
893                         continue;
894                 }
895                 if (!isdigit(c)) {
896                         if (c == ')' && seendigit) {
897                                 (*startpp)--;
898                                 break;
899                         }
900                         return (-1);
901                 }        
902                 (*startpp)++;
903                 n = n * 10 + (c - '0');
904                 seendigit = 1;
905         }
906         return (n + m);
907 }
908
909 /*
910  * Allocate a resource record buffer & save rr info.
911  */
912 ns_updrec *
913 res_mkupdrec(int section, const char *dname,
914              u_int class, u_int type, u_long ttl) {
915         ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
916
917         if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
918                 if (rrecp)
919                         free((char *)rrecp);
920                 return (NULL);
921         }
922         INIT_LINK(rrecp, r_link);
923         INIT_LINK(rrecp, r_glink);
924         rrecp->r_class = (ns_class)class;
925         rrecp->r_type = (ns_type)type;
926         rrecp->r_ttl = ttl;
927         rrecp->r_section = (ns_sect)section;
928         return (rrecp);
929 }
930
931 /*
932  * Free a resource record buffer created by res_mkupdrec.
933  */
934 void
935 res_freeupdrec(ns_updrec *rrecp) {
936         /* Note: freeing r_dp is the caller's responsibility. */
937         if (rrecp->r_dname != NULL)
938                 free(rrecp->r_dname);
939         free(rrecp);
940 }
941
942 struct valuelist {
943         struct valuelist *      next;
944         struct valuelist *      prev;
945         char *                  name;
946         char *                  proto;
947         int                     port;
948 };
949 static struct valuelist *servicelist, *protolist;
950
951 static void
952 res_buildservicelist() {
953         struct servent *sp;
954         struct valuelist *slp;
955
956 #ifdef MAYBE_HESIOD
957         setservent(0);
958 #else
959         setservent(1);
960 #endif
961         while ((sp = getservent()) != NULL) {
962                 slp = (struct valuelist *)malloc(sizeof(struct valuelist));
963                 if (!slp)
964                         break;
965                 slp->name = strdup(sp->s_name);
966                 slp->proto = strdup(sp->s_proto);
967                 if ((slp->name == NULL) || (slp->proto == NULL)) {
968                         if (slp->name) free(slp->name);
969                         if (slp->proto) free(slp->proto);
970                         free(slp);
971                         break;
972                 }
973                 slp->port = ntohs((u_int16_t)sp->s_port);  /* host byt order */
974                 slp->next = servicelist;
975                 slp->prev = NULL;
976                 if (servicelist)
977                         servicelist->prev = slp;
978                 servicelist = slp;
979         }
980         endservent();
981 }
982
983 void
984 res_destroyservicelist() {
985         struct valuelist *slp, *slp_next;
986
987         for (slp = servicelist; slp != NULL; slp = slp_next) {
988                 slp_next = slp->next;
989                 free(slp->name);
990                 free(slp->proto);
991                 free(slp);
992         }
993         servicelist = (struct valuelist *)0;
994 }
995
996 void
997 res_buildprotolist(void) {
998         struct protoent *pp;
999         struct valuelist *slp;
1000
1001 #ifdef MAYBE_HESIOD
1002         setprotoent(0);
1003 #else
1004         setprotoent(1);
1005 #endif
1006         while ((pp = getprotoent()) != NULL) {
1007                 slp = (struct valuelist *)malloc(sizeof(struct valuelist));
1008                 if (!slp)
1009                         break;
1010                 slp->name = strdup(pp->p_name);
1011                 if (slp->name == NULL) {
1012                         free(slp);
1013                         break;
1014                 }
1015                 slp->port = pp->p_proto;        /* host byte order */
1016                 slp->next = protolist;
1017                 slp->prev = NULL;
1018                 if (protolist)
1019                         protolist->prev = slp;
1020                 protolist = slp;
1021         }
1022         endprotoent();
1023 }
1024
1025 void
1026 res_destroyprotolist(void) {
1027         struct valuelist *plp, *plp_next;
1028
1029         for (plp = protolist; plp != NULL; plp = plp_next) {
1030                 plp_next = plp->next;
1031                 free(plp->name);
1032                 free(plp);
1033         }
1034         protolist = (struct valuelist *)0;
1035 }
1036
1037 static int
1038 findservice(const char *s, struct valuelist **list) {
1039         struct valuelist *lp = *list;
1040         int n;
1041
1042         for (; lp != NULL; lp = lp->next)
1043                 if (strcasecmp(lp->name, s) == 0) {
1044                         if (lp != *list) {
1045                                 lp->prev->next = lp->next;
1046                                 if (lp->next)
1047                                         lp->next->prev = lp->prev;
1048                                 (*list)->prev = lp;
1049                                 lp->next = *list;
1050                                 *list = lp;
1051                         }
1052                         return (lp->port);      /* host byte order */
1053                 }
1054         if (sscanf(s, "%d", &n) != 1 || n <= 0)
1055                 n = -1;
1056         return (n);
1057 }
1058
1059 /*
1060  * Convert service name or (ascii) number to int.
1061  */
1062 int
1063 res_servicenumber(const char *p) {
1064         if (servicelist == (struct valuelist *)0)
1065                 res_buildservicelist();
1066         return (findservice(p, &servicelist));
1067 }
1068
1069 /*
1070  * Convert protocol name or (ascii) number to int.
1071  */
1072 int
1073 res_protocolnumber(const char *p) {
1074         if (protolist == (struct valuelist *)0)
1075                 res_buildprotolist();
1076         return (findservice(p, &protolist));
1077 }
1078
1079 static struct servent *
1080 cgetservbyport(u_int16_t port, const char *proto) {     /* Host byte order. */
1081         struct valuelist **list = &servicelist;
1082         struct valuelist *lp = *list;
1083         static struct servent serv;
1084
1085         port = ntohs(port);
1086         for (; lp != NULL; lp = lp->next) {
1087                 if (port != (u_int16_t)lp->port)        /* Host byte order. */
1088                         continue;
1089                 if (strcasecmp(lp->proto, proto) == 0) {
1090                         if (lp != *list) {
1091                                 lp->prev->next = lp->next;
1092                                 if (lp->next)
1093                                         lp->next->prev = lp->prev;
1094                                 (*list)->prev = lp;
1095                                 lp->next = *list;
1096                                 *list = lp;
1097                         }
1098                         serv.s_name = lp->name;
1099                         serv.s_port = htons((u_int16_t)lp->port);
1100                         serv.s_proto = lp->proto;
1101                         return (&serv);
1102                 }
1103         }
1104         return (0);
1105 }
1106
1107 static struct protoent *
1108 cgetprotobynumber(int proto) {                          /* Host byte order. */
1109         struct valuelist **list = &protolist;
1110         struct valuelist *lp = *list;
1111         static struct protoent prot;
1112
1113         for (; lp != NULL; lp = lp->next)
1114                 if (lp->port == proto) {                /* Host byte order. */
1115                         if (lp != *list) {
1116                                 lp->prev->next = lp->next;
1117                                 if (lp->next)
1118                                         lp->next->prev = lp->prev;
1119                                 (*list)->prev = lp;
1120                                 lp->next = *list;
1121                                 *list = lp;
1122                         }
1123                         prot.p_name = lp->name;
1124                         prot.p_proto = lp->port;        /* Host byte order. */
1125                         return (&prot);
1126                 }
1127         return (0);
1128 }
1129
1130 const char *
1131 res_protocolname(int num) {
1132         static char number[8];
1133         struct protoent *pp;
1134
1135         if (protolist == (struct valuelist *)0)
1136                 res_buildprotolist();
1137         pp = cgetprotobynumber(num);
1138         if (pp == 0)  {
1139                 (void) sprintf(number, "%d", num);
1140                 return (number);
1141         }
1142         return (pp->p_name);
1143 }
1144
1145 const char *
1146 res_servicename(u_int16_t port, const char *proto) {    /* Host byte order. */
1147         static char number[8];
1148         struct servent *ss;
1149
1150         if (servicelist == (struct valuelist *)0)
1151                 res_buildservicelist();
1152         ss = cgetservbyport(htons(port), proto);
1153         if (ss == 0)  {
1154                 (void) sprintf(number, "%d", port);
1155                 return (number);
1156         }
1157         return (ss->s_name);
1158 }