release
[hcoop/zz_old/debian/djbdns.git] / tinydns-data.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include "uint16.h"
6 #include "uint32.h"
7 #include "str.h"
8 #include "byte.h"
9 #include "fmt.h"
10 #include "ip4.h"
11 #include "exit.h"
12 #include "case.h"
13 #include "scan.h"
14 #include "buffer.h"
15 #include "strerr.h"
16 #include "getln.h"
17 #include "cdb_make.h"
18 #include "stralloc.h"
19 #include "open.h"
20 #include "dns.h"
21
22 #define TTL_NS 259200
23 #define TTL_POSITIVE 86400
24 #define TTL_NEGATIVE 2560
25
26 #define FATAL "tinydns-data: fatal: "
27
28 void die_datatmp(void)
29 {
30 strerr_die2sys(111,FATAL,"unable to create data.tmp: ");
31 }
32 void nomem(void)
33 {
34 strerr_die1sys(111,FATAL);
35 }
36
37 void ttdparse(stralloc *sa,char ttd[8])
38 {
39 unsigned int i;
40 char ch;
41
42 byte_zero(ttd,8);
43 for (i = 0;(i < 16) && (i < sa->len);++i) {
44 ch = sa->s[i];
45 if ((ch >= '0') && (ch <= '9'))
46 ch -= '0';
47 else if ((ch >= 'a') && (ch <= 'f'))
48 ch -= 'a' - 10;
49 else
50 ch = 0;
51 if (!(i & 1)) ch <<= 4;
52 ttd[i >> 1] |= ch;
53 }
54 }
55
56 void locparse(stralloc *sa,char loc[2])
57 {
58 loc[0] = (sa->len > 0) ? sa->s[0] : 0;
59 loc[1] = (sa->len > 1) ? sa->s[1] : 0;
60 }
61
62 void ipprefix_cat(stralloc *out,char *s)
63 {
64 unsigned long u;
65 char ch;
66 unsigned int j;
67
68 for (;;)
69 if (*s == '.')
70 ++s;
71 else {
72 j = scan_ulong(s,&u);
73 if (!j) return;
74 s += j;
75 ch = u;
76 if (!stralloc_catb(out,&ch,1)) nomem();
77 }
78 }
79
80 void txtparse(stralloc *sa)
81 {
82 char ch;
83 unsigned int i;
84 unsigned int j;
85
86 j = 0;
87 i = 0;
88 while (i < sa->len) {
89 ch = sa->s[i++];
90 if (ch == '\\') {
91 if (i >= sa->len) break;
92 ch = sa->s[i++];
93 if ((ch >= '0') && (ch <= '7')) {
94 ch -= '0';
95 if ((i < sa->len) && (sa->s[i] >= '0') && (sa->s[i] <= '7')) {
96 ch <<= 3;
97 ch += sa->s[i++] - '0';
98 if ((i < sa->len) && (sa->s[i] >= '0') && (sa->s[i] <= '7')) {
99 ch <<= 3;
100 ch += sa->s[i++] - '0';
101 }
102 }
103 }
104 }
105 sa->s[j++] = ch;
106 }
107 sa->len = j;
108 }
109
110 char defaultsoa[20];
111
112 void defaultsoa_init(int fd)
113 {
114 struct stat st;
115 if (fstat(fd,&st) == -1)
116 strerr_die2sys(111,FATAL,"unable to stat data: ");
117 uint32_pack_big(defaultsoa,st.st_mtime);
118 if (byte_equal(defaultsoa,4,"\0\0\0\0"))
119 defaultsoa[3] = 1;
120 byte_copy(defaultsoa + 4,16,"\0\0\100\000\0\0\010\000\0\020\000\000\0\0\012\000");
121 }
122
123 int fdcdb;
124 struct cdb_make cdb;
125 static stralloc key;
126 static stralloc result;
127
128 void rr_add(const char *buf,unsigned int len)
129 {
130 if (!stralloc_catb(&result,buf,len)) nomem();
131 }
132 void rr_addname(const char *d)
133 {
134 rr_add(d,dns_domain_length(d));
135 }
136 void rr_start(const char type[2],unsigned long ttl,const char ttd[8],const char loc[2])
137 {
138 char buf[4];
139 if (!stralloc_copyb(&result,type,2)) nomem();
140 if (byte_equal(loc,2,"\0\0"))
141 rr_add("=",1);
142 else {
143 rr_add(">",1);
144 rr_add(loc,2);
145 }
146 uint32_pack_big(buf,ttl);
147 rr_add(buf,4);
148 rr_add(ttd,8);
149 }
150 void rr_finish(const char *owner)
151 {
152 if (byte_equal(owner,2,"\1*")) {
153 owner += 2;
154 result.s[2] -= 19;
155 }
156 if (!stralloc_copyb(&key,owner,dns_domain_length(owner))) nomem();
157 case_lowerb(key.s,key.len);
158 if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1)
159 die_datatmp();
160 }
161
162 buffer b;
163 char bspace[1024];
164
165 static stralloc line;
166 int match = 1;
167 unsigned long linenum = 0;
168
169 #define NUMFIELDS 15
170 static stralloc f[NUMFIELDS];
171
172 static char *d1;
173 static char *d2;
174 char dptr[DNS_NAME4_DOMAIN];
175
176 char strnum[FMT_ULONG];
177
178 void syntaxerror(const char *why)
179 {
180 strnum[fmt_ulong(strnum,linenum)] = 0;
181 strerr_die4x(111,FATAL,"unable to parse data line ",strnum,why);
182 }
183
184 int main()
185 {
186 int fddata;
187 int i;
188 int j;
189 int k;
190 char ch;
191 unsigned long ttl;
192 char ttd[8];
193 char loc[2];
194 unsigned long u;
195 char ip[4];
196 char type[2];
197 char soa[20];
198 char buf[4];
199
200 umask(022);
201
202 fddata = open_read("data");
203 if (fddata == -1)
204 strerr_die2sys(111,FATAL,"unable to open data: ");
205 defaultsoa_init(fddata);
206
207 buffer_init(&b,buffer_unixread,fddata,bspace,sizeof bspace);
208
209 fdcdb = open_trunc("data.tmp");
210 if (fdcdb == -1) die_datatmp();
211 if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp();
212
213 while (match) {
214 ++linenum;
215 if (getln(&b,&line,&match,'\n') == -1)
216 strerr_die2sys(111,FATAL,"unable to read line: ");
217
218 while (line.len) {
219 ch = line.s[line.len - 1];
220 if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break;
221 --line.len;
222 }
223 if (!line.len) continue;
224 if (line.s[0] == '#') continue;
225 if (line.s[0] == '-') continue;
226
227 j = 1;
228 for (i = 0;i < NUMFIELDS;++i) {
229 if (j >= line.len) {
230 if (!stralloc_copys(&f[i],"")) nomem();
231 }
232 else {
233 k = byte_chr(line.s + j,line.len - j,':');
234 if (!stralloc_copyb(&f[i],line.s + j,k)) nomem();
235 j += k + 1;
236 }
237 }
238
239 switch(line.s[0]) {
240
241 case '%':
242 locparse(&f[0],loc);
243 if (!stralloc_copyb(&key,"\0%",2)) nomem();
244 if (!stralloc_0(&f[1])) nomem();
245 ipprefix_cat(&key,f[1].s);
246 if (cdb_make_add(&cdb,key.s,key.len,loc,2) == -1)
247 die_datatmp();
248 break;
249
250 case 'Z':
251 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
252
253 if (!stralloc_0(&f[3])) nomem();
254 if (!scan_ulong(f[3].s,&u)) uint32_unpack_big(defaultsoa,&u);
255 uint32_pack_big(soa,u);
256 if (!stralloc_0(&f[4])) nomem();
257 if (!scan_ulong(f[4].s,&u)) uint32_unpack_big(defaultsoa + 4,&u);
258 uint32_pack_big(soa + 4,u);
259 if (!stralloc_0(&f[5])) nomem();
260 if (!scan_ulong(f[5].s,&u)) uint32_unpack_big(defaultsoa + 8,&u);
261 uint32_pack_big(soa + 8,u);
262 if (!stralloc_0(&f[6])) nomem();
263 if (!scan_ulong(f[6].s,&u)) uint32_unpack_big(defaultsoa + 12,&u);
264 uint32_pack_big(soa + 12,u);
265 if (!stralloc_0(&f[7])) nomem();
266 if (!scan_ulong(f[7].s,&u)) uint32_unpack_big(defaultsoa + 16,&u);
267 uint32_pack_big(soa + 16,u);
268
269 if (!stralloc_0(&f[8])) nomem();
270 if (!scan_ulong(f[8].s,&ttl)) ttl = TTL_NEGATIVE;
271 ttdparse(&f[9],ttd);
272 locparse(&f[10],loc);
273
274 rr_start(DNS_T_SOA,ttl,ttd,loc);
275 if (!dns_domain_fromdot(&d2,f[1].s,f[1].len)) nomem();
276 rr_addname(d2);
277 if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem();
278 rr_addname(d2);
279 rr_add(soa,20);
280 rr_finish(d1);
281 break;
282
283 case '.': case '&':
284 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
285 if (!stralloc_0(&f[3])) nomem();
286 if (!scan_ulong(f[3].s,&ttl)) ttl = TTL_NS;
287 ttdparse(&f[4],ttd);
288 locparse(&f[5],loc);
289
290 if (!stralloc_0(&f[1])) nomem();
291
292 if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) {
293 if (!stralloc_cats(&f[2],".ns.")) nomem();
294 if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem();
295 }
296 if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem();
297
298 if (line.s[0] == '.') {
299 rr_start(DNS_T_SOA,ttl ? TTL_NEGATIVE : 0,ttd,loc);
300 rr_addname(d2);
301 rr_add("\12hostmaster",11);
302 rr_addname(d1);
303 rr_add(defaultsoa,20);
304 rr_finish(d1);
305 }
306
307 rr_start(DNS_T_NS,ttl,ttd,loc);
308 rr_addname(d2);
309 rr_finish(d1);
310
311 if (ip4_scan(f[1].s,ip)) {
312 rr_start(DNS_T_A,ttl,ttd,loc);
313 rr_add(ip,4);
314 rr_finish(d2);
315 }
316
317 break;
318
319 case '+': case '=':
320 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
321 if (!stralloc_0(&f[2])) nomem();
322 if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE;
323 ttdparse(&f[3],ttd);
324 locparse(&f[4],loc);
325
326 if (!stralloc_0(&f[1])) nomem();
327
328 if (ip4_scan(f[1].s,ip)) {
329 rr_start(DNS_T_A,ttl,ttd,loc);
330 rr_add(ip,4);
331 rr_finish(d1);
332
333 if (line.s[0] == '=') {
334 dns_name4_domain(dptr,ip);
335 rr_start(DNS_T_PTR,ttl,ttd,loc);
336 rr_addname(d1);
337 rr_finish(dptr);
338 }
339 }
340 break;
341
342 case '@':
343 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
344 if (!stralloc_0(&f[4])) nomem();
345 if (!scan_ulong(f[4].s,&ttl)) ttl = TTL_POSITIVE;
346 ttdparse(&f[5],ttd);
347 locparse(&f[6],loc);
348
349 if (!stralloc_0(&f[1])) nomem();
350
351 if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) {
352 if (!stralloc_cats(&f[2],".mx.")) nomem();
353 if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem();
354 }
355 if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem();
356
357 if (!stralloc_0(&f[3])) nomem();
358 if (!scan_ulong(f[3].s,&u)) u = 0;
359
360 rr_start(DNS_T_MX,ttl,ttd,loc);
361 uint16_pack_big(buf,u);
362 rr_add(buf,2);
363 rr_addname(d2);
364 rr_finish(d1);
365
366 if (ip4_scan(f[1].s,ip)) {
367 rr_start(DNS_T_A,ttl,ttd,loc);
368 rr_add(ip,4);
369 rr_finish(d2);
370 }
371 break;
372
373 case '^': case 'C':
374 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
375 if (!dns_domain_fromdot(&d2,f[1].s,f[1].len)) nomem();
376 if (!stralloc_0(&f[2])) nomem();
377 if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE;
378 ttdparse(&f[3],ttd);
379 locparse(&f[4],loc);
380
381 if (line.s[0] == 'C')
382 rr_start(DNS_T_CNAME,ttl,ttd,loc);
383 else
384 rr_start(DNS_T_PTR,ttl,ttd,loc);
385 rr_addname(d2);
386 rr_finish(d1);
387 break;
388
389 case '\'':
390 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
391 if (!stralloc_0(&f[2])) nomem();
392 if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE;
393 ttdparse(&f[3],ttd);
394 locparse(&f[4],loc);
395
396 rr_start(DNS_T_TXT,ttl,ttd,loc);
397
398 txtparse(&f[1]);
399 i = 0;
400 while (i < f[1].len) {
401 k = f[1].len - i;
402 if (k > 127) k = 127;
403 ch = k;
404 rr_add(&ch,1);
405 rr_add(f[1].s + i,k);
406 i += k;
407 }
408
409 rr_finish(d1);
410 break;
411
412 case ':':
413 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
414 if (!stralloc_0(&f[3])) nomem();
415 if (!scan_ulong(f[3].s,&ttl)) ttl = TTL_POSITIVE;
416 ttdparse(&f[4],ttd);
417 locparse(&f[5],loc);
418
419 if (!stralloc_0(&f[1])) nomem();
420 scan_ulong(f[1].s,&u);
421 uint16_pack_big(type,u);
422 if (byte_equal(type,2,DNS_T_AXFR))
423 syntaxerror(": type AXFR prohibited");
424 if (byte_equal(type,2,"\0\0"))
425 syntaxerror(": type 0 prohibited");
426 if (byte_equal(type,2,DNS_T_SOA))
427 syntaxerror(": type SOA prohibited");
428 if (byte_equal(type,2,DNS_T_NS))
429 syntaxerror(": type NS prohibited");
430 if (byte_equal(type,2,DNS_T_CNAME))
431 syntaxerror(": type CNAME prohibited");
432 if (byte_equal(type,2,DNS_T_PTR))
433 syntaxerror(": type PTR prohibited");
434 if (byte_equal(type,2,DNS_T_MX))
435 syntaxerror(": type MX prohibited");
436
437 txtparse(&f[2]);
438
439 rr_start(type,ttl,ttd,loc);
440 rr_add(f[2].s,f[2].len);
441 rr_finish(d1);
442 break;
443
444 default:
445 syntaxerror(": unrecognized leading character");
446 }
447 }
448
449 if (cdb_make_finish(&cdb) == -1) die_datatmp();
450 if (fsync(fdcdb) == -1) die_datatmp();
451 if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */
452 if (rename("data.tmp","data.cdb") == -1)
453 strerr_die2sys(111,FATAL,"unable to move data.tmp to data.cdb: ");
454
455 _exit(0);
456 }