dnnotify.c 3.5 KB

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