[IOMultiplexerV2] Added iodns_print_address: inet_ntop eqivalent function for struct...
[NextIRCd.git] / src / IOHandler / IODNSLookup.c
1 /* IODNSLookup.c - IOMultiplexer
2  * Copyright (C) 2014  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
20 #include "IODNSLookup.h"
21 #include "IOLog.h"
22 #include "IOSockets.h"
23
24 #ifdef WIN32
25 #ifdef _WIN32_WINNT
26 #undef _WIN32_WINNT
27 #endif
28 #define _WIN32_WINNT 0x501
29 #include <winsock2.h>
30 #include <windows.h>
31 #include <ws2tcpip.h>
32 #else
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <netinet/ip.h> 
36 #include <arpa/inet.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #endif
40
41 #include <string.h>
42
43 struct _IODNSQuery *iodnsquery_first = NULL;
44 struct _IODNSQuery *iodnsquery_last = NULL;
45
46 struct IODNSEngine *dnsengine = NULL;
47
48 static void iodns_init_engine() {
49         if(dnsengine)
50                 return;
51         //try DNS engines
52         if(dnsengine_cares.init && dnsengine_cares.init())
53                 dnsengine = &dnsengine_cares;
54         else if(dnsengine_default.init && dnsengine_default.init())
55                 dnsengine = &dnsengine_default;
56         else {
57                 iolog_trigger(IOLOG_FATAL, "found no useable IO DNS engine");
58                 return;
59         }
60         iolog_trigger(IOLOG_DEBUG, "using %s IODNS engine", dnsengine->name);
61 }
62
63 void _init_iodns() {
64         iodns_init_engine();
65 }
66
67 struct _IODNSQuery *_create_dnsquery() {
68         struct _IODNSQuery *query = calloc(1, sizeof(*query));
69         if(!query) {
70                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IODNSQuery in %s:%d", __FILE__, __LINE__);
71                 return NULL;
72         }
73         if(iodnsquery_last)
74                 iodnsquery_last->next = query;
75         else
76                 iodnsquery_first = query;
77         query->prev = iodnsquery_last;
78         iodnsquery_last = query;
79         return query;
80 }
81
82 void _start_dnsquery(struct _IODNSQuery *query) {
83         query->flags |= IODNSFLAG_RUNNING;
84         dnsengine->add(query);
85 }
86
87 void _free_dnsquery(struct _IODNSQuery *query) {
88         if(query->prev)
89                 query->prev->next = query->next;
90         else
91                 iodnsquery_first = query->next;
92         if(query->next)
93                 query->next->prev = query->prev;
94         else
95                 iodnsquery_last = query->prev;
96         if((query->type & IODNS_REVERSE) && query->request.addr.address)
97                 free(query->request.addr.address);
98         free(query);
99 }
100
101 void _stop_dnsquery(struct _IODNSQuery *query) {
102         if((query->flags & IODNSFLAG_RUNNING)) {
103                 query->flags &= ~IODNSFLAG_RUNNING;
104                 dnsengine->remove(query);
105         }
106         if(!(query->flags & IODNSFLAG_PROCESSING))
107                 _free_dnsquery(query);
108 }
109
110 void iodns_socket_callback(struct _IOSocket *iosock, int wantread, int wantwrite) {
111         if(dnsengine && dnsengine->socket_callback)
112                 dnsengine->socket_callback(iosock, wantread, wantwrite);
113 }
114
115 void iodns_event_callback(struct _IODNSQuery *query, enum IODNSEventType state) {
116         if((query->flags & IODNSFLAG_PARENT_PUBLIC)) {
117                 struct IODNSQuery *descriptor = query->parent;
118                 struct IODNSEvent event;
119                 event.type = state;
120                 event.query = descriptor;
121                 event.result = query->result;
122                 
123                 descriptor->query = NULL;
124                 _stop_dnsquery(query);
125                 
126                 if(descriptor->callback)
127                         descriptor->callback(&event);
128                 
129                 iogc_add(descriptor);
130         } else if((query->flags & IODNSFLAG_PARENT_SOCKET)) {
131                 struct IODNSEvent event;
132                 event.type = state;
133                 event.query = NULL;
134                 event.result = query->result;
135                 void *parent = query->parent;
136                 
137                 _stop_dnsquery(query);
138                 iosocket_lookup_callback(parent, &event);
139                 
140         }
141 }
142
143 void iodns_poll() {
144         if(dnsengine)
145                 dnsengine->loop();
146 }
147
148 /* public functions */
149
150 struct IODNSQuery *iodns_getaddrinfo(char *hostname, int records, iodns_callback *callback, void *arg) {
151         if(!(records & IODNS_FORWARD) || !hostname || !callback)
152                 return NULL;
153         
154         struct IODNSQuery *descriptor = calloc(1, sizeof(*descriptor));
155         if(!descriptor) {
156                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IODNSQuery in %s:%d", __FILE__, __LINE__);
157                 return NULL;
158         }
159         
160         struct _IODNSQuery *query = _create_dnsquery();
161         if(!query) {
162                 free(descriptor);
163                 return NULL;
164         }
165         
166         query->parent = descriptor;
167         query->flags |= IODNSFLAG_PARENT_PUBLIC;
168         descriptor->query = query;
169         descriptor->data = arg;
170         
171         query->request.host = strdup(hostname);
172         query->type = (records & IODNS_FORWARD);
173         
174         descriptor->callback = callback;
175         
176         _start_dnsquery(query);
177         return descriptor;
178 }
179
180 struct IODNSQuery *iodns_getnameinfo(const struct sockaddr *addr, size_t addrlen, iodns_callback *callback, void *arg) {
181         if(!addr || !callback)
182                 return NULL;
183         
184         struct IODNSQuery *descriptor = calloc(1, sizeof(*descriptor));
185         if(!descriptor) {
186                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IODNSQuery in %s:%d", __FILE__, __LINE__);
187                 return NULL;
188         }
189         
190         struct _IODNSQuery *query = _create_dnsquery();
191         if(!query) {
192                 free(descriptor);
193                 return NULL;
194         }
195         
196         query->parent = descriptor;
197         query->flags |= IODNSFLAG_PARENT_PUBLIC;
198         descriptor->query = query;
199         descriptor->data = arg;
200         
201         query->type = IODNS_RECORD_PTR;
202         query->request.addr.addresslen = addrlen;
203         query->request.addr.address = malloc(addrlen);
204         if(!query->request.addr.address) {
205                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
206                 _free_dnsquery(query);
207                 free(descriptor);
208                 return NULL;
209         }
210         memcpy(query->request.addr.address, addr, addrlen);
211         
212         descriptor->callback = callback;
213         
214         _start_dnsquery(query);
215         return descriptor;
216 }
217
218 void iodns_abort(struct IODNSQuery *descriptor) {
219         if(!descriptor)
220                 return;
221         
222         struct _IODNSQuery *query = descriptor->query;
223         if(!query) {
224                 iolog_trigger(IOLOG_WARNING, "called iodns_abort for destroyed IODNSQuery in %s:%d", __FILE__, __LINE__);
225                 return;
226         }
227         
228         _stop_dnsquery(query);
229 }
230
231 int iodns_print_address(struct IODNSAddress *address, int ipv6, char *buffer, int length) {
232         int af;
233         void *addr;
234         if(ipv6) {
235                 af = AF_INET6;
236                 addr = (void *)(&((struct sockaddr_in6 *)address->address)->sin6_addr);
237         } else {
238                 af = AF_INET;
239                 addr = (void *)(&((struct sockaddr_in *)address->address)->sin_addr);
240         }
241         buffer = inet_ntop(af, addr, buffer, length);
242         if(!buffer)
243                 return 0;
244         else
245                 return strlen(buffer);
246 }
247
248 void iodns_free_result(struct IODNSResult *result) {
249         struct IODNSResult *next;
250         for(;result;result = next) {
251                 next = result->next;
252                 
253                 if((result->type & IODNS_FORWARD)) {
254                         if(result->result.addr.address)
255                                 free(result->result.addr.address);
256                 }
257                 if((result->type & IODNS_REVERSE)) {
258                         if(result->result.host)
259                                 free(result->result.host);
260                 }
261                 free(result);
262         }
263 }
264