dnnotify.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. /* get a notification from another system of a changed zone */
  8. void
  9. dnnotify(DNSmsg *reqp, DNSmsg *repp, Request *)
  10. {
  11. RR *tp;
  12. Area *a;
  13. /* move one question from reqp to repp */
  14. memset(repp, 0, sizeof(*repp));
  15. tp = reqp->qd;
  16. reqp->qd = tp->next;
  17. tp->next = 0;
  18. repp->qd = tp;
  19. repp->id = reqp->id;
  20. repp->flags = Fresp | Onotify | Fauth;
  21. /* anything to do? */
  22. if(zonerefreshprogram == nil)
  23. return;
  24. /* make sure its the right type */
  25. if(repp->qd->type != Tsoa)
  26. return;
  27. dnslog("notification for %s", repp->qd->owner->name);
  28. /* is it something we care about? */
  29. a = inmyarea(repp->qd->owner->name);
  30. if(a == nil)
  31. return;
  32. dnslog("serial old %lud new %lud", a->soarr->soa->serial,
  33. repp->qd->soa->serial);
  34. /* do nothing if it didn't change */
  35. if(a->soarr->soa->serial != repp->qd->soa->serial)
  36. a->needrefresh = 1;
  37. }
  38. static void
  39. ding(void*, char *msg)
  40. {
  41. if(strstr(msg, "alarm") != nil) {
  42. stats.alarms++;
  43. noted(NCONT); /* resume with system call error */
  44. } else
  45. noted(NDFLT); /* die */
  46. }
  47. /* notify a slave that an area has changed. */
  48. static void
  49. send_notify(char *slave, RR *soa, Request *req)
  50. {
  51. int i, len, n, reqno, status, fd;
  52. char *err;
  53. uchar ibuf[Maxudp+Udphdrsize], obuf[Maxudp+Udphdrsize];
  54. RR *rp;
  55. Udphdr *up = (Udphdr*)obuf;
  56. DNSmsg repmsg;
  57. /* create the request */
  58. reqno = rand();
  59. n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno);
  60. /* get an address */
  61. if(strcmp(ipattr(slave), "ip") == 0)
  62. parseip(up->raddr, slave);
  63. else {
  64. rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status);
  65. if(rp == nil)
  66. return;
  67. parseip(up->raddr, rp->ip->name);
  68. rrfreelist(rp); /* was rrfree */
  69. }
  70. fd = udpport(nil);
  71. if(fd < 0)
  72. return;
  73. notify(ding);
  74. /* send 3 times or until we get anything back */
  75. n += Udphdrsize;
  76. for(i = 0; i < 3; i++, freeanswers(&repmsg)){
  77. dnslog("sending %d byte notify to %s/%I.%d about %s", n, slave,
  78. up->raddr, nhgets(up->rport), soa->owner->name);
  79. memset(&repmsg, 0, sizeof repmsg);
  80. if(write(fd, obuf, n) != n)
  81. break;
  82. alarm(2*1000);
  83. len = read(fd, ibuf, sizeof ibuf);
  84. alarm(0);
  85. if(len <= Udphdrsize)
  86. continue;
  87. err = convM2DNS(&ibuf[Udphdrsize], len, &repmsg, nil);
  88. if(err != nil) {
  89. free(err);
  90. continue;
  91. }
  92. if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify)
  93. break;
  94. }
  95. if (i < 3)
  96. freeanswers(&repmsg);
  97. close(fd);
  98. }
  99. /* send notifies for any updated areas */
  100. static void
  101. notify_areas(Area *a, Request *req)
  102. {
  103. Server *s;
  104. for(; a != nil; a = a->next){
  105. if(!a->neednotify)
  106. continue;
  107. /* send notifies to all slaves */
  108. for(s = a->soarr->soa->slaves; s != nil; s = s->next)
  109. send_notify(s->name, a->soarr, req);
  110. a->neednotify = 0;
  111. }
  112. }
  113. /*
  114. * process to notify other servers of changes
  115. * (also reads in new databases)
  116. */
  117. void
  118. notifyproc(void)
  119. {
  120. Request req;
  121. switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
  122. case -1:
  123. return;
  124. case 0:
  125. break;
  126. default:
  127. return;
  128. }
  129. procsetname("notify slaves");
  130. memset(&req, 0, sizeof req);
  131. req.isslave = 1; /* don't fork off subprocesses */
  132. for(;;){
  133. getactivity(&req, 0);
  134. notify_areas(owned, &req);
  135. putactivity(0);
  136. sleep(60*1000);
  137. }
  138. }