dnudpserver.c 5.7 KB

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