dnudpserver.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include "dns.h"
  5. enum {
  6. Logqueries = 0,
  7. };
  8. static int udpannounce(char*);
  9. static void reply(int, uchar*, DNSmsg*, Request*);
  10. static void
  11. ding(void *x, char *msg)
  12. {
  13. USED(x);
  14. if(strcmp(msg, "alarm") == 0)
  15. noted(NCONT);
  16. else
  17. noted(NDFLT);
  18. }
  19. typedef struct Inprogress Inprogress;
  20. struct Inprogress
  21. {
  22. int inuse;
  23. Udphdr uh;
  24. DN *owner;
  25. int type;
  26. int id;
  27. };
  28. Inprogress inprog[Maxactive+2];
  29. /*
  30. * record client id and ignore retransmissions.
  31. * we're still single thread at this point.
  32. */
  33. static Inprogress*
  34. clientrxmit(DNSmsg *req, uchar *buf)
  35. {
  36. Inprogress *p, *empty;
  37. Udphdr *uh;
  38. uh = (Udphdr *)buf;
  39. empty = nil;
  40. for(p = inprog; p < &inprog[Maxactive]; p++){
  41. if(p->inuse == 0){
  42. if(empty == nil)
  43. empty = p;
  44. continue;
  45. }
  46. if(req->id == p->id)
  47. if(req->qd->owner == p->owner)
  48. if(req->qd->type == p->type)
  49. if(memcmp(uh, &p->uh, Udphdrsize) == 0)
  50. return nil;
  51. }
  52. if(empty == nil)
  53. return nil; /* shouldn't happen: see slave() & Maxactive def'n */
  54. empty->id = req->id;
  55. empty->owner = req->qd->owner;
  56. empty->type = req->qd->type;
  57. memmove(&empty->uh, uh, Udphdrsize);
  58. empty->inuse = 1;
  59. return empty;
  60. }
  61. /*
  62. * a process to act as a dns server for outside reqeusts
  63. */
  64. void
  65. dnudpserver(char *mntpt)
  66. {
  67. volatile int fd, len, op, rcode;
  68. char *volatile err;
  69. volatile char tname[32];
  70. volatile uchar buf[Udphdrsize + Maxudp + 1024];
  71. volatile DNSmsg reqmsg, repmsg;
  72. Inprogress *volatile p;
  73. volatile Request req;
  74. Udphdr *volatile uh;
  75. /* fork sharing text, data, and bss with parent */
  76. switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
  77. case -1:
  78. break;
  79. case 0:
  80. break;
  81. default:
  82. return;
  83. }
  84. fd = -1;
  85. notify(ding);
  86. restart:
  87. procsetname("udp server announcing");
  88. if(fd >= 0)
  89. close(fd);
  90. while((fd = udpannounce(mntpt)) < 0)
  91. sleep(5000);
  92. procsetname("udp server loop");
  93. memset(&req, 0, sizeof req);
  94. if(setjmp(req.mret))
  95. putactivity(0);
  96. req.isslave = 0;
  97. req.id = 0;
  98. req.aborttime = 0;
  99. /* loop on requests */
  100. for(;; putactivity(0)){
  101. memset(&repmsg, 0, sizeof repmsg);
  102. memset(&reqmsg, 0, sizeof reqmsg);
  103. alarm(60*1000);
  104. len = read(fd, buf, sizeof buf);
  105. alarm(0);
  106. if(len <= Udphdrsize)
  107. goto restart;
  108. uh = (Udphdr*)buf;
  109. len -= Udphdrsize;
  110. // dnslog("read received UDP from %I to %I",
  111. // ((Udphdr*)buf)->raddr, ((Udphdr*)buf)->laddr);
  112. getactivity(&req, 0);
  113. req.aborttime = now + Maxreqtm;
  114. // req.from = smprint("%I", ((Udphdr*)buf)->raddr);
  115. req.from = smprint("%I", buf);
  116. rcode = 0;
  117. stats.qrecvdudp++;
  118. err = convM2DNS(&buf[Udphdrsize], len, &reqmsg, &rcode);
  119. if(err){
  120. /* first bytes in buf are source IP addr */
  121. dnslog("server: input error: %s from %I", err, buf);
  122. free(err);
  123. goto freereq;
  124. }
  125. if (rcode == 0)
  126. if(reqmsg.qdcount < 1){
  127. dnslog("server: no questions from %I", buf);
  128. goto freereq;
  129. } else if(reqmsg.flags & Fresp){
  130. dnslog("server: reply not request from %I", buf);
  131. goto freereq;
  132. }
  133. op = reqmsg.flags & Omask;
  134. if(op != Oquery && op != Onotify){
  135. dnslog("server: op %d from %I", reqmsg.flags & Omask,
  136. buf);
  137. goto freereq;
  138. }
  139. if(debug || (trace && subsume(trace, reqmsg.qd->owner->name)))
  140. dnslog("%d: serve (%I/%d) %d %s %s",
  141. req.id, buf, uh->rport[0]<<8 | uh->rport[1],
  142. reqmsg.id, reqmsg.qd->owner->name,
  143. rrname(reqmsg.qd->type, tname, sizeof tname));
  144. p = clientrxmit(&reqmsg, buf);
  145. if(p == nil){
  146. if(debug)
  147. dnslog("%d: duplicate", req.id);
  148. goto freereq;
  149. }
  150. if (Logqueries) {
  151. RR *rr;
  152. for (rr = reqmsg.qd; rr; rr = rr->next)
  153. syslog(0, "dnsq", "id %d: (%I/%d) %d %s %s",
  154. req.id, buf, uh->rport[0]<<8 |
  155. uh->rport[1], reqmsg.id,
  156. reqmsg.qd->owner->name,
  157. rrname(reqmsg.qd->type, tname,
  158. sizeof tname)); // DEBUG
  159. }
  160. /* loop through each question */
  161. while(reqmsg.qd){
  162. memset(&repmsg, 0, sizeof repmsg);
  163. switch(op){
  164. case Oquery:
  165. dnserver(&reqmsg, &repmsg, &req, buf, rcode);
  166. break;
  167. case Onotify:
  168. dnnotify(&reqmsg, &repmsg, &req);
  169. break;
  170. }
  171. /* send reply on fd to address in buf's udp hdr */
  172. reply(fd, buf, &repmsg, &req);
  173. freeanswers(&repmsg);
  174. }
  175. p->inuse = 0;
  176. freereq:
  177. free(req.from);
  178. freeanswers(&reqmsg);
  179. if(req.isslave){
  180. putactivity(0);
  181. _exits(0);
  182. }
  183. }
  184. }
  185. /*
  186. * announce on well-known dns udp port and set message style interface
  187. */
  188. static char *hmsg = "headers";
  189. static int
  190. udpannounce(char *mntpt)
  191. {
  192. int data, ctl;
  193. char dir[64], datafile[64+6];
  194. static int whined;
  195. /* get a udp port */
  196. sprint(datafile, "%s/udp!*!dns", mntpt);
  197. ctl = announce(datafile, dir);
  198. if(ctl < 0){
  199. if(!whined++)
  200. warning("can't announce on dns udp port");
  201. return -1;
  202. }
  203. snprint(datafile, sizeof(datafile), "%s/data", dir);
  204. /* turn on header style interface */
  205. if(write(ctl, hmsg, strlen(hmsg)) , 0)
  206. abort(); /* hmsg */
  207. data = open(datafile, ORDWR);
  208. if(data < 0){
  209. close(ctl);
  210. if(!whined++)
  211. warning("can't announce on dns udp port");
  212. return -1;
  213. }
  214. close(ctl);
  215. return data;
  216. }
  217. static void
  218. reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp)
  219. {
  220. int len;
  221. char tname[32];
  222. if(debug || (trace && subsume(trace, rep->qd->owner->name)))
  223. dnslog("%d: reply (%I/%d) %d %s %s qd %R an %R ns %R ar %R",
  224. reqp->id, buf, buf[4]<<8 | buf[5],
  225. rep->id, rep->qd->owner->name,
  226. rrname(rep->qd->type, tname, sizeof tname),
  227. rep->qd, rep->an, rep->ns, rep->ar);
  228. len = convDNS2M(rep, &buf[Udphdrsize], Maxudp);
  229. len += Udphdrsize;
  230. if(write(fd, buf, len) != len)
  231. dnslog("error sending reply: %r");
  232. }