aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou/libggnet_dns.c
blob: 9685cde87d430930a1c1d012ccf04b7ea44c1ffc (plain) (blame)
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
#include <stdlib.h>
#include <string.h>

#include "libggnet_dns.h"

/*
 * For dns with libevent, see
 * http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/dns_8h.html
 * http://www.wangafu.net/~nickm/libevent-book/Ref9_dns.html
 * spike/evdns_chrooted.c
 * spike/evdns.c
 */

static void _cb_evdns_reverse(int, char, int, int, void *, void *);

struct req_reverse {
  LIST_ENTRY(req_reverse) entry;
  struct ggnet_dns *ggdns;
  struct evdns_request *ereq;
  struct in_addr ip;
  void (*cb_usr)(struct in_addr *, char *, void *);
  void  *data;
};

struct ggnet_dns *
ggnet_dns_new(struct event_base *ev_base)
{
  struct ggnet_dns *dns = NULL;

  dns = calloc(1, sizeof(struct ggnet_dns));
  if (!dns) {
    printf("could not allocate ggnet_dns\n");
    exit(1);
  }
  dns->ev_base = ev_base;
  dns->evdns_base = evdns_base_new(ev_base, 1);
  if (!dns->evdns_base)
    goto err;
  return dns;

err:
  if (dns)
    free(dns);
  return NULL;
}

void
ggnet_dns_free(struct ggnet_dns *dns)
{
  evdns_base_free(dns->evdns_base, 1);
  free(dns);
}

int
ggnet_dns_reverse(struct ggnet_dns *dns,
                  struct in_addr *ip,
                    void (*cb_usr)(struct in_addr *, char *, void *),
                    void *data)
{
  struct evutil_addrinfo hints;
  struct req_reverse *req;
  struct evdns_request *ereq;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_flags = EVUTIL_AI_CANONNAME;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;

  req = malloc(sizeof(struct req_reverse));
  if (!req) {
    printf("could not allocate req_reverse\n");
    exit(1);
  }
  req->ggdns = dns;
  memcpy(&req->ip, ip, sizeof(struct in_addr));
  req->cb_usr = cb_usr;
  req->data = data;

  LIST_INSERT_HEAD(&dns->req_reverse_list, req, entry);
  dns->req_reverse_pending++;
  ereq = evdns_base_resolve_reverse(dns->evdns_base, ip, 0,
                                    _cb_evdns_reverse, req);
  if (ereq == NULL) {
    printf("libggnet_dns WARNING: dns request for %d returned immediately\n",
           ip->s_addr);
    /* remove req from list and free it happened in the callback. */
    return 0;
  }
  req->ereq = ereq;

  return 1;
}

static void
_cb_evdns_reverse(int result, char type, int count,
                  int ttl, void *addresses, void *arg)
{
  struct req_reverse *req;

  req = arg;
  if (type != DNS_PTR) {
    printf("libggnet_dns WARNING: dns reverse for %d received non DNS_PTR\n",
           req->ip.s_addr);
    goto free;
  }
  req->cb_usr(&req->ip, addresses, req->data);

free:
  LIST_REMOVE(req, entry);
  req->ggdns->req_reverse_pending--;
  free(req);
}