djbdnscurve6  38
djbdnscurve6
tinydns-edit.c
Go to the documentation of this file.
1 #include <unistd.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include "stralloc.h"
5 #include "buffer.h"
6 #include "exit.h"
7 #include "open.h"
8 #include "getln.h"
9 #include "logmsg.h"
10 #include "scan.h"
11 #include "byte.h"
12 #include "str.h"
13 #include "fmt.h"
14 #include "ip.h"
15 #include "dns.h"
16 
17 #define WHO "tinydns-edit"
18 
19 #define TTL_NS 259200
20 #define TTL_POSITIVE 86400
21 
22 char *fn;
23 char *fnnew;
24 
25 void die_usage()
26 {
27  logmsg(WHO,100,USAGE,"tinydns-edit data data.new add [ns|childns|host|alias|mx] domain a.b.c.d\n"
28  "tinydns-edit data data.new add [ns|childns|host6|alias6|mx] domain a:b:c:d:e:f:g:h");
29 }
30 void nomem()
31 {
32  logmsg(WHO,111,FATAL,"out of memory");
33 }
34 void die_read()
35 {
36  logmsg(WHO,100,FATAL,B("fatal: unable to read: ",fn));
37 }
38 void die_write()
39 {
40  logmsg(WHO,111,FATAL,B("fatal: unable to write: ",fnnew));
41 }
42 
43 char mode;
44 static char *target;
45 char targetip4[4];
46 char targetip6[16];
47 
48 int fd;
49 buffer b;
50 char bspace[1024];
51 
52 int fdnew;
53 buffer bnew;
54 char bnewspace[1024];
55 
56 static stralloc line;
57 int match = 1;
58 
59 #define NUMFIELDS 10
60 static stralloc f[NUMFIELDS];
61 
62 static char *d1;
63 static char *d2;
64 char ip4[4];
65 char ip6[16];
66 char ip4str[IP4_FMT];
67 char ip6str[IP6_FMT];
68 char strnum[FMT_ULONG];
69 
70 static char *names[26];
71 static int used[26];
72 
73 void put(const char *buf,unsigned int len)
74 {
75  if (buffer_putalign(&bnew,buf,len) == -1) die_write();
76 }
77 
78 int main(int argc,char **argv)
79 {
80  unsigned long ttl;
81  struct stat st;
82  int i;
83  int j;
84  int k;
85  char ch;
86 
87  if (!*argv) die_usage();
88 
89  if (!*++argv) die_usage();
90  fn = *argv;
91 
92  if (!*++argv) die_usage();
93  fnnew = *argv;
94 
95  if (!*++argv) die_usage();
96  if (str_diff(*argv,"add")) die_usage();
97 
98  if (!*++argv) die_usage();
99  if (str_equal(*argv,"ns")) mode = '.';
100  else if (str_equal(*argv,"childns")) mode = '&';
101  else if (str_equal(*argv,"host")) mode = '=';
102  else if (str_equal(*argv,"host6")) mode = ':';
103  else if (str_equal(*argv,"alias")) mode = '+';
104  else if (str_equal(*argv,"alias6")) mode = '~';
105  else if (str_equal(*argv,"mx")) mode = '@';
106  else die_usage();
107 
108  if (!*++argv) die_usage();
109  if (dns_domain_fromdot(&target,*argv,str_len(*argv)) <= 0) nomem();
110 
111  if (!*++argv) die_usage();
112  if (mode == ':' || mode == '~') {
113  if (!ip6_scan(*argv,targetip6)) die_usage();
114  } else {
115  if (!ip4_scan(*argv,targetip4)) die_usage();
116  }
117 
118  umask(077);
119 
120  fd = open_read(fn);
121  if (fd == -1) die_read();
122  if (fstat(fd,&st) == -1) die_read();
123  buffer_init(&b,buffer_unixread,fd,bspace,sizeof(bspace));
124 
125  fdnew = open_trunc(fnnew);
126  if (fdnew == -1) die_write();
127  if (fchmod(fdnew,st.st_mode & 0644) == -1) die_write();
128  buffer_init(&bnew,buffer_unixwrite,fdnew,bnewspace,sizeof(bnewspace));
129 
130  switch (mode) {
131  case '.': case '&':
132  ttl = TTL_NS;
133  for (i = 0; i < 26; ++i) {
134  ch = 'a' + i;
135  if (!stralloc_copyb(&f[0],&ch,1)) nomem();
136  if (!stralloc_cats(&f[0],".ns.")) nomem();
137  if (dns_domain_todot_cat(&f[0],target) <= 0) nomem();
138  if (dns_domain_fromdot(&names[i],f[0].s,f[0].len) <= 0) nomem();
139  }
140  break;
141  case '+': case '=': case ':': case '~':
142  ttl = TTL_POSITIVE;
143  break;
144  case '@':
145  ttl = TTL_POSITIVE;
146  for (i = 0; i < 26; ++i) {
147  ch = 'a' + i;
148  if (!stralloc_copyb(&f[0],&ch,1)) nomem();
149  if (!stralloc_cats(&f[0],".mx.")) nomem();
150  if (dns_domain_todot_cat(&f[0],target) <= 0) nomem();
151  if (dns_domain_fromdot(&names[i],f[0].s,f[0].len) <= 0) nomem();
152  }
153  break;
154  }
155 
156  while (match) {
157  if (getln(&b,&line,&match,'\n') == -1) die_read();
158 
159  put(line.s,line.len);
160  if (line.len && !match) put("\n",1);
161 
162  while (line.len) {
163  ch = line.s[line.len - 1];
164  if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break;
165  --line.len;
166  }
167  if (!line.len) continue;
168  if (line.s[0] == '#') continue;
169 
170  j = 1;
171  for (i = 0; i < NUMFIELDS; ++i) {
172  if (j >= line.len) {
173  if (!stralloc_copys(&f[i],"")) nomem();
174  }
175  else {
176  k = byte_chr(line.s + j,line.len - j,'|');
177  if (!stralloc_copyb(&f[i],line.s + j,k)) nomem();
178  j += k + 1;
179  }
180  }
181 
182  switch (mode) {
183  case '.': case '&':
184  if (line.s[0] == mode) {
185  if (dns_domain_fromdot(&d1,f[0].s,f[0].len) <= 0) nomem();
186  if (dns_domain_equal(d1,target)) {
187  if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) {
188  if (!stralloc_cats(&f[2],".ns.")) nomem();
189  if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem();
190  }
191  if (dns_domain_fromdot(&d2,f[2].s,f[2].len) <= 0) nomem();
192  if (!stralloc_0(&f[3])) nomem();
193  if (!scan_ulong(f[3].s,&ttl)) ttl = TTL_NS;
194  for (i = 0; i < 26; ++i)
195  if (dns_domain_equal(d2,names[i])) {
196  used[i] = 1;
197  break;
198  }
199  }
200  }
201  break;
202 
203  case '=':
204  if (line.s[0] == '=') {
205  if (dns_domain_fromdot(&d1,f[0].s,f[0].len) <= 0) nomem();
206  if (dns_domain_equal(d1,target))
207  logmsg(WHO,100,FATAL,"host name already used");
208  if (!stralloc_0(&f[1])) nomem();
209  if (ip4_scan(f[1].s,ip4))
210  if (byte_equal(ip4,4,targetip4))
211  logmsg(WHO,100,FATAL,"IP address already used");
212  }
213  break;
214 
215  case ':':
216  if (line.s[0] == ':') {
217  if (dns_domain_fromdot(&d1,f[0].s,f[0].len) <= 0) nomem();
218  if (dns_domain_equal(d1,target))
219  logmsg(WHO,100,FATAL,"host name already used");
220  if (!stralloc_0(&f[1])) nomem();
221  if (ip6_scan(f[1].s,ip6))
222  if (byte_equal(ip6,16,targetip6))
223  logmsg(WHO,100,FATAL,"IPv6 address already used");
224  }
225  break;
226 
227  case '@':
228  if (line.s[0] == '@') {
229  if (dns_domain_fromdot(&d1,f[0].s,f[0].len) <= 0) nomem();
230  if (dns_domain_equal(d1,target)) {
231  if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) {
232  if (!stralloc_cats(&f[2],".mx.")) nomem();
233  if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem();
234  }
235  if (dns_domain_fromdot(&d2,f[2].s,f[2].len) <= 0) nomem();
236  if (!stralloc_0(&f[4])) nomem();
237  if (!scan_ulong(f[4].s,&ttl)) ttl = TTL_POSITIVE;
238  for (i = 0; i < 26; ++i)
239  if (dns_domain_equal(d2,names[i])) {
240  used[i] = 1;
241  break;
242  }
243  }
244  }
245  break;
246  }
247  }
248 
249  if (!stralloc_copyb(&f[0],&mode,1)) nomem();
250  if (dns_domain_todot_cat(&f[0],target) <= 0) nomem();
251  if (!stralloc_cats(&f[0],"|")) nomem();
252  if (mode == ':' || mode == '~') {
253  if (!stralloc_catb(&f[0],ip6str,ip6_fmt(ip6str,targetip6))) nomem();
254  } else {
255  if (!stralloc_catb(&f[0],ip4str,ip4_fmt(ip4str,targetip4))) nomem();
256  }
257  switch (mode) {
258  case '.': case '&': case '@':
259  for (i = 0; i < 26; ++i)
260  if (!used[i])
261  break;
262  if (i >= 26)
263  logmsg(WHO,100,FATAL,"too many records for that domain");
264  ch = 'a' + i;
265  if (!stralloc_cats(&f[0],"|")) nomem();
266  if (!stralloc_catb(&f[0],&ch,1)) nomem();
267  if (mode == '@')
268  if (!stralloc_cats(&f[0],"|")) nomem();
269  break;
270  }
271  if (!stralloc_cats(&f[0],"|")) nomem();
272  if (!stralloc_catb(&f[0],strnum,fmt_ulong(strnum,ttl))) nomem();
273  if (!stralloc_cats(&f[0],"\n")) nomem();
274  put(f[0].s,f[0].len);
275 
276  if (buffer_flush(&bnew) == -1) die_write();
277  if (fsync(fdnew) == -1) die_write();
278  if (close(fdnew) == -1) die_write(); /* NFS dorks */
279  if (rename(fnnew,fn) == -1)
280  logmsg(WHO,111,FATAL,B("unable to move ",fnnew," to: ",fn));
281  _exit(0);
282 }
int rename(const char *, const char *)
stralloc line
Definition: axfr-get.c:126
uint16 len
Definition: axfrdns.c:302
char buf[MSGSIZE]
Definition: axfrdns.c:301
int dns_domain_equal(const char *, const char *)
Definition: dns_domain.c:39
int dns_domain_fromdot(char **, const char *, unsigned int)
Definition: dns_dfd.c:6
int dns_domain_todot_cat(stralloc *, const char *)
Definition: dns_dtda.c:11
char mode
Definition: tinydns-edit.c:43
char ip6str[IP6_FMT]
Definition: tinydns-edit.c:67
int fdnew
Definition: tinydns-edit.c:52
char bspace[1024]
Definition: tinydns-edit.c:50
int main(int argc, char **argv)
Definition: tinydns-edit.c:78
char * fnnew
Definition: tinydns-edit.c:23
char strnum[FMT_ULONG]
Definition: tinydns-edit.c:68
void die_usage()
Definition: tinydns-edit.c:25
char targetip4[4]
Definition: tinydns-edit.c:45
buffer bnew
Definition: tinydns-edit.c:53
char ip6[16]
Definition: tinydns-edit.c:65
void put(const char *buf, unsigned int len)
Definition: tinydns-edit.c:73
buffer b
Definition: tinydns-edit.c:49
int fd
Definition: tinydns-edit.c:48
void die_write()
Definition: tinydns-edit.c:38
char bnewspace[1024]
Definition: tinydns-edit.c:54
#define TTL_POSITIVE
Definition: tinydns-edit.c:20
void nomem()
Definition: tinydns-edit.c:30
#define TTL_NS
Definition: tinydns-edit.c:19
void die_read()
Definition: tinydns-edit.c:34
#define NUMFIELDS
Definition: tinydns-edit.c:59
char targetip6[16]
Definition: tinydns-edit.c:46
char ip4[4]
Definition: tinydns-edit.c:64
char * fn
Definition: tinydns-edit.c:22
int match
Definition: tinydns-edit.c:57
#define WHO
Definition: tinydns-edit.c:17
char ip4str[IP4_FMT]
Definition: tinydns-edit.c:66
Definition: dnsfilter.c:23