dnudpserver.c 6.7 KB

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