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