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