]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/inform.c
merge
[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];
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         if(debug){
177                 print("ns=%s\n", ns);
178                 print("dnsdomain=%s\n", dnsdomain);
179                 print("dom=%s\n", dom);
180         }
181
182         if((fd = dial(netmkaddr(ns, "udp", "dns"), 0, 0, 0)) < 0)
183                 sysfatal("can't dial %s: %r", ns);
184
185         txid = time(nil) + getpid();
186
187         p = buf;
188         p16(&p, txid);          /* ID */
189         p16(&p, 5<<11);         /* flags */
190         p16(&p, 1);             /* # Zones */
191         p16(&p, 0);             /* # prerequisites */
192         p16(&p, 2);             /* # updates */
193         p16(&p, 0);             /* # additionals */
194
195         pname(&p, dnsdomain);   /* zone */
196         p16(&p, Tsoa);          /* zone type */
197         p16(&p, Cin);           /* zone class */
198
199         /* delete old name */
200         pname(&p, dom);         /* name */
201         p16(&p, Ta);            /* type: v4 addr */
202         p16(&p, Call);          /* class */
203         p32(&p, 0);             /* TTL */
204         p16(&p, 0);             /* data len */
205
206         pname(&p, dom);         /* name */
207         p16(&p, Taaaa);         /* type: v6 addr */
208         p16(&p, Call);          /* class */
209         p32(&p, 0);             /* TTL */
210         p16(&p, 0);             /* data len */
211
212         for(ifc = readipifc(net, nil, -1); ifc != nil; ifc = ifc->next){
213                 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
214                         /* unspecified */
215                         if(ipcmp(lifc->ip, IPnoaddr) == 0)
216                                 continue;
217
218                         /* ipv6 loopback */
219                         if(ipcmp(lifc->ip, loopback6) == 0)
220                                 continue;
221
222                         /* ipv4 loopback */
223                         maskip(lifc->ip, loopbackmask, mynet);
224                         if(ipcmp(mynet, loopbacknet) == 0)
225                                 continue;
226
227                         if(debug)
228                                 print("ip=%I\n", lifc->ip);
229
230                         /* add new A record */
231                         pname(&p, dom);         /* name */
232                         p16(&p, isv4(lifc->ip)?Ta:Taaaa);
233                         p16(&p, Cin);           /* class */
234                         p32(&p, 60*60*25);      /* TTL (25 hours) */
235                         if(isv4(lifc->ip)){
236                                 p16(&p, IPv4addrlen);
237                                 pmem(&p, lifc->ip+IPv4off, IPv4addrlen);
238                         } else {
239                                 p16(&p, IPaddrlen);
240                                 pmem(&p, lifc->ip, IPaddrlen);
241                         }
242                 }
243         }
244
245         len = p - buf;
246         if(write(fd, buf, len) != len)
247                 sysfatal("write failed: %r");
248
249         notify(ding);
250         alarm(3000);
251         do{
252                 if(read(fd, buf, sizeof buf) < 0)
253                         sysfatal("timeout");
254                 p = buf;
255         }while(g16(&p) != txid);
256         alarm(0);
257
258         err = g16(&p) & 7;
259         if(err != 0 && err != 7)        /* err==7 is just a "yes, I know" warning */
260                 if(err < nelem(errmsgs))
261                         sysfatal("%s", errmsgs[err]);
262                 else
263                         sysfatal("unknown dns server error %d", err);
264         exits(nil);
265 }