1 /*
2  * Copyright (c) 1985, 1993
3  *    The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32  *
33  * Permission to use, copy, modify, and distribute this software for any
34  * purpose with or without fee is hereby granted, provided that the above
35  * copyright notice and this permission notice appear in all copies, and that
36  * the name of Digital Equipment Corporation not be used in advertising or
37  * publicity pertaining to distribution of the document or software without
38  * specific, written prior permission.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47  * SOFTWARE.
48  */
49 
50 /*
51  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
52  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
53  *
54  * Permission to use, copy, modify, and distribute this software for any
55  * purpose with or without fee is hereby granted, provided that the above
56  * copyright notice and this permission notice appear in all copies.
57  *
58  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
59  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
60  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
61  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
62  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
63  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
64  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
65  */
66 
67 #include "tscore/ink_config.h"
68 #include "tscore/ink_defs.h"
69 
70 #include <sys/types.h>
71 #include <sys/param.h>
72 #include <netinet/in.h>
73 #include <arpa/nameser.h>
74 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
75 #include <arpa/nameser_compat.h>
76 #endif
77 #include <netdb.h>
78 #include <resolv.h>
79 #include <cstdio>
80 #include <cstring>
81 
82 #include "tscore/ink_error.h"
83 #include "tscore/ink_resolver.h"
84 
85 #define SPRINTF(x) (sprintf x)
86 
87 /*%
88  * Form all types of queries.
89  * Returns the size of the result or -1.
90  */
91 int ink_res_mkquery(ink_res_state statp, int op,               /*!< opcode of query  */
92                     const char *dname,                         /*!< domain name  */
93                     int _class, int type,                      /*!< _class and type of query  */
94                     const u_char *data,                        /*!< resource record data  */
95                     int datalen,                               /*!< length of data  */
96                     const u_char * /* newrr_in  ATS_UNUSED */, /*!< new rr for modify or append  */
97                     u_char *buf,                               /*!< buffer to put query  */
98                     int buflen)                                /*!< size of buffer  */
99 {
100   HEADER *hp;
101   u_char *cp, *ep;
102   int n;
103   u_char *dnptrs[20], **dpp, **lastdnptr;
104 
105   /*
106    * Initialize header fields.
107    */
108   if ((buf == nullptr) || (buflen < HFIXEDSZ)) {
109     return (-1);
110   }
111   memset(buf, 0, HFIXEDSZ);
112   hp         = reinterpret_cast<HEADER *>(buf);
113   hp->id     = htons(++statp->id);
114   hp->opcode = op;
115   hp->rd     = (statp->options & INK_RES_RECURSE) != 0U;
116   hp->rcode  = NOERROR;
117   cp         = buf + HFIXEDSZ;
118   ep         = buf + buflen;
119   dpp        = dnptrs;
120   *dpp++     = buf;
121   *dpp++     = nullptr;
122   lastdnptr  = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
123   /*
124    * perform opcode specific processing
125    */
126   switch (op) {
127   case QUERY: /*FALLTHROUGH*/
128   case NS_NOTIFY_OP:
129     if (ep - cp < QFIXEDSZ) {
130       return (-1);
131     }
132     if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr)) < 0) {
133       return (-1);
134     }
135     cp += n;
136     NS_PUT16(type, cp);
137     NS_PUT16(_class, cp);
138     hp->qdcount = htons(1);
139     if (op == QUERY || data == nullptr) {
140       break;
141     }
142     /*
143      * Make an additional record for completion domain.
144      */
145     if ((ep - cp) < RRFIXEDSZ) {
146       return (-1);
147     }
148     n = dn_comp(reinterpret_cast<const char *>(data), cp, ep - cp - RRFIXEDSZ, dnptrs, lastdnptr);
149     if (n < 0) {
150       return (-1);
151     }
152     cp += n;
153     NS_PUT16(T_NULL, cp);
154     NS_PUT16(_class, cp);
155     NS_PUT32(0, cp);
156     NS_PUT16(0, cp);
157     hp->arcount = htons(1);
158     break;
159 
160   case IQUERY:
161     /*
162      * Initialize answer section
163      */
164     if (ep - cp < 1 + RRFIXEDSZ + datalen) {
165       return (-1);
166     }
167     *cp++ = '\0'; /*%< no domain name */
168     NS_PUT16(type, cp);
169     NS_PUT16(_class, cp);
170     NS_PUT32(0, cp);
171     NS_PUT16(datalen, cp);
172     if (datalen) {
173       memcpy(cp, data, datalen);
174       cp += datalen;
175     }
176     hp->ancount = htons(1);
177     break;
178 
179   default:
180     return (-1);
181   }
182   return (cp - buf);
183 }
184 
185 /* Public. */
186 
187 /*%
188  *	Thinking in noninternationalized USASCII (per the DNS spec),
189  *	is this character visible and not a space when printed ?
190  *
191  * return:
192  *\li	boolean.
193  */
194 static int
195 printable(int ch)
196 {
197   return (ch > 0x20 && ch < 0x7f);
198 }
199 
200 static const char digits[] = "0123456789";
201 
202 static int
203 labellen(const u_char *lp)
204 {
205   int bitlen;
206   u_char l = *lp;
207 
208   if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
209     /* should be avoided by the caller */
210     return (-1);
211   }
212 
213   if ((l & NS_CMPRSFLGS) == INK_NS_TYPE_ELT) {
214     if (l == INK_DNS_LABELTYPE_BITSTRING) {
215       if ((bitlen = *(lp + 1)) == 0) {
216         bitlen = 256;
217       }
218       return ((bitlen + 7) / 8 + 1);
219     }
220     return (-1); /*%< unknown ELT */
221   }
222   return (l);
223 }
224 
225 static int
226 decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
227 {
228   const unsigned char *cp = *cpp;
229   char *beg               = dn, tc;
230   int b, blen, plen, i;
231 
232   if ((blen = (*cp & 0xff)) == 0) {
233     blen = 256;
234   }
235   plen = (blen + 3) / 4;
236   plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
237   if (dn + plen >= eom) {
238     return (-1);
239   }
240 
241   cp++;
242   i = SPRINTF((dn, "\\[x"));
243   if (i < 0) {
244     return (-1);
245   }
246   dn += i;
247   for (b = blen; b > 7; b -= 8, cp++) {
248     i = SPRINTF((dn, "%02x", *cp & 0xff));
249     if (i < 0) {
250       return (-1);
251     }
252     dn += i;
253   }
254   if (b > 4) {
255     tc = *cp++;
256     i  = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
257     if (i < 0) {
258       return (-1);
259     }
260     dn += i;
261   } else if (b > 0) {
262     tc = *cp++;
263     i  = SPRINTF((dn, "%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
264     if (i < 0) {
265       return (-1);
266     }
267     dn += i;
268   }
269   i = SPRINTF((dn, "/%d]", blen));
270   if (i < 0) {
271     return (-1);
272   }
273   dn += i;
274 
275   *cpp = cp;
276   return (dn - beg);
277 }
278 
279 /*%
280  *	Thinking in noninternationalized USASCII (per the DNS spec),
281  *	is this character special ("in need of quoting") ?
282  *
283  * return:
284  *\li	boolean.
285  */
286 static int
287 special(int ch)
288 {
289   switch (ch) {
290   case 0x22: /*%< '"' */
291   case 0x2E: /*%< '.' */
292   case 0x3B: /*%< ';' */
293   case 0x5C: /*%< '\\' */
294   case 0x28: /*%< '(' */
295   case 0x29: /*%< ')' */
296   /* Special modifiers in zone files. */
297   case 0x40: /*%< '@' */
298   case 0x24: /*%< '$' */
299     return (1);
300   default:
301     return (0);
302   }
303 }
304 
305 /*%
306  *	Convert an encoded domain name to printable ascii as per RFC1035.
307 
308  * return:
309  *\li	Number of bytes written to buffer, or -1 (with errno set)
310  *
311  * notes:
312  *\li	The root is returned as "."
313  *\li	All other domains are returned in non absolute form
314  */
315 int
316 ink_ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
317 {
318   const u_char *cp;
319   char *dn, *eom;
320   u_char c;
321   unsigned n;
322   int l;
323 
324   cp  = src;
325   dn  = dst;
326   eom = dst + dstsiz;
327 
328   while ((n = *cp++) != 0) {
329     if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
330       /* Some kind of compression pointer. */
331       errno = EMSGSIZE;
332       return (-1);
333     }
334     if (dn != dst) {
335       if (dn >= eom) {
336         errno = EMSGSIZE;
337         return (-1);
338       }
339       *dn++ = '.';
340     }
341     if ((l = labellen(cp - 1)) < 0) {
342       errno = EMSGSIZE; /*%< XXX */
343       return (-1);
344     }
345     if (dn + l >= eom) {
346       errno = EMSGSIZE;
347       return (-1);
348     }
349     if ((n & NS_CMPRSFLGS) == INK_NS_TYPE_ELT) {
350       int m;
351 
352       if (n != INK_DNS_LABELTYPE_BITSTRING) {
353         /* XXX: labellen should reject this case */
354         errno = EINVAL;
355         return (-1);
356       }
357       if ((m = decode_bitstring(&cp, dn, eom)) < 0) {
358         errno = EMSGSIZE;
359         return (-1);
360       }
361       dn += m;
362       continue;
363     }
364     for ((void)nullptr; l > 0; l--) {
365       c = *cp++;
366       if (special(c)) {
367         if (dn + 1 >= eom) {
368           errno = EMSGSIZE;
369           return (-1);
370         }
371         *dn++ = '\\';
372         *dn++ = static_cast<char>(c);
373       } else if (!printable(c)) {
374         if (dn + 3 >= eom) {
375           errno = EMSGSIZE;
376           return (-1);
377         }
378         *dn++ = '\\';
379         *dn++ = digits[c / 100];
380         *dn++ = digits[(c % 100) / 10];
381         *dn++ = digits[c % 10];
382       } else {
383         if (dn >= eom) {
384           errno = EMSGSIZE;
385           return (-1);
386         }
387         *dn++ = static_cast<char>(c);
388       }
389     }
390   }
391   if (dn == dst) {
392     if (dn >= eom) {
393       errno = EMSGSIZE;
394       return (-1);
395     }
396     *dn++ = '.';
397   }
398   if (dn >= eom) {
399     errno = EMSGSIZE;
400     return (-1);
401   }
402   *dn++ = '\0';
403   return (dn - dst);
404 }
405 
406 /*%
407  *	Convert an encoded domain name to printable ascii as per RFC1035.
408 
409  * return:
410  *\li	Number of bytes written to buffer, or -1 (with errno set)
411  *
412  * notes:
413  *\li	The root is returned as "."
414  *\li	All other domains are returned in non absolute form
415  */
416 #if defined(linux)
417 int
418 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) __THROW
419 #else
420 int
421 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
422 #endif
423 {
424   const u_char *cp;
425   char *dn, *eom;
426   u_char c;
427   unsigned n;
428   int l;
429 
430   cp  = src;
431   dn  = dst;
432   eom = dst + dstsiz;
433 
434   while ((n = *cp++) != 0) {
435     if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
436       /* Some kind of compression pointer. */
437       errno = EMSGSIZE;
438       return (-1);
439     }
440     if (dn != dst) {
441       if (dn >= eom) {
442         errno = EMSGSIZE;
443         return (-1);
444       }
445       *dn++ = '.';
446     }
447     if ((l = labellen(cp - 1)) < 0) {
448       errno = EMSGSIZE; /*%< XXX */
449       return (-1);
450     }
451     if (dn + l >= eom) {
452       errno = EMSGSIZE;
453       return (-1);
454     }
455     if ((n & NS_CMPRSFLGS) == INK_NS_TYPE_ELT) {
456       int m;
457 
458       if (n != INK_DNS_LABELTYPE_BITSTRING) {
459         /* XXX: labellen should reject this case */
460         errno = EINVAL;
461         return (-1);
462       }
463       if ((m = decode_bitstring(&cp, dn, eom)) < 0) {
464         errno = EMSGSIZE;
465         return (-1);
466       }
467       dn += m;
468       continue;
469     }
470     for ((void)nullptr; l > 0; l--) {
471       c = *cp++;
472       if (special(c)) {
473         if (dn + 1 >= eom) {
474           errno = EMSGSIZE;
475           return (-1);
476         }
477         *dn++ = '\\';
478         *dn++ = static_cast<char>(c);
479       } else if (!printable(c)) {
480         if (dn + 3 >= eom) {
481           errno = EMSGSIZE;
482           return (-1);
483         }
484         *dn++ = '\\';
485         *dn++ = digits[c / 100];
486         *dn++ = digits[(c % 100) / 10];
487         *dn++ = digits[c % 10];
488       } else {
489         if (dn >= eom) {
490           errno = EMSGSIZE;
491           return (-1);
492         }
493         *dn++ = static_cast<char>(c);
494       }
495     }
496   }
497   if (dn == dst) {
498     if (dn >= eom) {
499       errno = EMSGSIZE;
500       return (-1);
501     }
502     *dn++ = '.';
503   }
504   if (dn >= eom) {
505     errno = EMSGSIZE;
506     return (-1);
507   }
508   *dn++ = '\0';
509   return (dn - dst);
510 }
511 
512 HostResStyle
513 ats_host_res_from(int family, HostResPreferenceOrder const &order)
514 {
515   bool v4 = false, v6 = false;
516   HostResPreference client = AF_INET6 == family ? HOST_RES_PREFER_IPV6 : HOST_RES_PREFER_IPV4;
517 
518   for (int i = 0; i < N_HOST_RES_PREFERENCE_ORDER; ++i) {
519     HostResPreference p = order[i];
520     if (HOST_RES_PREFER_CLIENT == p) {
521       p = client; // CLIENT -> actual value
522     }
523     if (HOST_RES_PREFER_IPV4 == p) {
524       if (v6) {
525         return HOST_RES_IPV6;
526       } else {
527         v4 = true;
528       }
529     } else if (HOST_RES_PREFER_IPV6 == p) {
530       if (v4) {
531         return HOST_RES_IPV4;
532       } else {
533         v6 = true;
534       }
535     } else {
536       break;
537     }
538   }
539   if (v4) {
540     return HOST_RES_IPV4_ONLY;
541   } else if (v6) {
542     return HOST_RES_IPV6_ONLY;
543   }
544   return HOST_RES_NONE;
545 }
546 
547 HostResStyle
548 ats_host_res_match(sockaddr const *addr)
549 {
550   HostResStyle zret = HOST_RES_NONE;
551   if (ats_is_ip6(addr)) {
552     zret = HOST_RES_IPV6_ONLY;
553   } else if (ats_is_ip4(addr)) {
554     zret = HOST_RES_IPV4_ONLY;
555   }
556   return zret;
557 }
558