aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou/libggnet_dns.c
blob: c6f8ccec3c39825a7c2ef9d83b8a0fcf3c72070f (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
114
115
116
#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 ggnet_dns *
ggnet_dns_new(struct event_base *ev_base)
{
	struct ggnet_dns *ggdns = NULL;

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

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

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

struct ggnet_dns_req *
ggnet_dns_reverse(struct ggnet_dns *ggdns,
		struct in_addr *ip,
		void (*cb_usr)(struct in_addr *, char *, void *),
		void *data)
{
	struct evutil_addrinfo hints;
	struct ggnet_dns_req *req;
	struct evdns_request *ereq;
	struct in_addr nip;

	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 ggnet_dns_req));
	if (!req) {
		printf("could not allocate ggnet_dns_req\n");
		exit(1);
	}
	req->ggdns = ggdns;
	memcpy(&req->ip, ip, sizeof(struct in_addr));
	req->cb_usr = cb_usr;
	req->data = data;

	nip.s_addr = htonl(ip->s_addr); /* evdns eats network byte order */

	LIST_INSERT_HEAD(&ggdns->req_list, req, entry);
	ggdns->req_pending++;
	ereq = evdns_base_resolve_reverse(ggdns->evdns_base, &nip, 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 NULL;
	}
	req->ereq = ereq;

	return req;
}

void
ggnet_dns_cancel(struct ggnet_dns *ggdns, struct ggnet_dns_req *req)
{
	evdns_cancel_request(ggdns->evdns_base, req->ereq);
	/* remove req from list and free it happened in the callback. */
}

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

	if (count > 1)
		printf("libggnet_dns XXX: has %d PTR records !\n", count); // XXX

	req = arg;
	name = addresses;
	if (result != DNS_ERR_NONE || count == 0)
		req->cb_usr(&req->ip, NULL, req->data);
	else
		req->cb_usr(&req->ip, *name, req->data);

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