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