summaryrefslogtreecommitdiff
path: root/src/server/shibari_packet_tdb_axfr.c
blob: 5613b67efea2099766ccb00d930450b05a757c98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/* ISC license. */

#include <stdint.h>
#include <string.h>

#include <skalibs/bytestr.h>
#include <skalibs/cdb.h>
#include <skalibs/tai.h>
#include <skalibs/unix-timed.h>

#include <s6-dns/s6dns-domain.h>
#include <s6-dns/s6dns-message.h>

#include <shibari/constants.h>
#include <shibari/tdb.h>
#include <shibari/packet.h>
#include <shibari/util.h>

static int add (buffer *b, shibari_packet *pkt, shibari_tdb_entry const *entry, int prefixlen, uint16_t id, s6dns_domain_t const *zone, tain const *deadline, tain *stamp)
{
  if (!shibari_packet_add_rr(pkt, entry, prefixlen, 0, 2))
  {
    shibari_packet_end(pkt) ;
    if (!buffer_timed_put(b, pkt->buf - 2, pkt->pos + 2, deadline, stamp)) return 0 ;
    shibari_packet_begin(pkt, id, zone, SHIBARI_T_AXFR) ;
    shibari_packet_add_rr(pkt, entry, prefixlen, 0, 2) ;
  }
  return 1 ;
}

#define SEPS "/,; \t\n"

int shibari_packet_tdb_axfr (buffer *b, char const *axfrok, char const *loc, cdb const *tdb, s6dns_message_header_t const *qhdr, s6dns_domain_t const *zone, shibari_packet *pkt, tain const *deadline, tain const *wstamp, tain *stamp)
{
  shibari_tdb_entry soa ;
  shibari_tdb_entry cur ;
  uint32_t pos = CDB_TRAVERSE_INIT() ;
  if (axfrok && axfrok[0] != '*')
  {
    s6dns_domain_t decoded = *zone ;
    unsigned int zonelen ;
    size_t len = strlen(axfrok) + 1 ;
    char zbuf[256] ;
    if (!s6dns_domain_decode(&decoded)) return 1 ;
    zonelen = s6dns_domain_tostring(zbuf, 256, &decoded) ;
    while (len)
    {
      size_t seppos = byte_in(axfrok, len, SEPS, sizeof(SEPS)) ;
      if (!memcmp(zbuf, axfrok, seppos) && (seppos == zonelen || seppos + 1 == zonelen)) break ;
      axfrok += seppos + 1 ;
      len -= seppos + 1 ;
    }
    if (!len) return 5 ;
  }

  {
    cdb_find_state state = CDB_FIND_STATE_ZERO ;
    int r = shibari_tdb_read_entry(tdb, &state, &soa, zone->s, zone->len, SHIBARI_T_SOA, 0, loc, wstamp, 0) ;
    if (r == -1) return 2 ;
    if (!r) return 9 ;
  }

  shibari_packet_begin(pkt, qhdr->id, zone, SHIBARI_T_AXFR) ;
  pkt->hdr.aa = 1 ;
  if (!add(b, pkt, &soa, 0, qhdr->id, zone, deadline, stamp)) return -1 ;

  for (;;)
  {
    cdb_data data ;
    int prefixlen ;
    int r = cdb_traverse_next(tdb, &cur.key, &data, &pos) ;
    if (r == -1) return 2 ;
    if (!r) break ;
    prefixlen = shibari_util_get_prefixlen(cur.key.s, cur.key.len, zone->s, zone->len) ;
    if (prefixlen == -1) continue ;
    r = shibari_tdb_entry_parse(&cur, data.s, data.len, SHIBARI_T_ANY, 2, loc, wstamp) ;
    if (r == -1) return 2 ;
    if (!r) continue ;
    if (cur.type == SHIBARI_T_SOA) continue ;
    if (!add(b, pkt, &cur, prefixlen, qhdr->id, zone, deadline, stamp)) return -1 ;
  }

  if (!add(b, pkt, &soa, 0, qhdr->id, zone, deadline, stamp)) return -1 ;
  shibari_packet_end(pkt) ;
  return 0 ;
}