convDNS2M.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include "dns.h"
  5. /*
  6. * a dictionary of domain names for packing messages
  7. */
  8. enum
  9. {
  10. Ndict= 64,
  11. };
  12. typedef struct Dict Dict;
  13. struct Dict
  14. {
  15. struct {
  16. ushort offset; /* pointer to packed name in message */
  17. char *name; /* pointer to unpacked name in buf */
  18. } x[Ndict];
  19. int n; /* size of dictionary */
  20. uchar *start; /* start of packed message */
  21. char buf[4*1024]; /* buffer for unpacked names */
  22. char *ep; /* first free char in buf */
  23. };
  24. #define NAME(x) p = pname(p, ep, x, dp)
  25. #define STRING(x) p = pstring(p, ep, x)
  26. #define BYTES(x, n) p = pbytes(p, ep, x, n)
  27. #define USHORT(x) p = pushort(p, ep, x)
  28. #define UCHAR(x) p = puchar(p, ep, x)
  29. #define ULONG(x) p = pulong(p, ep, x)
  30. #define V4ADDR(x) p = pv4addr(p, ep, x)
  31. #define V6ADDR(x) p = pv6addr(p, ep, x)
  32. static uchar*
  33. pstring(uchar *p, uchar *ep, char *np)
  34. {
  35. int n;
  36. n = strlen(np);
  37. if(n >= Strlen) /* DNS maximum length string */
  38. n = Strlen - 1;
  39. if(ep - p < n+1) /* see if it fits in the buffer */
  40. return ep+1;
  41. *p++ = n;
  42. memcpy(p, np, n);
  43. return p + n;
  44. }
  45. static uchar*
  46. pbytes(uchar *p, uchar *ep, uchar *np, int n)
  47. {
  48. if(ep - p < n)
  49. return ep+1;
  50. memcpy(p, np, n);
  51. return p + n;
  52. }
  53. static uchar*
  54. puchar(uchar *p, uchar *ep, int val)
  55. {
  56. if(ep - p < 1)
  57. return ep+1;
  58. *p++ = val;
  59. return p;
  60. }
  61. static uchar*
  62. pushort(uchar *p, uchar *ep, int val)
  63. {
  64. if(ep - p < 2)
  65. return ep+1;
  66. *p++ = val>>8;
  67. *p++ = val;
  68. return p;
  69. }
  70. static uchar*
  71. pulong(uchar *p, uchar *ep, int val)
  72. {
  73. if(ep - p < 4)
  74. return ep+1;
  75. *p++ = val>>24;
  76. *p++ = val>>16;
  77. *p++ = val>>8;
  78. *p++ = val;
  79. return p;
  80. }
  81. static uchar*
  82. pv4addr(uchar *p, uchar *ep, char *name)
  83. {
  84. uchar ip[IPaddrlen];
  85. if(ep - p < 4)
  86. return ep+1;
  87. parseip(ip, name);
  88. v6tov4(p, ip);
  89. return p + 4;
  90. }
  91. static uchar*
  92. pv6addr(uchar *p, uchar *ep, char *name)
  93. {
  94. if(ep - p < IPaddrlen)
  95. return ep+1;
  96. parseip(p, name);
  97. return p + IPaddrlen;
  98. }
  99. static uchar*
  100. pname(uchar *p, uchar *ep, char *np, Dict *dp)
  101. {
  102. char *cp;
  103. int i;
  104. char *last; /* last component packed */
  105. if(strlen(np) >= Domlen) /* make sure we don't exceed DNS limits */
  106. return ep+1;
  107. last = 0;
  108. while(*np){
  109. /* look through every component in the dictionary for a match */
  110. for(i = 0; i < dp->n; i++){
  111. if(strcmp(np, dp->x[i].name) == 0){
  112. if(ep - p < 2)
  113. return ep+1;
  114. *p++ = (dp->x[i].offset>>8) | 0xc0;
  115. *p++ = dp->x[i].offset;
  116. return p;
  117. }
  118. }
  119. /* if there's room, enter this name in dictionary */
  120. if(dp->n < Ndict){
  121. if(last){
  122. /* the whole name is already in dp->buf */
  123. last = strchr(last, '.') + 1;
  124. dp->x[dp->n].name = last;
  125. dp->x[dp->n].offset = p - dp->start;
  126. dp->n++;
  127. } else {
  128. /* add to dp->buf */
  129. i = strlen(np);
  130. if(dp->ep + i + 1 < &dp->buf[sizeof(dp->buf)]){
  131. strcpy(dp->ep, np);
  132. dp->x[dp->n].name = dp->ep;
  133. last = dp->ep;
  134. dp->x[dp->n].offset = p - dp->start;
  135. dp->ep += i + 1;
  136. dp->n++;
  137. }
  138. }
  139. }
  140. /* put next component into message */
  141. cp = strchr(np, '.');
  142. if(cp == 0){
  143. i = strlen(np);
  144. cp = np + i; /* point to null terminator */
  145. } else {
  146. i = cp - np;
  147. cp++; /* point past '.' */
  148. }
  149. if(ep-p < i+1)
  150. return ep+1;
  151. *p++ = i; /* count of chars in label */
  152. memcpy(p, np, i);
  153. np = cp;
  154. p += i;
  155. }
  156. if(p >= ep)
  157. return ep+1;
  158. *p++ = 0; /* add top level domain */
  159. return p;
  160. }
  161. static uchar*
  162. convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
  163. {
  164. uchar *lp, *data;
  165. int len, ttl;
  166. NAME(rp->owner->name);
  167. USHORT(rp->type);
  168. USHORT(rp->owner->class);
  169. /* egregious overuse of ttl (it's absolute time in the cache) */
  170. if(rp->db)
  171. ttl = rp->ttl;
  172. else
  173. ttl = rp->ttl - now;
  174. if(ttl < 0)
  175. ttl = 0;
  176. ULONG(ttl);
  177. lp = p; /* leave room for the rdata length */
  178. p += 2;
  179. data = p;
  180. if(data >= ep)
  181. return p+1;
  182. switch(rp->type){
  183. case Thinfo:
  184. STRING(rp->cpu->name);
  185. STRING(rp->os->name);
  186. break;
  187. case Tcname:
  188. case Tmb:
  189. case Tmd:
  190. case Tmf:
  191. case Tns:
  192. NAME(rp->host->name);
  193. break;
  194. case Tmg:
  195. case Tmr:
  196. NAME(rp->mb->name);
  197. break;
  198. case Tminfo:
  199. NAME(rp->rmb->name);
  200. NAME(rp->mb->name);
  201. break;
  202. case Tmx:
  203. USHORT(rp->pref);
  204. NAME(rp->host->name);
  205. break;
  206. case Ta:
  207. V4ADDR(rp->ip->name);
  208. break;
  209. case Taaaa:
  210. V6ADDR(rp->ip->name);
  211. break;
  212. case Tptr:
  213. NAME(rp->ptr->name);
  214. break;
  215. case Tsoa:
  216. NAME(rp->host->name);
  217. NAME(rp->rmb->name);
  218. ULONG(rp->soa->serial);
  219. ULONG(rp->soa->refresh);
  220. ULONG(rp->soa->retry);
  221. ULONG(rp->soa->expire);
  222. ULONG(rp->soa->minttl);
  223. break;
  224. case Ttxt:
  225. STRING(rp->txt->name);
  226. break;
  227. case Tnull:
  228. BYTES(rp->null->data, rp->null->dlen);
  229. break;
  230. case Trp:
  231. NAME(rp->rmb->name);
  232. NAME(rp->txt->name);
  233. break;
  234. case Tkey:
  235. USHORT(rp->key->flags);
  236. UCHAR(rp->key->proto);
  237. UCHAR(rp->key->alg);
  238. BYTES(rp->key->data, rp->key->dlen);
  239. break;
  240. case Tsig:
  241. USHORT(rp->sig->type);
  242. UCHAR(rp->sig->alg);
  243. UCHAR(rp->sig->labels);
  244. ULONG(rp->sig->ttl);
  245. ULONG(rp->sig->exp);
  246. ULONG(rp->sig->incep);
  247. USHORT(rp->sig->tag);
  248. NAME(rp->sig->signer->name);
  249. BYTES(rp->sig->data, rp->sig->dlen);
  250. break;
  251. case Tcert:
  252. USHORT(rp->cert->type);
  253. USHORT(rp->cert->tag);
  254. UCHAR(rp->cert->alg);
  255. BYTES(rp->cert->data, rp->cert->dlen);
  256. break;
  257. }
  258. /* stuff in the rdata section length */
  259. len = p - data;
  260. *lp++ = len >> 8;
  261. *lp = len;
  262. return p;
  263. }
  264. static uchar*
  265. convQ2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
  266. {
  267. NAME(rp->owner->name);
  268. USHORT(rp->type);
  269. USHORT(rp->owner->class);
  270. return p;
  271. }
  272. static uchar*
  273. rrloop(RR *rp, int *countp, uchar *p, uchar *ep, Dict *dp, int quest)
  274. {
  275. uchar *np;
  276. *countp = 0;
  277. for(; rp && p < ep; rp = rp->next){
  278. if(quest)
  279. np = convQ2M(rp, p, ep, dp);
  280. else
  281. np = convRR2M(rp, p, ep, dp);
  282. if(np > ep)
  283. break;
  284. p = np;
  285. (*countp)++;
  286. }
  287. return p;
  288. }
  289. /*
  290. * convert into a message
  291. */
  292. int
  293. convDNS2M(DNSmsg *m, uchar *buf, int len)
  294. {
  295. uchar *p, *ep, *np;
  296. Dict d;
  297. d.n = 0;
  298. d.start = buf;
  299. d.ep = d.buf;
  300. memset(buf, 0, len);
  301. m->qdcount = m->ancount = m->nscount = m->arcount = 0;
  302. /* first pack in the RR's so we can get real counts */
  303. p = buf + 12;
  304. ep = buf + len;
  305. p = rrloop(m->qd, &m->qdcount, p, ep, &d, 1);
  306. p = rrloop(m->an, &m->ancount, p, ep, &d, 0);
  307. p = rrloop(m->ns, &m->nscount, p, ep, &d, 0);
  308. p = rrloop(m->ar, &m->arcount, p, ep, &d, 0);
  309. if(p > ep)
  310. return -1;
  311. /* now pack the rest */
  312. np = p;
  313. p = buf;
  314. ep = buf + len;
  315. USHORT(m->id);
  316. USHORT(m->flags);
  317. USHORT(m->qdcount);
  318. USHORT(m->ancount);
  319. USHORT(m->nscount);
  320. USHORT(m->arcount);
  321. if(p > ep)
  322. return -1;
  323. return np - buf;
  324. }