dnudpserver.c 5.5 KB

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