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