xref: /plan9/sys/src/cmd/ndb/inform.c (revision ad6ca847b1a6a504acb0003cd6c5c6d92687369b)
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
usage(void)28 usage(void)
29 {
30 	fprint(2, "usage: %s [-x netmtpt]\n", argv0);
31 	exits("usage");
32 }
33 
34 void
ding(void *,char * msg)35 ding(void *, char *msg)
36 {
37 	if(strstr(msg, "alarm") != nil)
38 		noted(NCONT);
39 	noted(NDFLT);
40 }
41 
42 int
g16(uchar ** p)43 g16(uchar **p)
44 {
45 	int n;
46 
47 	n  = *(*p)++ << 8;
48 	n |= *(*p)++;
49 	return n;
50 }
51 
52 void
p16(uchar ** p,int n)53 p16(uchar **p, int n)
54 {
55 	*(*p)++ = n >> 8;
56 	*(*p)++ = n;
57 }
58 
59 void
p32(uchar ** p,int n)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
pmem(uchar ** p,void * v,int len)69 pmem(uchar **p, void *v, int len)
70 {
71 	memmove(*p, v, len);
72 	*p += len;
73 }
74 
75 void
pname(uchar ** p,char * s)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
main(int argc,char * argv[])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