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