]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/inform.c
ndb/dns: do recursive lookup for dnsslave=
[plan9front.git] / sys / src / cmd / ndb / inform.c
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 static uchar loopbacknet[IPaddrlen] = {
28         0, 0, 0, 0,
29         0, 0, 0, 0,
30         0, 0, 0xff, 0xff,
31         127, 0, 0, 0
32 };
33 static uchar loopbackmask[IPaddrlen] = {
34         0xff, 0xff, 0xff, 0xff,
35         0xff, 0xff, 0xff, 0xff,
36         0xff, 0xff, 0xff, 0xff,
37         0xff, 0, 0, 0
38 };
39 static uchar loopback6[IPaddrlen] = {
40         0, 0, 0, 0,
41         0, 0, 0, 0,
42         0, 0, 0, 0,
43         0, 0, 0, 1
44 };
45
46 void
47 usage(void)
48 {
49         fprint(2, "usage: %s [-x netmtpt]\n", argv0);
50         exits("usage");
51 }
52
53 void
54 ding(void *, char *msg)
55 {
56         if(strstr(msg, "alarm") != nil)
57                 noted(NCONT);
58         noted(NDFLT);
59 }
60
61 int
62 g16(uchar **p)
63 {
64         int n;
65
66         n  = *(*p)++ << 8;
67         n |= *(*p)++;
68         return n;
69 }
70
71 void
72 p16(uchar **p, int n)
73 {
74         *(*p)++ = n >> 8;
75         *(*p)++ = n;
76 }
77
78 void
79 p32(uchar **p, int n)
80 {
81         *(*p)++ = n >> 24;
82         *(*p)++ = n >> 16;
83         *(*p)++ = n >> 8;
84         *(*p)++ = n;
85 }
86
87 void
88 pmem(uchar **p, void *v, int len)
89 {
90         memmove(*p, v, len);
91         *p += len;
92 }
93
94 void
95 pname(uchar **p, char *s)
96 {
97         uchar *len;
98
99         while (*s){
100                 len = (*p)++;
101                 while(*s && *s != '.')
102                         *(*p)++ = *s++;
103                 *len = *p - len - 1;
104                 if(*s == '.')
105                         s++;
106         }
107         *(*p)++ = 0;
108 }
109
110 void
111 main(int argc, char *argv[])
112 {
113         static char *query[] = { "dom", "dnsdomain", "ns", "inform" };
114         char *sysname, *dnsdomain, *dom, *inform, *ns, net[32], dn[256], ds[256];
115         int debug, len, fd;
116         uint err;
117         uchar *p, buf[4096], mynet[IPaddrlen];
118         ushort txid;
119         Ndb *db;
120         Ndbtuple *t, *tt;
121         Ipifc *ifc;
122         Iplifc *lifc;
123
124         fmtinstall('I', eipfmt);
125         fmtinstall('V', eipfmt);
126         setnetmtpt(net, sizeof net, nil);
127
128         debug = 0;
129         ns = nil;
130         dom = nil;
131         inform = nil;
132         dnsdomain = nil;
133         ARGBEGIN{
134         case 'd':
135                 debug = 1;
136                 break;
137         case 'x':
138                 setnetmtpt(net, sizeof net, EARGF(usage()));
139                 break;
140         default:
141                 usage();
142         }ARGEND;
143
144         if(argc != 0)
145                 usage();
146
147         if((sysname = getenv("sysname")) == nil)
148                 sysfatal("$sysname not set");
149
150         if((db = ndbopen(nil)) == nil)
151                 sysfatal("can't open ndb: %r");
152         tt = ndbipinfo(db, "sys", sysname, query, nelem(query));
153         for(t = tt; t; t = t->entry){
154                 if(strcmp(t->attr, "ns") == 0)
155                         ns = t->val;
156                 else if(strcmp(t->attr, "dom") == 0)
157                         dom = t->val;
158                 else if(strcmp(t->attr, "dnsdomain") == 0)
159                         dnsdomain = t->val;
160                 else if(strcmp(t->attr, "inform") == 0)
161                         inform = t->val;
162         }
163
164         ndbfree(tt);
165         ndbclose(db);
166
167         if(inform)
168                 dom = inform;
169         if(!ns)
170                 sysfatal("no relevant ns=");
171         if(!dom)
172                 sysfatal("no relevant dom=");
173         if(!dnsdomain)
174                 sysfatal("no relevant dnsdomain=");
175
176
177         if(utf2idn(dom, dn, sizeof(dn)) <= 0)
178                 sysfatal("cannot convert dom");
179
180         if(utf2idn(dnsdomain, ds, sizeof(ds)) <= 0)
181                 sysfatal("cannot convert dnsdomain");
182
183         if(debug){
184                 print("ns=%s\n", ns);
185                 print("dnsdomain=%s\n", dnsdomain);
186                 print("dom=%s\n", dom);
187         }
188
189         if((fd = dial(netmkaddr(ns, "udp", "dns"), 0, 0, 0)) < 0)
190                 sysfatal("can't dial %s: %r", ns);
191
192         txid = time(nil) + getpid();
193
194         p = buf;
195         p16(&p, txid);          /* ID */
196         p16(&p, 5<<11);         /* flags */
197         p16(&p, 1);             /* # Zones */
198         p16(&p, 0);             /* # prerequisites */
199         p16(&p, 2);             /* # updates */
200         p16(&p, 0);             /* # additionals */
201
202         pname(&p, ds);          /* zone */
203         p16(&p, Tsoa);          /* zone type */
204         p16(&p, Cin);           /* zone class */
205
206         /* delete old name */
207         pname(&p, dn);          /* name */
208         p16(&p, Ta);            /* type: v4 addr */
209         p16(&p, Call);          /* class */
210         p32(&p, 0);             /* TTL */
211         p16(&p, 0);             /* data len */
212
213         pname(&p, dn);          /* name */
214         p16(&p, Taaaa);         /* type: v6 addr */
215         p16(&p, Call);          /* class */
216         p32(&p, 0);             /* TTL */
217         p16(&p, 0);             /* data len */
218
219         for(ifc = readipifc(net, nil, -1); ifc != nil; ifc = ifc->next){
220                 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
221                         /* unspecified */
222                         if(ipcmp(lifc->ip, IPnoaddr) == 0)
223                                 continue;
224
225                         /* ipv6 loopback */
226                         if(ipcmp(lifc->ip, loopback6) == 0)
227                                 continue;
228
229                         /* ipv4 loopback */
230                         maskip(lifc->ip, loopbackmask, mynet);
231                         if(ipcmp(mynet, loopbacknet) == 0)
232                                 continue;
233
234                         if(debug)
235                                 print("ip=%I\n", lifc->ip);
236
237                         /* add new A record */
238                         pname(&p, dn);          /* name */
239                         p16(&p, isv4(lifc->ip)?Ta:Taaaa);
240                         p16(&p, Cin);           /* class */
241                         p32(&p, 60*60*25);      /* TTL (25 hours) */
242                         if(isv4(lifc->ip)){
243                                 p16(&p, IPv4addrlen);
244                                 pmem(&p, lifc->ip+IPv4off, IPv4addrlen);
245                         } else {
246                                 p16(&p, IPaddrlen);
247                                 pmem(&p, lifc->ip, IPaddrlen);
248                         }
249                 }
250         }
251
252         len = p - buf;
253         if(write(fd, buf, len) != len)
254                 sysfatal("write failed: %r");
255
256         notify(ding);
257         alarm(3000);
258         do{
259                 if(read(fd, buf, sizeof buf) < 0)
260                         sysfatal("timeout");
261                 p = buf;
262         }while(g16(&p) != txid);
263         alarm(0);
264
265         err = g16(&p) & 7;
266         if(err != 0 && err != 7)        /* err==7 is just a "yes, I know" warning */
267                 if(err < nelem(errmsgs))
268                         sysfatal("%s", errmsgs[err]);
269                 else
270                         sysfatal("unknown dns server error %d", err);
271         exits(nil);
272 }