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