xref: /plan9-contrib/sys/src/cmd/ndb/inform.c (revision 3468a4915d661daa200976acc4f80f51aae144b2)
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