125fc6993SDavid du Colombier /* RFC2136 DNS inform - necessary for Win2k3 DNS servers */
225fc6993SDavid du Colombier #include <u.h>
325fc6993SDavid du Colombier #include <libc.h>
425fc6993SDavid du Colombier #include <bio.h>
525fc6993SDavid du Colombier #include <ndb.h>
625fc6993SDavid du Colombier #include <ip.h>
76d0458a2SDavid du Colombier #include "dns.h"
825fc6993SDavid du Colombier
925fc6993SDavid du Colombier enum {
1025fc6993SDavid du Colombier FQDNMAX = 255,
1125fc6993SDavid du Colombier };
1225fc6993SDavid du Colombier
1325fc6993SDavid du Colombier char *errmsgs[] = {
1425fc6993SDavid du Colombier [0] "ok",
1525fc6993SDavid du Colombier [1] "request format error",
1625fc6993SDavid du Colombier [2] "internal server error",
1725fc6993SDavid du Colombier [3] "domain name does not exist",
1825fc6993SDavid du Colombier [4] "request not supported",
1925fc6993SDavid du Colombier [5] "permission denied",
2025fc6993SDavid du Colombier [6] "domain name already exists",
2125fc6993SDavid du Colombier [7] "resource record already exists",
2225fc6993SDavid du Colombier [8] "resource record does not exist",
2325fc6993SDavid du Colombier [9] "server not authoritative",
2425fc6993SDavid du Colombier [10] "domain name not in zone",
2525fc6993SDavid du Colombier };
2625fc6993SDavid du Colombier
2725fc6993SDavid du Colombier void
usage(void)2825fc6993SDavid du Colombier usage(void)
2925fc6993SDavid du Colombier {
3025fc6993SDavid du Colombier fprint(2, "usage: %s [-x netmtpt]\n", argv0);
3125fc6993SDavid du Colombier exits("usage");
3225fc6993SDavid du Colombier }
3325fc6993SDavid du Colombier
3425fc6993SDavid du Colombier void
ding(void *,char * msg)3525fc6993SDavid du Colombier ding(void *, char *msg)
3625fc6993SDavid du Colombier {
3725fc6993SDavid du Colombier if(strstr(msg, "alarm") != nil)
3825fc6993SDavid du Colombier noted(NCONT);
3925fc6993SDavid du Colombier noted(NDFLT);
4025fc6993SDavid du Colombier }
4125fc6993SDavid du Colombier
4225fc6993SDavid du Colombier int
g16(uchar ** p)4325fc6993SDavid du Colombier g16(uchar **p)
4425fc6993SDavid du Colombier {
4525fc6993SDavid du Colombier int n;
4625fc6993SDavid du Colombier
4725fc6993SDavid du Colombier n = *(*p)++ << 8;
4825fc6993SDavid du Colombier n |= *(*p)++;
4925fc6993SDavid du Colombier return n;
5025fc6993SDavid du Colombier }
5125fc6993SDavid du Colombier
5225fc6993SDavid du Colombier void
p16(uchar ** p,int n)5325fc6993SDavid du Colombier p16(uchar **p, int n)
5425fc6993SDavid du Colombier {
5525fc6993SDavid du Colombier *(*p)++ = n >> 8;
5625fc6993SDavid du Colombier *(*p)++ = n;
5725fc6993SDavid du Colombier }
5825fc6993SDavid du Colombier
5925fc6993SDavid du Colombier void
p32(uchar ** p,int n)6025fc6993SDavid du Colombier p32(uchar **p, int n)
6125fc6993SDavid du Colombier {
6225fc6993SDavid du Colombier *(*p)++ = n >> 24;
6325fc6993SDavid du Colombier *(*p)++ = n >> 16;
6425fc6993SDavid du Colombier *(*p)++ = n >> 8;
6525fc6993SDavid du Colombier *(*p)++ = n;
6625fc6993SDavid du Colombier }
6725fc6993SDavid du Colombier
6825fc6993SDavid du Colombier void
pmem(uchar ** p,void * v,int len)6925fc6993SDavid du Colombier pmem(uchar **p, void *v, int len)
7025fc6993SDavid du Colombier {
7125fc6993SDavid du Colombier memmove(*p, v, len);
7225fc6993SDavid du Colombier *p += len;
7325fc6993SDavid du Colombier }
7425fc6993SDavid du Colombier
7525fc6993SDavid du Colombier void
pname(uchar ** p,char * s)7625fc6993SDavid du Colombier pname(uchar **p, char *s)
7725fc6993SDavid du Colombier {
7825fc6993SDavid du Colombier uchar *len;
7925fc6993SDavid du Colombier
8025fc6993SDavid du Colombier while (*s){
8125fc6993SDavid du Colombier len = (*p)++;
8225fc6993SDavid du Colombier while(*s && *s != '.')
8325fc6993SDavid du Colombier *(*p)++ = *s++;
8425fc6993SDavid du Colombier *len = *p - len - 1;
8525fc6993SDavid du Colombier if(*s == '.')
8625fc6993SDavid du Colombier s++;
8725fc6993SDavid du Colombier }
8825fc6993SDavid du Colombier *(*p)++ = 0;
8925fc6993SDavid du Colombier }
9025fc6993SDavid du Colombier
9125fc6993SDavid du Colombier void
main(int argc,char * argv[])9225fc6993SDavid du Colombier main(int argc, char *argv[])
9325fc6993SDavid du Colombier {
9425fc6993SDavid du Colombier int debug, len, fd;
9525fc6993SDavid du Colombier uint err;
96*ad6ca847SDavid du Colombier char *sysname, *dnsdomain, *dom, *inform, *ns, net[32];
9725fc6993SDavid du Colombier uchar *p, buf[4096], addr[IPv4addrlen], v6addr[IPaddrlen];
9825fc6993SDavid du Colombier ushort txid;
9925fc6993SDavid du Colombier Ndb *db;
10025fc6993SDavid du Colombier Ndbtuple *t, *tt;
101*ad6ca847SDavid du Colombier static char *query[] = { "dom", "dnsdomain", "ns", "inform" };
10225fc6993SDavid du Colombier
10325fc6993SDavid du Colombier fmtinstall('I', eipfmt);
10425fc6993SDavid du Colombier fmtinstall('V', eipfmt);
10525fc6993SDavid du Colombier setnetmtpt(net, sizeof net, nil);
10625fc6993SDavid du Colombier
10725fc6993SDavid du Colombier debug = 0;
10825fc6993SDavid du Colombier ns = nil;
10925fc6993SDavid du Colombier dom = nil;
110*ad6ca847SDavid du Colombier inform = nil;
11125fc6993SDavid du Colombier dnsdomain = nil;
11225fc6993SDavid du Colombier ARGBEGIN{
11325fc6993SDavid du Colombier case 'd':
11425fc6993SDavid du Colombier debug = 1;
11525fc6993SDavid du Colombier break;
11625fc6993SDavid du Colombier case 'x':
11725fc6993SDavid du Colombier setnetmtpt(net, sizeof net, EARGF(usage()));
11825fc6993SDavid du Colombier break;
11925fc6993SDavid du Colombier default:
12025fc6993SDavid du Colombier usage();
12125fc6993SDavid du Colombier }ARGEND;
12225fc6993SDavid du Colombier
12325fc6993SDavid du Colombier if(argc != 0)
12425fc6993SDavid du Colombier usage();
12525fc6993SDavid du Colombier
12625fc6993SDavid du Colombier if((sysname = getenv("sysname")) == nil)
12725fc6993SDavid du Colombier sysfatal("$sysname not set");
12825fc6993SDavid du Colombier
12925fc6993SDavid du Colombier if((db = ndbopen(nil)) == nil)
13025fc6993SDavid du Colombier sysfatal("can't open ndb: %r");
13125fc6993SDavid du Colombier tt = ndbipinfo(db, "sys", sysname, query, nelem(query));
132*ad6ca847SDavid du Colombier for(t = tt; t; t = t->entry){
13325fc6993SDavid du Colombier if(strcmp(t->attr, "ns") == 0)
13425fc6993SDavid du Colombier ns = t->val;
13525fc6993SDavid du Colombier else if(strcmp(t->attr, "dom") == 0)
13625fc6993SDavid du Colombier dom = t->val;
13725fc6993SDavid du Colombier else if(strcmp(t->attr, "dnsdomain") == 0)
13825fc6993SDavid du Colombier dnsdomain = t->val;
139*ad6ca847SDavid du Colombier else if(strcmp(t->attr, "inform") == 0)
140*ad6ca847SDavid du Colombier inform = t->val;
141*ad6ca847SDavid du Colombier }
142*ad6ca847SDavid du Colombier
14325fc6993SDavid du Colombier ndbfree(tt);
14425fc6993SDavid du Colombier ndbclose(db);
14525fc6993SDavid du Colombier
146*ad6ca847SDavid du Colombier if(inform)
147*ad6ca847SDavid du Colombier dom = inform;
14825fc6993SDavid du Colombier if(!ns)
14925fc6993SDavid du Colombier sysfatal("no relevant ns=");
15025fc6993SDavid du Colombier if(!dom)
15125fc6993SDavid du Colombier sysfatal("no relevant dom=");
15225fc6993SDavid du Colombier if(!dnsdomain)
15325fc6993SDavid du Colombier sysfatal("no relevant dnsdomain=");
15425fc6993SDavid du Colombier
15525fc6993SDavid du Colombier myipaddr(v6addr, net);
15625fc6993SDavid du Colombier memmove(addr, v6addr + IPaddrlen - IPv4addrlen, IPv4addrlen);
15725fc6993SDavid du Colombier
15825fc6993SDavid du Colombier if(debug){
15925fc6993SDavid du Colombier print("ip=%V\n", addr);
16025fc6993SDavid du Colombier print("ns=%s\n", ns);
16125fc6993SDavid du Colombier print("dnsdomain=%s\n", dnsdomain);
16225fc6993SDavid du Colombier print("dom=%s\n", dom);
16325fc6993SDavid du Colombier }
16425fc6993SDavid du Colombier
16525fc6993SDavid du Colombier if((fd = dial(netmkaddr(ns, "udp", "dns"), 0, 0, 0)) < 0)
16625fc6993SDavid du Colombier sysfatal("can't dial %s: %r", ns);
16725fc6993SDavid du Colombier
16825fc6993SDavid du Colombier txid = time(nil) + getpid();
16925fc6993SDavid du Colombier
17025fc6993SDavid du Colombier p = buf;
17125fc6993SDavid du Colombier p16(&p, txid); /* ID */
17225fc6993SDavid du Colombier p16(&p, 5<<11); /* flags */
17325fc6993SDavid du Colombier p16(&p, 1); /* # Zones */
17425fc6993SDavid du Colombier p16(&p, 0); /* # prerequisites */
17525fc6993SDavid du Colombier p16(&p, 2); /* # updates */
17625fc6993SDavid du Colombier p16(&p, 0); /* # additionals */
17725fc6993SDavid du Colombier
17825fc6993SDavid du Colombier pname(&p, dnsdomain); /* zone */
17925fc6993SDavid du Colombier p16(&p, Tsoa); /* zone type */
18025fc6993SDavid du Colombier p16(&p, Cin); /* zone class */
18125fc6993SDavid du Colombier
18225fc6993SDavid du Colombier /* delete old name */
18325fc6993SDavid du Colombier pname(&p, dom); /* name */
18425fc6993SDavid du Colombier p16(&p, Ta); /* type: v4 addr */
18525fc6993SDavid du Colombier p16(&p, Call); /* class */
18625fc6993SDavid du Colombier p32(&p, 0); /* TTL */
18725fc6993SDavid du Colombier p16(&p, 0); /* data len */
18825fc6993SDavid du Colombier
18925fc6993SDavid du Colombier /* add new A record */
19025fc6993SDavid du Colombier pname(&p, dom); /* name */
19125fc6993SDavid du Colombier p16(&p, Ta); /* type: v4 addr */
19225fc6993SDavid du Colombier p16(&p, Cin); /* class */
19325fc6993SDavid du Colombier p32(&p, 60*60*25); /* TTL (25 hours) */
19425fc6993SDavid du Colombier p16(&p, IPv4addrlen); /* data len */
19525fc6993SDavid du Colombier pmem(&p, addr, IPv4addrlen); /* v4 address */
19625fc6993SDavid du Colombier
19725fc6993SDavid du Colombier len = p - buf;
19825fc6993SDavid du Colombier if(write(fd, buf, len) != len)
19925fc6993SDavid du Colombier sysfatal("write failed: %r");
20025fc6993SDavid du Colombier
20125fc6993SDavid du Colombier notify(ding);
20225fc6993SDavid du Colombier alarm(3000);
20325fc6993SDavid du Colombier do{
20425fc6993SDavid du Colombier if(read(fd, buf, sizeof buf) < 0)
20525fc6993SDavid du Colombier sysfatal("timeout");
20625fc6993SDavid du Colombier p = buf;
20725fc6993SDavid du Colombier }while(g16(&p) != txid);
20825fc6993SDavid du Colombier alarm(0);
20925fc6993SDavid du Colombier
21025fc6993SDavid du Colombier close(fd);
21125fc6993SDavid du Colombier
21225fc6993SDavid du Colombier err = g16(&p) & 7;
21325fc6993SDavid du Colombier if(err != 0 && err != 7) /* err==7 is just a "yes, I know" warning */
21425fc6993SDavid du Colombier if(err < nelem(errmsgs))
21525fc6993SDavid du Colombier sysfatal("%s", errmsgs[err]);
21625fc6993SDavid du Colombier else
21725fc6993SDavid du Colombier sysfatal("unknown dns server error %d", err);
21825fc6993SDavid du Colombier exits(0);
21925fc6993SDavid du Colombier }
220