summaryrefslogtreecommitdiff
path: root/src/cache/query.c
blob: 7fb27c4c8ce1bb2fb3d7a62ba3d71f432a294a15 (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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/* ISC license. */

#include <stdint.h>

#include <s6-dns/s6dns.h>

#include <shibari/constants.h>
#include "shibari-cache-internal.h"

static uint16_t query_delete (query *q)
{
  uint16_t newi = q->prev ;
  QUERY(newi)->next = q->next ;
  QUERY(q->next)->prev = q->prev ;
  q->xindex = UINT16_MAX ;
  q->qname.len = 0 ;
  return newi ;
}

uint16_t query_abort (uint16_t id)
{
  query *q = QUERY(id) ;
  s6dns_engine_recycle(&q->dt) ;
  return query_delete(q) ;
}

uint16_t query_fail (uint16_t id)
{
  query *q = QUERY(id) ;

  if (q->source == 2) tcpconnection_removequery(TCPCONNECTION(q->i), id) ;
  return query_delete(q) ;
}

uint16_t query_succeed (uint16_t id)
{
  query *q = QUERY(id) ;

  if (q->source == 2) tcpconnection_removequery(TCPCONNECTION(q->i), id) ;
  return query_delete(q) ;
}

int query_end (uint8_t source, uint16_t i, char const *ip, uint16_t port, char const *buf, uint16_t len)
{
  return source < 2 ?
    udpqueue_add(g->udpqueues[source] + i, source, ip, port, buf, len) :
    tcpconnection_add(g->tcpconnections + i, buf, len) ;
}

int query_error (uint8_t source, uint16_t i, char const *ip, uint16_t port, s6dns_domain_t *name, uint16_t qtype, uint16_t id, unsigned int rcode)
{
  s6dns_message_header_t hdr = S6DNS_MESSAGE_HEADER_ZERO ;
  unsigned int pos = 12 ;
  char pkt[name->len + 16] ;
  hdr.id = id ;
  hdr.qr = 1 ;
  hdr.ra = 1 ;
  hdr.rcode = rcode ;
  hdr.counts.qd = 1 ;
  s6dns_message_header_pack(pkt, &hdr) ;
  memcpy(pkt + pos, name->s, name->len) ; pos += name->len ;
  uint16_pack_big(pkt + pos, qtype) ; pos += 2 ;
  uint16_pack_big(pkt + pos, SHIBARI_C_IN) ; pos += 2 ;
  return query_end(source, i, ip, port, pkt, pos) ;
}

static void query_init (query *q, uint8_t source, uint16_t i, char const *ip, uint16_t port, s6dns_domain_t const *name, uint16_t qtype)
{
  q->source = source ;
  q->i = i ;
  if (source < 2)
  {
    memcpy(q->ip, ip, source ? 16 : 4) ;
    q->port = port ;
  }
  q->port = port ;
  if (!stralloc_catb(&q->qname, name->s, name->len)) dienomem() ;
  q->qtype = qtype ;
  q->prefixlen = 0 ;
}

static query *query_new (uint8_t source, uint16_t i, char const *ip, uint16_t port, s6dns_domain_t const *name, uint16_t qtype)
{
  uint16_t n = genset_new(&g->queries) ;
  query *sentinel = QUERY(g->qsentinel) ;
  query *q = QUERY(n) ;
  query_init(q, source, i, ip, port, name, type) ;
  q->prev = g->qsentinel ;
  q->next = sentinel->next ;
  QUERY(sentinel->next)->prev = n ;
  sentinel->next = n ;
  return q ;
}

int query_start (uint8_t source, uint16_t i, char const *ip, uint16_t port, char const *buf, uint16_t len)
{
  dcache_key_t data ;
  s6dns_message_header_t hdr ;
  s6dns_message_counts_t counts ;
  s6dns_domain_t name ;
  unsigned int pos ;
  unsigned int rcode ;
  uint16_t qtype ;

  if (!s6dns_message_parse_init(&hdr, &counts, buf, len, &pos)
   || !s6dns_message_parse_question(&counts, &name, &qtype, buf, len, &pos)
   || !s6dns_domain_encode(&name)) return 0 ;
  if (hdr.opcode) return query_error(source, i, ip, port, &name, qtype, hdr.id, 4) ;
  if (!hdr.rd) return query_error(source, i, ip, port, &name, qtype, hdr.id, 9) ;

  if (cache_search(&name, qtype, &data))
    return query_end(source, i, ip, port, data.s, data.len) ;

  {
    uint16_t j = genset_new(&g->queries) ;
    query *q = QUERY(j) ;
  }

  return 1 ;
}