convM2DNS.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include "dns.h"
  5. typedef struct Scan Scan;
  6. struct Scan
  7. {
  8. uchar *base;
  9. uchar *p;
  10. uchar *ep;
  11. char *err;
  12. char errbuf[256]; /* hold a formatted error sometimes */
  13. int rcode; /* outgoing response codes (reply flags) */
  14. int stop; /* flag: stop processing */
  15. int trunc; /* flag: input truncated */
  16. };
  17. #define NAME(x) gname(x, rp, sp)
  18. #define SYMBOL(x) (x = gsym(rp, sp))
  19. #define STRING(x) (x = gstr(rp, sp))
  20. #define USHORT(x) (x = gshort(rp, sp))
  21. #define ULONG(x) (x = glong(rp, sp))
  22. #define UCHAR(x) (x = gchar(rp, sp))
  23. #define V4ADDR(x) (x = gv4addr(rp, sp))
  24. #define V6ADDR(x) (x = gv6addr(rp, sp))
  25. #define BYTES(x, y) (y = gbytes(rp, sp, &x, len - (sp->p - data)))
  26. static int
  27. errneg(RR *rp, Scan *sp, int actual)
  28. {
  29. snprint(sp->errbuf, sizeof sp->errbuf, "negative len %d: %R",
  30. actual, rp);
  31. sp->err = sp->errbuf;
  32. return 0;
  33. }
  34. static int
  35. errtoolong(RR *rp, Scan *sp, int remain, int need, char *where)
  36. {
  37. char *p, *ep;
  38. char ptype[64];
  39. p = sp->errbuf;
  40. ep = sp->errbuf + sizeof sp->errbuf - 1;
  41. if (where)
  42. p = seprint(p, ep, "%s: ", where);
  43. if (rp)
  44. p = seprint(p, ep, "type %s RR: ",
  45. rrname(rp->type, ptype, sizeof ptype));
  46. p = seprint(p, ep, "%d bytes needed; %d remain", need, remain);
  47. if (rp)
  48. seprint(p, ep, ": %R", rp);
  49. sp->err = sp->errbuf;
  50. /* hack to cope with servers that don't set Ftrunc when they should */
  51. if (remain < Maxudp && need > Maxudp)
  52. sp->trunc = 1;
  53. return 0;
  54. }
  55. /*
  56. * get a ushort/ulong
  57. */
  58. static ushort
  59. gchar(RR *rp, Scan *sp)
  60. {
  61. ushort x;
  62. if(sp->err)
  63. return 0;
  64. if(sp->ep - sp->p < 1)
  65. return errtoolong(rp, sp, sp->ep - sp->p, 1, "gchar");
  66. x = sp->p[0];
  67. sp->p += 1;
  68. return x;
  69. }
  70. static ushort
  71. gshort(RR *rp, Scan *sp)
  72. {
  73. ushort x;
  74. if(sp->err)
  75. return 0;
  76. if(sp->ep - sp->p < 2)
  77. return errtoolong(rp, sp, sp->ep - sp->p, 2, "gshort");
  78. x = sp->p[0]<<8 | sp->p[1];
  79. sp->p += 2;
  80. return x;
  81. }
  82. static ulong
  83. glong(RR *rp, Scan *sp)
  84. {
  85. ulong x;
  86. if(sp->err)
  87. return 0;
  88. if(sp->ep - sp->p < 4)
  89. return errtoolong(rp, sp, sp->ep - sp->p, 4, "glong");
  90. x = sp->p[0]<<24 | sp->p[1]<<16 | sp->p[2]<<8 | sp->p[3];
  91. sp->p += 4;
  92. return x;
  93. }
  94. /*
  95. * get an ip address
  96. */
  97. static DN*
  98. gv4addr(RR *rp, Scan *sp)
  99. {
  100. char addr[32];
  101. if(sp->err)
  102. return 0;
  103. if(sp->ep - sp->p < 4)
  104. return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr");
  105. snprint(addr, sizeof addr, "%V", sp->p);
  106. sp->p += 4;
  107. return dnlookup(addr, Cin, 1);
  108. }
  109. static DN*
  110. gv6addr(RR *rp, Scan *sp)
  111. {
  112. char addr[64];
  113. if(sp->err)
  114. return 0;
  115. if(sp->ep - sp->p < IPaddrlen)
  116. return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen,
  117. "gv6addr");
  118. snprint(addr, sizeof addr, "%I", sp->p);
  119. sp->p += IPaddrlen;
  120. return dnlookup(addr, Cin, 1);
  121. }
  122. /*
  123. * get a string. make it an internal symbol.
  124. */
  125. static DN*
  126. gsym(RR *rp, Scan *sp)
  127. {
  128. int n;
  129. char sym[Strlen+1];
  130. if(sp->err)
  131. return 0;
  132. n = 0;
  133. if (sp->p < sp->ep)
  134. n = *(sp->p++);
  135. if(sp->ep - sp->p < n)
  136. return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym");
  137. if(n > Strlen){
  138. sp->err = "illegal string (symbol)";
  139. return 0;
  140. }
  141. strncpy(sym, (char*)sp->p, n);
  142. sym[n] = 0;
  143. if (strlen(sym) != n)
  144. sp->err = "symbol shorter than declared length";
  145. sp->p += n;
  146. return dnlookup(sym, Csym, 1);
  147. }
  148. /*
  149. * get a string. don't make it an internal symbol.
  150. */
  151. static Txt*
  152. gstr(RR *rp, Scan *sp)
  153. {
  154. int n;
  155. char sym[Strlen+1];
  156. Txt *t;
  157. if(sp->err)
  158. return 0;
  159. n = 0;
  160. if (sp->p < sp->ep)
  161. n = *(sp->p++);
  162. if(sp->ep - sp->p < n)
  163. return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr");
  164. if(n > Strlen){
  165. sp->err = "illegal string";
  166. return 0;
  167. }
  168. strncpy(sym, (char*)sp->p, n);
  169. sym[n] = 0;
  170. if (strlen(sym) != n)
  171. sp->err = "string shorter than declared length";
  172. sp->p += n;
  173. t = emalloc(sizeof(*t));
  174. t->next = nil;
  175. t->p = estrdup(sym);
  176. return t;
  177. }
  178. /*
  179. * get a sequence of bytes
  180. */
  181. static int
  182. gbytes(RR *rp, Scan *sp, uchar **p, int n)
  183. {
  184. *p = nil; /* i think this is a good idea */
  185. if(sp->err)
  186. return 0;
  187. if(n < 0)
  188. return errneg(rp, sp, n);
  189. if(sp->ep - sp->p < n)
  190. return errtoolong(rp, sp, sp->ep - sp->p, n, "gbytes");
  191. *p = emalloc(n);
  192. memmove(*p, sp->p, n);
  193. sp->p += n;
  194. return n;
  195. }
  196. /*
  197. * get a domain name. 'to' must point to a buffer at least Domlen+1 long.
  198. */
  199. static char*
  200. gname(char *to, RR *rp, Scan *sp)
  201. {
  202. int len, off, pointer, n;
  203. char *tostart, *toend;
  204. uchar *p;
  205. tostart = to;
  206. if(sp->err || sp->stop)
  207. goto err;
  208. pointer = 0;
  209. p = sp->p;
  210. toend = to + Domlen;
  211. for(len = 0; *p && p < sp->ep; len += (pointer? 0: n+1)) {
  212. n = 0;
  213. switch (*p & 0300) {
  214. case 0: /* normal label */
  215. if (p < sp->ep)
  216. n = *p++ & 077; /* pick up length */
  217. if(len + n < Domlen - 1){
  218. if(n > toend - to){
  219. errtoolong(rp, sp, toend - to, n,
  220. "name too long");
  221. goto err;
  222. }
  223. memmove(to, p, n);
  224. to += n;
  225. }
  226. p += n;
  227. if(*p){
  228. if(to >= toend){
  229. errtoolong(rp, sp, toend - to, 2,
  230. "more name components but no bytes left");
  231. goto err;
  232. }
  233. *to++ = '.';
  234. }
  235. break;
  236. case 0100: /* edns extended label type, rfc 2671 */
  237. /*
  238. * treat it like an EOF for now; it seems to be at
  239. * the end of a long tcp reply.
  240. */
  241. dnslog("edns label; first byte 0%o = '%c'", *p, *p);
  242. sp->stop = 1;
  243. goto err;
  244. case 0200: /* reserved */
  245. sp->err = "reserved-use label present";
  246. goto err;
  247. case 0300: /* pointer to other spot in message */
  248. if(pointer++ > 10){
  249. sp->err = "pointer loop";
  250. goto err;
  251. }
  252. off = (p[0] & 077)<<8 | p[1];
  253. p = sp->base + off;
  254. if(p >= sp->ep){
  255. sp->err = "bad pointer";
  256. goto err;
  257. }
  258. n = 0;
  259. break;
  260. }
  261. }
  262. *to = 0;
  263. if(pointer)
  264. sp->p += len + 2; /* + 2 for pointer */
  265. else
  266. sp->p += len + 1; /* + 1 for the null domain */
  267. return tostart;
  268. err:
  269. *tostart = 0;
  270. return tostart;
  271. }
  272. /*
  273. * ms windows 2000 seems to get the bytes backward in the type field
  274. * of ptr records, so return a format error as feedback.
  275. */
  276. static void
  277. mstypehack(Scan *sp, int type, char *where)
  278. {
  279. if ((uchar)type == 0 && (uchar)(type>>8) != 0) {
  280. USED(where);
  281. // dnslog("%s: byte-swapped type field in ptr rr from win2k",
  282. // where);
  283. if (sp->rcode == 0)
  284. sp->rcode = Rformat;
  285. }
  286. }
  287. /*
  288. * convert the next RR from a message
  289. */
  290. static RR*
  291. convM2RR(Scan *sp, char *what)
  292. {
  293. int type, class, len;
  294. char dname[Domlen+1];
  295. uchar *data;
  296. RR *rp = nil;
  297. Txt *t, **l;
  298. retry:
  299. NAME(dname);
  300. USHORT(type);
  301. USHORT(class);
  302. mstypehack(sp, type, "convM2RR");
  303. rp = rralloc(type);
  304. rp->owner = dnlookup(dname, class, 1);
  305. rp->type = type;
  306. ULONG(rp->ttl);
  307. rp->ttl += now;
  308. USHORT(len);
  309. data = sp->p;
  310. /*
  311. * ms windows generates a lot of badly-formatted hints.
  312. * hints are only advisory, so don't log complaints about them.
  313. * it also generates answers in which p overshoots ep by exactly
  314. * one byte; this seems to be harmless, so don't log them either.
  315. */
  316. if (sp->ep - sp->p < len &&
  317. !(strcmp(what, "hints") == 0 ||
  318. sp->p == sp->ep + 1 && strcmp(what, "answers") == 0))
  319. errtoolong(rp, sp, sp->ep - sp->p, len, "convM2RR");
  320. if(sp->err || sp->rcode || sp->stop){
  321. rrfree(rp);
  322. return nil;
  323. }
  324. switch(type){
  325. default:
  326. /* unknown type, just ignore it */
  327. sp->p = data + len;
  328. rrfree(rp);
  329. rp = nil;
  330. goto retry;
  331. case Thinfo:
  332. SYMBOL(rp->cpu);
  333. SYMBOL(rp->os);
  334. break;
  335. case Tcname:
  336. case Tmb:
  337. case Tmd:
  338. case Tmf:
  339. case Tns:
  340. rp->host = dnlookup(NAME(dname), Cin, 1);
  341. break;
  342. case Tmg:
  343. case Tmr:
  344. rp->mb = dnlookup(NAME(dname), Cin, 1);
  345. break;
  346. case Tminfo:
  347. rp->rmb = dnlookup(NAME(dname), Cin, 1);
  348. rp->mb = dnlookup(NAME(dname), Cin, 1);
  349. break;
  350. case Tmx:
  351. USHORT(rp->pref);
  352. rp->host = dnlookup(NAME(dname), Cin, 1);
  353. break;
  354. case Ta:
  355. V4ADDR(rp->ip);
  356. break;
  357. case Taaaa:
  358. V6ADDR(rp->ip);
  359. break;
  360. case Tptr:
  361. rp->ptr = dnlookup(NAME(dname), Cin, 1);
  362. break;
  363. case Tsoa:
  364. rp->host = dnlookup(NAME(dname), Cin, 1);
  365. rp->rmb = dnlookup(NAME(dname), Cin, 1);
  366. ULONG(rp->soa->serial);
  367. ULONG(rp->soa->refresh);
  368. ULONG(rp->soa->retry);
  369. ULONG(rp->soa->expire);
  370. ULONG(rp->soa->minttl);
  371. break;
  372. case Tsrv:
  373. USHORT(rp->srv->pri);
  374. USHORT(rp->srv->weight);
  375. USHORT(rp->port);
  376. /*
  377. * rfc2782 sez no name compression but to be
  378. * backward-compatible with rfc2052, we try to expand the name.
  379. * if the length is under 64 bytes, either interpretation is
  380. * fine; if it's longer, we'll assume it's compressed,
  381. * as recommended by rfc3597.
  382. */
  383. rp->host = dnlookup(NAME(dname), Cin, 1);
  384. break;
  385. case Ttxt:
  386. l = &rp->txt;
  387. *l = nil;
  388. while(sp->p - data < len){
  389. STRING(t);
  390. *l = t;
  391. l = &t->next;
  392. }
  393. break;
  394. case Tnull:
  395. BYTES(rp->null->data, rp->null->dlen);
  396. break;
  397. case Trp:
  398. rp->rmb = dnlookup(NAME(dname), Cin, 1);
  399. rp->rp = dnlookup(NAME(dname), Cin, 1);
  400. break;
  401. case Tkey:
  402. USHORT(rp->key->flags);
  403. UCHAR(rp->key->proto);
  404. UCHAR(rp->key->alg);
  405. BYTES(rp->key->data, rp->key->dlen);
  406. break;
  407. case Tsig:
  408. USHORT(rp->sig->type);
  409. UCHAR(rp->sig->alg);
  410. UCHAR(rp->sig->labels);
  411. ULONG(rp->sig->ttl);
  412. ULONG(rp->sig->exp);
  413. ULONG(rp->sig->incep);
  414. USHORT(rp->sig->tag);
  415. rp->sig->signer = dnlookup(NAME(dname), Cin, 1);
  416. BYTES(rp->sig->data, rp->sig->dlen);
  417. break;
  418. case Tcert:
  419. USHORT(rp->cert->type);
  420. USHORT(rp->cert->tag);
  421. UCHAR(rp->cert->alg);
  422. BYTES(rp->cert->data, rp->cert->dlen);
  423. break;
  424. }
  425. if(sp->p - data != len) {
  426. char ptype[64];
  427. /*
  428. * ms windows 2000 generates cname queries for reverse lookups
  429. * with this particular error. don't bother logging it.
  430. *
  431. * server: input error: bad cname RR len (actual 2 != len 0):
  432. * 235.9.104.135.in-addr.arpa cname
  433. * 235.9.104.135.in-addr.arpa from 135.104.9.235
  434. */
  435. if (type == Tcname && sp->p - data == 2 && len == 0) {
  436. // dnslog("convM2RR: got %R", rp);
  437. return rp;
  438. }
  439. if (len > sp->p - data){
  440. dnslog("bad %s RR len (%d bytes nominal, %lud actual): %R",
  441. rrname(type, ptype, sizeof ptype), len,
  442. sp->p - data, rp);
  443. rrfree(rp);
  444. rp = nil;
  445. }
  446. }
  447. // if(rp) dnslog("convM2RR: got %R", rp);
  448. return rp;
  449. }
  450. /*
  451. * convert the next question from a message
  452. */
  453. static RR*
  454. convM2Q(Scan *sp)
  455. {
  456. char dname[Domlen+1];
  457. int type, class;
  458. RR *rp = nil;
  459. NAME(dname);
  460. USHORT(type);
  461. USHORT(class);
  462. if(sp->err || sp->rcode || sp->stop)
  463. return nil;
  464. mstypehack(sp, type, "convM2Q");
  465. rp = rralloc(type);
  466. rp->owner = dnlookup(dname, class, 1);
  467. return rp;
  468. }
  469. static RR*
  470. rrloop(Scan *sp, char *what, int count, int quest)
  471. {
  472. int i;
  473. RR *first, *rp, **l;
  474. if(sp->err || sp->rcode || sp->stop)
  475. return nil;
  476. l = &first;
  477. first = nil;
  478. for(i = 0; i < count; i++){
  479. rp = quest? convM2Q(sp): convM2RR(sp, what);
  480. if(rp == nil)
  481. break;
  482. setmalloctag(rp, getcallerpc(&sp));
  483. if(sp->err || sp->rcode || sp->stop){
  484. rrfree(rp);
  485. break;
  486. }
  487. *l = rp;
  488. l = &rp->next;
  489. }
  490. // setmalloctag(first, getcallerpc(&sp));
  491. return first;
  492. }
  493. /*
  494. * convert the next DNS from a message stream.
  495. * if there are formatting errors or the like during parsing of the message,
  496. * set *codep to the outgoing response code (e.g., Rformat), which will
  497. * abort processing and reply immediately with the outgoing response code.
  498. */
  499. char*
  500. convM2DNS(uchar *buf, int len, DNSmsg *m, int *codep)
  501. {
  502. char *err = nil;
  503. RR *rp = nil;
  504. Scan scan;
  505. Scan *sp;
  506. if (codep)
  507. *codep = 0;
  508. assert(len >= 0);
  509. sp = &scan;
  510. memset(sp, 0, sizeof *sp);
  511. sp->base = sp->p = buf;
  512. sp->ep = buf + len;
  513. sp->err = nil;
  514. sp->errbuf[0] = '\0';
  515. memset(m, 0, sizeof *m);
  516. USHORT(m->id);
  517. USHORT(m->flags);
  518. USHORT(m->qdcount);
  519. USHORT(m->ancount);
  520. USHORT(m->nscount);
  521. USHORT(m->arcount);
  522. m->qd = rrloop(sp, "questions", m->qdcount, 1);
  523. m->an = rrloop(sp, "answers", m->ancount, 0);
  524. m->ns = rrloop(sp, "nameservers",m->nscount, 0);
  525. if (sp->stop)
  526. sp->err = nil;
  527. if (sp->err)
  528. err = strdup(sp->err); /* live with bad ar's */
  529. m->ar = rrloop(sp, "hints", m->arcount, 0);
  530. if (sp->trunc)
  531. m->flags |= Ftrunc;
  532. if (sp->stop)
  533. sp->rcode = 0;
  534. if (codep)
  535. *codep = sp->rcode;
  536. return err;
  537. }