~ubuntu-branches/ubuntu/intrepid/djbdns/intrepid-security

« back to all changes in this revision

Viewing changes to axfrdns.c

  • Committer: Bazaar Package Importer
  • Author(s): Gerrit Pape
  • Date: 2008-03-02 23:22:04 UTC
  • Revision ID: james.westby@ubuntu.com-20080302232204-wa3owprcpeiyu8kj
Tags: upstream-1.05
ImportĀ upstreamĀ versionĀ 1.05

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <unistd.h>
 
2
#include "droproot.h"
 
3
#include "exit.h"
 
4
#include "env.h"
 
5
#include "uint32.h"
 
6
#include "uint16.h"
 
7
#include "ip4.h"
 
8
#include "tai.h"
 
9
#include "buffer.h"
 
10
#include "timeoutread.h"
 
11
#include "timeoutwrite.h"
 
12
#include "open.h"
 
13
#include "seek.h"
 
14
#include "cdb.h"
 
15
#include "stralloc.h"
 
16
#include "strerr.h"
 
17
#include "str.h"
 
18
#include "byte.h"
 
19
#include "case.h"
 
20
#include "dns.h"
 
21
#include "scan.h"
 
22
#include "qlog.h"
 
23
#include "response.h"
 
24
 
 
25
extern int respond(char *,char *,char *);
 
26
 
 
27
#define FATAL "axfrdns: fatal: "
 
28
 
 
29
void nomem()
 
30
{
 
31
  strerr_die2x(111,FATAL,"out of memory");
 
32
}
 
33
void die_truncated()
 
34
{
 
35
  strerr_die2x(111,FATAL,"truncated request");
 
36
}
 
37
void die_netwrite()
 
38
{
 
39
  strerr_die2sys(111,FATAL,"unable to write to network: ");
 
40
}
 
41
void die_netread()
 
42
{
 
43
  strerr_die2sys(111,FATAL,"unable to read from network: ");
 
44
}
 
45
void die_outside()
 
46
{
 
47
  strerr_die2x(111,FATAL,"unable to locate information in data.cdb");
 
48
}
 
49
void die_cdbread()
 
50
{
 
51
  strerr_die2sys(111,FATAL,"unable to read data.cdb: ");
 
52
}
 
53
void die_cdbformat()
 
54
{
 
55
  strerr_die3x(111,FATAL,"unable to read data.cdb: ","format error");
 
56
}
 
57
 
 
58
int safewrite(int fd,char *buf,unsigned int len)
 
59
{
 
60
  int w;
 
61
 
 
62
  w = timeoutwrite(60,fd,buf,len);
 
63
  if (w <= 0) die_netwrite();
 
64
  return w;
 
65
}
 
66
 
 
67
char netwritespace[1024];
 
68
buffer netwrite = BUFFER_INIT(safewrite,1,netwritespace,sizeof netwritespace);
 
69
 
 
70
void print(char *buf,unsigned int len)
 
71
{
 
72
  char tcpheader[2];
 
73
  uint16_pack_big(tcpheader,len);
 
74
  buffer_put(&netwrite,tcpheader,2);
 
75
  buffer_put(&netwrite,buf,len);
 
76
  buffer_flush(&netwrite);
 
77
}
 
78
 
 
79
char *axfr;
 
80
static char *axfrok;
 
81
 
 
82
void axfrcheck(char *q)
 
83
{
 
84
  int i;
 
85
  int j;
 
86
 
 
87
  if (!axfr) return;
 
88
 
 
89
  i = j = 0;
 
90
  for (;;) {
 
91
    if (!axfr[i] || (axfr[i] == '/')) {
 
92
      if (i > j) {
 
93
        if (!dns_domain_fromdot(&axfrok,axfr + j,i - j)) nomem();
 
94
        if (dns_domain_equal(q,axfrok)) return;
 
95
      }
 
96
      j = i + 1;
 
97
    }
 
98
    if (!axfr[i]) break;
 
99
    ++i;
 
100
  }
 
101
 
 
102
  strerr_die2x(111,FATAL,"disallowed zone transfer request");
 
103
}
 
104
 
 
105
static char *zone;
 
106
unsigned int zonelen;
 
107
char typeclass[4];
 
108
 
 
109
int fdcdb;
 
110
buffer bcdb;
 
111
char bcdbspace[1024];
 
112
 
 
113
void get(char *buf,unsigned int len)
 
114
{
 
115
  int r;
 
116
 
 
117
  while (len > 0) {
 
118
    r = buffer_get(&bcdb,buf,len);
 
119
    if (r < 0) die_cdbread();
 
120
    if (!r) die_cdbformat();
 
121
    buf += r;
 
122
    len -= r;
 
123
  }
 
124
}
 
125
 
 
126
char ip[4];
 
127
unsigned long port;
 
128
char clientloc[2];
 
129
 
 
130
struct tai now;
 
131
char data[32767];
 
132
uint32 dlen;
 
133
uint32 dpos;
 
134
 
 
135
void copy(char *buf,unsigned int len)
 
136
{
 
137
  dpos = dns_packet_copy(data,dlen,dpos,buf,len);
 
138
  if (!dpos) die_cdbread();
 
139
}
 
140
 
 
141
void doname(stralloc *sa)
 
142
{
 
143
  static char *d;
 
144
  dpos = dns_packet_getname(data,dlen,dpos,&d);
 
145
  if (!dpos) die_cdbread();
 
146
  if (!stralloc_catb(sa,d,dns_domain_length(d))) nomem();
 
147
}
 
148
 
 
149
int build(stralloc *sa,char *q,int flagsoa,char id[2])
 
150
{
 
151
  unsigned int rdatapos;
 
152
  char misc[20];
 
153
  char type[2];
 
154
  char recordloc[2];
 
155
  char ttl[4];
 
156
  char ttd[8];
 
157
  struct tai cutoff;
 
158
 
 
159
  dpos = 0;
 
160
  copy(type,2);
 
161
  if (flagsoa) if (byte_diff(type,2,DNS_T_SOA)) return 0;
 
162
  if (!flagsoa) if (byte_equal(type,2,DNS_T_SOA)) return 0;
 
163
 
 
164
  if (!stralloc_copyb(sa,id,2)) nomem();
 
165
  if (!stralloc_catb(sa,"\204\000\0\0\0\1\0\0\0\0",10)) nomem();
 
166
  copy(misc,1);
 
167
  if ((misc[0] == '=' + 1) || (misc[0] == '*' + 1)) {
 
168
    --misc[0];
 
169
    copy(recordloc,2);
 
170
    if (byte_diff(recordloc,2,clientloc)) return 0;
 
171
  }
 
172
  if (misc[0] == '*') {
 
173
    if (flagsoa) return 0;
 
174
    if (!stralloc_catb(sa,"\1*",2)) nomem();
 
175
  }
 
176
  if (!stralloc_catb(sa,q,dns_domain_length(q))) nomem();
 
177
  if (!stralloc_catb(sa,type,2)) nomem();
 
178
 
 
179
  copy(ttl,4);
 
180
  copy(ttd,8);
 
181
  if (byte_diff(ttd,8,"\0\0\0\0\0\0\0\0")) {
 
182
    tai_unpack(ttd,&cutoff);
 
183
    if (byte_equal(ttl,4,"\0\0\0\0")) {
 
184
      if (tai_less(&cutoff,&now)) return 0;
 
185
      uint32_pack_big(ttl,2);
 
186
    }
 
187
    else
 
188
      if (!tai_less(&cutoff,&now)) return 0;
 
189
  }
 
190
 
 
191
  if (!stralloc_catb(sa,DNS_C_IN,2)) nomem();
 
192
  if (!stralloc_catb(sa,ttl,4)) nomem();
 
193
  if (!stralloc_catb(sa,"\0\0",2)) nomem();
 
194
  rdatapos = sa->len;
 
195
 
 
196
  if (byte_equal(type,2,DNS_T_SOA)) {
 
197
    doname(sa);
 
198
    doname(sa);
 
199
    copy(misc,20);
 
200
    if (!stralloc_catb(sa,misc,20)) nomem();
 
201
  }
 
202
  else if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_PTR) || byte_equal(type,2,DNS_T_CNAME)) {
 
203
    doname(sa);
 
204
  }
 
205
  else if (byte_equal(type,2,DNS_T_MX)) {
 
206
    copy(misc,2);
 
207
    if (!stralloc_catb(sa,misc,2)) nomem();
 
208
    doname(sa);
 
209
  }
 
210
  else
 
211
    if (!stralloc_catb(sa,data + dpos,dlen - dpos)) nomem();
 
212
 
 
213
  if (sa->len > 65535) die_cdbformat();
 
214
  uint16_pack_big(sa->s + rdatapos - 2,sa->len - rdatapos);
 
215
  return 1;
 
216
}
 
217
 
 
218
static struct cdb c;
 
219
static char *q;
 
220
static stralloc soa;
 
221
static stralloc message;
 
222
 
 
223
void doaxfr(char id[2])
 
224
{
 
225
  char key[512];
 
226
  uint32 klen;
 
227
  char num[4];
 
228
  uint32 eod;
 
229
  uint32 pos;
 
230
  int r;
 
231
 
 
232
  axfrcheck(zone);
 
233
 
 
234
  tai_now(&now);
 
235
  cdb_init(&c,fdcdb);
 
236
 
 
237
  byte_zero(clientloc,2);
 
238
  key[0] = 0;
 
239
  key[1] = '%';
 
240
  byte_copy(key + 2,4,ip);
 
241
  r = cdb_find(&c,key,6);
 
242
  if (!r) r = cdb_find(&c,key,5);
 
243
  if (!r) r = cdb_find(&c,key,4);
 
244
  if (!r) r = cdb_find(&c,key,3);
 
245
  if (!r) r = cdb_find(&c,key,2);
 
246
  if (r == -1) die_cdbread();
 
247
  if (r && (cdb_datalen(&c) == 2))
 
248
    if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) die_cdbread();
 
249
 
 
250
  cdb_findstart(&c);
 
251
  for (;;) {
 
252
    r = cdb_findnext(&c,zone,zonelen);
 
253
    if (r == -1) die_cdbread();
 
254
    if (!r) die_outside();
 
255
    dlen = cdb_datalen(&c);
 
256
    if (dlen > sizeof data) die_cdbformat();
 
257
    if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) die_cdbformat();
 
258
    if (build(&soa,zone,1,id)) break;
 
259
  }
 
260
 
 
261
  cdb_free(&c);
 
262
  print(soa.s,soa.len);
 
263
 
 
264
  seek_begin(fdcdb);
 
265
  buffer_init(&bcdb,buffer_unixread,fdcdb,bcdbspace,sizeof bcdbspace);
 
266
 
 
267
  pos = 0;
 
268
  get(num,4); pos += 4;
 
269
  uint32_unpack(num,&eod);
 
270
  while (pos < 2048) { get(num,4); pos += 4; }
 
271
 
 
272
  while (pos < eod) {
 
273
    if (eod - pos < 8) die_cdbformat();
 
274
    get(num,4); pos += 4;
 
275
    uint32_unpack(num,&klen);
 
276
    get(num,4); pos += 4;
 
277
    uint32_unpack(num,&dlen);
 
278
    if (eod - pos < klen) die_cdbformat();
 
279
    pos += klen;
 
280
    if (eod - pos < dlen) die_cdbformat();
 
281
    pos += dlen;
 
282
 
 
283
    if (klen > sizeof key) die_cdbformat();
 
284
    get(key,klen);
 
285
    if (dlen > sizeof data) die_cdbformat();
 
286
    get(data,dlen);
 
287
 
 
288
    if ((klen > 1) && (key[0] == 0)) continue; /* location */
 
289
    if (klen < 1) die_cdbformat();
 
290
    if (dns_packet_getname(key,klen,0,&q) != klen) die_cdbformat();
 
291
    if (!dns_domain_suffix(q,zone)) continue;
 
292
    if (!build(&message,q,0,id)) continue;
 
293
    print(message.s,message.len);
 
294
  }
 
295
 
 
296
  print(soa.s,soa.len);
 
297
}
 
298
 
 
299
void netread(char *buf,unsigned int len)
 
300
{
 
301
  int r;
 
302
 
 
303
  while (len > 0) {
 
304
    r = timeoutread(60,0,buf,len);
 
305
    if (r == 0) _exit(0);
 
306
    if (r < 0) die_netread();
 
307
    buf += r; len -= r;
 
308
  }
 
309
}
 
310
 
 
311
char tcpheader[2];
 
312
char buf[512];
 
313
uint16 len;
 
314
 
 
315
static char seed[128];
 
316
 
 
317
int main()
 
318
{
 
319
  unsigned int pos;
 
320
  char header[12];
 
321
  char qtype[2];
 
322
  char qclass[2];
 
323
  const char *x;
 
324
 
 
325
  droproot(FATAL);
 
326
  dns_random_init(seed);
 
327
 
 
328
  axfr = env_get("AXFR");
 
329
  
 
330
  x = env_get("TCPREMOTEIP");
 
331
  if (x && ip4_scan(x,ip))
 
332
    ;
 
333
  else
 
334
    byte_zero(ip,4);
 
335
 
 
336
  x = env_get("TCPREMOTEPORT");
 
337
  if (!x) x = "0";
 
338
  scan_ulong(x,&port);
 
339
 
 
340
  for (;;) {
 
341
    netread(tcpheader,2);
 
342
    uint16_unpack_big(tcpheader,&len);
 
343
    if (len > 512) strerr_die2x(111,FATAL,"excessively large request");
 
344
    netread(buf,len);
 
345
 
 
346
    pos = dns_packet_copy(buf,len,0,header,12); if (!pos) die_truncated();
 
347
    if (header[2] & 254) strerr_die2x(111,FATAL,"bogus query");
 
348
    if (header[4] || (header[5] != 1)) strerr_die2x(111,FATAL,"bogus query");
 
349
 
 
350
    pos = dns_packet_getname(buf,len,pos,&zone); if (!pos) die_truncated();
 
351
    zonelen = dns_domain_length(zone);
 
352
    pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) die_truncated();
 
353
    pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) die_truncated();
 
354
 
 
355
    if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY))
 
356
      strerr_die2x(111,FATAL,"bogus query: bad class");
 
357
 
 
358
    qlog(ip,port,header,zone,qtype," ");
 
359
 
 
360
    if (byte_equal(qtype,2,DNS_T_AXFR)) {
 
361
      case_lowerb(zone,zonelen);
 
362
      fdcdb = open_read("data.cdb");
 
363
      if (fdcdb == -1) die_cdbread();
 
364
      doaxfr(header);
 
365
      close(fdcdb);
 
366
    }
 
367
    else {
 
368
      if (!response_query(zone,qtype,qclass)) nomem();
 
369
      response[2] |= 4;
 
370
      case_lowerb(zone,zonelen);
 
371
      response_id(header);
 
372
      response[3] &= ~128;
 
373
      if (!(header[2] & 1)) response[2] &= ~1;
 
374
      if (!respond(zone,qtype,ip)) die_outside();
 
375
      print(response,response_len);
 
376
    }
 
377
  }
 
378
}