inform.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. /* RFC2136 DNS inform - necessary for Win2k3 DNS servers */
  10. #include <u.h>
  11. #include <libc.h>
  12. #include <bio.h>
  13. #include <ndb.h>
  14. #include <ip.h>
  15. #include "dns.h"
  16. enum {
  17. FQDNMAX = 255,
  18. };
  19. char *errmsgs[] = {
  20. [0] "ok",
  21. [1] "request format error",
  22. [2] "internal server error",
  23. [3] "domain name does not exist",
  24. [4] "request not supported",
  25. [5] "permission denied",
  26. [6] "domain name already exists",
  27. [7] "resource record already exists",
  28. [8] "resource record does not exist",
  29. [9] "server not authoritative",
  30. [10] "domain name not in zone",
  31. };
  32. void
  33. usage(void)
  34. {
  35. fprint(2, "usage: %s [-x netmtpt]\n", argv0);
  36. exits("usage");
  37. }
  38. void
  39. ding(void *v, char *msg)
  40. {
  41. if(strstr(msg, "alarm") != nil)
  42. noted(NCONT);
  43. noted(NDFLT);
  44. }
  45. int
  46. g16(uint8_t **p)
  47. {
  48. int n;
  49. n = *(*p)++ << 8;
  50. n |= *(*p)++;
  51. return n;
  52. }
  53. void
  54. p16(uint8_t **p, int n)
  55. {
  56. *(*p)++ = n >> 8;
  57. *(*p)++ = n;
  58. }
  59. void
  60. p32(uint8_t **p, int n)
  61. {
  62. *(*p)++ = n >> 24;
  63. *(*p)++ = n >> 16;
  64. *(*p)++ = n >> 8;
  65. *(*p)++ = n;
  66. }
  67. void
  68. pmem(uint8_t **p, void *v, int len)
  69. {
  70. memmove(*p, v, len);
  71. *p += len;
  72. }
  73. void
  74. pname(uint8_t **p, char *s)
  75. {
  76. uint8_t *len;
  77. while (*s){
  78. len = (*p)++;
  79. while(*s && *s != '.')
  80. *(*p)++ = *s++;
  81. *len = *p - len - 1;
  82. if(*s == '.')
  83. s++;
  84. }
  85. *(*p)++ = 0;
  86. }
  87. void
  88. main(int argc, char *argv[])
  89. {
  90. int debug, len, fd;
  91. uint err;
  92. char *sysname, *dnsdomain, *dom, *inform, *ns, net[32];
  93. unsigned char *p, buf[4096], addr[IPv4addrlen], v6addr[IPaddrlen];
  94. uint16_t txid;
  95. Ndb *db;
  96. Ndbtuple *t, *tt;
  97. static char *query[] = { "dom", "dnsdomain", "ns", "inform" };
  98. fmtinstall('I', eipfmt);
  99. fmtinstall('V', eipfmt);
  100. setnetmtpt(net, sizeof net, nil);
  101. debug = 0;
  102. ns = nil;
  103. dom = nil;
  104. inform = nil;
  105. dnsdomain = nil;
  106. ARGBEGIN{
  107. case 'd':
  108. debug = 1;
  109. break;
  110. case 'x':
  111. setnetmtpt(net, sizeof net, EARGF(usage()));
  112. break;
  113. default:
  114. usage();
  115. }ARGEND;
  116. if(argc != 0)
  117. usage();
  118. if((sysname = getenv("sysname")) == nil)
  119. sysfatal("$sysname not set");
  120. if((db = ndbopen(nil)) == nil)
  121. sysfatal("can't open ndb: %r");
  122. tt = ndbipinfo(db, "sys", sysname, query, nelem(query));
  123. for(t = tt; t; t = t->entry){
  124. if(strcmp(t->attr, "ns") == 0)
  125. ns = t->val;
  126. else if(strcmp(t->attr, "dom") == 0)
  127. dom = t->val;
  128. else if(strcmp(t->attr, "dnsdomain") == 0)
  129. dnsdomain = t->val;
  130. else if(strcmp(t->attr, "inform") == 0)
  131. inform = t->val;
  132. }
  133. ndbfree(tt);
  134. ndbclose(db);
  135. if(inform)
  136. dom = inform;
  137. if(!ns)
  138. sysfatal("no relevant ns=");
  139. if(!dom)
  140. sysfatal("no relevant dom=");
  141. if(!dnsdomain)
  142. sysfatal("no relevant dnsdomain=");
  143. myipaddr(v6addr, net);
  144. memmove(addr, v6addr + IPaddrlen - IPv4addrlen, IPv4addrlen);
  145. if(debug){
  146. print("ip=%V\n", addr);
  147. print("ns=%s\n", ns);
  148. print("dnsdomain=%s\n", dnsdomain);
  149. print("dom=%s\n", dom);
  150. }
  151. if((fd = dial(netmkaddr(ns, "udp", "dns"), 0, 0, 0)) < 0)
  152. sysfatal("can't dial %s: %r", ns);
  153. txid = time(nil) + getpid();
  154. p = buf;
  155. p16(&p, txid); /* ID */
  156. p16(&p, 5<<11); /* flags */
  157. p16(&p, 1); /* # Zones */
  158. p16(&p, 0); /* # prerequisites */
  159. p16(&p, 2); /* # updates */
  160. p16(&p, 0); /* # additionals */
  161. pname(&p, dnsdomain); /* zone */
  162. p16(&p, Tsoa); /* zone type */
  163. p16(&p, Cin); /* zone class */
  164. /* delete old name */
  165. pname(&p, dom); /* name */
  166. p16(&p, Ta); /* type: v4 addr */
  167. p16(&p, Call); /* class */
  168. p32(&p, 0); /* TTL */
  169. p16(&p, 0); /* data len */
  170. /* add new A record */
  171. pname(&p, dom); /* name */
  172. p16(&p, Ta); /* type: v4 addr */
  173. p16(&p, Cin); /* class */
  174. p32(&p, 60*60*25); /* TTL (25 hours) */
  175. p16(&p, IPv4addrlen); /* data len */
  176. pmem(&p, addr, IPv4addrlen); /* v4 address */
  177. len = p - buf;
  178. if(write(fd, buf, len) != len)
  179. sysfatal("write failed: %r");
  180. notify(ding);
  181. alarm(3000);
  182. do{
  183. if(read(fd, buf, sizeof buf) < 0)
  184. sysfatal("timeout");
  185. p = buf;
  186. }while(g16(&p) != txid);
  187. alarm(0);
  188. close(fd);
  189. err = g16(&p) & 7;
  190. if(err != 0 && err != 7) /* err==7 is just a "yes, I know" warning */
  191. if(err < nelem(errmsgs))
  192. sysfatal("%s", errmsgs[err]);
  193. else
  194. sysfatal("unknown dns server error %d", err);
  195. exits(0);
  196. }