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