dnsquery.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 <bio.h>
  12. #include <ndb.h>
  13. #include <ndbhf.h>
  14. static void nstrcpy(char*, char*, int);
  15. static void mkptrname(char*, char*, int);
  16. static Ndbtuple *doquery(int, char *dn, char *type);
  17. /*
  18. * search for a tuple that has the given 'attr=val' and also 'rattr=x'.
  19. * copy 'x' into 'buf' and return the whole tuple.
  20. *
  21. * return 0 if not found.
  22. */
  23. Ndbtuple*
  24. dnsquery(char *net, char *val, char *type)
  25. {
  26. char rip[128];
  27. char *p;
  28. Ndbtuple *t;
  29. int fd;
  30. /* if the address is V4 or V6 null address, give up early */
  31. if(strcmp(val, "::") == 0 || strcmp(val, "0.0.0.0") == 0)
  32. return nil;
  33. if(net == nil)
  34. net = "/net";
  35. snprint(rip, sizeof(rip), "%s/dns", net);
  36. fd = open(rip, ORDWR);
  37. if(fd < 0){
  38. if(strcmp(net, "/net") == 0)
  39. snprint(rip, sizeof(rip), "/srv/dns");
  40. else {
  41. snprint(rip, sizeof(rip), "/srv/dns%s", net);
  42. p = strrchr(rip, '/');
  43. *p = '_';
  44. }
  45. fd = open(rip, ORDWR);
  46. if(fd < 0)
  47. return nil;
  48. if(mount(fd, -1, net, MBEFORE, "", 'M') < 0){
  49. close(fd);
  50. return nil;
  51. }
  52. /* fd is now closed */
  53. snprint(rip, sizeof(rip), "%s/dns", net);
  54. fd = open(rip, ORDWR);
  55. if(fd < 0)
  56. return nil;
  57. }
  58. /* zero out the error string */
  59. werrstr("");
  60. /* if this is a reverse lookup, first lookup the domain name */
  61. if(strcmp(type, "ptr") == 0){
  62. mkptrname(val, rip, sizeof rip);
  63. t = doquery(fd, rip, "ptr");
  64. } else
  65. t = doquery(fd, val, type);
  66. /*
  67. * TODO: make fd static and keep it open to reduce 9P traffic
  68. * walking to /net*^/dns. Must be prepared to re-open it on error.
  69. */
  70. close(fd);
  71. ndbsetmalloctag(t, getcallerpc());
  72. return t;
  73. }
  74. /*
  75. * convert address into a reverse lookup address
  76. */
  77. static void
  78. mkptrname(char *ip, char *rip, int rlen)
  79. {
  80. char buf[128];
  81. char *p, *np;
  82. int len;
  83. if(cistrstr(ip, "in-addr.arpa") || cistrstr(ip, "ip6.arpa")){
  84. nstrcpy(rip, ip, rlen);
  85. return;
  86. }
  87. nstrcpy(buf, ip, sizeof buf);
  88. for(p = buf; *p; p++)
  89. ;
  90. *p = '.';
  91. np = rip;
  92. len = 0;
  93. while(p >= buf){
  94. len++;
  95. p--;
  96. if(*p == '.'){
  97. memmove(np, p+1, len);
  98. np += len;
  99. len = 0;
  100. }
  101. }
  102. memmove(np, p+1, len);
  103. np += len;
  104. strcpy(np, "in-addr.arpa");
  105. }
  106. static void
  107. nstrcpy(char *to, char *from, int len)
  108. {
  109. strncpy(to, from, len);
  110. to[len-1] = 0;
  111. }
  112. static Ndbtuple*
  113. doquery(int fd, char *dn, char *type)
  114. {
  115. char buf[1024];
  116. int n;
  117. Ndbtuple *t, *first, *last;
  118. seek(fd, 0, 0);
  119. snprint(buf, sizeof(buf), "!%s %s", dn, type);
  120. if(write(fd, buf, strlen(buf)) < 0)
  121. return nil;
  122. seek(fd, 0, 0);
  123. first = last = nil;
  124. for(;;){
  125. n = read(fd, buf, sizeof(buf)-2);
  126. if(n <= 0)
  127. break;
  128. if(buf[n-1] != '\n')
  129. buf[n++] = '\n'; /* ndbparsline needs a trailing new line */
  130. buf[n] = 0;
  131. /* check for the error condition */
  132. if(buf[0] == '!'){
  133. werrstr("%s", buf+1);
  134. return nil;
  135. }
  136. t = _ndbparseline(buf);
  137. if(t != nil){
  138. if(first)
  139. last->entry = t;
  140. else
  141. first = t;
  142. last = t;
  143. while(last->entry)
  144. last = last->entry;
  145. }
  146. }
  147. ndbsetmalloctag(first, getcallerpc());
  148. return first;
  149. }