convM2DNS.c 13 KB

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