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