dnresolve.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include <bio.h>
  5. #include <ndb.h>
  6. #include "dns.h"
  7. enum
  8. {
  9. Maxdest= 24, /* maximum destinations for a request message */
  10. Maxtrans= 3, /* maximum transmissions to a server */
  11. };
  12. static int netquery(DN*, int, RR*, Request*, int);
  13. static RR* dnresolve1(char*, int, int, Request*, int, int);
  14. char *LOG = "dns";
  15. /*
  16. * reading /proc/pid/args yields either "name" or "name [display args]",
  17. * so return only display args, if any.
  18. */
  19. static char *
  20. procgetname(void)
  21. {
  22. int fd, n;
  23. char *lp, *rp;
  24. char buf[256];
  25. snprint(buf, sizeof buf, "#p/%d/args", getpid());
  26. if((fd = open(buf, OREAD)) < 0)
  27. return strdup("");
  28. *buf = '\0';
  29. n = read(fd, buf, sizeof buf-1);
  30. close(fd);
  31. if (n >= 0)
  32. buf[n] = '\0';
  33. if ((lp = strchr(buf, '[')) == nil ||
  34. (rp = strrchr(buf, ']')) == nil)
  35. return strdup("");
  36. *rp = '\0';
  37. return strdup(lp+1);
  38. }
  39. /*
  40. * lookup 'type' info for domain name 'name'. If it doesn't exist, try
  41. * looking it up as a canonical name.
  42. */
  43. RR*
  44. dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
  45. int recurse, int rooted, int *status)
  46. {
  47. RR *rp, *nrp, *drp;
  48. DN *dp;
  49. int loops;
  50. char *procname;
  51. char nname[Domlen];
  52. if(status)
  53. *status = 0;
  54. procname = procgetname();
  55. /*
  56. * hack for systems that don't have resolve search
  57. * lists. Just look up the simple name in the database.
  58. */
  59. if(!rooted && strchr(name, '.') == 0){
  60. rp = nil;
  61. drp = domainlist(class);
  62. for(nrp = drp; nrp != nil; nrp = nrp->next){
  63. snprint(nname, sizeof nname, "%s.%s", name,
  64. nrp->ptr->name);
  65. rp = dnresolve(nname, class, type, req, cn, depth,
  66. recurse, rooted, status);
  67. rrfreelist(rrremneg(&rp));
  68. if(rp != nil)
  69. break;
  70. }
  71. if(drp != nil)
  72. rrfree(drp);
  73. procsetname(procname);
  74. free(procname);
  75. return rp;
  76. }
  77. /*
  78. * try the name directly
  79. */
  80. rp = dnresolve1(name, class, type, req, depth, recurse);
  81. if(rp) {
  82. procsetname(procname);
  83. free(procname);
  84. return randomize(rp);
  85. }
  86. /* try it as a canonical name if we weren't told the name didn't exist */
  87. dp = dnlookup(name, class, 0);
  88. if(type != Tptr && dp->nonexistent != Rname)
  89. for(loops=0; rp == nil && loops < 32; loops++){
  90. rp = dnresolve1(name, class, Tcname, req, depth, recurse);
  91. if(rp == nil)
  92. break;
  93. if(rp->negative){
  94. rrfreelist(rp);
  95. rp = nil;
  96. break;
  97. }
  98. name = rp->host->name;
  99. if(cn)
  100. rrcat(cn, rp);
  101. else
  102. rrfreelist(rp);
  103. rp = dnresolve1(name, class, type, req, depth, recurse);
  104. }
  105. /* distinction between not found and not good */
  106. if(rp == nil && status != nil && dp->nonexistent != 0)
  107. *status = dp->nonexistent;
  108. procsetname(procname);
  109. free(procname);
  110. return randomize(rp);
  111. }
  112. static RR*
  113. dnresolve1(char *name, int class, int type, Request *req, int depth,
  114. int recurse)
  115. {
  116. DN *dp, *nsdp;
  117. RR *rp, *nsrp, *dbnsrp;
  118. char *cp;
  119. if(debug)
  120. syslog(0, LOG, "[%d] dnresolve1 %s %d %d",
  121. getpid(), name, type, class);
  122. /* only class Cin implemented so far */
  123. if(class != Cin)
  124. return nil;
  125. dp = dnlookup(name, class, 1);
  126. /*
  127. * Try the cache first
  128. */
  129. rp = rrlookup(dp, type, OKneg);
  130. if(rp)
  131. if(rp->db){
  132. /* unauthenticated db entries are hints */
  133. if(rp->auth)
  134. return rp;
  135. } else
  136. /* cached entry must still be valid */
  137. if(rp->ttl > now)
  138. /* but Tall entries are special */
  139. if(type != Tall || rp->query == Tall)
  140. return rp;
  141. rrfreelist(rp);
  142. /*
  143. * try the cache for a canonical name. if found punt
  144. * since we'll find it during the canonical name search
  145. * in dnresolve().
  146. */
  147. if(type != Tcname){
  148. rp = rrlookup(dp, Tcname, NOneg);
  149. rrfreelist(rp);
  150. if(rp)
  151. return nil;
  152. }
  153. /*
  154. * if we're running as just a resolver, go to our
  155. * designated name servers
  156. */
  157. if(resolver){
  158. nsrp = randomize(getdnsservers(class));
  159. if(nsrp != nil) {
  160. if(netquery(dp, type, nsrp, req, depth+1)){
  161. rrfreelist(nsrp);
  162. return rrlookup(dp, type, OKneg);
  163. }
  164. rrfreelist(nsrp);
  165. }
  166. }
  167. /*
  168. * walk up the domain name looking for
  169. * a name server for the domain.
  170. */
  171. for(cp = name; cp; cp = walkup(cp)){
  172. /*
  173. * if this is a local (served by us) domain,
  174. * return answer
  175. */
  176. dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0));
  177. if(dbnsrp && dbnsrp->local){
  178. rp = dblookup(name, class, type, 1, dbnsrp->ttl);
  179. rrfreelist(dbnsrp);
  180. return rp;
  181. }
  182. /*
  183. * if recursion isn't set, just accept local
  184. * entries
  185. */
  186. if(recurse == Dontrecurse){
  187. if(dbnsrp)
  188. rrfreelist(dbnsrp);
  189. continue;
  190. }
  191. /* look for ns in cache */
  192. nsdp = dnlookup(cp, class, 0);
  193. nsrp = nil;
  194. if(nsdp)
  195. nsrp = randomize(rrlookup(nsdp, Tns, NOneg));
  196. /* if the entry timed out, ignore it */
  197. if(nsrp && nsrp->ttl < now){
  198. rrfreelist(nsrp);
  199. nsrp = nil;
  200. }
  201. if(nsrp){
  202. rrfreelist(dbnsrp);
  203. /* try the name servers found in cache */
  204. if(netquery(dp, type, nsrp, req, depth+1)){
  205. rrfreelist(nsrp);
  206. return rrlookup(dp, type, OKneg);
  207. }
  208. rrfreelist(nsrp);
  209. continue;
  210. }
  211. /* use ns from db */
  212. if(dbnsrp){
  213. /* try the name servers found in db */
  214. if(netquery(dp, type, dbnsrp, req, depth+1)){
  215. /* we got an answer */
  216. rrfreelist(dbnsrp);
  217. return rrlookup(dp, type, NOneg);
  218. }
  219. rrfreelist(dbnsrp);
  220. }
  221. }
  222. /* settle for a non-authoritative answer */
  223. rp = rrlookup(dp, type, OKneg);
  224. if(rp)
  225. return rp;
  226. /* noone answered. try the database, we might have a chance. */
  227. return dblookup(name, class, type, 0, 0);
  228. }
  229. /*
  230. * walk a domain name one element to the right.
  231. * return a pointer to that element.
  232. * in other words, return a pointer to the parent domain name.
  233. */
  234. char*
  235. walkup(char *name)
  236. {
  237. char *cp;
  238. cp = strchr(name, '.');
  239. if(cp)
  240. return cp+1;
  241. else if(*name)
  242. return "";
  243. else
  244. return 0;
  245. }
  246. /*
  247. * Get a udpport for requests and replies. Put the port
  248. * into "headers" mode.
  249. */
  250. static char *hmsg = "headers";
  251. static char *ohmsg = "oldheaders";
  252. int
  253. udpport(char *mtpt)
  254. {
  255. int fd, ctl;
  256. char ds[64], adir[64];
  257. /* get a udp port */
  258. snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt? mtpt: "/net"));
  259. ctl = announce(ds, adir);
  260. if(ctl < 0){
  261. /* warning("can't get udp port"); */
  262. return -1;
  263. }
  264. /* turn on header style interface */
  265. if(write(ctl, hmsg, strlen(hmsg)) , 0){
  266. close(ctl);
  267. warning(hmsg);
  268. return -1;
  269. }
  270. write(ctl, ohmsg, strlen(ohmsg));
  271. /* grab the data file */
  272. snprint(ds, sizeof ds, "%s/data", adir);
  273. fd = open(ds, ORDWR);
  274. close(ctl);
  275. if(fd < 0)
  276. warning("can't open udp port %s: %r", ds);
  277. return fd;
  278. }
  279. int
  280. mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno)
  281. {
  282. DNSmsg m;
  283. int len;
  284. OUdphdr *uh = (OUdphdr*)buf;
  285. /* stuff port number into output buffer */
  286. memset(uh, 0, sizeof(*uh));
  287. hnputs(uh->rport, 53);
  288. /* make request and convert it to output format */
  289. memset(&m, 0, sizeof(m));
  290. m.flags = flags;
  291. m.id = reqno;
  292. m.qd = rralloc(type);
  293. m.qd->owner = dp;
  294. m.qd->type = type;
  295. len = convDNS2M(&m, &buf[OUdphdrsize], Maxudp);
  296. if(len < 0)
  297. abort(); /* "can't convert" */
  298. rrfree(m.qd);
  299. return len;
  300. }
  301. /* for alarms in readreply */
  302. static void
  303. ding(void *x, char *msg)
  304. {
  305. USED(x);
  306. if(strcmp(msg, "alarm") == 0)
  307. noted(NCONT);
  308. else
  309. noted(NDFLT);
  310. }
  311. static void
  312. freeanswers(DNSmsg *mp)
  313. {
  314. rrfreelist(mp->qd);
  315. rrfreelist(mp->an);
  316. rrfreelist(mp->ns);
  317. rrfreelist(mp->ar);
  318. mp->qd = mp->an = mp->ns = mp->ar = nil;
  319. }
  320. /*
  321. * read replies to a request. ignore any of the wrong type.
  322. * wait at most 5 seconds.
  323. */
  324. static int
  325. readreply(int fd, DN *dp, int type, ushort req,
  326. uchar *ibuf, DNSmsg *mp, ulong endtime, Request *reqp)
  327. {
  328. char *err;
  329. int len;
  330. ulong now;
  331. RR *rp;
  332. notify(ding);
  333. for(; ; freeanswers(mp)){
  334. now = time(0);
  335. if(now >= endtime)
  336. return -1; /* timed out */
  337. /* timed read */
  338. alarm((endtime - now) * 1000);
  339. len = read(fd, ibuf, OUdphdrsize+Maxudpin);
  340. alarm(0);
  341. len -= OUdphdrsize;
  342. if(len < 0)
  343. return -1; /* timed out */
  344. /* convert into internal format */
  345. memset(mp, 0, sizeof(*mp));
  346. err = convM2DNS(&ibuf[OUdphdrsize], len, mp, nil);
  347. if(err){
  348. syslog(0, LOG, "input err: %s: %I", err, ibuf);
  349. continue;
  350. }
  351. if(debug)
  352. logreply(reqp->id, ibuf, mp);
  353. /* answering the right question? */
  354. if(mp->id != req){
  355. syslog(0, LOG, "%d: id %d instead of %d: %I", reqp->id,
  356. mp->id, req, ibuf);
  357. continue;
  358. }
  359. if(mp->qd == 0){
  360. syslog(0, LOG, "%d: no question RR: %I", reqp->id, ibuf);
  361. continue;
  362. }
  363. if(mp->qd->owner != dp){
  364. syslog(0, LOG, "%d: owner %s instead of %s: %I",
  365. reqp->id, mp->qd->owner->name, dp->name, ibuf);
  366. continue;
  367. }
  368. if(mp->qd->type != type){
  369. syslog(0, LOG, "%d: type %d instead of %d: %I",
  370. reqp->id, mp->qd->type, type, ibuf);
  371. continue;
  372. }
  373. /* remember what request this is in answer to */
  374. for(rp = mp->an; rp; rp = rp->next)
  375. rp->query = type;
  376. return 0;
  377. }
  378. }
  379. /*
  380. * return non-0 if first list includes second list
  381. */
  382. int
  383. contains(RR *rp1, RR *rp2)
  384. {
  385. RR *trp1, *trp2;
  386. for(trp2 = rp2; trp2; trp2 = trp2->next){
  387. for(trp1 = rp1; trp1; trp1 = trp1->next){
  388. if(trp1->type == trp2->type)
  389. if(trp1->host == trp2->host)
  390. if(trp1->owner == trp2->owner)
  391. break;
  392. }
  393. if(trp1 == nil)
  394. return 0;
  395. }
  396. return 1;
  397. }
  398. typedef struct Dest Dest;
  399. struct Dest
  400. {
  401. uchar a[IPaddrlen]; /* ip address */
  402. DN *s; /* name server */
  403. int nx; /* number of transmissions */
  404. int code;
  405. };
  406. /*
  407. * return multicast version if any
  408. */
  409. int
  410. ipisbm(uchar *ip)
  411. {
  412. if(isv4(ip)){
  413. if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 ||
  414. ipcmp(ip, IPv4bcast) == 0)
  415. return 4;
  416. } else
  417. if(ip[0] == 0xff)
  418. return 6;
  419. return 0;
  420. }
  421. static Ndbtuple *indoms, *innmsrvs, *outnmsrvs;
  422. static QLock readlock;
  423. /*
  424. * is this domain (or DOMAIN or Domain or dOMAIN)
  425. * internal to our organisation (behind our firewall)?
  426. */
  427. static int
  428. insideaddr(char *dom)
  429. {
  430. int domlen, vallen;
  431. Ndb *db;
  432. Ndbs s;
  433. Ndbtuple *t;
  434. if (0 && indoms == nil) { /* not ready for prime time */
  435. db = ndbopen("/lib/ndb/local");
  436. if (db != nil) {
  437. qlock(&readlock);
  438. if (indoms == nil) { /* retest under lock */
  439. free(ndbgetvalue(db, &s, "sys", "inside-dom",
  440. "dom", &indoms));
  441. free(ndbgetvalue(db, &s, "sys", "inside-ns",
  442. "ip", &innmsrvs));
  443. free(ndbgetvalue(db, &s, "sys", "outside-ns",
  444. "ip", &outnmsrvs));
  445. }
  446. qunlock(&readlock);
  447. ndbclose(db); /* destroys *indoms, *innmsrvs? */
  448. }
  449. }
  450. if (indoms == nil)
  451. return 1; /* no "inside" sys, try inside nameservers */
  452. domlen = strlen(dom);
  453. for (t = indoms; t != nil; t = t->entry) {
  454. if (strcmp(t->attr, "dom") != 0)
  455. continue;
  456. vallen = strlen(t->val);
  457. if (cistrcmp(dom, t->val) == 0 ||
  458. domlen > vallen &&
  459. cistrcmp(dom + domlen - vallen, t->val) == 0 &&
  460. dom[domlen - vallen - 1] == '.')
  461. return 1;
  462. }
  463. return 0;
  464. }
  465. static int
  466. insidens(uchar *ip)
  467. {
  468. uchar ipa[IPaddrlen];
  469. Ndbtuple *t;
  470. for (t = innmsrvs; t != nil; t = t->entry)
  471. if (strcmp(t->attr, "ip") == 0) {
  472. parseip(ipa, t->val);
  473. if (memcmp(ipa, ip, sizeof ipa) == 0)
  474. return 1;
  475. }
  476. return 0;
  477. }
  478. static uchar *
  479. outsidens(void)
  480. {
  481. Ndbtuple *t;
  482. static uchar ipa[IPaddrlen];
  483. for (t = outnmsrvs; t != nil; t = t->entry)
  484. if (strcmp(t->attr, "ip") == 0) {
  485. parseip(ipa, t->val);
  486. return ipa;
  487. }
  488. return nil;
  489. }
  490. /*
  491. * Get next server address
  492. */
  493. static int
  494. serveraddrs(DN *dp, RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
  495. {
  496. RR *rp, *arp, *trp;
  497. Dest *cur;
  498. if(nd >= Maxdest)
  499. return 0;
  500. /*
  501. * look for a server whose address we already know.
  502. * if we find one, mark it so we ignore this on
  503. * subsequent passes.
  504. */
  505. arp = 0;
  506. for(rp = nsrp; rp; rp = rp->next){
  507. assert(rp->magic == RRmagic);
  508. if(rp->marker)
  509. continue;
  510. arp = rrlookup(rp->host, Ta, NOneg);
  511. if(arp){
  512. rp->marker = 1;
  513. break;
  514. }
  515. arp = dblookup(rp->host->name, Cin, Ta, 0, 0);
  516. if(arp){
  517. rp->marker = 1;
  518. break;
  519. }
  520. }
  521. /*
  522. * if the cache and database lookup didn't find any new
  523. * server addresses, try resolving one via the network.
  524. * Mark any we try to resolve so we don't try a second time.
  525. */
  526. if(arp == 0)
  527. for(rp = nsrp; rp; rp = rp->next){
  528. if(rp->marker)
  529. continue;
  530. rp->marker = 1;
  531. /*
  532. * avoid loops looking up a server under itself
  533. */
  534. if(subsume(rp->owner->name, rp->host->name))
  535. continue;
  536. arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0,
  537. depth+1, Recurse, 1, 0);
  538. rrfreelist(rrremneg(&arp));
  539. if(arp)
  540. break;
  541. }
  542. /* use any addresses that we found */
  543. for(trp = arp; trp; trp = trp->next){
  544. if(nd >= Maxdest)
  545. break;
  546. cur = &dest[nd];
  547. parseip(cur->a, trp->ip->name);
  548. if (ipisbm(cur->a) ||
  549. !insideaddr(dp->name) && insidens(cur->a))
  550. continue;
  551. cur->nx = 0;
  552. cur->s = trp->owner;
  553. cur->code = Rtimeout;
  554. nd++;
  555. }
  556. rrfreelist(arp);
  557. return nd;
  558. }
  559. /*
  560. * cache negative responses
  561. */
  562. static void
  563. cacheneg(DN *dp, int type, int rcode, RR *soarr)
  564. {
  565. RR *rp;
  566. DN *soaowner;
  567. ulong ttl;
  568. /* no cache time specified, don't make anything up */
  569. if(soarr != nil){
  570. if(soarr->next != nil){
  571. rrfreelist(soarr->next);
  572. soarr->next = nil;
  573. }
  574. soaowner = soarr->owner;
  575. } else
  576. soaowner = nil;
  577. /* the attach can cause soarr to be freed so mine it now */
  578. if(soarr != nil && soarr->soa != nil)
  579. ttl = soarr->soa->minttl+now;
  580. else
  581. ttl = 5*Min;
  582. /* add soa and negative RR to the database */
  583. rrattach(soarr, 1);
  584. rp = rralloc(type);
  585. rp->owner = dp;
  586. rp->negative = 1;
  587. rp->negsoaowner = soaowner;
  588. rp->negrcode = rcode;
  589. rp->ttl = ttl;
  590. rrattach(rp, 1);
  591. }
  592. /*
  593. * query name servers. If the name server returns a pointer to another
  594. * name server, recurse.
  595. */
  596. static int
  597. netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth,
  598. uchar *ibuf, uchar *obuf, int waitsecs, int inns)
  599. {
  600. int ndest, j, len, replywaits, rv;
  601. ulong endtime;
  602. ushort req;
  603. char buf[12];
  604. DN *ndp;
  605. DNSmsg m;
  606. Dest *p, *l, *np;
  607. Dest dest[Maxdest];
  608. RR *tp, *soarr;
  609. /* pack request into a message */
  610. req = rand();
  611. len = mkreq(dp, type, obuf, Frecurse|Oquery, req);
  612. /* no server addresses yet */
  613. l = dest;
  614. /*
  615. * transmit requests and wait for answers.
  616. * at most Maxtrans attempts to each address.
  617. * each cycle send one more message than the previous.
  618. */
  619. for(ndest = 1; ndest < Maxdest; ndest++){
  620. p = dest;
  621. endtime = time(0);
  622. if(endtime >= reqp->aborttime)
  623. break;
  624. /* get a server address if we need one */
  625. if(ndest > l - p){
  626. j = serveraddrs(dp, nsrp, dest, l - p, depth, reqp);
  627. l = &dest[j];
  628. }
  629. /* no servers, punt */
  630. if(l == dest)
  631. if (0 && inside) { /* not ready for prime time */
  632. /* HACK: use sys=outside ips */
  633. if (0 && outsidens() == nil)
  634. sysfatal("no outside-ns in ndb");
  635. p = dest;
  636. memmove(p->a, outsidens(), sizeof p->a);
  637. p->s = dnlookup("outside", Cin, 1);
  638. p->nx = p->code = 0;
  639. l = p + 1;
  640. } else {
  641. syslog(0, LOG, "netquery1: no servers for %s", dp->name); // DEBUG
  642. break;
  643. }
  644. /* send to first 'ndest' destinations */
  645. j = 0;
  646. for(; p < &dest[ndest] && p < l; p++){
  647. /* skip destinations we've finished with */
  648. if(p->nx >= Maxtrans)
  649. continue;
  650. j++;
  651. /* exponential backoff of requests */
  652. if((1<<p->nx) > ndest)
  653. continue;
  654. memmove(obuf, p->a, sizeof p->a);
  655. procsetname("req slave: %sside query to %I/%s %s %s",
  656. (inns? "in": "out"), obuf, p->s->name, dp->name,
  657. rrname(type, buf, sizeof buf));
  658. if(debug)
  659. logsend(reqp->id, depth, obuf, p->s->name,
  660. dp->name, type);
  661. /* actually send the UDP packet */
  662. if(write(fd, obuf, len + OUdphdrsize) < 0)
  663. warning("sending udp msg %r");
  664. p->nx++;
  665. }
  666. if(j == 0)
  667. break; /* no destinations left */
  668. endtime = time(0) + waitsecs;
  669. if(endtime > reqp->aborttime)
  670. endtime = reqp->aborttime;
  671. for(replywaits = 0; replywaits < ndest; replywaits++){
  672. procsetname(
  673. "req slave: reading %sside reply from %I for %s %s",
  674. (inns? "in": "out"), obuf, dp->name,
  675. rrname(type, buf, sizeof buf));
  676. memset(&m, 0, sizeof m);
  677. if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) < 0)
  678. break; /* timed out */
  679. /* find responder */
  680. for(p = dest; p < l; p++)
  681. if(memcmp(p->a, ibuf, sizeof(p->a)) == 0)
  682. break;
  683. /* remove all addrs of responding server from list */
  684. for(np = dest; np < l; np++)
  685. if(np->s == p->s)
  686. p->nx = Maxtrans;
  687. /* ignore any error replies */
  688. if((m.flags & Rmask) == Rserver){
  689. rrfreelist(m.qd);
  690. rrfreelist(m.an);
  691. rrfreelist(m.ar);
  692. rrfreelist(m.ns);
  693. if(p != l)
  694. p->code = Rserver;
  695. continue;
  696. }
  697. /* ignore any bad delegations */
  698. if(m.ns && baddelegation(m.ns, nsrp, ibuf)){
  699. rrfreelist(m.ns);
  700. m.ns = nil;
  701. if(m.an == nil){
  702. rrfreelist(m.qd);
  703. rrfreelist(m.ar);
  704. if(p != l)
  705. p->code = Rserver;
  706. continue;
  707. }
  708. }
  709. /* remove any soa's from the authority section */
  710. soarr = rrremtype(&m.ns, Tsoa);
  711. /* incorporate answers */
  712. if(m.an)
  713. rrattach(m.an, (m.flags & Fauth) != 0);
  714. if(m.ar)
  715. rrattach(m.ar, 0);
  716. if(m.ns){
  717. ndp = m.ns->owner;
  718. rrattach(m.ns, 0);
  719. } else
  720. ndp = nil;
  721. /* free the question */
  722. if(m.qd)
  723. rrfreelist(m.qd);
  724. /*
  725. * Any reply from an authoritative server,
  726. * or a positive reply terminates the search
  727. */
  728. if(m.an != nil || (m.flags & Fauth)){
  729. if(m.an == nil && (m.flags & Rmask) == Rname)
  730. dp->nonexistent = Rname;
  731. else
  732. dp->nonexistent = 0;
  733. /*
  734. * cache any negative responses, free soarr
  735. */
  736. if((m.flags & Fauth) && m.an == nil)
  737. cacheneg(dp, type, (m.flags & Rmask),
  738. soarr);
  739. else
  740. rrfreelist(soarr);
  741. return 1;
  742. }
  743. rrfreelist(soarr);
  744. /*
  745. * if we've been given better name servers,
  746. * recurse. we're called from udpquery, called from
  747. * netquery, which current holds dp->querylck,
  748. * so release it now and acquire it upon return.
  749. */
  750. if(m.ns){
  751. tp = rrlookup(ndp, Tns, NOneg);
  752. if(!contains(nsrp, tp)){
  753. procsetname(
  754. "req slave: recursive query for %s %s",
  755. dp->name,
  756. rrname(type, buf, sizeof buf));
  757. qunlock(&dp->querylck);
  758. rv = netquery(dp, type, tp, reqp,
  759. depth + 1);
  760. qlock(&dp->querylck);
  761. rrfreelist(tp);
  762. return rv;
  763. } else
  764. rrfreelist(tp);
  765. }
  766. }
  767. }
  768. /* if all servers returned failure, propagate it */
  769. dp->nonexistent = Rserver;
  770. for(p = dest; p < l; p++)
  771. if(p->code != Rserver)
  772. dp->nonexistent = 0;
  773. return 0;
  774. }
  775. enum { Hurry, Patient, };
  776. enum { Outns, Inns, };
  777. static int
  778. udpquery(char *mntpt, DN *dp, int type, RR *nsrp, Request *reqp, int depth,
  779. int patient, int inns)
  780. {
  781. int fd, rv = 0;
  782. uchar *obuf, *ibuf;
  783. /* use alloced buffers rather than ones from the stack */
  784. ibuf = emalloc(Maxudpin+OUdphdrsize);
  785. obuf = emalloc(Maxudp+OUdphdrsize);
  786. fd = udpport(mntpt);
  787. if(fd >= 0) {
  788. reqp->aborttime = time(0) + (patient? Maxreqtm: Maxreqtm/2);
  789. rv = netquery1(fd, dp, type, nsrp, reqp, depth,
  790. ibuf, obuf, (patient? 15: 10), inns);
  791. close(fd);
  792. }
  793. free(obuf);
  794. free(ibuf);
  795. return rv;
  796. }
  797. /* look up (dp->name,type) via *nsrp with results in *reqp */
  798. static int
  799. netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth)
  800. {
  801. int lock, rv, triedin;
  802. RR *rp;
  803. if(depth > 12) /* in a recursive loop? */
  804. return 0;
  805. slave(reqp); /* might fork */
  806. /* if so, parent process longjmped to req->mret; we're child slave */
  807. if (!reqp->isslave)
  808. syslog(0, LOG,
  809. "[%d] netquery: slave returned with reqp->isslave==0",
  810. getpid());
  811. /* don't lock before call to slave so only children can block */
  812. lock = reqp->isslave != 0;
  813. if(lock) {
  814. procsetname("waiting for query lock on %s", dp->name);
  815. /* don't make concurrent queries for this name */
  816. qlock(&dp->querylck);
  817. procsetname("netquery: %s", dp->name);
  818. }
  819. /* prepare server RR's for incremental lookup */
  820. for(rp = nsrp; rp; rp = rp->next)
  821. rp->marker = 0;
  822. rv = 0; /* pessimism */
  823. triedin = 0;
  824. /*
  825. * don't bother to query the broken inside nameservers for outside
  826. * addresses.
  827. */
  828. if (!inside || insideaddr(dp->name)) {
  829. rv = udpquery(mntpt, dp, type, nsrp, reqp, depth, Hurry,
  830. (inside? Inns: Outns));
  831. triedin = 1;
  832. }
  833. /*
  834. * if we're still looking and have an outside address,
  835. * try it on our outside interface, if any.
  836. */
  837. if (rv == 0 && inside && !insideaddr(dp->name)) {
  838. if (triedin)
  839. syslog(0, LOG,
  840. "[%d] netquery: internal nameservers failed for %s; trying external",
  841. getpid(), dp->name);
  842. /* prepare server RR's for incremental lookup */
  843. for(rp = nsrp; rp; rp = rp->next)
  844. rp->marker = 0;
  845. rv = udpquery("/net.alt", dp, type, nsrp, reqp, depth, Patient,
  846. Outns);
  847. if (rv == 0)
  848. syslog(0, LOG, "[%d] netquery: no luck for %s",
  849. getpid(), dp->name);
  850. }
  851. if(lock)
  852. qunlock(&dp->querylck);
  853. return rv;
  854. }