/[cvs]/eggdrop1.8/src/dns.c
ViewVC logotype

Annotation of /eggdrop1.8/src/dns.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (hide annotations) (download) (as text)
Thu Aug 5 18:12:05 2010 UTC (9 years, 2 months ago) by pseudo
Branch: MAIN
Branch point for: gettext
Changes since 1.1: +71 -63 lines
File MIME type: text/x-chdr
Added new, full IPv6 support to eggdrop.

1 simple 1.1 /*
2     * dns.c -- handles:
3     * DNS resolve calls and events
4     * provides the code used by the bot if the DNS module is not loaded
5     * DNS Tcl commands
6     *
7 pseudo 1.2 * $Id: dns.c,v 1.1.1.1 2010/07/26 21:11:06 simple Exp $
8 simple 1.1 */
9     /*
10     * Written by Fabian Knittel <fknittel@gmx.de>
11     *
12     * Copyright (C) 1999 - 2010 Eggheads Development Team
13     *
14     * This program is free software; you can redistribute it and/or
15     * modify it under the terms of the GNU General Public License
16     * as published by the Free Software Foundation; either version 2
17     * of the License, or (at your option) any later version.
18     *
19     * This program is distributed in the hope that it will be useful,
20     * but WITHOUT ANY WARRANTY; without even the implied warranty of
21     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22     * GNU General Public License for more details.
23     *
24     * You should have received a copy of the GNU General Public License
25     * along with this program; if not, write to the Free Software
26     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27     */
28    
29     #include "main.h"
30     #include <netdb.h>
31     #include <setjmp.h>
32     #include <sys/socket.h>
33     #include <netinet/in.h>
34     #include <arpa/inet.h>
35    
36     #include "dns.h"
37    
38     extern struct dcc_t *dcc;
39     extern int dcc_total;
40     extern int resolve_timeout;
41     extern time_t now;
42     extern sigjmp_buf alarmret;
43     extern Tcl_Interp *interp;
44    
45     devent_t *dns_events = NULL;
46    
47    
48     /*
49     * DCC functions
50     */
51    
52     void dcc_dnswait(int idx, char *buf, int len)
53     {
54     /* Ignore anything now. */
55     }
56    
57     void eof_dcc_dnswait(int idx)
58     {
59     putlog(LOG_MISC, "*", "Lost connection while resolving hostname [%s/%d]",
60 pseudo 1.2 iptostr(&dcc[idx].sockname.addr.sa), dcc[idx].port);
61 simple 1.1 killsock(dcc[idx].sock);
62     lostdcc(idx);
63     }
64    
65     static void display_dcc_dnswait(int idx, char *buf)
66     {
67     sprintf(buf, "dns waited %lis", (long) now - dcc[idx].timeval);
68     }
69    
70     static int expmem_dcc_dnswait(void *x)
71     {
72     register struct dns_info *p = (struct dns_info *) x;
73     int size = 0;
74    
75     if (p) {
76     size = sizeof(struct dns_info);
77     if (p->host)
78     size += strlen(p->host) + 1;
79     if (p->cbuf)
80     size += strlen(p->cbuf) + 1;
81     }
82     return size;
83     }
84    
85     static void kill_dcc_dnswait(int idx, void *x)
86     {
87     register struct dns_info *p = (struct dns_info *) x;
88    
89     if (p) {
90     if (p->host)
91     nfree(p->host);
92     if (p->cbuf)
93     nfree(p->cbuf);
94     nfree(p);
95     }
96     }
97    
98     struct dcc_table DCC_DNSWAIT = {
99     "DNSWAIT",
100     DCT_VALIDIDX,
101     eof_dcc_dnswait,
102     dcc_dnswait,
103     0,
104     0,
105     display_dcc_dnswait,
106     expmem_dcc_dnswait,
107     kill_dcc_dnswait,
108     0
109     };
110    
111    
112     /*
113     * DCC events
114     */
115    
116     /* Walk through every dcc entry and look for waiting DNS requests
117     * of RES_HOSTBYIP for our IP address.
118     */
119 pseudo 1.2 static void dns_dcchostbyip(sockname_t *ip, char *hostn, int ok, void *other)
120 simple 1.1 {
121     int idx;
122    
123     for (idx = 0; idx < dcc_total; idx++) {
124     if ((dcc[idx].type == &DCC_DNSWAIT) &&
125 pseudo 1.2 (dcc[idx].u.dns->dns_type == RES_HOSTBYIP) && (
126     #ifdef IPV6
127     (ip->family == AF_INET6 &&
128     IN6_ARE_ADDR_EQUAL(&dcc[idx].u.dns->ip->addr.s6.sin6_addr,
129     &ip->addr.s6.sin6_addr)) ||
130     #endif
131     (dcc[idx].u.dns->ip->addr.s4.sin_addr.s_addr ==
132     ip->addr.s4.sin_addr.s_addr))) {
133 simple 1.1 if (dcc[idx].u.dns->host)
134     nfree(dcc[idx].u.dns->host);
135     dcc[idx].u.dns->host = get_data_ptr(strlen(hostn) + 1);
136     strcpy(dcc[idx].u.dns->host, hostn);
137     if (ok)
138     dcc[idx].u.dns->dns_success(idx);
139     else
140     dcc[idx].u.dns->dns_failure(idx);
141     }
142     }
143     }
144    
145     /* Walk through every dcc entry and look for waiting DNS requests
146     * of RES_IPBYHOST for our hostname.
147     */
148 pseudo 1.2 static void dns_dccipbyhost(sockname_t *ip, char *hostn, int ok, void *other)
149 simple 1.1 {
150     int idx;
151    
152     for (idx = 0; idx < dcc_total; idx++) {
153     if ((dcc[idx].type == &DCC_DNSWAIT) &&
154     (dcc[idx].u.dns->dns_type == RES_IPBYHOST) &&
155     !egg_strcasecmp(dcc[idx].u.dns->host, hostn)) {
156 pseudo 1.2 if (ok) {
157     if (dcc[idx].u.dns->ip)
158     egg_memcpy(dcc[idx].u.dns->ip, ip, sizeof(sockname_t));
159     else
160     egg_memcpy(&dcc[idx].sockname, ip, sizeof(sockname_t));
161 simple 1.1 dcc[idx].u.dns->dns_success(idx);
162 pseudo 1.2 } else
163 simple 1.1 dcc[idx].u.dns->dns_failure(idx);
164     }
165     }
166     }
167    
168     static int dns_dccexpmem(void *other)
169     {
170     return 0;
171     }
172    
173     devent_type DNS_DCCEVENT_HOSTBYIP = {
174     "DCCEVENT_HOSTBYIP",
175     dns_dccexpmem,
176     dns_dcchostbyip
177     };
178    
179     devent_type DNS_DCCEVENT_IPBYHOST = {
180     "DCCEVENT_IPBYHOST",
181     dns_dccexpmem,
182     dns_dccipbyhost
183     };
184    
185     void dcc_dnsipbyhost(char *hostn)
186     {
187     devent_t *de;
188    
189     for (de = dns_events; de; de = de->next) {
190     if (de->type && (de->type == &DNS_DCCEVENT_IPBYHOST) &&
191     (de->lookup == RES_IPBYHOST)) {
192     if (de->res_data.hostname &&
193     !egg_strcasecmp(de->res_data.hostname, hostn))
194     /* No need to add anymore. */
195     return;
196     }
197     }
198    
199     de = nmalloc(sizeof(devent_t));
200     egg_bzero(de, sizeof(devent_t));
201    
202     /* Link into list. */
203     de->next = dns_events;
204     dns_events = de;
205    
206     de->type = &DNS_DCCEVENT_IPBYHOST;
207     de->lookup = RES_IPBYHOST;
208     de->res_data.hostname = nmalloc(strlen(hostn) + 1);
209     strcpy(de->res_data.hostname, hostn);
210    
211     /* Send request. */
212     dns_ipbyhost(hostn);
213     }
214    
215 pseudo 1.2 void dcc_dnshostbyip(sockname_t *ip)
216 simple 1.1 {
217     devent_t *de;
218    
219     for (de = dns_events; de; de = de->next) {
220     if (de->type && (de->type == &DNS_DCCEVENT_HOSTBYIP) &&
221     (de->lookup == RES_HOSTBYIP)) {
222     if (de->res_data.ip_addr == ip)
223     /* No need to add anymore. */
224     return;
225     }
226     }
227    
228     de = nmalloc(sizeof(devent_t));
229     egg_bzero(de, sizeof(devent_t));
230    
231     /* Link into list. */
232     de->next = dns_events;
233     dns_events = de;
234    
235     de->type = &DNS_DCCEVENT_HOSTBYIP;
236     de->lookup = RES_HOSTBYIP;
237     de->res_data.ip_addr = ip;
238    
239     /* Send request. */
240     dns_hostbyip(ip);
241     }
242    
243    
244     /*
245     * Tcl events
246     */
247    
248 pseudo 1.2 static void dns_tcl_iporhostres(sockname_t *ip, char *hostn, int ok, void *other)
249 simple 1.1 {
250     devent_tclinfo_t *tclinfo = (devent_tclinfo_t *) other;
251     Tcl_DString list;
252    
253     Tcl_DStringInit(&list);
254     Tcl_DStringAppendElement(&list, tclinfo->proc);
255 pseudo 1.2 Tcl_DStringAppendElement(&list, iptostr(&ip->addr.sa));
256 simple 1.1 Tcl_DStringAppendElement(&list, hostn);
257     Tcl_DStringAppendElement(&list, ok ? "1" : "0");
258    
259     if (tclinfo->paras) {
260     EGG_CONST char *argv[2];
261     char *output;
262    
263     argv[0] = Tcl_DStringValue(&list);
264     argv[1] = tclinfo->paras;
265     output = Tcl_Concat(2, argv);
266    
267     if (Tcl_Eval(interp, output) == TCL_ERROR)
268     putlog(LOG_MISC, "*", DCC_TCLERROR, tclinfo->proc, tcl_resultstring());
269     Tcl_Free(output);
270     } else if (Tcl_Eval(interp, Tcl_DStringValue(&list)) == TCL_ERROR)
271     putlog(LOG_MISC, "*", DCC_TCLERROR, tclinfo->proc, tcl_resultstring());
272    
273     Tcl_DStringFree(&list);
274    
275     nfree(tclinfo->proc);
276     if (tclinfo->paras)
277     nfree(tclinfo->paras);
278     nfree(tclinfo);
279     }
280    
281     static int dns_tclexpmem(void *other)
282     {
283     devent_tclinfo_t *tclinfo = (devent_tclinfo_t *) other;
284     int l = 0;
285    
286     if (tclinfo) {
287     l = sizeof(devent_tclinfo_t);
288     if (tclinfo->proc)
289     l += strlen(tclinfo->proc) + 1;
290     if (tclinfo->paras)
291     l += strlen(tclinfo->paras) + 1;
292     }
293     return l;
294     }
295    
296     devent_type DNS_TCLEVENT_HOSTBYIP = {
297     "TCLEVENT_HOSTBYIP",
298     dns_tclexpmem,
299     dns_tcl_iporhostres
300     };
301    
302     devent_type DNS_TCLEVENT_IPBYHOST = {
303     "TCLEVENT_IPBYHOST",
304     dns_tclexpmem,
305     dns_tcl_iporhostres
306     };
307    
308     static void tcl_dnsipbyhost(char *hostn, char *proc, char *paras)
309     {
310     devent_t *de;
311     devent_tclinfo_t *tclinfo;
312    
313     de = nmalloc(sizeof(devent_t));
314     egg_bzero(de, sizeof(devent_t));
315    
316     /* Link into list. */
317     de->next = dns_events;
318     dns_events = de;
319    
320     de->type = &DNS_TCLEVENT_IPBYHOST;
321     de->lookup = RES_IPBYHOST;
322     de->res_data.hostname = nmalloc(strlen(hostn) + 1);
323     strcpy(de->res_data.hostname, hostn);
324    
325     /* Store additional data. */
326     tclinfo = nmalloc(sizeof(devent_tclinfo_t));
327     tclinfo->proc = nmalloc(strlen(proc) + 1);
328     strcpy(tclinfo->proc, proc);
329     if (paras) {
330     tclinfo->paras = nmalloc(strlen(paras) + 1);
331     strcpy(tclinfo->paras, paras);
332     } else
333     tclinfo->paras = NULL;
334     de->other = tclinfo;
335    
336     /* Send request. */
337     dns_ipbyhost(hostn);
338     }
339    
340 pseudo 1.2 static void tcl_dnshostbyip(sockname_t *ip, char *proc, char *paras)
341 simple 1.1 {
342     devent_t *de;
343     devent_tclinfo_t *tclinfo;
344    
345     de = nmalloc(sizeof(devent_t));
346     egg_bzero(de, sizeof(devent_t));
347    
348     /* Link into list. */
349     de->next = dns_events;
350     dns_events = de;
351    
352     de->type = &DNS_TCLEVENT_HOSTBYIP;
353     de->lookup = RES_HOSTBYIP;
354     de->res_data.ip_addr = ip;
355    
356     /* Store additional data. */
357     tclinfo = nmalloc(sizeof(devent_tclinfo_t));
358     tclinfo->proc = nmalloc(strlen(proc) + 1);
359     strcpy(tclinfo->proc, proc);
360 pseudo 1.2 memcpy(&tclinfo->sockname, ip, sizeof(sockname_t));
361     de->res_data.ip_addr = &tclinfo->sockname;
362 simple 1.1 if (paras) {
363     tclinfo->paras = nmalloc(strlen(paras) + 1);
364     strcpy(tclinfo->paras, paras);
365     } else
366     tclinfo->paras = NULL;
367     de->other = tclinfo;
368    
369     /* Send request. */
370     dns_hostbyip(ip);
371     }
372    
373    
374     /*
375     * Event functions
376     */
377    
378     inline static int dnsevent_expmem(void)
379     {
380     devent_t *de;
381     int tot = 0;
382    
383     for (de = dns_events; de; de = de->next) {
384     tot += sizeof(devent_t);
385     if ((de->lookup == RES_IPBYHOST) && de->res_data.hostname)
386     tot += strlen(de->res_data.hostname) + 1;
387     if (de->type && de->type->expmem)
388     tot += de->type->expmem(de->other);
389     }
390     return tot;
391     }
392    
393 pseudo 1.2 void call_hostbyip(sockname_t *ip, char *hostn, int ok)
394 simple 1.1 {
395     devent_t *de = dns_events, *ode = NULL, *nde = NULL;
396    
397     while (de) {
398     nde = de->next;
399 pseudo 1.2 if ((de->lookup == RES_HOSTBYIP) && (
400     #ifdef IPV6
401     (ip->family == AF_INET6 &&
402     IN6_ARE_ADDR_EQUAL(&de->res_data.ip_addr->addr.s6.sin6_addr,
403     &ip->addr.s6.sin6_addr)) ||
404     #endif
405     (de->res_data.ip_addr->addr.s4.sin_addr.s_addr ==
406     ip->addr.s4.sin_addr.s_addr))) {
407     /* A memcmp() could have perfectly done it .. */
408 simple 1.1 /* Remove the event from the list here, to avoid conflicts if one of
409     * the event handlers re-adds another event. */
410     if (ode)
411     ode->next = de->next;
412     else
413     dns_events = de->next;
414    
415     if (de->type && de->type->event)
416     de->type->event(ip, hostn, ok, de->other);
417     else
418     putlog(LOG_MISC, "*", "(!) Unknown DNS event type found: %s",
419     (de->type && de->type->name) ? de->type->name : "<empty>");
420     nfree(de);
421     de = ode;
422     }
423     ode = de;
424     de = nde;
425     }
426     }
427    
428 pseudo 1.2 void call_ipbyhost(char *hostn, sockname_t *ip, int ok)
429 simple 1.1 {
430     devent_t *de = dns_events, *ode = NULL, *nde = NULL;
431    
432     while (de) {
433     nde = de->next;
434     if ((de->lookup == RES_IPBYHOST) && (!de->res_data.hostname ||
435     !egg_strcasecmp(de->res_data.hostname, hostn))) {
436     /* Remove the event from the list here, to avoid conflicts if one of
437     * the event handlers re-adds another event. */
438     if (ode)
439     ode->next = de->next;
440     else
441     dns_events = de->next;
442    
443     if (de->type && de->type->event)
444     de->type->event(ip, hostn, ok, de->other);
445     else
446     putlog(LOG_MISC, "*", "(!) Unknown DNS event type found: %s",
447     (de->type && de->type->name) ? de->type->name : "<empty>");
448    
449     if (de->res_data.hostname)
450     nfree(de->res_data.hostname);
451     nfree(de);
452     de = ode;
453     }
454     ode = de;
455     de = nde;
456     }
457     }
458    
459    
460     /*
461     * Async DNS emulation functions
462     */
463 pseudo 1.2 void block_dns_hostbyip(sockname_t *addr)
464 simple 1.1 {
465 pseudo 1.2 struct hostent *hp = 0;
466 simple 1.1 static char s[UHOSTLEN];
467 pseudo 1.2 const char *r = 0;
468 simple 1.1
469 pseudo 1.2 if (addr->family == AF_INET) {
470     if (!sigsetjmp(alarmret, 1)) {
471     alarm(resolve_timeout);
472     hp = gethostbyaddr(&addr->addr.s4.sin_addr,
473     sizeof (struct in_addr), AF_INET);
474     alarm(0);
475     }
476     if (!hp)
477     r = inet_ntop(AF_INET, &addr->addr.s4.sin_addr.s_addr, s, sizeof s);
478     #ifdef IPV6
479 simple 1.1 } else {
480 pseudo 1.2 if (!sigsetjmp(alarmret, 1)) {
481     alarm(resolve_timeout);
482     hp = gethostbyaddr((char *) &addr->addr.s6.sin6_addr,
483     sizeof (struct in6_addr), AF_INET6);
484     alarm(0);
485     }
486     if (!hp)
487     r = inet_ntop(AF_INET6, &addr->addr.s6.sin6_addr, s, sizeof s);
488     }
489     #else
490 simple 1.1 }
491 pseudo 1.2 #endif
492     if (hp)
493     strncpyz(s, hp->h_name, sizeof s);
494     call_hostbyip(addr, s, hp ? 1 : 0);
495     }
496 simple 1.1
497     void block_dns_ipbyhost(char *host)
498     {
499 pseudo 1.2 sockname_t name;
500 simple 1.1
501 pseudo 1.2 if (setsockname(&name, host, 0, 1) == AF_UNSPEC)
502     call_ipbyhost(host, &name, 0);
503     else
504     call_ipbyhost(host, &name, 1);
505 simple 1.1 }
506    
507     /*
508     * Misc functions
509     */
510    
511     int expmem_dns(void)
512     {
513     return dnsevent_expmem();
514     }
515    
516    
517     /*
518     * Tcl functions
519     */
520    
521     /* dnslookup <ip-address> <proc> */
522     static int tcl_dnslookup STDVAR
523     {
524 pseudo 1.2 sockname_t addr;
525 simple 1.1 Tcl_DString paras;
526    
527     if (argc < 3) {
528     Tcl_AppendResult(irp, "wrong # args: should be \"", argv[0],
529     " ip-address/hostname proc ?args...?\"", NULL);
530     return TCL_ERROR;
531     }
532    
533     Tcl_DStringInit(&paras);
534     if (argc > 3) {
535     int p;
536    
537     for (p = 3; p < argc; p++)
538     Tcl_DStringAppendElement(&paras, argv[p]);
539     }
540    
541 pseudo 1.2 if (setsockname(&addr, argv[1], 0, 0) != AF_UNSPEC)
542     tcl_dnshostbyip(&addr, argv[2], Tcl_DStringValue(&paras));
543 simple 1.1 else
544     tcl_dnsipbyhost(argv[1], argv[2], Tcl_DStringValue(&paras));
545    
546     Tcl_DStringFree(&paras);
547     return TCL_OK;
548     }
549    
550     tcl_cmds tcldns_cmds[] = {
551     {"dnslookup", tcl_dnslookup},
552     {NULL, NULL}
553     };

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23