domain.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:41k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /*
  2.  * DOMAIN.C -- domain name system stub resolver
  3.  *
  4.  * Original code by Phil Karn, KA9Q.
  5.  *
  6.  * Apr 90 Bill Simpson added address->name resolution, time-to-live,
  7.  * thru memory caching, generalized multi-record multi-type searches,
  8.  * Oct 90 and many minor changes to conform more closely to the RFCs.
  9.  * Feb 91 Bill Simpson added "query" command and TYPE_ANY processing.
  10.  * Jul 91 Bill Simpson added "more" sessions for query and cache list.
  11.  */
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include <time.h>
  15. #include <sys/stat.h>
  16. #include "global.h"
  17. #include "mbuf.h"
  18. #include "proc.h"
  19. #include "ip.h"
  20. #include "netuser.h"
  21. #include "session.h"
  22. #include "socket.h"
  23. #include "cmdparse.h"
  24. #include "commands.h"
  25. #include "files.h"
  26. #include "main.h"
  27. #include "domain.h"
  28. #undef DEBUG /* for certain trace messages */
  29. #undef DEBUG_PAIN /* for painful debugging */
  30. static struct rr *Dcache = NULL; /* Cache of resource records */
  31. static int Dcache_size = 20; /* size limit */
  32. static time_t Dcache_time = 0L;  /* timestamp */
  33. static int Dfile_clean = FALSE;  /* discard expired records (flag) */
  34. static int Dfile_reading = 0; /* read interlock (count) */
  35. static int Dfile_writing = 0; /* write interlock (count) */
  36. struct proc *Dfile_updater = NULL;
  37. static int32 Dfile_wait_absolute = 0L; /* timeout Clock time */
  38. static int Dfile_wait_relative = 300; /* timeout file activity (seconds) */
  39. static struct dserver *Dservers = NULL; /* List of potential servers */
  40. static int Dserver_retries = 2; /* Attempts to reach servers */
  41. static char *Dsuffix = NULL; /* Default suffix for names without periods */
  42. static int Dtrace = FALSE;
  43. static char *Dtypes[] = {
  44. "",
  45. "A",
  46. "NS",
  47. "MD",
  48. "MF",
  49. "CNAME",
  50. "SOA",
  51. "MB",
  52. "MG",
  53. "MR",
  54. "NULL",
  55. "WKS",
  56. "PTR",
  57. "HINFO",
  58. "MINFO",
  59. "MX",
  60. "TXT"
  61. };
  62. static int Ndtypes = 17;
  63. static char delim[] = " trn";
  64. static int docache(int argc,char *argv[],void *p);
  65. static int dosuffix(int argc,char *argv[],void *p);
  66. static int docacheclean(int argc,char *argv[],void *p);
  67. static int docachelist(int argc,char *argv[],void *p);
  68. static int docachesize(int argc,char *argv[],void *p);
  69. static int docachewait(int argc,char *argv[],void *p);
  70. static void dlist_add(struct dserver *dp);
  71. static void dlist_drop(struct dserver *dp);
  72. static int dodnsadd(int argc,char *argv[],void *p);
  73. static int dodnsdrop(int argc,char *argv[],void *p);
  74. static int dodnslist(int argc,char *argv[],void *p);
  75. static int dodnsquery(int argc,char *argv[],void *p);
  76. static int dodnsretry(int argc,char *argv[],void *p);
  77. static int dodnstrace(int argc,char *argv[],void *p);
  78. static char * dtype(int value);
  79. static int check_ttl(struct rr *rrlp);
  80. static int compare_rr(struct rr *search_rrp,struct rr *target_rrp);
  81. static int compare_rr_list(struct rr *rrlp,struct rr *target_rrp);
  82. static struct rr *copy_rr(struct rr *rrp);
  83. static struct rr *copy_rr_list(struct rr *rrlp);
  84. static struct rr *make_rr(int source,
  85. char *dname,uint16 class,uint16 type,int32 ttl,uint16 rdl,void *data);
  86. static void dcache_add(struct rr *rrlp);
  87. static void dcache_drop(struct rr *rrp);
  88. static struct rr *dcache_search(struct rr *rrlp);
  89. static void dcache_update(struct rr *rrlp);
  90. static struct rr *get_rr(FILE *fp, struct rr *lastrrp);
  91. static void put_rr(FILE *fp,struct rr *rrp);
  92. static struct rr *dfile_search(struct rr *rrlp);
  93. static void dfile_update(int s,void *unused,void *p);
  94. static void dumpdomain(struct dhdr *dhp,int32 rtt);
  95. static int dns_makequery(uint16 op,struct rr *rrp,
  96. uint8 *buffer,uint16 buflen);
  97. static int dns_query(struct rr *rrlp);
  98. static int isaddr(char *s);
  99. static char *checksuffix(char *dname);
  100. static struct rr *resolver(struct rr *rrlp);
  101. /**
  102.  ** Domain Resolver Commands
  103.  **/
  104. static struct cmds Dcmds[] = {
  105. "addserver", dodnsadd, 0, 2, "add <hostid>",
  106. "dropserver", dodnsdrop, 0, 2, "drop <hostid>",
  107. "list", dodnslist, 0, 0, NULL,
  108. "query", dodnsquery,   512, 2, "query <hostid>",
  109. "retry", dodnsretry, 0, 0, NULL,
  110. "suffix", dosuffix, 0, 0, NULL,
  111. "trace", dodnstrace, 0, 0, NULL,
  112. "cache", docache, 0, 0, NULL,
  113. NULL,
  114. };
  115. static struct cmds Dcachecmds[] = {
  116. "clean", docacheclean, 0, 0, NULL,
  117. "list", docachelist,  512, 0, NULL,
  118. "size", docachesize, 0, 0, NULL,
  119. "wait", docachewait, 0, 0, NULL,
  120. NULL,
  121. };
  122. int
  123. dodomain(argc,argv,p)
  124. int argc;
  125. char *argv[];
  126. void *p;
  127. {
  128. return subcmd(Dcmds,argc,argv,p);
  129. }
  130. static int
  131. docache(argc,argv,p)
  132. int argc;
  133. char *argv[];
  134. void *p;
  135. {
  136. return subcmd(Dcachecmds,argc,argv,p);
  137. }
  138. static int
  139. dosuffix(argc,argv,p)
  140. int argc;
  141. char *argv[];
  142. void *p;
  143. {
  144. if(argc < 2){
  145. if(Dsuffix != NULL)
  146. printf("%sn",Dsuffix);
  147. return 0;
  148. }
  149. free(Dsuffix);
  150. Dsuffix = strdup(argv[1]);
  151. return 0;
  152. }
  153. static int
  154. docacheclean(argc,argv,p)
  155. int argc;
  156. char *argv[];
  157. void *p;
  158. {
  159. return setbool( &Dfile_clean, "discard expired records", argc,argv );
  160. }
  161. static int
  162. docachelist(argc,argv,p)
  163. int argc;
  164. char *argv[];
  165. void *p;
  166. {
  167. struct rr *rrp;
  168. struct session *sp;
  169. int row = 25;
  170. if((sp = newsession(Cmdline,DCLIST,1)) == NULL){
  171. return -1;
  172. }
  173. (void)dcache_search(NULL); /* update ttl */
  174. /* Put tty into raw mode so single-char responses will work */
  175. sp->ttystate.echo = sp->ttystate.edit = 0;
  176. for(rrp=Dcache;rrp!=NULL;rrp=rrp->next)
  177. {
  178. put_rr(stdout,rrp);
  179. if(--row == 0){
  180. row = keywait("--More--",0);
  181. switch(row){
  182. case -1:
  183. case 'q':
  184. case 'Q':
  185. rrp = NULL;
  186. break;
  187. case 'n':
  188. case 'r':
  189. row = 1;
  190. break;
  191. case ' ':
  192. default:
  193. row = 25;
  194. };
  195. }
  196. }
  197. fflush(stdout);
  198. keywait(NULL,1);
  199. freesession(sp);
  200. return 0;
  201. }
  202. static int
  203. docachesize(argc,argv,p)
  204. int argc;
  205. char *argv[];
  206. void *p;
  207. {
  208. int newsize;
  209. int oldsize;
  210. int result;
  211. newsize = oldsize = Dcache_size;
  212. result = setint( &newsize, "memory cache size", argc,argv );
  213. if(newsize > 0){
  214. Dcache_size = newsize;
  215. if(newsize < oldsize){
  216. (void)dcache_search(NULL); /* update size */
  217. }
  218. }
  219. return result;
  220. }
  221. static int
  222. docachewait(argc,argv,p)
  223. int argc;
  224. char *argv[];
  225. void *p;
  226. {
  227. return setint( &Dfile_wait_relative, "time before file update (seconds)", argc,argv );
  228. }
  229. static void
  230. dlist_add(dp)
  231. register struct dserver *dp;
  232. {
  233. dp->prev = NULL;
  234. dp->next = Dservers;
  235. if(Dservers != NULL)
  236. Dservers->prev = dp;
  237. Dservers = dp;
  238. }
  239. static void
  240. dlist_drop(dp)
  241. register struct dserver *dp;
  242. {
  243. if(dp->prev != NULL)
  244. dp->prev->next = dp->next;
  245. else
  246. Dservers = dp->next;
  247. if(dp->next != NULL)
  248. dp->next->prev = dp->prev;
  249. }
  250. static int
  251. dodnsadd(argc,argv,p)
  252. int argc;
  253. char *argv[];
  254. void *p;
  255. {
  256. int32 address;
  257. if((address = resolve(argv[1])) == 0L){
  258. printf("Resolver %s unknownn",argv[1]);
  259. return 1;
  260. }
  261. return add_nameserver(address);
  262. }
  263. int
  264. add_nameserver(address)
  265. int32 address;
  266. {
  267. struct dserver *dp;
  268. dp = (struct dserver *)callocw(1,sizeof(struct dserver));
  269. dp->address = address;
  270. dp->srtt = INITRTT;
  271. dp->mdev = 0;
  272. dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  273. dlist_add(dp);
  274. return 0;
  275. }
  276. static int
  277. dodnsdrop(argc,argv,p)
  278. int argc;
  279. char *argv[];
  280. void *p;
  281. {
  282. struct dserver *dp;
  283. int32 addr;
  284. addr = resolve(argv[1]);
  285. for(dp = Dservers;dp != NULL;dp = dp->next)
  286. if(addr == dp->address)
  287. break;
  288. if(dp == NULL){
  289. printf("Not foundn");
  290. return 1;
  291. }
  292. dlist_drop(dp);
  293. free(dp);
  294. return 0;
  295. }
  296. static int
  297. dodnslist(argc,argv,p)
  298. int argc;
  299. char *argv[];
  300. void *p;
  301. {
  302. register struct dserver *dp;
  303. printf("Server address          srtt    mdev   timeout   queries responsesn");
  304. for(dp = Dservers;dp != NULL;dp = dp->next){
  305. printf("%-20s%8lu%8lu%10lu%10lu%10lun",
  306.  inet_ntoa(dp->address),
  307.  dp->srtt,dp->mdev,dp->timeout,
  308.  dp->queries,dp->responses);
  309. }
  310. return 0;
  311. }
  312. static int
  313. dodnsquery(argc,argv,p)
  314. int argc;
  315. char *argv[];
  316. void *p;
  317. {
  318. struct rr *rrp;
  319. struct rr *result_rrlp;
  320. char *sname;
  321. struct session *sp;
  322. int row = 25;
  323. if((sp = newsession(Cmdline,DQUERY,1)) == NULL){
  324. return -1;
  325. }
  326. if ( isaddr( argv[1] ) ) {
  327. result_rrlp = inverse_a( aton( argv[1] ) );
  328. } else {
  329. sname = checksuffix( argv[1] );
  330. rrp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_ANY,0,0,NULL);
  331. FREE(sname);
  332. dns_query(rrp);
  333. result_rrlp = dcache_search(rrp);
  334. free_rr(rrp);
  335. }
  336. /* Put tty into raw mode so single-char responses will work */
  337. sp->ttystate.echo = sp->ttystate.edit = 0;
  338. for( rrp=result_rrlp; rrp!=NULL; rrp=rrp->next)
  339. {
  340. put_rr(stdout,rrp);
  341. if(--row == 0){
  342. row = keywait("--More--",0);
  343. switch(row){
  344. case -1:
  345. case 'q':
  346. case 'Q':
  347. rrp = NULL;
  348. break;
  349. case 'n':
  350. case 'r':
  351. row = 1;
  352. break;
  353. case ' ':
  354. default:
  355. row = 25;
  356. };
  357. }
  358. }
  359. fflush(stdout);
  360. free_rr(result_rrlp);
  361. keywait(NULL,1);
  362. freesession(sp);
  363. return 0;
  364. }
  365. static int
  366. dodnsretry(argc,argv,p)
  367. int argc;
  368. char *argv[];
  369. void *p;
  370. {
  371. return setint( &Dserver_retries, "server retries", argc,argv );
  372. }
  373. static int
  374. dodnstrace(argc,argv,p)
  375. int argc;
  376. char *argv[];
  377. void *p;
  378. {
  379. return setbool(&Dtrace,"server trace",argc,argv);
  380. }
  381. /**
  382.  ** Domain Resource Record Utilities
  383.  **/
  384. static char *
  385. dtype(value)
  386. int value;
  387. {
  388. static char buf[10];
  389. if (value < Ndtypes)
  390. return Dtypes[value];
  391. sprintf( buf, "{%d}", value);
  392. return buf;
  393. }
  394. /* check list of resource records for any expired ones.
  395.  * returns number of expired records.
  396.  */
  397. static int
  398. check_ttl(rrlp)
  399. register struct rr *rrlp;
  400. {
  401. int count = 0;
  402. while(rrlp != NULL){
  403. if(rrlp->ttl == 0L)
  404. count++;
  405. rrlp = rrlp->next;
  406. }
  407. return count;
  408. }
  409. /* Compare two resource records.
  410.  * returns 0 if match, nonzero otherwise.
  411.  */
  412. static int
  413. compare_rr(search_rrp,target_rrp)
  414. register struct rr *search_rrp,*target_rrp;
  415. {
  416. int i;
  417. if(search_rrp == NULL || target_rrp == NULL)
  418. return -32765;
  419. if(search_rrp->class != target_rrp->class)
  420. return -32763;
  421. if(search_rrp->type != TYPE_ANY
  422. && search_rrp->type != target_rrp->type
  423. && (search_rrp->source != RR_QUERY
  424.  || (target_rrp->type != TYPE_CNAME
  425.   && target_rrp->type != TYPE_PTR)))
  426. return -32761;
  427. if(search_rrp->source != RR_INQUERY){
  428. if((i = strlen(search_rrp->name)) != strlen(target_rrp->name))
  429. return -32759;
  430. if((i = strnicmp(search_rrp->name,target_rrp->name,i)) != 0)
  431. return i;
  432. /* match negative records so that they are replaced */
  433. if(target_rrp->rdlength == 0)
  434. return 0;
  435. }
  436. /* if a query has gotten this far, match it */
  437. if(search_rrp->source == RR_QUERY)
  438. return 0;
  439. /* ensure negative records don't replace older records */
  440. if(search_rrp->rdlength == 0)
  441. return -32757;
  442. /* match expired records so that they are replaced */
  443. if(search_rrp->source != RR_INQUERY){
  444. if(target_rrp->ttl == 0L)
  445. return 0;
  446. }
  447. /* Note: rdlengths are not compared because they vary depending
  448.  * on the representation (ASCII or encoded) this record was
  449.  * generated from.
  450.  */
  451. switch(search_rrp->type){
  452. case TYPE_A:
  453. i = search_rrp->rdata.addr != target_rrp->rdata.addr;
  454. break;
  455. case TYPE_CNAME:
  456. case TYPE_MB:
  457. case TYPE_MG:
  458. case TYPE_MR:
  459. case TYPE_NS:
  460. case TYPE_PTR:
  461. case TYPE_TXT:
  462. i = stricmp(search_rrp->rdata.data,target_rrp->rdata.data);
  463. break;
  464. case TYPE_HINFO:
  465. i = strcmp(search_rrp->rdata.hinfo.cpu,target_rrp->rdata.hinfo.cpu) ||
  466. strcmp(search_rrp->rdata.hinfo.os,target_rrp->rdata.hinfo.os);
  467. break;
  468. case TYPE_MX:
  469. i = stricmp(search_rrp->rdata.mx.exch,target_rrp->rdata.mx.exch);
  470. break;
  471. case TYPE_SOA:
  472. i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
  473. break;
  474. default:
  475. i = -32755; /* unsupported */
  476. }
  477. return i;
  478. }
  479. static int
  480. compare_rr_list(rrlp,target_rrp)
  481. register struct rr *rrlp,*target_rrp;
  482. {
  483. while(rrlp != NULL){
  484. if(compare_rr(rrlp,target_rrp) == 0)
  485. return 0;
  486. #ifdef DEBUG_PAIN
  487. if(Dtrace)
  488. printf("%15d %sn",
  489. compare_rr(rrlp,target_rrp),
  490. target_rrp->name);
  491. #endif
  492. rrlp = rrlp->next;
  493. }
  494. return -32767;
  495. }
  496. /* Make a new copy of a resource record */
  497. static struct rr *
  498. copy_rr(rrp)
  499. register struct rr *rrp;
  500. {
  501. register struct rr *newrr;
  502. if(rrp == NULL)
  503. return NULL;
  504. newrr = (struct rr *)callocw(1,sizeof(struct rr));
  505. newrr->source = rrp->source;
  506. newrr->name = strdup(rrp->name);
  507. newrr->type = rrp->type;
  508. newrr->class = rrp->class;
  509. newrr->ttl = rrp->ttl;
  510. if((newrr->rdlength = rrp->rdlength) == 0)
  511. return newrr;
  512. switch(rrp->type){
  513. case TYPE_A:
  514. newrr->rdata.addr = rrp->rdata.addr;
  515. break;
  516. case TYPE_CNAME:
  517. case TYPE_MB:
  518. case TYPE_MG:
  519. case TYPE_MR:
  520. case TYPE_NS:
  521. case TYPE_PTR:
  522. case TYPE_TXT:
  523. newrr->rdata.name = strdup(rrp->rdata.name);
  524. break;
  525. case TYPE_HINFO:
  526. newrr->rdata.hinfo.cpu = strdup(rrp->rdata.hinfo.cpu);
  527. newrr->rdata.hinfo.os = strdup(rrp->rdata.hinfo.os);
  528. break;
  529. case TYPE_MX:
  530. newrr->rdata.mx.pref = rrp->rdata.mx.pref;
  531. newrr->rdata.mx.exch = strdup(rrp->rdata.mx.exch);
  532. break;
  533. case TYPE_SOA:
  534. newrr->rdata.soa.mname =  strdup(rrp->rdata.soa.mname);
  535. newrr->rdata.soa.rname =  strdup(rrp->rdata.soa.rname);
  536. newrr->rdata.soa.serial =  rrp->rdata.soa.serial;
  537. newrr->rdata.soa.refresh =  rrp->rdata.soa.refresh;
  538. newrr->rdata.soa.retry =  rrp->rdata.soa.retry;
  539. newrr->rdata.soa.expire =  rrp->rdata.soa.expire;
  540. newrr->rdata.soa.minimum =  rrp->rdata.soa.minimum;
  541. break;
  542. }
  543. return newrr;
  544. }
  545. static struct rr *
  546. copy_rr_list(rrlp)
  547. register struct rr *rrlp;
  548. {
  549. register struct rr **rrpp;
  550. struct rr *result_rrlp;
  551. rrpp = &result_rrlp;
  552. while(rrlp != NULL){
  553. *rrpp = copy_rr(rrlp);
  554. rrpp = &(*rrpp)->next;
  555. rrlp = rrlp->next;
  556. }
  557. *rrpp = NULL;
  558. return result_rrlp;
  559. }
  560. /* Free (list of) resource records */
  561. void
  562. free_rr(rrlp)
  563. register struct rr *rrlp;
  564. {
  565. register struct rr *rrp;
  566. while((rrp = rrlp) != NULL){
  567. rrlp = rrlp->next;
  568. free(rrp->comment);
  569. free(rrp->name);
  570. if(rrp->rdlength > 0){
  571. switch(rrp->type){
  572. case TYPE_A:
  573. break; /* Nothing allocated in rdata section */
  574. case TYPE_CNAME:
  575. case TYPE_MB:
  576. case TYPE_MG:
  577. case TYPE_MR:
  578. case TYPE_NS:
  579. case TYPE_PTR:
  580. case TYPE_TXT:
  581. free(rrp->rdata.name);
  582. break;
  583. case TYPE_HINFO:
  584. free(rrp->rdata.hinfo.cpu);
  585. free(rrp->rdata.hinfo.os);
  586. break;
  587. case TYPE_MX:
  588. free(rrp->rdata.mx.exch);
  589. break;
  590. case TYPE_SOA:
  591. free(rrp->rdata.soa.mname);
  592. free(rrp->rdata.soa.rname);
  593. break;
  594. }
  595. }
  596. free(rrp);
  597. }
  598. }
  599. static struct rr *
  600. make_rr(source,dname,dclass,dtype,ttl,rdl,data)
  601. int source;
  602. char *dname;
  603. uint16 dclass;
  604. uint16 dtype;
  605. int32 ttl;
  606. uint16 rdl;
  607. void *data;
  608. {
  609. register struct rr *newrr;
  610. newrr = (struct rr *)callocw(1,sizeof(struct rr));
  611. newrr->source = source;
  612. newrr->name = strdup(dname);
  613. newrr->class = dclass;
  614. newrr->type = dtype;
  615. newrr->ttl = ttl;
  616. if((newrr->rdlength = rdl) == 0)
  617. return newrr;
  618. switch(dtype){
  619. case TYPE_A:
  620.   {
  621. register int32 *ap = (int32 *)data;
  622. newrr->rdata.addr = *ap;
  623. break;
  624.   }
  625. case TYPE_CNAME:
  626. case TYPE_MB:
  627. case TYPE_MG:
  628. case TYPE_MR:
  629. case TYPE_NS:
  630. case TYPE_PTR:
  631. case TYPE_TXT:
  632.   {
  633. newrr->rdata.name = strdup((char *)data);
  634. break;
  635.   }
  636. case TYPE_HINFO:
  637.   {
  638. register struct hinfo *hinfop = (struct hinfo *)data;
  639. newrr->rdata.hinfo.cpu = strdup(hinfop->cpu);
  640. newrr->rdata.hinfo.os = strdup(hinfop->os);
  641. break;
  642.   }
  643. case TYPE_MX:
  644.   {
  645. register struct mx *mxp = (struct mx *)data;
  646. newrr->rdata.mx.pref = mxp->pref;
  647. newrr->rdata.mx.exch = strdup(mxp->exch);
  648. break;
  649.   }
  650. case TYPE_SOA:
  651.   {
  652. register struct soa *soap = (struct soa *)data;
  653. newrr->rdata.soa.mname =  strdup(soap->mname);
  654. newrr->rdata.soa.rname =  strdup(soap->rname);
  655. newrr->rdata.soa.serial =  soap->serial;
  656. newrr->rdata.soa.refresh =  soap->refresh;
  657. newrr->rdata.soa.retry =  soap->retry;
  658. newrr->rdata.soa.expire =  soap->expire;
  659. newrr->rdata.soa.minimum =  soap->minimum;
  660. break;
  661.   }
  662. }
  663. return newrr;
  664. }
  665. /**
  666.  ** Domain Cache Utilities
  667.  **/
  668. static void
  669. dcache_add(rrlp)
  670. register struct rr *rrlp;
  671. {
  672. register struct rr *last_rrp;
  673. struct rr *save_rrp;
  674. if(rrlp == NULL)
  675. return;
  676. save_rrp = rrlp;
  677. last_rrp = NULL;
  678. while(rrlp != NULL){
  679. rrlp->last = last_rrp;
  680. last_rrp = rrlp;
  681. rrlp = rrlp->next;
  682. }
  683. last_rrp->next = Dcache;
  684. if(Dcache != NULL)
  685. Dcache->last = last_rrp;
  686. Dcache = save_rrp;
  687. }
  688. static void
  689. dcache_drop(rrp)
  690. register struct rr *rrp;
  691. {
  692. if(rrp->last != NULL)
  693. rrp->last->next = rrp->next;
  694. else
  695. Dcache = rrp->next;
  696. if(rrp->next != NULL)
  697. rrp->next->last = rrp->last;
  698. rrp->last =
  699. rrp->next = NULL;
  700. }
  701. /* Search cache for resource records, removing them from the cache.
  702.  * Also, timeout cache entries, and trim cache to size.
  703.  * (Calling with NULL is legal -- will timeout & trim only.)
  704.  * Note that an answer from the cache cannot be authoritative, because
  705.  * we cannot guarantee that all the entries remain from a previous request.
  706.  * Returns RR list, or NULL if no record found.
  707.  */
  708. static struct rr *
  709. dcache_search(rrlp)
  710. struct rr *rrlp;
  711. {
  712. register struct rr *rrp, *test_rrp;
  713. struct rr **rrpp, *result_rrlp;
  714. int32 elapsed;
  715. time_t now;
  716. int count = 0;
  717. #ifdef DEBUG
  718. if(Dtrace && rrlp != NULL){
  719. printf("dcache_search: searching for %sn",rrlp->name);
  720. }
  721. #endif
  722. elapsed = (int32)(time(&now) - Dcache_time);
  723. Dcache_time = now;
  724. rrpp = &result_rrlp;
  725. for(rrp = Dcache; (test_rrp = rrp) != NULL;){
  726. rrp = rrp->next;
  727. /* timeout entries */
  728. if(test_rrp->ttl > 0L
  729. && (test_rrp->ttl -= elapsed) <= 0L)
  730. test_rrp->ttl = 0L;
  731. if(compare_rr_list(rrlp,test_rrp) == 0){
  732. dcache_drop( *rrpp = test_rrp );
  733. rrpp = &(*rrpp)->next;
  734. } else if(test_rrp->source == RR_FILE && ++count > Dcache_size){
  735. dcache_drop(test_rrp);
  736. free_rr(test_rrp);
  737. }
  738. }
  739. *rrpp = NULL;
  740. return result_rrlp;
  741. }
  742. /* Move a list of resource records to the cache, removing duplicates. */
  743. static void
  744. dcache_update(rrlp)
  745. register struct rr *rrlp;
  746. {
  747. if(rrlp == NULL)
  748. return;
  749. free_rr(dcache_search(rrlp)); /* remove duplicates, first */
  750. dcache_add(rrlp);
  751. }
  752. /**
  753.  ** File Utilities
  754.  **/
  755. static struct rr *
  756. get_rr(fp,lastrrp)
  757. FILE *fp;
  758. struct rr *lastrrp;
  759. {
  760. char *line,*lp,*strtok();
  761. struct rr *rrp;
  762. char *name,*ttl,*class,*type,*data;
  763. int i;
  764. line = mallocw(256);
  765. if(fgets(line,256,fp) == NULL){
  766. free(line);
  767. return NULL;
  768. }
  769. rrp = (struct rr *)callocw(1,sizeof(struct rr));
  770. rrp->source = RR_FILE;
  771. if(line[0] == '' || line[0] == '#' || line[0] == ';'){
  772. rrp->comment = line;
  773. return rrp;
  774. }
  775. if(!isspace(line[0]) || lastrrp == NULL){
  776. name = strtok(line,delim);
  777. lp = NULL;
  778. } else { /* Name field is missing */
  779. name = lastrrp->name;
  780. lp = line;
  781. }
  782. if(name == NULL || (i = strlen(name)) == 0){
  783. rrp->comment = strdup("n");
  784. free(line);
  785. return rrp;
  786. }
  787. if(name[i-1] != '.'){
  788. /* Tack on a trailing period if it's not there */
  789. /* !!! need to implement $ORIGIN suffix here */
  790. rrp->name = mallocw(i+2);
  791. strcpy(rrp->name,name);
  792. strcat(rrp->name,".");
  793. } else
  794. rrp->name = strdup(name);
  795. ttl = strtok(lp,delim);
  796. if(ttl == NULL || (!isdigit(ttl[0]) && ttl[0] != '-')){
  797. /* Optional ttl field is missing */
  798. rrp->ttl = TTL_MISSING;
  799. class = ttl;
  800. } else {
  801. rrp->ttl = atol(ttl);
  802. class = strtok(NULL,delim);
  803. }
  804. if(class == NULL){
  805. /* we're in trouble, but keep processing */
  806. rrp->class = CLASS_MISSING;
  807. type = class;
  808. } else if(class[0] == '<'){
  809. rrp->class = atoi(&class[1]);
  810. type = strtok(NULL,delim);
  811. } else if(stricmp(class,"IN") == 0){
  812. rrp->class = CLASS_IN;
  813. type = strtok(NULL,delim);
  814. } else {
  815. /* Optional class field is missing; assume IN */
  816. rrp->class = CLASS_IN;
  817. type = class;
  818. }
  819. if(type == NULL){
  820. /* we're in trouble, but keep processing */
  821. rrp->type = TYPE_MISSING;
  822. data = type;
  823. } else if(type[0] == '{'){
  824. rrp->type = atoi(&class[1]);
  825. data = strtok(NULL,delim);
  826. } else {
  827. rrp->type = TYPE_MISSING;
  828. for(i=1;i<Ndtypes;i++){
  829. if(stricmp(type,Dtypes[i]) == 0){
  830. rrp->type = i;
  831. data = strtok(NULL,delim);
  832. break;
  833. }
  834. }
  835. }
  836. if(rrp->type == TYPE_MISSING){
  837. data = NULL;
  838. }
  839. if(data == NULL){
  840. /* Empty record, just return */
  841. free(line);
  842. return rrp;
  843. }
  844. switch(rrp->type){
  845. case TYPE_A:
  846. rrp->rdlength = 4;
  847. rrp->rdata.addr = aton(data);
  848. break;
  849. case TYPE_CNAME:
  850. case TYPE_MB:
  851. case TYPE_MG:
  852. case TYPE_MR:
  853. case TYPE_NS:
  854. case TYPE_PTR:
  855. case TYPE_TXT:
  856. rrp->rdlength = strlen(data);
  857. rrp->rdata.name = strdup(data);
  858. break;
  859. case TYPE_HINFO:
  860. rrp->rdlength = strlen(data);
  861. rrp->rdata.hinfo.cpu = strdup(data);
  862. if((data = strtok(NULL,delim)) != NULL){
  863. rrp->rdlength += strlen(data);
  864. rrp->rdata.hinfo.os = strdup(data);
  865. }
  866. break;
  867. case TYPE_MX:
  868. rrp->rdata.mx.pref = atoi(data);
  869. rrp->rdlength = 2;
  870. /* Get domain name of exchanger */
  871. if((data = strtok(NULL,delim)) != NULL){
  872. rrp->rdlength += strlen(data);
  873. rrp->rdata.mx.exch = strdup(data);
  874. }
  875. break;
  876. case TYPE_SOA:
  877. /* Get domain name of master name server */
  878. rrp->rdlength = strlen(data);
  879. rrp->rdata.soa.mname = strdup(data);
  880. /* Get domain name of irresponsible person */
  881. if((data = strtok(NULL,delim)) != NULL){
  882. rrp->rdata.soa.rname = strdup(data);
  883. rrp->rdlength += strlen(data);
  884. }
  885. data = strtok(NULL,delim);
  886. rrp->rdata.soa.serial = atol(data);
  887. data = strtok(NULL,delim);
  888. rrp->rdata.soa.refresh = atol(data);
  889. data = strtok(NULL,delim);
  890. rrp->rdata.soa.retry = atol(data);
  891. data = strtok(NULL,delim);
  892. rrp->rdata.soa.expire = atol(data);
  893. data = strtok(NULL,delim);
  894. rrp->rdata.soa.minimum = atol(data);
  895. rrp->rdlength += 20;
  896. break;
  897. }
  898. /* !!! need to handle trailing comments */
  899. free(line);
  900. return rrp;
  901. }
  902. /* Print a resource record */
  903. static void
  904. put_rr(fp,rrp)
  905. FILE *fp;
  906. struct rr *rrp;
  907. {
  908. char * stuff;
  909. if(fp == NULL || rrp == NULL)
  910. return;
  911. if(rrp->name == NULL && rrp->comment != NULL){
  912. fprintf(fp,"%s",rrp->comment);
  913. return;
  914. }
  915. fprintf(fp,"%s",rrp->name);
  916. if(rrp->ttl != TTL_MISSING)
  917. fprintf(fp,"t%ld",rrp->ttl);
  918. if(rrp->class == CLASS_IN)
  919. fprintf(fp,"tIN");
  920. else
  921. fprintf(fp,"t<%u>",rrp->class);
  922. stuff = dtype(rrp->type);
  923. fprintf(fp,"t%s",stuff);
  924. if(rrp->rdlength == 0){
  925. /* Null data portion, indicates nonexistent record */
  926. /* or unsupported type.  Hopefully, these will filter */
  927. /* as time goes by. */
  928. fprintf(fp,"n");
  929. return;
  930. }
  931. switch(rrp->type){
  932. case TYPE_A:
  933. fprintf(fp,"t%sn",inet_ntoa(rrp->rdata.addr));
  934. break;
  935. case TYPE_CNAME:
  936. case TYPE_MB:
  937. case TYPE_MG:
  938. case TYPE_MR:
  939. case TYPE_NS:
  940. case TYPE_PTR:
  941. case TYPE_TXT:
  942. /* These are all printable text strings */
  943. fprintf(fp,"t%sn",rrp->rdata.data);
  944. break;
  945. case TYPE_HINFO:
  946. fprintf(fp,"t%st%sn",
  947.  rrp->rdata.hinfo.cpu,
  948.  rrp->rdata.hinfo.os);
  949. break;
  950. case TYPE_MX:
  951. fprintf(fp,"t%ut%sn",
  952.  rrp->rdata.mx.pref,
  953.  rrp->rdata.mx.exch);
  954. break;
  955. case TYPE_SOA:
  956. fprintf(fp,"t%st%st%lut%lut%lut%lut%lun",
  957.  rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  958.  rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  959.  rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  960.  rrp->rdata.soa.minimum);
  961. break;
  962. default:
  963. fprintf(fp,"n");
  964. break;
  965. }
  966. }
  967. /* Search local database for resource records.
  968.  * Returns RR list, or NULL if no record found.
  969.  */
  970. static struct rr *
  971. dfile_search(rrlp)
  972. struct rr *rrlp;
  973. {
  974. register struct rr *frrp;
  975. struct rr **rrpp, *result_rrlp, *oldrrp;
  976. int32 elapsed;
  977. FILE *dbase;
  978. struct stat dstat;
  979. #ifdef DEBUG
  980. if(Dtrace){
  981. printf("dfile_search: searching for %sn",rrlp->name);
  982. }
  983. #endif
  984. while(Dfile_writing > 0)
  985. kwait(&Dfile_reading);
  986. Dfile_reading++;
  987. if((dbase = fopen(Dfile,READ_TEXT)) == NULL){
  988. Dfile_reading--;
  989. return NULL;
  990. }
  991. if(fstat(fileno(dbase),&dstat) != 0){
  992. printf("dfile_search: can't get file statusn");
  993. fclose(dbase);
  994. Dfile_reading--;
  995. return NULL;
  996. }
  997. if((elapsed = (int32)(Dcache_time - (time_t)dstat.st_ctime)) < 0L)
  998. elapsed = -elapsed; /* arbitrary time mismatch */
  999. result_rrlp = NULL; /* for contiguous test below */
  1000. oldrrp = NULL;
  1001. rrpp = &result_rrlp;
  1002. while((frrp = get_rr(dbase,oldrrp)) != NULL){
  1003. free_rr(oldrrp);
  1004. if(frrp->type != TYPE_MISSING
  1005. && frrp->rdlength > 0
  1006. && compare_rr_list(rrlp,frrp) == 0){
  1007. if(frrp->ttl > 0L
  1008. && (frrp->ttl -= elapsed) <= 0L)
  1009. frrp->ttl = 0L;
  1010. *rrpp = frrp;
  1011. rrpp = &(*rrpp)->next;
  1012. oldrrp = copy_rr(frrp);
  1013. } else {
  1014. oldrrp = frrp;
  1015. /*
  1016. All records of the same name and the same type
  1017. are contiguous.  Therefore, for a single query,
  1018. we can stop searching.  Multiple queries must
  1019. read the whole file.
  1020. */
  1021. if(rrlp->type != TYPE_ANY
  1022. && rrlp->next == NULL
  1023. && result_rrlp != NULL)
  1024. break;
  1025. }
  1026. if(!main_exit)
  1027. kwait(NULL); /* run multiple sessions */
  1028. }
  1029. free_rr(oldrrp);
  1030. *rrpp = NULL;
  1031. fclose(dbase);
  1032. if(--Dfile_reading <= 0){
  1033. Dfile_reading = 0;
  1034. ksignal(&Dfile_writing,0);
  1035. }
  1036. return result_rrlp;
  1037. }
  1038. /* Process which will add new resource records from the cache
  1039.  * to the local file, eliminating duplicates while it goes.
  1040.  */
  1041. static void
  1042. dfile_update(s,unused,p)
  1043. int s;
  1044. void *unused;
  1045. void *p;
  1046. {
  1047. struct rr **rrpp, *rrlp, *oldrrp;
  1048. char *newname;
  1049. FILE *old_fp, *new_fp;
  1050. struct stat old_stat, new_stat;
  1051. logmsg(-1,"update Domain.txt initiated");
  1052. /* Produce output on command session rather than the one
  1053.  * that invoked us
  1054.  */
  1055. fclose(stdin);
  1056. stdin = fdup(Cmdpp->input);
  1057. fclose(stdout);
  1058. stdout = fdup(Cmdpp->output);
  1059. newname = strdup(Dfile);
  1060. strcpy(&newname[strlen(newname)-3],"tmp");
  1061. while(Dfile_wait_absolute != 0L && !main_exit){
  1062. register struct rr *frrp;
  1063. int32 elapsed;
  1064. while(Dfile_wait_absolute != 0L){
  1065. elapsed = Dfile_wait_absolute - secclock();
  1066. Dfile_wait_absolute = 0L;
  1067. if(elapsed > 0L && !main_exit){
  1068. kalarm(elapsed*1000L);
  1069. kwait(&Dfile_wait_absolute);
  1070. kalarm(0L);
  1071. }
  1072. }
  1073. logmsg(-1,"update Domain.txt");
  1074. /* create new file for copy */
  1075. if((new_fp = fopen(newname,WRITE_TEXT)) == NULL){
  1076. printf("dfile_update: can't create %s!n",newname);
  1077. break;
  1078. }
  1079. if(fstat(fileno(new_fp),&new_stat) != 0){
  1080. printf("dfile_update: can't get new_file status!n");
  1081. fclose(new_fp);
  1082. break;
  1083. }
  1084. kwait(NULL); /* file operations can be slow */
  1085. /* timeout the cache one last time before writing */
  1086. (void)dcache_search(NULL);
  1087. /* copy new RRs out to the new file */
  1088. /* (can't wait here, the cache might change) */
  1089. rrpp = &rrlp;
  1090. for(frrp = Dcache; frrp != NULL; frrp = frrp->next ){
  1091. switch(frrp->source){
  1092. case RR_QUESTION:
  1093. case RR_ANSWER:
  1094. case RR_AUTHORITY:
  1095. case RR_ADDITIONAL:
  1096. *rrpp = copy_rr(frrp);
  1097. if(frrp->type != TYPE_MISSING
  1098. && frrp->rdlength > 0)
  1099. put_rr(new_fp,frrp);
  1100. rrpp = &(*rrpp)->next;
  1101. frrp->source = RR_FILE;
  1102. break;
  1103. }
  1104. }
  1105. *rrpp = NULL;
  1106. /* open up the old file, concurrently with everyone else */
  1107. if((old_fp = fopen(Dfile,READ_TEXT)) == NULL){
  1108. /* great! no old file, so we're ready to go. */
  1109. fclose(new_fp);
  1110. rename(newname,Dfile);
  1111. free_rr(rrlp);
  1112. break;
  1113. }
  1114. if(fstat(fileno(old_fp),&old_stat) != 0){
  1115. printf("dfile_update: can't get old_file status!n");
  1116. fclose(new_fp);
  1117. fclose(old_fp);
  1118. free_rr(rrlp);
  1119. break;
  1120. }
  1121. if((elapsed = (int32)(new_stat.st_ctime - old_stat.st_ctime)) < 0L)
  1122. elapsed = -elapsed; /* file times are inconsistant */
  1123. /* Now append any non-duplicate records */
  1124. oldrrp = NULL;
  1125. while((frrp = get_rr(old_fp,oldrrp)) != NULL){
  1126. free_rr(oldrrp);
  1127. if(frrp->name == NULL
  1128. && frrp->comment != NULL)
  1129. put_rr(new_fp,frrp);
  1130. if(frrp->type != TYPE_MISSING
  1131. && frrp->rdlength > 0
  1132. && compare_rr_list(rrlp,frrp) != 0){
  1133. if(frrp->ttl > 0L
  1134. && (frrp->ttl -= elapsed) <= 0L)
  1135. frrp->ttl = 0L;
  1136. if(frrp->ttl != 0 || !Dfile_clean)
  1137. put_rr(new_fp,frrp);
  1138. }
  1139. oldrrp = frrp;
  1140. if(!main_exit)
  1141. kwait(NULL); /* run in background */
  1142. }
  1143. free_rr(oldrrp);
  1144. fclose(new_fp);
  1145. fclose(old_fp);
  1146. free_rr(rrlp);
  1147. /* wait for everyone else to finish reading */
  1148. Dfile_writing++;
  1149. while(Dfile_reading > 0)
  1150. kwait(&Dfile_writing);
  1151. unlink(Dfile);
  1152. rename(newname,Dfile);
  1153. Dfile_writing = 0;
  1154. ksignal(&Dfile_reading,0);
  1155. }
  1156. free(newname);
  1157. logmsg(-1,"update Domain.txt finished");
  1158. Dfile_updater = NULL;
  1159. }
  1160. /**
  1161.  ** Domain Server Utilities
  1162.  **/
  1163. static void
  1164. dumpdomain(dhp,rtt)
  1165. struct dhdr *dhp;
  1166. int32 rtt;
  1167. {
  1168. struct rr *rrp;
  1169. char * stuff;
  1170. printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %un",
  1171.  dhp->id,(long)rtt / 1000L,
  1172.  dhp->qr,dhp->opcode,dhp->aa,dhp->tc,dhp->rd,
  1173.  dhp->ra,dhp->rcode);
  1174. printf("%u questions:n",dhp->qdcount);
  1175. for(rrp = dhp->questions; rrp != NULL; rrp = rrp->next){
  1176. stuff = dtype(rrp->type);
  1177. printf("%s type %s class %un",rrp->name,
  1178.  stuff,rrp->class);
  1179. }
  1180. printf("%u answers:n",dhp->ancount);
  1181. for(rrp = dhp->answers; rrp != NULL; rrp = rrp->next){
  1182. put_rr(stdout,rrp);
  1183. }
  1184. printf("%u authority:n",dhp->nscount);
  1185. for(rrp = dhp->authority; rrp != NULL; rrp = rrp->next){
  1186. put_rr(stdout,rrp);
  1187. }
  1188. printf("%u additional:n",dhp->arcount);
  1189. for(rrp = dhp->additional; rrp != NULL; rrp = rrp->next){
  1190. put_rr(stdout,rrp);
  1191. }
  1192. fflush(stdout);
  1193. }
  1194. static int
  1195. dns_makequery(op,srrp,buffer,buflen)
  1196. uint16 op; /* operation */
  1197. struct rr *srrp;/* Search RR */
  1198. uint8 *buffer; /* Area for query */
  1199. uint16 buflen; /* Length of same */
  1200. {
  1201. uint8 *cp;
  1202. char *cp1;
  1203. char *dname, *sname;
  1204. uint16 parameter;
  1205. uint16 dlen,len;
  1206. cp = buffer;
  1207. /* Use millisecond clock for timestamping */
  1208. cp = put16(cp,(uint16)msclock());
  1209. parameter = (op << 11)
  1210. | 0x0100; /* Recursion desired */
  1211. cp = put16(cp,parameter);
  1212. cp = put16(cp,1);
  1213. cp = put16(cp,0);
  1214. cp = put16(cp,0);
  1215. cp = put16(cp,0);
  1216. sname = strdup(srrp->name);
  1217. dname = sname;
  1218. dlen = strlen(dname);
  1219. for(;;){
  1220. /* Look for next dot */
  1221. cp1 = strchr(dname,'.');
  1222. if(cp1 != NULL)
  1223. len = cp1-dname; /* More to come */
  1224. else
  1225. len = dlen; /* Last component */
  1226. *cp++ = len; /* Write length of component */
  1227. if(len == 0)
  1228. break;
  1229. /* Copy component up to (but not including) dot */
  1230. strncpy((char *)cp,dname,len);
  1231. cp += len;
  1232. if(cp1 == NULL){
  1233. *cp++ = 0; /* Last one; write null and finish */
  1234. break;
  1235. }
  1236. dname += len+1;
  1237. dlen -= len+1;
  1238. }
  1239. free(sname);
  1240. cp = put16(cp,srrp->type);
  1241. cp = put16(cp,srrp->class);
  1242. return cp - buffer;
  1243. }
  1244. /* domain server resolution loop
  1245.  * returns: any answers in cache.
  1246.  * (future features)
  1247.  * multiple queries.
  1248.  * inverse queries.
  1249.  * return value: 0 if something added to cache, -1 if error
  1250.  */
  1251. static int
  1252. dns_query(rrlp)
  1253. struct rr *rrlp;
  1254. {
  1255. struct mbuf *bp;
  1256. struct dhdr *dhp;
  1257. struct dserver *dp; /* server list */
  1258. int32 rtt,abserr;
  1259. int tried = 0; /* server list has been retried (count) */
  1260. if((dp = Dservers) == NULL)
  1261. return -1;
  1262. for(;;){
  1263. uint8 *buf;
  1264. int len;
  1265. struct sockaddr_in server_in;
  1266. int s;
  1267. int rval;
  1268. dp->queries++;
  1269. s = socket(AF_INET,SOCK_DGRAM,0);
  1270. server_in.sin_family = AF_INET;
  1271. server_in.sin_port = IPPORT_DOMAIN;
  1272. server_in.sin_addr.s_addr = dp->address;
  1273. if(Dtrace){
  1274. printf("dns_query: querying server %s for %sn",
  1275.  inet_ntoa(dp->address),rrlp->name);
  1276. }
  1277. buf = mallocw(512);
  1278. len = dns_makequery(0,rrlp,buf,512);
  1279. if(sendto(s,buf,len,0,(struct sockaddr *)&server_in,sizeof(server_in)) == -1)
  1280. perror("domain sendto");
  1281. FREE(buf);
  1282. kalarm(max(dp->timeout,100));
  1283. /* Wait for something to happen */
  1284. rval = recv_mbuf(s,&bp,0,NULL,0);
  1285. kalarm(0L);
  1286. close_s(s);
  1287. if(Dtrace){
  1288. if(errno == 0)
  1289. printf("dns_query: received message length %dn",rval);
  1290. else
  1291. perror("dns_query");
  1292. }
  1293. if(rval > 0)
  1294. break;
  1295. if(errno == EABORT)
  1296. return -1; /* Killed by "reset" command */
  1297. /* Timeout; back off this one and try another server */
  1298. dp->timeout <<= 1;
  1299. if((dp = dp->next) == NULL){
  1300. dp = Dservers;
  1301. if(Dserver_retries > 0 && ++tried > Dserver_retries)
  1302. return -1;
  1303. }
  1304. }
  1305. /* got a response */
  1306. dp->responses++;
  1307. dhp = (struct dhdr *) mallocw(sizeof(struct dhdr));
  1308. ntohdomain(dhp,&bp); /* Convert to local format */
  1309. /* Compute and update the round trip time */
  1310. rtt = (int32) ((uint16)msclock() - dhp->id);
  1311. abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
  1312. dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  1313. dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  1314. dp->timeout = 4 * dp->mdev + dp->srtt;
  1315. /* move to top of list for next time */
  1316. if(dp->prev != NULL){
  1317. dlist_drop(dp);
  1318. dlist_add(dp);
  1319. }
  1320. if(Dtrace)
  1321. dumpdomain(dhp,rtt);
  1322. /* Add negative reply to answers.  This assumes that there was
  1323.  * only one question, which is true for all questions we send.
  1324.  */
  1325. if(dhp->aa && (dhp->rcode == NAME_ERROR || dhp->ancount == 0)){
  1326. register struct rr *rrp;
  1327. long ttl = 600L; /* Default TTL for negative records */
  1328. /* look for SOA ttl */
  1329. for(rrp = dhp->authority; rrp != NULL; rrp = rrp->next){
  1330. if(rrp->type == TYPE_SOA)
  1331. ttl = rrp->ttl;
  1332. }
  1333. /* make the questions the negative answers */
  1334. for(rrp = dhp->questions; rrp != NULL; rrp = rrp->next)
  1335. rrp->ttl = ttl;
  1336. } else {
  1337. free_rr(dhp->questions);
  1338. dhp->questions = NULL;
  1339. }
  1340. /* post in reverse order to maintain original order */
  1341. dcache_update(dhp->additional);
  1342. dcache_update(dhp->authority);
  1343. dcache_update(dhp->answers);
  1344. dcache_update(dhp->questions);
  1345. Dfile_wait_absolute = secclock() + Dfile_wait_relative;
  1346. if(Dfile_updater == NULL){
  1347. Dfile_updater = newproc("domain update",
  1348. 512,dfile_update,0,NULL,NULL,0);
  1349. }
  1350. #ifdef DEBUG
  1351. if(Dtrace)
  1352. keywait(NULL,1); /* so we can look around */
  1353. #endif
  1354. free(dhp);
  1355. return 0;
  1356. }
  1357. /**
  1358.  ** Resolver Utilities
  1359.  **/
  1360. /* Return TRUE if string appears to be an IP address in dotted decimal;
  1361.  * return FALSE otherwise (i.e., if string is a domain name)
  1362.  */
  1363. static int
  1364. isaddr(s)
  1365. register char *s;
  1366. {
  1367. char c;
  1368. if(s == NULL)
  1369. return TRUE; /* Can't happen */
  1370. while((c = *s++) != ''){
  1371. if(c != '[' && c != ']' && !isdigit(c) && c != '.')
  1372. return FALSE;
  1373. }
  1374. return TRUE;
  1375. }
  1376. /* Return "normalized" domain name, with default suffix and trailing '.'
  1377.  */
  1378. static char *
  1379. checksuffix(dname)
  1380. char *dname;
  1381. {
  1382. char *sname, *tname;
  1383. sname = strdup(dname);
  1384. if(strchr(sname,'.') == NULL && Dsuffix != NULL){
  1385. /* Append default suffix */
  1386. tname = mallocw(strlen(sname)+strlen(Dsuffix)+2);
  1387. sprintf(tname,"%s.%s",sname,Dsuffix);
  1388. free(sname);
  1389. sname = tname;
  1390. }
  1391. if(sname[strlen(sname)-1] != '.'){
  1392. /* Append trailing dot */
  1393. tname = mallocw(strlen(sname)+2);
  1394. sprintf(tname,"%s.",sname);
  1395. free(sname);
  1396. sname = tname;
  1397. }
  1398. return sname;
  1399. }
  1400. /* Search for resource records.
  1401.  * Returns RR list, or NULL if no record found.
  1402.  */
  1403. static struct rr *
  1404. resolver(rrlp)
  1405. register struct rr *rrlp;
  1406. {
  1407. register struct rr *result_rrlp;
  1408. if((result_rrlp = dcache_search(rrlp)) == NULL){
  1409. result_rrlp = dfile_search(rrlp);
  1410. }
  1411. if(result_rrlp == NULL || check_ttl(result_rrlp) != 0){
  1412. dcache_add(result_rrlp);  /* save any expired RRs */
  1413. if(dns_query(rrlp) == -1)
  1414. return NULL;
  1415. result_rrlp = dcache_search(rrlp);
  1416. }
  1417. dcache_add(copy_rr_list(result_rrlp));
  1418. return result_rrlp;
  1419. }
  1420. /* general entry point for address -> domain name resolution.
  1421.  * Returns RR list, or NULL if no record found.
  1422.  */
  1423. struct rr *
  1424. inverse_a(ip_address)
  1425. int32 ip_address;
  1426. {
  1427. struct rr *prrp;
  1428. struct rr *result_rrlp;
  1429. char pname[30];
  1430. if(ip_address == 0L)
  1431. return NULL;
  1432. sprintf( pname, "%u.%u.%u.%u.IN-ADDR.ARPA.",
  1433. lobyte(loword(ip_address)),
  1434. hibyte(loword(ip_address)),
  1435. lobyte(hiword(ip_address)),
  1436. hibyte(hiword(ip_address)) );
  1437. prrp = make_rr(RR_QUERY,pname,CLASS_IN,TYPE_PTR,0,0,NULL);
  1438. prrp->next =  /* make list to speed search */
  1439. make_rr(RR_INQUERY,NULL,CLASS_IN,TYPE_A,0,4,&ip_address);
  1440. result_rrlp = resolver(prrp);
  1441. free_rr(prrp);
  1442. return result_rrlp;
  1443. }
  1444. /* general entry point for domain name -> resource resolution.
  1445.  * Returns RR list, or NULL if no record found.
  1446.  */
  1447. struct rr *
  1448. resolve_rr(dname,dtype)
  1449. char *dname;
  1450. uint16 dtype;
  1451. {
  1452. struct rr *qrrp;
  1453. struct rr *result_rrlp;
  1454. char *sname;
  1455. int looping = MAXCNAME;
  1456. if(dname == NULL)
  1457. return NULL;
  1458. sname = checksuffix(dname);
  1459. qrrp = make_rr(RR_QUERY,sname,CLASS_IN,dtype,0,0,NULL);
  1460. FREE(sname);
  1461. while(looping > 0){
  1462. if((result_rrlp=resolver(qrrp)) == NULL
  1463. || result_rrlp->type == dtype)
  1464. break;
  1465. #ifdef DEBUG
  1466. if(Dtrace)
  1467. put_rr(stdout,result_rrlp);
  1468. #endif
  1469. /* Should be CNAME or PTR record */
  1470. /* Replace name and try again */
  1471. free(qrrp->name);
  1472. qrrp->name = strdup(result_rrlp->rdata.name);
  1473. free_rr(result_rrlp);
  1474. result_rrlp = NULL;
  1475. looping--;
  1476. }
  1477. free_rr(qrrp);
  1478. return result_rrlp;
  1479. }
  1480. /* main entry point for address -> domain name resolution.
  1481.  * Returns string, or NULL if no name found.
  1482.  */
  1483. char *
  1484. resolve_a(ip_address,shorten)
  1485. int32 ip_address; /* search address */
  1486. int shorten; /* return only first part of name (flag)*/
  1487. {
  1488. struct rr *save_rrlp, *rrlp;
  1489. char *result = NULL;
  1490. for( rrlp = save_rrlp = inverse_a(ip_address);
  1491.      rrlp != NULL && result == NULL;
  1492.      rrlp = rrlp->next ){
  1493. if(rrlp->rdlength > 0){
  1494. switch(rrlp->type){
  1495. case TYPE_PTR:
  1496. result = strdup(rrlp->rdata.name);
  1497. break;
  1498. case TYPE_A:
  1499. result = strdup(rrlp->name);
  1500. break;
  1501. }
  1502. }
  1503. }
  1504. free_rr(save_rrlp);
  1505. if(result != NULL && shorten){
  1506. int dot;
  1507. char *shortened;
  1508. if((dot = strcspn(result, ".")) == 0){
  1509. shortened = mallocw(dot+1);
  1510. strncpy(shortened, result, dot);
  1511. shortened[dot] = '';
  1512. free(result);
  1513. result = shortened;
  1514. }
  1515. }
  1516. return result;
  1517. }
  1518. /* Main entry point for domain name -> address resolution.
  1519.  * Returns 0 if name is currently unresolvable.
  1520.  */
  1521. int32
  1522. resolve(name)
  1523. char *name;
  1524. {
  1525. register struct rr *rrlp;
  1526. int32 ip_address = 0;
  1527. if(name == NULL)
  1528. return 0;
  1529. if(isaddr(name))
  1530. return aton(name);
  1531. if((rrlp = resolve_rr(name,TYPE_A)) != NULL
  1532.  && rrlp->rdlength > 0)
  1533. ip_address = rrlp->rdata.addr;
  1534. /* multi-homed hosts are handled here */
  1535. if(rrlp != NULL && rrlp->next != NULL) {
  1536. register struct rr *rrp;
  1537. register struct route *rp;
  1538. uint16 cost = MAXINT16;
  1539. rrp = rrlp;
  1540. /* choose the best of a set of routes */
  1541. while(rrp != NULL) {
  1542. if(rrp->rdlength > 0
  1543.  && (rp = rt_lookup(rrp->rdata.addr)) != NULL
  1544.  && rp->metric <= cost) {
  1545. ip_address = rrp->rdata.addr;
  1546. cost = rp->metric;
  1547. }
  1548. rrp = rrp->next;
  1549. }
  1550. }
  1551. free_rr(rrlp);
  1552. return ip_address;
  1553. }
  1554. /* Main entry point for MX record lookup.
  1555.  * Returns 0 if name is currently unresolvable.
  1556.  */
  1557. int32
  1558. resolve_mx(name)
  1559. char *name;
  1560. {
  1561. register struct rr *rrp, *arrp;
  1562. char *sname, *tmp, *cp;
  1563. int32 addr, ip_address = 0;
  1564. uint16 pref = MAXINT16;
  1565. if(name == NULL)
  1566. return 0;
  1567. if(isaddr(name)){
  1568. if((sname = resolve_a(aton(name),FALSE)) == NULL)
  1569. return 0;
  1570. }
  1571. else
  1572. sname = strdup(name);
  1573. cp = sname;
  1574. while(1){
  1575. rrp = arrp = resolve_rr(sname,TYPE_MX);
  1576. /* Search this list of rr's for an MX record */
  1577. while(rrp != NULL){
  1578. if(rrp->rdlength > 0 && rrp->rdata.mx.pref <= pref &&
  1579.    (addr = resolve(rrp->rdata.mx.exch)) != 0L){
  1580. pref = rrp->rdata.mx.pref;
  1581. ip_address = addr;
  1582. }
  1583. rrp = rrp->next;
  1584. }
  1585. free_rr(arrp);
  1586. if(ip_address != 0)
  1587. break;
  1588. /* Compose wild card one level up */
  1589. if((cp = strchr(cp,'.')) == NULL)
  1590. break;
  1591. tmp = mallocw(strlen(cp)+2);
  1592. sprintf(tmp,"*%s",cp); /* wildcard expansion */
  1593. free(sname);
  1594. sname = tmp;
  1595. cp = sname + 2;
  1596. }
  1597. free(sname);
  1598. return ip_address;
  1599. }
  1600. /* Search for local records of the MB, MG and MR type. Returns list of
  1601.  * matching records.
  1602.  */
  1603. struct rr *
  1604. resolve_mailb(name)
  1605. char *name; /* local username, without trailing dot */
  1606. {
  1607. register struct rr *result_rrlp;
  1608. struct rr *rrlp;
  1609. char *sname;
  1610. /* Append trailing dot */
  1611. sname = mallocw(strlen(name)+2);
  1612. sprintf(sname,"%s.",name);
  1613. rrlp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MB,0,0,NULL);
  1614. rrlp->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MG,0,0,NULL);
  1615. rrlp->next->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MR,0,0,NULL);
  1616. FREE(sname);
  1617. if((result_rrlp = dcache_search(rrlp)) == NULL){
  1618. result_rrlp = dfile_search(rrlp);
  1619. }
  1620. free_rr(rrlp);
  1621. if(Dsuffix != NULL){
  1622. rrlp = result_rrlp;
  1623. while(rrlp != NULL){ /* add domain suffix to data */
  1624. if(rrlp->rdlength > 0 &&
  1625.    rrlp->rdata.name[rrlp->rdlength-1] != '.'){
  1626. sname = mallocw(rrlp->rdlength +
  1627. strlen(Dsuffix)+2);
  1628. sprintf(sname,"%s.%s",rrlp->rdata.name,Dsuffix);
  1629. free(rrlp->rdata.name);
  1630. rrlp->rdata.name = sname;
  1631. rrlp->rdlength = strlen(sname);
  1632. }
  1633. rrlp = rrlp->next;
  1634. }
  1635. }
  1636. dcache_add(copy_rr_list(result_rrlp));
  1637. return result_rrlp;
  1638. }