dn_expand.c 8.4 KB

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