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