dn_expand.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /* libc uncompressing functions for dns answers
  2. *
  3. */
  4. #include "memcpy.h"
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <errno.h>
  8. #include <stdlib.h>
  9. /*
  10. * Define constants based on RFC 883, RFC 1034, RFC 1035
  11. */
  12. #define NS_PACKETSZ 512 /* maximum packet size */
  13. #define NS_MAXDNAME 1025 /* maximum domain name */
  14. #define NS_MAXCDNAME 255 /* maximum compressed domain name */
  15. #define NS_MAXLABEL 63 /* maximum length of domain label */
  16. #define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
  17. #define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
  18. #define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
  19. #define NS_INT32SZ 4 /* #/bytes of data in a uint32_t */
  20. #define NS_INT16SZ 2 /* #/bytes of data in a uint16_t */
  21. #define NS_INT8SZ 1 /* #/bytes of data in a uint8_t */
  22. #define NS_INADDRSZ 4 /* IPv4 T_A */
  23. #define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */
  24. #define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */
  25. #define NS_DEFAULTPORT 53 /* For both TCP and UDP. */
  26. static const char digits[] = "0123456789";
  27. /*
  28. * special(ch)
  29. * Thinking in noninternationalized USASCII (per the DNS spec),
  30. * is this characted special ("in need of quoting") ?
  31. * return:
  32. * boolean.
  33. */
  34. static inline int special(int ch) {
  35. switch (ch) {
  36. case 0x22: /* '"' */
  37. case 0x2E: /* '.' */
  38. case 0x3B: /* ';' */
  39. case 0x5C: /* '\\' */
  40. /* Special modifiers in zone files. */
  41. case 0x40: /* '@' */
  42. case 0x24: /* '$' */
  43. return (1);
  44. default:
  45. return (0);
  46. }
  47. }
  48. /*
  49. * printable(ch)
  50. * Thinking in noninternationalized USASCII (per the DNS spec),
  51. * is this character visible and not a space when printed ?
  52. * return:
  53. * boolean.
  54. */
  55. static inline int printable(int ch) {
  56. return (ch > 0x20 && ch < 0x7f);
  57. }
  58. /*
  59. * ns_name_ntop(src, dst, dstsiz)
  60. * Convert an encoded domain name to printable ascii as per RFC1035.
  61. * return:
  62. * Number of bytes written to buffer, or -1 (with errno set)
  63. * notes:
  64. * The root is returned as "."
  65. * All other domains are returned in non absolute form
  66. */
  67. static int my_ns_name_ntop(const unsigned char *src, char *dst, size_t dstsiz) {
  68. const unsigned char *cp;
  69. char *dn, *eom;
  70. unsigned char c, n;
  71. cp = src;
  72. dn = dst;
  73. eom = dst + dstsiz;
  74. while ((n = *cp++) != 0) {
  75. if ((n & NS_CMPRSFLGS) != 0) {
  76. /* Some kind of compression pointer. */
  77. errno = EMSGSIZE;
  78. return (-1);
  79. }
  80. if (dn != dst) {
  81. if (dn >= eom) {
  82. errno = EMSGSIZE;
  83. return (-1);
  84. }
  85. *dn++ = '.';
  86. }
  87. if (dn + n >= eom) {
  88. errno = EMSGSIZE;
  89. return (-1);
  90. }
  91. for ((void)NULL; n > 0; n--) {
  92. c = *cp++;
  93. if (special(c)) {
  94. if (dn + 1 >= eom) {
  95. errno = EMSGSIZE;
  96. return (-1);
  97. }
  98. *dn++ = '\\';
  99. *dn++ = (char)c;
  100. } else if (!printable(c)) {
  101. if (dn + 3 >= eom) {
  102. errno = EMSGSIZE;
  103. return (-1);
  104. }
  105. *dn++ = '\\';
  106. *dn++ = digits[c / 100];
  107. *dn++ = digits[(c % 100) / 10];
  108. *dn++ = digits[c % 10];
  109. } else {
  110. if (dn >= eom) {
  111. errno = EMSGSIZE;
  112. return (-1);
  113. }
  114. *dn++ = (char)c;
  115. }
  116. }
  117. }
  118. if (dn == dst) {
  119. if (dn >= eom) {
  120. errno = EMSGSIZE;
  121. return (-1);
  122. }
  123. *dn++ = '.';
  124. }
  125. if (dn >= eom) {
  126. errno = EMSGSIZE;
  127. return (-1);
  128. }
  129. *dn++ = '\0';
  130. return (dn - dst);
  131. }
  132. /*
  133. * ns_name_unpack(msg, eom, src, dst, dstsiz)
  134. * Unpack a domain name from a message, source may be compressed.
  135. * return:
  136. * -1 if it fails, or consumed octets if it succeeds.
  137. */
  138. static int my_ns_name_unpack(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, unsigned char *dst, size_t dstsiz)
  139. {
  140. const unsigned char *srcp, *dstlim;
  141. unsigned char *dstp;
  142. int n, len, checked;
  143. len = -1;
  144. checked = 0;
  145. dstp = dst;
  146. srcp = src;
  147. dstlim = dst + dstsiz;
  148. if (srcp < msg || srcp >= eom) {
  149. errno = EMSGSIZE;
  150. return (-1);
  151. }
  152. /* Fetch next label in domain name. */
  153. while ((n = *srcp++) != 0) {
  154. /* Check for indirection. */
  155. switch (n & NS_CMPRSFLGS) {
  156. case 0:
  157. /* Limit checks. */
  158. if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
  159. errno = EMSGSIZE;
  160. return (-1);
  161. }
  162. checked += n + 1;
  163. *dstp++ = n;
  164. memcpy(dstp, srcp, n);
  165. dstp += n;
  166. srcp += n;
  167. break;
  168. case NS_CMPRSFLGS:
  169. if (srcp >= eom) {
  170. errno = EMSGSIZE;
  171. return (-1);
  172. }
  173. if (len < 0)
  174. len = srcp - src + 1;
  175. srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
  176. if (srcp < msg || srcp >= eom) { /* Out of range. */
  177. errno = EMSGSIZE;
  178. return (-1);
  179. }
  180. checked += 2;
  181. /*
  182. * Check for loops in the compressed name;
  183. * if we've looked at the whole message,
  184. * there must be a loop.
  185. */
  186. if (checked >= eom - msg) {
  187. errno = EMSGSIZE;
  188. return (-1);
  189. }
  190. break;
  191. default:
  192. errno = EMSGSIZE;
  193. return (-1); /* flag error */
  194. }
  195. }
  196. *dstp = '\0';
  197. if (len < 0)
  198. len = srcp - src;
  199. return (len);
  200. }
  201. /*
  202. * ns_name_uncompress(msg, eom, src, dst, dstsiz)
  203. * Expand compressed domain name to presentation format.
  204. * return:
  205. * Number of bytes read out of `src', or -1 (with errno set).
  206. * note:
  207. * Root domain returns as "." not "".
  208. */
  209. static int my_ns_name_uncompress(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, size_t dstsiz)
  210. {
  211. unsigned char tmp[NS_MAXCDNAME];
  212. int n;
  213. if ((n = my_ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
  214. return (-1);
  215. if (my_ns_name_ntop(tmp, dst, dstsiz) == -1)
  216. return (-1);
  217. return (n);
  218. }
  219. /*
  220. * Expand compressed domain name 'comp_dn' to full domain name.
  221. * 'msg' is a pointer to the begining of the message,
  222. * 'eomorig' points to the first location after the message,
  223. * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
  224. * Return size of compressed name or -1 if there was an error.
  225. */
  226. int my_dn_expand(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, int dstsiz)
  227. {
  228. int n = my_ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
  229. if (n > 0 && dst[0] == '.')
  230. dst[0] = '\0';
  231. return (n);
  232. }