convM2DNS.c 11 KB

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