convM2DNS.c 13 KB

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