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

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

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


Revision 1.4 - (hide annotations) (download) (as text)
Tue Sep 14 19:45:29 2010 UTC (9 years, 1 month ago) by pseudo
Branch: MAIN
Changes since 1.3: +3 -2 lines
File MIME type: text/x-chdr
Fixed a bug in setsockname() making it fail with IPv6 enabled due to a variable not being set.

1 simple 1.1 /*
2     * net.c -- handles:
3     * all raw network i/o
4     *
5 pseudo 1.4 * $Id: net.c,v 1.3 2010/08/23 21:27:40 pseudo Exp $
6 simple 1.1 */
7     /*
8     * This is hereby released into the public domain.
9     * Robey Pointer, robey@netcom.com
10     *
11     * Changes after Feb 23, 1999 Copyright Eggheads Development Team
12     *
13     * Copyright (C) 1999 - 2010 Eggheads Development Team
14     *
15     * This program is free software; you can redistribute it and/or
16     * modify it under the terms of the GNU General Public License
17     * as published by the Free Software Foundation; either version 2
18     * of the License, or (at your option) any later version.
19     *
20     * This program is distributed in the hope that it will be useful,
21     * but WITHOUT ANY WARRANTY; without even the implied warranty of
22     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23     * GNU General Public License for more details.
24     *
25     * You should have received a copy of the GNU General Public License
26     * along with this program; if not, write to the Free Software
27     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28     */
29    
30     #include <fcntl.h>
31     #include "main.h"
32     #include <limits.h>
33     #include <string.h>
34     #include <netdb.h>
35     #include <sys/socket.h>
36     #if HAVE_SYS_SELECT_H
37     # include <sys/select.h>
38     #endif
39     #include <netinet/in.h>
40     #include <arpa/inet.h>
41     #include <errno.h>
42     #if HAVE_UNISTD_H
43     # include <unistd.h>
44     #endif
45     #include <setjmp.h>
46    
47     #ifndef HAVE_GETDTABLESIZE
48     # ifdef FD_SETSIZE
49     # define getdtablesize() FD_SETSIZE
50     # else
51     # define getdtablesize() 200
52     # endif
53     #endif
54    
55     extern struct dcc_t *dcc;
56     extern int backgrd, use_stderr, resolve_timeout, dcc_total;
57     extern unsigned long otraffic_irc_today, otraffic_bn_today, otraffic_dcc_today,
58     otraffic_filesys_today, otraffic_trans_today,
59     otraffic_unknown_today;
60    
61 pseudo 1.2 char natip[121] = ""; /* Public IPv4 to report for systems behind NAT */
62     char listen_ip[121] = ""; /* IP (or hostname) for listening sockets */
63 pseudo 1.3 char vhost[121] = ""; /* IPv4 vhost for outgoing connections */
64 pseudo 1.2 #ifdef IPV6
65 pseudo 1.3 char vhost6[121] = ""; /* IPv6 vhost for outgoing connections */
66 pseudo 1.2 int pref_af = 0; /* Prefer IPv6 over IPv4? */
67     #endif
68 simple 1.1 char firewall[121] = ""; /* Socks server for firewall. */
69     int firewallport = 1080; /* Default port of socks 4/5 firewalls. */
70     char botuser[21] = "eggdrop"; /* Username of the user running the bot. */
71     int dcc_sanitycheck = 0; /* Do some sanity checking on dcc connections. */
72    
73     sock_list *socklist = NULL; /* Enough to be safe. */
74     sigjmp_buf alarmret; /* Env buffer for alarm() returns. */
75    
76     /* Types of proxies */
77     #define PROXY_SOCKS 1
78     #define PROXY_SUN 2
79    
80    
81     /* I need an UNSIGNED long for dcc type stuff
82     */
83     IP my_atoul(char *s)
84     {
85     IP ret = 0;
86    
87     while ((*s >= '0') && (*s <= '9')) {
88     ret *= 10;
89     ret += ((*s) - '0');
90     s++;
91     }
92     return ret;
93     }
94    
95     int expmem_net()
96     {
97     int i, tot = 0;
98     struct threaddata *td = threaddata();
99    
100     for (i = 0; i < td->MAXSOCKS; i++) {
101     if (!(td->socklist[i].flags & (SOCK_UNUSED | SOCK_TCL))) {
102     if (td->socklist[i].handler.sock.inbuf != NULL)
103     tot += strlen(td->socklist[i].handler.sock.inbuf) + 1;
104     if (td->socklist[i].handler.sock.outbuf != NULL)
105     tot += td->socklist[i].handler.sock.outbuflen;
106     }
107     }
108     return tot;
109     }
110    
111 pseudo 1.2 /* Extract the IP address from a sockaddr struct and convert it
112     * to presentation format.
113     */
114     char *iptostr(struct sockaddr *sa)
115     {
116     #ifdef IPV6
117     static char s[INET6_ADDRSTRLEN] = "";
118     if (sa->sa_family == AF_INET6)
119     inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
120     s, sizeof s);
121     else
122     #else
123     static char s[sizeof "255.255.255.255"] = "";
124     #endif
125     inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr.s_addr, s,
126     sizeof s);
127     return s;
128     }
129    
130     /* Fills in a sockname struct with the given server and port. If the string
131     * pointed by src isn't an IP address and allowres is not null, the function
132     * will assume it's a hostname and will attempt to resolve it. This is
133     * convenient, but you should use the async dns functions where possible, to
134     * avoid blocking the bot while the lookup is performed.
135 simple 1.1 */
136 pseudo 1.2 int setsockname(sockname_t *addr, char *src, int port, int allowres)
137 simple 1.1 {
138     struct hostent *hp;
139 pseudo 1.2 int af = AF_UNSPEC;
140     #ifdef IPV6
141     int pref;
142    
143     /* Clean start */
144     egg_bzero(addr, sizeof(sockname_t));
145     af = pref = pref_af ? AF_INET6 : AF_INET;
146     if (pref == AF_INET) {
147     if (!egg_inet_aton(src, &addr->addr.s4.sin_addr))
148     af = AF_INET6;
149     } else {
150     if (inet_pton(af, src, &addr->addr.s6.sin6_addr) != 1)
151     af = AF_INET;
152     }
153     if (af != pref)
154     if (((af == AF_INET6) &&
155     (inet_pton(af, src, &addr->addr.s6.sin6_addr) != 1)) ||
156     ((af == AF_INET) &&
157     !egg_inet_aton(src, &addr->addr.s4.sin_addr)))
158     af = AF_UNSPEC;
159    
160     if (af == AF_UNSPEC && allowres) {
161     /* src is a hostname. Attempt to resolve it.. */
162     if (!sigsetjmp(alarmret, 1)) {
163     alarm(resolve_timeout);
164     hp = gethostbyname2(src, pref_af ? AF_INET6 : AF_INET);
165     if (!hp)
166     hp = gethostbyname2(src, pref_af ? AF_INET : AF_INET6);
167     alarm(0);
168     } else
169     hp = NULL;
170     if (hp) {
171     if (hp->h_addrtype == AF_INET)
172     egg_memcpy(&addr->addr.s4.sin_addr, hp->h_addr, hp->h_length);
173     else
174     egg_memcpy(&addr->addr.s6.sin6_addr, hp->h_addr, hp->h_length);
175     af = hp->h_addrtype;
176     }
177     }
178    
179     addr->family = (af == AF_UNSPEC) ? pref : af;
180     addr->addr.sa.sa_family = addr->family;
181     if (addr->family == AF_INET6) {
182     addr->addrlen = sizeof(struct sockaddr_in6);
183     addr->addr.s6.sin6_port = htons(port);
184     addr->addr.s6.sin6_family = AF_INET6;
185     } else {
186     addr->addrlen = sizeof(struct sockaddr_in);
187     addr->addr.s4.sin_port = htons(port);
188     addr->addr.s4.sin_family = AF_INET;
189     }
190     #else
191     egg_bzero(addr, sizeof(sockname_t));
192     if (!egg_inet_aton(src, &addr->addr.s4.sin_addr) && allowres) {
193     /* src is a hostname. Attempt to resolve it.. */
194     if (!sigsetjmp(alarmret, 1)) {
195     alarm(resolve_timeout);
196     hp = gethostbyname(src);
197     alarm(0);
198     } else
199     hp = NULL;
200     if (hp) {
201     egg_memcpy(&addr->addr.s4.sin_addr, hp->h_addr, hp->h_length);
202     af = hp->h_addrtype;
203     }
204 pseudo 1.4 } else
205     af = AF_INET;
206 pseudo 1.2
207     addr->family = addr->addr.s4.sin_family = AF_INET;
208     addr->addr.sa.sa_family = addr->family;
209     addr->addrlen = sizeof(struct sockaddr_in);
210     addr->addr.s4.sin_port = htons(port);
211 simple 1.1 #endif
212 pseudo 1.2 return af;
213     }
214    
215     /* Get socket address to bind to for outbound connections
216     */
217     void getvhost(sockname_t *addr, int af)
218     {
219     char *h;
220    
221     if (af == AF_INET)
222     h = vhost;
223     #ifdef IPV6
224     else
225     h = vhost6;
226 simple 1.1 #endif
227 pseudo 1.2 if (setsockname(addr, h, 0, 1) != af)
228     setsockname(addr, (af == AF_INET ? "0" : "::"), 0, 0);
229     /* Remember this 'self-lookup failed' thingie?
230     I have good news - you won't see it again ;) */
231 simple 1.1 }
232    
233     /* Sets/Unsets options for a specific socket.
234     *
235     * Returns: 0 - on success
236     * -1 - socket not found
237     * -2 - illegal operation
238     */
239     int sockoptions(int sock, int operation, int sock_options)
240     {
241     int i;
242     struct threaddata *td = threaddata();
243    
244     for (i = 0; i < td->MAXSOCKS; i++)
245     if ((td->socklist[i].sock == sock) &&
246     !(td->socklist[i].flags & SOCK_UNUSED)) {
247     if (operation == EGG_OPTION_SET)
248     td->socklist[i].flags |= sock_options;
249     else if (operation == EGG_OPTION_UNSET)
250     td->socklist[i].flags &= ~sock_options;
251     else
252     return -2;
253     return 0;
254     }
255     return -1;
256     }
257    
258     /* Return a free entry in the socket entry
259     */
260     int allocsock(int sock, int options)
261     {
262     int i;
263     struct threaddata *td = threaddata();
264    
265     for (i = 0; i < td->MAXSOCKS; i++) {
266     if (td->socklist[i].flags & SOCK_UNUSED) {
267     /* yay! there is table space */
268     td->socklist[i].handler.sock.inbuf = NULL;
269     td->socklist[i].handler.sock.outbuf = NULL;
270     td->socklist[i].handler.sock.inbuflen = 0;
271     td->socklist[i].handler.sock.outbuflen = 0;
272     td->socklist[i].flags = options;
273     td->socklist[i].sock = sock;
274     return i;
275     }
276     }
277     /* Try again if enlarging socketlist works */
278     if (increase_socks_max())
279     return -1;
280     else
281     return allocsock(sock, options);
282     }
283    
284     /* Return a free entry in the socket entry for a tcl socket
285     *
286     * alloctclsock() can be called by Tcl threads
287     */
288     int alloctclsock(register int sock, int mask, Tcl_FileProc *proc, ClientData cd)
289     {
290     int f = -1;
291     register int i;
292     struct threaddata *td = threaddata();
293    
294     for (i = 0; i < td->MAXSOCKS; i++) {
295     if (td->socklist[i].flags & SOCK_UNUSED) {
296     if (f == -1)
297     f = i;
298     } else if ((td->socklist[i].flags & SOCK_TCL) &&
299     td->socklist[i].sock == sock) {
300     f = i;
301     break;
302     }
303     }
304     if (f != -1) {
305     td->socklist[f].sock = sock;
306     td->socklist[f].flags = SOCK_TCL;
307     td->socklist[f].handler.tclsock.mask = mask;
308     td->socklist[f].handler.tclsock.proc = proc;
309     td->socklist[f].handler.tclsock.cd = cd;
310     return f;
311     }
312     /* Try again if enlarging socketlist works */
313     if (increase_socks_max())
314     return -1;
315     else
316     return alloctclsock(sock, mask, proc, cd);
317     }
318    
319     /* Request a normal socket for i/o
320     */
321     void setsock(int sock, int options)
322     {
323     int i = allocsock(sock, options), parm;
324     struct threaddata *td = threaddata();
325    
326     if (i == -1) {
327     putlog(LOG_MISC, "*", "Sockettable full.");
328     return;
329     }
330     if (((sock != STDOUT) || backgrd) && !(td->socklist[i].flags & SOCK_NONSOCK)) {
331     parm = 1;
332     setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &parm, sizeof(int));
333    
334     parm = 0;
335     setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &parm, sizeof(int));
336     }
337     if (options & SOCK_LISTEN) {
338     /* Tris says this lets us grab the same port again next time */
339     parm = 1;
340     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &parm, sizeof(int));
341     }
342     /* Yay async i/o ! */
343     fcntl(sock, F_SETFL, O_NONBLOCK);
344     }
345    
346 pseudo 1.2 int getsock(int af, int options)
347 simple 1.1 {
348 pseudo 1.2 int sock = socket(af, SOCK_STREAM, 0);
349    
350 simple 1.1 if (sock >= 0)
351     setsock(sock, options);
352     else
353 pseudo 1.2 putlog(LOG_MISC, "*", "Warning: Can't create new socket: %s!",
354     strerror(errno));
355 simple 1.1 return sock;
356     }
357    
358     /* Done with a socket
359     */
360     void killsock(register int sock)
361     {
362     register int i;
363     struct threaddata *td = threaddata();
364    
365     /* Ignore invalid sockets. */
366     if (sock < 0)
367     return;
368    
369     for (i = 0; i < td->MAXSOCKS; i++) {
370     if ((td->socklist[i].sock == sock) && !(td->socklist[i].flags & SOCK_UNUSED)) {
371     if (!(td->socklist[i].flags & SOCK_TCL)) { /* nothing to free for tclsocks */
372     close(td->socklist[i].sock);
373     if (td->socklist[i].handler.sock.inbuf != NULL) {
374     nfree(td->socklist[i].handler.sock.inbuf);
375     td->socklist[i].handler.sock.inbuf = NULL;
376     }
377     if (td->socklist[i].handler.sock.outbuf != NULL) {
378     nfree(td->socklist[i].handler.sock.outbuf);
379     td->socklist[i].handler.sock.outbuf = NULL;
380     td->socklist[i].handler.sock.outbuflen = 0;
381     }
382     }
383     td->socklist[i].flags = SOCK_UNUSED;
384     return;
385     }
386     }
387     putlog(LOG_MISC, "*", "Warning: Attempt to kill un-allocated socket %d!", sock);
388     }
389    
390     /* Done with a tcl socket
391     *
392     * killtclsock() can be called by Tcl threads
393     */
394     void killtclsock(register int sock)
395     {
396     register int i;
397     struct threaddata *td = threaddata();
398    
399     if (sock < 0)
400     return;
401    
402     for (i = 0; i < td->MAXSOCKS; i++) {
403     if ((td->socklist[i].flags & SOCK_TCL) && td->socklist[i].sock == sock) {
404     td->socklist[i].flags = SOCK_UNUSED;
405     return;
406     }
407     }
408     }
409    
410     /* Send connection request to proxy
411     */
412 pseudo 1.2 static int proxy_connect(int sock, sockname_t *addr)
413 simple 1.1 {
414 pseudo 1.2 sockname_t name;
415     char host[121], s[256];
416     int i, port, proxy;
417    
418     if (!firewall[0])
419     return -2;
420     #ifdef IPV6
421     if (addr->family == AF_INET6) {
422     putlog(LOG_MISC, "*", "Eggdrop doesn't support IPv6 connections "
423     "through proxies yet.");
424     return -1;
425     }
426     #endif
427     if (firewall[0] == '!') {
428     proxy = PROXY_SUN;
429     strcpy(host, &firewall[1]);
430     } else {
431     proxy = PROXY_SOCKS;
432     strcpy(host, firewall);
433     }
434     port = addr->addr.s4.sin_port;
435     setsockname(&name, host, firewallport, 1);
436     if (connect(sock, &name.addr.sa, name.addrlen) < 0 && errno != EINPROGRESS)
437     return -1;
438 simple 1.1 if (proxy == PROXY_SOCKS) {
439 pseudo 1.2 for (i = 0; i < threaddata()->MAXSOCKS; i++)
440 simple 1.1 if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
441     socklist[i].flags |= SOCK_PROXYWAIT; /* drummer */
442 pseudo 1.2 egg_memcpy(host, &addr->addr.s4.sin_addr.s_addr, 4);
443     egg_snprintf(s, sizeof s, "\004\001%c%c%c%c%c%c%s", port % 256,
444     (port >> 8) % 256, host[0], host[1], host[2], host[3], botuser);
445 simple 1.1 tputs(sock, s, strlen(botuser) + 9); /* drummer */
446     } else if (proxy == PROXY_SUN) {
447 pseudo 1.2 inet_ntop(AF_INET, &addr->addr.s4.sin_addr, host, sizeof host);
448 simple 1.1 egg_snprintf(s, sizeof s, "%s %d\n", host, port);
449     tputs(sock, s, strlen(s)); /* drummer */
450     }
451     return sock;
452     }
453    
454 pseudo 1.2 /* Starts a connection attempt through a socket
455 simple 1.1 *
456 pseudo 1.2 * The server address should be filled in addr by setsockname() or by the
457     * non-blocking dns functions and setsnport().
458 simple 1.1 *
459 pseudo 1.2 * returns < 0 if connection refused:
460     * -1 strerror() type error
461 simple 1.1 */
462 pseudo 1.2 int open_telnet_raw(int sock, sockname_t *addr)
463 simple 1.1 {
464 pseudo 1.2 sockname_t name;
465     int i, rc;
466    
467     getvhost(&name, addr->family);
468     if (bind(sock, &name.addr.sa, name.addrlen) < 0) {
469 simple 1.1 return -1;
470     }
471     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
472     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == sock))
473     socklist[i].flags = (socklist[i].flags & ~SOCK_VIRTUAL) | SOCK_CONNECT;
474     }
475 pseudo 1.2 if (addr->family == AF_INET && firewall[0])
476     return proxy_connect(sock, addr);
477     rc = connect(sock, &addr->addr.sa, addr->addrlen);
478 simple 1.1 if (rc < 0) {
479 pseudo 1.2 if (errno == EINPROGRESS)
480 simple 1.1 return sock; /* async success! */
481 pseudo 1.2 else
482 simple 1.1 return -1;
483     }
484     return sock;
485     }
486    
487 pseudo 1.2 /* Ordinary non-binary connection attempt
488     * Return values:
489     * >=0: connect successful, returned is the socket number
490     * -1: look at errno or use strerror()
491     * -2: lookup failed or server is not a valid IP string
492     */
493 simple 1.1 int open_telnet(char *server, int port)
494     {
495 pseudo 1.2 int ret, sock;
496     sockname_t name;
497    
498     ret = setsockname(&name, server, port, 1);
499     if (ret == AF_UNSPEC)
500     return -2;
501     sock = getsock(ret, 0);
502     if (sock < 0)
503     return -1;
504     ret = open_telnet_raw(sock, &name);
505     if (ret < 0)
506     killsock(sock);
507 simple 1.1 return ret;
508     }
509    
510     /* Returns a socket number for a listening socket that will accept any
511 pseudo 1.2 * connection on the given address. The address can be filled in by
512     * setsockname().
513 simple 1.1 */
514 pseudo 1.2 int open_address_listen(sockname_t *addr)
515     {
516 simple 1.1 int sock = 0;
517    
518 pseudo 1.2 sock = getsock(addr->family, SOCK_LISTEN);
519     if (sock < 0)
520 simple 1.1 return -1;
521 pseudo 1.2 #if defined IPV6 && IPV6_V6ONLY
522     if (addr->family == AF_INET6) {
523     int on = 0;
524     setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, sizeof(on));
525     }
526     #endif
527     if (bind(sock, &addr->addr.sa, addr->addrlen) < 0) {
528     killsock(sock);
529     return -2;
530 simple 1.1 }
531    
532 pseudo 1.2 if (getsockname(sock, &addr->addr.sa, &addr->addrlen) < 0) {
533     killsock(sock);
534     return -1;
535     }
536     if (listen(sock, 1) < 0) {
537     killsock(sock);
538     return -1;
539 simple 1.1 }
540    
541     return sock;
542     }
543    
544     /* Returns a socket number for a listening socket that will accept any
545     * connection -- port # is returned in port
546     */
547     inline int open_listen(int *port)
548     {
549 pseudo 1.2 int sock;
550     sockname_t name;
551 simple 1.1
552 pseudo 1.2 (void) setsockname(&name, listen_ip, *port, 1);
553     sock = open_address_listen(&name);
554     if (name.addr.sa.sa_family == AF_INET)
555     *port = ntohs(name.addr.s4.sin_port);
556     #ifdef IPV6
557     else
558     *port = ntohs(name.addr.s6.sin6_port);
559     #endif
560     return sock;
561 simple 1.1 }
562    
563 pseudo 1.2 /* Short routine to answer a connect received on a listening socket.
564     * Returned is the new socket.
565     * If port is not NULL, it points to an integer to hold the port number
566     * of the caller.
567 simple 1.1 */
568 pseudo 1.2 int answer(int sock, sockname_t *caller, unsigned short *port, int binary)
569 simple 1.1 {
570     int new_sock;
571 pseudo 1.2 caller->addrlen = sizeof(caller->addr);
572     new_sock = accept(sock, &caller->addr.sa, &caller->addrlen);
573    
574 simple 1.1 if (new_sock < 0)
575     return -1;
576 pseudo 1.2
577     caller->family = caller->addr.sa.sa_family;
578     if (port) {
579     if (caller->family == AF_INET)
580     *port = ntohs(caller->addr.s4.sin_port);
581     #ifdef IPV6
582     else
583     *port = ntohs(caller->addr.s6.sin6_port);
584     #endif
585     }
586 simple 1.1 setsock(new_sock, (binary ? SOCK_BINARY : 0));
587     return new_sock;
588     }
589    
590 pseudo 1.2 /* Get DCC compatible address for a client to connect (e.g. 1660944385)
591     * If addr is not NULL, it should point to the listening socket's address.
592     * Otherwise, this function will try to figure out the public address of the
593     * machine, using listen_ip and natip.
594     * The result is a string useable for DCC requests
595 simple 1.1 */
596 pseudo 1.2 int getdccaddr(sockname_t *addr, char *s, size_t l)
597 simple 1.1 {
598 pseudo 1.2 char h[121];
599     sockname_t name, *r = &name;
600 simple 1.1
601 pseudo 1.2 if (addr)
602     r = addr;
603 simple 1.1 else
604 pseudo 1.2 setsockname(r, listen_ip, 0, 1);
605     if (
606     #ifdef IPV6
607     ((r->family == AF_INET6) &&
608     IN6_IS_ADDR_UNSPECIFIED(&r->addr.s6.sin6_addr)) ||
609     #endif
610     (r->family == AF_INET && !r->addr.s4.sin_addr.s_addr)) {
611     /* We can't send :: or 0.0.0.0 for dcc, so try
612     to figure out some real address */
613     r = &name;
614     gethostname(h, sizeof h);
615     setsockname(r, h, 0, 1);
616     }
617    
618     if (
619     #ifdef IPV6
620     ((r->family == AF_INET6) &&
621     IN6_IS_ADDR_UNSPECIFIED(&r->addr.s6.sin6_addr)) ||
622     #endif
623     (!natip[0] && (r->family == AF_INET) && !r->addr.s4.sin_addr.s_addr))
624     return 0;
625    
626     #ifdef IPV6
627     if (r->family == AF_INET6) {
628     if (IN6_IS_ADDR_V4MAPPED(&r->addr.s6.sin6_addr) ||
629     IN6_IS_ADDR_UNSPECIFIED(&r->addr.s6.sin6_addr))
630     snprintf(s, l, "%lu", natip[0] ? iptolong(inet_addr(natip)) :
631 pseudo 1.3 ntohl(*(IP *) &r->addr.s6.sin6_addr.s6_addr[12]));
632 pseudo 1.2 else
633     inet_ntop(AF_INET6, &r->addr.s6.sin6_addr, s, l);
634     } else
635     #endif
636     snprintf(s, l, "%lu", natip[0] ? iptolong(inet_addr(natip)) :
637     ntohl(r->addr.s4.sin_addr.s_addr));
638     return 1;
639 simple 1.1 }
640    
641     /* Builds the fd_sets for select(). Eggdrop only cares about readable
642     * sockets, but tcl also cares for writable/exceptions.
643     * preparefdset() can be called by Tcl Threads
644     */
645     int preparefdset(fd_set *fd, sock_list *slist, int slistmax, int tclonly, int tclmask)
646     {
647     int fdtmp, i, foundsocks = 0;
648    
649     FD_ZERO(fd);
650     for (i = 0; i < slistmax; i++) {
651     if (!(slist[i].flags & (SOCK_UNUSED | SOCK_VIRTUAL))) {
652     if ((slist[i].sock == STDOUT) && !backgrd)
653     fdtmp = STDIN;
654     else
655     fdtmp = slist[i].sock;
656     /*
657     * Looks like that having more than a call, in the same
658     * program, to the FD_SET macro, triggers a bug in gcc.
659     * SIGBUS crashing binaries used to be produced on a number
660     * (prolly all?) of 64 bits architectures.
661     * Make your best to avoid to make it happen again.
662     *
663     * ITE
664     */
665     if (slist[i].flags & SOCK_TCL) {
666     if (!(slist[i].handler.tclsock.mask & tclmask))
667     continue;
668     } else if (tclonly)
669     continue;
670     foundsocks = 1;
671     FD_SET(fdtmp, fd);
672     }
673     }
674     return foundsocks;
675     }
676    
677     /* Attempts to read from all sockets in slist (upper array boundary slistmax-1)
678     * fills s with up to 511 bytes if available, and returns the array index
679     * Also calls all handler procs for Tcl sockets
680     * sockread() can be called by Tcl threads
681     *
682     * on EOF: returns -1, with socket in len
683     * on socket error: returns -2
684     * if nothing is ready: returns -3
685     * tcl sockets busy: returns -5
686     */
687     int sockread(char *s, int *len, sock_list *slist, int slistmax, int tclonly)
688     {
689     struct timeval t;
690     fd_set fdr, fdw, fde;
691     int fds, i, x, have_r, have_w, have_e;
692     int grab = 511, tclsock = -1, events = 0;
693     struct threaddata *td = threaddata();
694    
695     fds = getdtablesize();
696     #ifdef FD_SETSIZE
697     if (fds > FD_SETSIZE)
698     fds = FD_SETSIZE; /* Fixes YET ANOTHER freebsd bug!!! */
699     #endif
700    
701     have_r = preparefdset(&fdr, slist, slistmax, tclonly, TCL_READABLE);
702     have_w = preparefdset(&fdw, slist, slistmax, 1, TCL_WRITABLE);
703     have_e = preparefdset(&fde, slist, slistmax, 1, TCL_EXCEPTION);
704    
705     /* select() may modify the timeval argument - copy it */
706     t.tv_sec = td->blocktime.tv_sec;
707     t.tv_usec = td->blocktime.tv_usec;
708    
709     x = select((SELECT_TYPE_ARG1) fds,
710     SELECT_TYPE_ARG234 (have_r ? &fdr : NULL),
711     SELECT_TYPE_ARG234 (have_w ? &fdw : NULL),
712     SELECT_TYPE_ARG234 (have_e ? &fde : NULL),
713     SELECT_TYPE_ARG5 &t);
714     if (x > 0) {
715     /* Something happened */
716     for (i = 0; i < slistmax; i++) {
717     if (!tclonly && ((!(slist[i].flags & (SOCK_UNUSED | SOCK_TCL))) &&
718     ((FD_ISSET(slist[i].sock, &fdr)) ||
719     ((slist[i].sock == STDOUT) && (!backgrd) &&
720     (FD_ISSET(STDIN, &fdr)))))) {
721     if (slist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
722     /* Listening socket -- don't read, just return activity */
723     /* Same for connection attempt */
724     /* (for strong connections, require a read to succeed first) */
725     if (slist[i].flags & SOCK_PROXYWAIT) /* drummer */
726     /* Hang around to get the return code from proxy */
727     grab = 10;
728     else if (!(slist[i].flags & SOCK_STRONGCONN)) {
729     debug1("net: connect! sock %d", slist[i].sock);
730     s[0] = 0;
731     *len = 0;
732     return i;
733     }
734     } else if (slist[i].flags & SOCK_PASS) {
735     s[0] = 0;
736     *len = 0;
737     return i;
738     }
739     errno = 0;
740     if ((slist[i].sock == STDOUT) && !backgrd)
741     x = read(STDIN, s, grab);
742     else
743     x = read(slist[i].sock, s, grab);
744     if (x <= 0) { /* eof */
745     if (errno != EAGAIN) { /* EAGAIN happens when the operation would
746     * block on a non-blocking socket, if the
747     * socket is going to die, it will die later,
748     * otherwise it will connect. */
749     *len = slist[i].sock;
750     slist[i].flags &= ~SOCK_CONNECT;
751     debug1("net: eof!(read) socket %d", slist[i].sock);
752     return -1;
753     } else {
754     debug3("sockread EAGAIN: %d %d (%s)", slist[i].sock, errno,
755     strerror(errno));
756     continue; /* EAGAIN */
757     }
758     }
759     s[x] = 0;
760     *len = x;
761     if (slist[i].flags & SOCK_PROXYWAIT) {
762     debug2("net: socket: %d proxy errno: %d", slist[i].sock, s[1]);
763     slist[i].flags &= ~(SOCK_CONNECT | SOCK_PROXYWAIT);
764     switch (s[1]) {
765     case 90: /* Success */
766     s[0] = 0;
767     *len = 0;
768     return i;
769     case 91: /* Failed */
770     errno = ECONNREFUSED;
771     break;
772     case 92: /* No identd */
773     case 93: /* Identd said wrong username */
774     /* A better error message would be "socks misconfigured"
775     * or "identd not working" but this is simplest.
776     */
777     errno = ENETUNREACH;
778     break;
779     }
780     *len = slist[i].sock;
781     return -1;
782     }
783     return i;
784     } else if (tclsock == -1 && (slist[i].flags & SOCK_TCL)) {
785     events = FD_ISSET(slist[i].sock, &fdr) ? TCL_READABLE : 0;
786     events |= FD_ISSET(slist[i].sock, &fdw) ? TCL_WRITABLE : 0;
787     events |= FD_ISSET(slist[i].sock, &fde) ? TCL_EXCEPTION : 0;
788     events &= slist[i].handler.tclsock.mask;
789     if (events)
790     tclsock = i;
791     }
792     }
793     } else if (x == -1)
794     return -2; /* socket error */
795     else if (!tclonly) {
796     s[0] = 0;
797     *len = 0;
798     }
799     if (tclsock != -1) {
800     (*slist[tclsock].handler.tclsock.proc)(slist[tclsock].handler.tclsock.cd,
801     events);
802     return -5;
803     }
804     return -3;
805     }
806    
807     /* sockgets: buffer and read from sockets
808     *
809     * Attempts to read from all registered sockets for up to one second. if
810     * after one second, no complete data has been received from any of the
811     * sockets, 's' will be empty, 'len' will be 0, and sockgets will return -3.
812     * if there is returnable data received from a socket, the data will be
813     * in 's' (null-terminated if non-binary), the length will be returned
814     * in len, and the socket number will be returned.
815     * normal sockets have their input buffered, and each call to sockgets
816     * will return one line terminated with a '\n'. binary sockets are not
817     * buffered and return whatever coems in as soon as it arrives.
818     * listening sockets will return an empty string when a connection comes in.
819     * connecting sockets will return an empty string on a successful connect,
820     * or EOF on a failed connect.
821     * if an EOF is detected from any of the sockets, that socket number will be
822     * put in len, and -1 will be returned.
823     * the maximum length of the string returned is 512 (including null)
824     *
825     * Returns -4 if we handled something that shouldn't be handled by the
826     * dcc functions. Simply ignore it.
827     * Returns -5 if tcl sockets are busy but not eggdrop sockets.
828     */
829    
830     int sockgets(char *s, int *len)
831     {
832     char xx[514], *p, *px;
833     int ret, i, data = 0;
834    
835     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
836     /* Check for stored-up data waiting to be processed */
837     if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL | SOCK_BUFFER)) &&
838     (socklist[i].handler.sock.inbuf != NULL)) {
839     if (!(socklist[i].flags & SOCK_BINARY)) {
840     /* look for \r too cos windows can't follow RFCs */
841     p = strchr(socklist[i].handler.sock.inbuf, '\n');
842     if (p == NULL)
843     p = strchr(socklist[i].handler.sock.inbuf, '\r');
844     if (p != NULL) {
845     *p = 0;
846     if (strlen(socklist[i].handler.sock.inbuf) > 510)
847     socklist[i].handler.sock.inbuf[510] = 0;
848     strcpy(s, socklist[i].handler.sock.inbuf);
849     px = nmalloc(strlen(p + 1) + 1);
850     strcpy(px, p + 1);
851     nfree(socklist[i].handler.sock.inbuf);
852     if (px[0])
853     socklist[i].handler.sock.inbuf = px;
854     else {
855     nfree(px);
856     socklist[i].handler.sock.inbuf = NULL;
857     }
858     /* Strip CR if this was CR/LF combo */
859     if (s[strlen(s) - 1] == '\r')
860     s[strlen(s) - 1] = 0;
861     *len = strlen(s);
862     return socklist[i].sock;
863     }
864     } else {
865     /* Handling buffered binary data (must have been SOCK_BUFFER before). */
866     if (socklist[i].handler.sock.inbuflen <= 510) {
867     *len = socklist[i].handler.sock.inbuflen;
868     egg_memcpy(s, socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
869     nfree(socklist[i].handler.sock.inbuf);
870     socklist[i].handler.sock.inbuf = NULL;
871     socklist[i].handler.sock.inbuflen = 0;
872     } else {
873     /* Split up into chunks of 510 bytes. */
874     *len = 510;
875     egg_memcpy(s, socklist[i].handler.sock.inbuf, *len);
876     egg_memcpy(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuf + *len, *len);
877     socklist[i].handler.sock.inbuflen -= *len;
878     socklist[i].handler.sock.inbuf = nrealloc(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
879     }
880     return socklist[i].sock;
881     }
882     }
883     /* Also check any sockets that might have EOF'd during write */
884     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].flags & SOCK_EOFD)) {
885     s[0] = 0;
886     *len = socklist[i].sock;
887     return -1;
888     }
889     }
890     /* No pent-up data of any worth -- down to business */
891     *len = 0;
892     ret = sockread(xx, len, socklist, threaddata()->MAXSOCKS, 0);
893     if (ret < 0) {
894     s[0] = 0;
895     return ret;
896     }
897     /* Binary, listening and passed on sockets don't get buffered. */
898     if (socklist[ret].flags & SOCK_CONNECT) {
899     if (socklist[ret].flags & SOCK_STRONGCONN) {
900     socklist[ret].flags &= ~SOCK_STRONGCONN;
901     /* Buffer any data that came in, for future read. */
902     socklist[ret].handler.sock.inbuflen = *len;
903     socklist[ret].handler.sock.inbuf = nmalloc(*len + 1);
904     /* It might be binary data. You never know. */
905     egg_memcpy(socklist[ret].handler.sock.inbuf, xx, *len);
906     socklist[ret].handler.sock.inbuf[*len] = 0;
907     }
908     socklist[ret].flags &= ~SOCK_CONNECT;
909     s[0] = 0;
910     return socklist[ret].sock;
911     }
912     if (socklist[ret].flags & SOCK_BINARY) {
913     egg_memcpy(s, xx, *len);
914     return socklist[ret].sock;
915     }
916     if (socklist[ret].flags & (SOCK_LISTEN | SOCK_PASS | SOCK_TCL)) {
917     s[0] = 0; /* for the dcc traffic counters in the mainloop */
918     return socklist[ret].sock;
919     }
920     if (socklist[ret].flags & SOCK_BUFFER) {
921     socklist[ret].handler.sock.inbuf = (char *) nrealloc(socklist[ret].handler.sock.inbuf,
922     socklist[ret].handler.sock.inbuflen + *len + 1);
923     egg_memcpy(socklist[ret].handler.sock.inbuf + socklist[ret].handler.sock.inbuflen, xx, *len);
924     socklist[ret].handler.sock.inbuflen += *len;
925     /* We don't know whether it's binary data. Make sure normal strings
926     * will be handled properly later on too. */
927     socklist[ret].handler.sock.inbuf[socklist[ret].handler.sock.inbuflen] = 0;
928     return -4; /* Ignore this one. */
929     }
930     /* Might be necessary to prepend stored-up data! */
931     if (socklist[ret].handler.sock.inbuf != NULL) {
932     p = socklist[ret].handler.sock.inbuf;
933     socklist[ret].handler.sock.inbuf = nmalloc(strlen(p) + strlen(xx) + 1);
934     strcpy(socklist[ret].handler.sock.inbuf, p);
935     strcat(socklist[ret].handler.sock.inbuf, xx);
936     nfree(p);
937     if (strlen(socklist[ret].handler.sock.inbuf) < 512) {
938     strcpy(xx, socklist[ret].handler.sock.inbuf);
939     nfree(socklist[ret].handler.sock.inbuf);
940     socklist[ret].handler.sock.inbuf = NULL;
941     socklist[ret].handler.sock.inbuflen = 0;
942     } else {
943     p = socklist[ret].handler.sock.inbuf;
944     socklist[ret].handler.sock.inbuflen = strlen(p) - 510;
945     socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
946     strcpy(socklist[ret].handler.sock.inbuf, p + 510);
947     *(p + 510) = 0;
948     strcpy(xx, p);
949     nfree(p);
950     /* (leave the rest to be post-pended later) */
951     }
952     }
953     /* Look for EOL marker; if it's there, i have something to show */
954     p = strchr(xx, '\n');
955     if (p == NULL)
956     p = strchr(xx, '\r');
957     if (p != NULL) {
958     *p = 0;
959     strcpy(s, xx);
960     memmove(xx, p + 1, strlen(p + 1) + 1);
961     if (s[strlen(s) - 1] == '\r')
962     s[strlen(s) - 1] = 0;
963     data = 1; /* DCC_CHAT may now need to process a blank line */
964     /* NO! */
965     /* if (!s[0]) strcpy(s," "); */
966     } else {
967     s[0] = 0;
968     if (strlen(xx) >= 510) {
969     /* String is too long, so just insert fake \n */
970     strcpy(s, xx);
971     xx[0] = 0;
972     data = 1;
973     }
974     }
975     *len = strlen(s);
976     /* Anything left that needs to be saved? */
977     if (!xx[0]) {
978     if (data)
979     return socklist[ret].sock;
980     else
981     return -3;
982     }
983     /* Prepend old data back */
984     if (socklist[ret].handler.sock.inbuf != NULL) {
985     p = socklist[ret].handler.sock.inbuf;
986     socklist[ret].handler.sock.inbuflen = strlen(p) + strlen(xx);
987     socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
988     strcpy(socklist[ret].handler.sock.inbuf, xx);
989     strcat(socklist[ret].handler.sock.inbuf, p);
990     nfree(p);
991     } else {
992     socklist[ret].handler.sock.inbuflen = strlen(xx);
993     socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
994     strcpy(socklist[ret].handler.sock.inbuf, xx);
995     }
996     if (data)
997     return socklist[ret].sock;
998     else
999     return -3;
1000     }
1001    
1002     /* Dump something to a socket
1003     *
1004     * NOTE: Do NOT put Contexts in here if you want DEBUG to be meaningful!!
1005     */
1006     void tputs(register int z, char *s, unsigned int len)
1007     {
1008     register int i, x, idx;
1009     char *p;
1010     static int inhere = 0;
1011    
1012     if (z < 0) /* um... HELLO?! sanity check please! */
1013     return;
1014    
1015     if (((z == STDOUT) || (z == STDERR)) && (!backgrd || use_stderr)) {
1016     write(z, s, len);
1017     return;
1018     }
1019    
1020     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1021     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == z)) {
1022     for (idx = 0; idx < dcc_total; idx++) {
1023     if ((dcc[idx].sock == z) && dcc[idx].type && dcc[idx].type->name) {
1024     if (!strncmp(dcc[idx].type->name, "BOT", 3))
1025     otraffic_bn_today += len;
1026     else if (!strcmp(dcc[idx].type->name, "SERVER"))
1027     otraffic_irc_today += len;
1028     else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
1029     otraffic_dcc_today += len;
1030     else if (!strncmp(dcc[idx].type->name, "FILES", 5))
1031     otraffic_filesys_today += len;
1032     else if (!strcmp(dcc[idx].type->name, "SEND"))
1033     otraffic_trans_today += len;
1034     else if (!strncmp(dcc[idx].type->name, "GET", 3))
1035     otraffic_trans_today += len;
1036     else
1037     otraffic_unknown_today += len;
1038     break;
1039     }
1040     }
1041    
1042     if (socklist[i].handler.sock.outbuf != NULL) {
1043     /* Already queueing: just add it */
1044     p = (char *) nrealloc(socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen + len);
1045     egg_memcpy(p + socklist[i].handler.sock.outbuflen, s, len);
1046     socklist[i].handler.sock.outbuf = p;
1047     socklist[i].handler.sock.outbuflen += len;
1048     return;
1049     }
1050     /* Try. */
1051     x = write(z, s, len);
1052     if (x == -1)
1053     x = 0;
1054     if (x < len) {
1055     /* Socket is full, queue it */
1056     socklist[i].handler.sock.outbuf = nmalloc(len - x);
1057     egg_memcpy(socklist[i].handler.sock.outbuf, &s[x], len - x);
1058     socklist[i].handler.sock.outbuflen = len - x;
1059     }
1060     return;
1061     }
1062     }
1063     /* Make sure we don't cause a crash by looping here */
1064     if (!inhere) {
1065     inhere = 1;
1066    
1067     putlog(LOG_MISC, "*", "!!! writing to nonexistent socket: %d", z);
1068     s[strlen(s) - 1] = 0;
1069     putlog(LOG_MISC, "*", "!-> '%s'", s);
1070    
1071     inhere = 0;
1072     }
1073     }
1074    
1075     /* tputs might queue data for sockets, let's dump as much of it as
1076     * possible.
1077     */
1078     void dequeue_sockets()
1079     {
1080     int i, x;
1081    
1082     int z = 0, fds;
1083     fd_set wfds;
1084     struct timeval tv;
1085    
1086     /* ^-- start poptix test code, this should avoid writes to sockets not ready to be written to. */
1087     fds = getdtablesize();
1088    
1089     #ifdef FD_SETSIZE
1090     if (fds > FD_SETSIZE)
1091     fds = FD_SETSIZE; /* Fixes YET ANOTHER freebsd bug!!! */
1092     #endif
1093     FD_ZERO(&wfds);
1094     tv.tv_sec = 0;
1095     tv.tv_usec = 0; /* we only want to see if it's ready for writing, no need to actually wait.. */
1096     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1097     if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
1098     socklist[i].handler.sock.outbuf != NULL) {
1099     FD_SET(socklist[i].sock, &wfds);
1100     z = 1;
1101     }
1102     }
1103     if (!z)
1104     return; /* nothing to write */
1105    
1106     select((SELECT_TYPE_ARG1) fds, SELECT_TYPE_ARG234 NULL,
1107     SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 NULL,
1108     SELECT_TYPE_ARG5 &tv);
1109    
1110     /* end poptix */
1111    
1112     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1113     if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
1114     (socklist[i].handler.sock.outbuf != NULL) && (FD_ISSET(socklist[i].sock, &wfds))) {
1115     /* Trick tputs into doing the work */
1116     errno = 0;
1117     x = write(socklist[i].sock, socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen);
1118     if ((x < 0) && (errno != EAGAIN)
1119     #ifdef EBADSLT
1120     && (errno != EBADSLT)
1121     #endif
1122     #ifdef ENOTCONN
1123     && (errno != ENOTCONN)
1124     #endif
1125     ) {
1126     /* This detects an EOF during writing */
1127     debug3("net: eof!(write) socket %d (%s,%d)", socklist[i].sock,
1128     strerror(errno), errno);
1129     socklist[i].flags |= SOCK_EOFD;
1130     } else if (x == socklist[i].handler.sock.outbuflen) {
1131     /* If the whole buffer was sent, nuke it */
1132     nfree(socklist[i].handler.sock.outbuf);
1133     socklist[i].handler.sock.outbuf = NULL;
1134     socklist[i].handler.sock.outbuflen = 0;
1135     } else if (x > 0) {
1136     char *p = socklist[i].handler.sock.outbuf;
1137    
1138     /* This removes any sent bytes from the beginning of the buffer */
1139     socklist[i].handler.sock.outbuf = nmalloc(socklist[i].handler.sock.outbuflen - x);
1140     egg_memcpy(socklist[i].handler.sock.outbuf, p + x, socklist[i].handler.sock.outbuflen - x);
1141     socklist[i].handler.sock.outbuflen -= x;
1142     nfree(p);
1143     } else {
1144     debug3("dequeue_sockets(): errno = %d (%s) on %d", errno,
1145     strerror(errno), socklist[i].sock);
1146     }
1147     /* All queued data was sent. Call handler if one exists and the
1148     * dcc entry wants it.
1149     */
1150     if (!socklist[i].handler.sock.outbuf) {
1151     int idx = findanyidx(socklist[i].sock);
1152    
1153     if (idx > 0 && dcc[idx].type && dcc[idx].type->outdone)
1154     dcc[idx].type->outdone(idx);
1155     }
1156     }
1157     }
1158     }
1159    
1160    
1161     /*
1162     * Debugging stuff
1163     */
1164    
1165     void tell_netdebug(int idx)
1166     {
1167     int i;
1168     char s[80];
1169    
1170     dprintf(idx, "Open sockets:");
1171     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1172     if (!(socklist[i].flags & SOCK_UNUSED)) {
1173     sprintf(s, " %d", socklist[i].sock);
1174     if (socklist[i].flags & SOCK_BINARY)
1175     strcat(s, " (binary)");
1176     if (socklist[i].flags & SOCK_LISTEN)
1177     strcat(s, " (listen)");
1178     if (socklist[i].flags & SOCK_PASS)
1179     strcat(s, " (passed on)");
1180     if (socklist[i].flags & SOCK_CONNECT)
1181     strcat(s, " (connecting)");
1182     if (socklist[i].flags & SOCK_STRONGCONN)
1183     strcat(s, " (strong)");
1184     if (socklist[i].flags & SOCK_NONSOCK)
1185     strcat(s, " (file)");
1186     if (socklist[i].flags & SOCK_TCL)
1187     strcat(s, " (tcl)");
1188     if (!(socklist[i].flags & SOCK_TCL)) {
1189     if (socklist[i].handler.sock.inbuf != NULL)
1190     sprintf(&s[strlen(s)], " (inbuf: %04X)",
1191     (unsigned int) strlen(socklist[i].handler.sock.inbuf));
1192     if (socklist[i].handler.sock.outbuf != NULL)
1193     sprintf(&s[strlen(s)], " (outbuf: %06lX)", socklist[i].handler.sock.outbuflen);
1194     }
1195     strcat(s, ",");
1196     dprintf(idx, "%s", s);
1197     }
1198     }
1199     dprintf(idx, " done.\n");
1200     }
1201    
1202     /* Security-flavoured sanity checking on DCC connections of all sorts can be
1203     * done with this routine. Feed it the proper information from your DCC
1204     * before you attempt the connection, and this will make an attempt at
1205     * figuring out if the connection is really that person, or someone screwing
1206     * around. It's not foolproof, but anything that fails this check probably
1207     * isn't going to work anyway due to masquerading firewalls, NAT routers,
1208     * or bugs in mIRC.
1209     */
1210     int sanitycheck_dcc(char *nick, char *from, char *ipaddy, char *port)
1211     {
1212     /* According to the latest RFC, the clients SHOULD be able to handle
1213     * DNS names that are up to 255 characters long. This is not broken.
1214     */
1215    
1216 pseudo 1.2 #ifdef IPV6
1217     char badaddress[INET6_ADDRSTRLEN];
1218     sockname_t name;
1219     IP ip = 0;
1220     #else
1221     char badaddress[sizeof "255.255.255.255"];
1222 simple 1.1 IP ip = my_atoul(ipaddy);
1223 pseudo 1.2 #endif
1224 simple 1.1 int prt = atoi(port);
1225    
1226     /* It is disabled HERE so we only have to check in *one* spot! */
1227     if (!dcc_sanitycheck)
1228     return 1;
1229    
1230     if (prt < 1) {
1231     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible port of %u!",
1232     nick, from, prt);
1233     return 0;
1234     }
1235 pseudo 1.2 #ifdef IPV6
1236     if (strchr(ipaddy, ':')) {
1237     if (inet_pton(AF_INET6, ipaddy, &name.addr.s6.sin6_addr) != 1) {
1238     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an invalid IPv6 "
1239     "address of %s!", nick, from, ipaddy);
1240     return 0;
1241     }
1242     if (IN6_IS_ADDR_V4MAPPED(&name.addr.s6.sin6_addr))
1243     ip = ntohl(*(IP *) &name.addr.s6.sin6_addr.s6_addr[12]);
1244     }
1245     #endif
1246     if (ip && inet_ntop(AF_INET, &ip, badaddress, sizeof badaddress) &&
1247     (ip < (1 << 24))) {
1248 simple 1.1 putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible IP of %s!",
1249     nick, from, badaddress);
1250     return 0;
1251     }
1252     return 1;
1253     }
1254    
1255 pseudo 1.2 int hostsanitycheck_dcc(char *nick, char *from, sockname_t *ip, char *dnsname,
1256 simple 1.1 char *prt)
1257     {
1258 pseudo 1.2 char badaddress[INET6_ADDRSTRLEN];
1259    
1260 simple 1.1 /* According to the latest RFC, the clients SHOULD be able to handle
1261     * DNS names that are up to 255 characters long. This is not broken.
1262     */
1263 pseudo 1.2 char hostn[256];
1264 simple 1.1
1265     /* It is disabled HERE so we only have to check in *one* spot! */
1266     if (!dcc_sanitycheck)
1267     return 1;
1268 pseudo 1.2 strcpy(badaddress, iptostr(&ip->addr.sa));
1269 simple 1.1 /* These should pad like crazy with zeros, since 120 bytes or so is
1270     * where the routines providing our data currently lose interest. I'm
1271     * using the n-variant in case someone changes that...
1272     */
1273     strncpyz(hostn, extracthostname(from), sizeof hostn);
1274     if (!egg_strcasecmp(hostn, dnsname)) {
1275     putlog(LOG_DEBUG, "*", "DNS information for submitted IP checks out.");
1276     return 1;
1277     }
1278     if (!strcmp(badaddress, dnsname))
1279     putlog(LOG_MISC, "*", "ALERT: (%s!%s) sent a DCC request with bogus IP "
1280     "information of %s port %s. %s does not resolve to %s!", nick, from,
1281     badaddress, prt, from, badaddress);
1282     else
1283     return 1; /* <- usually happens when we have
1284     * a user with an unresolved hostmask! */
1285     return 0;
1286     }
1287    
1288     /* Checks wether the referenced socket has data queued.
1289     *
1290     * Returns true if the incoming/outgoing (depending on 'type') queues
1291     * contain data, otherwise false.
1292     */
1293     int sock_has_data(int type, int sock)
1294     {
1295     int ret = 0, i;
1296    
1297     for (i = 0; i < threaddata()->MAXSOCKS; i++)
1298     if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
1299     break;
1300     if (i < threaddata()->MAXSOCKS) {
1301     switch (type) {
1302     case SOCK_DATA_OUTGOING:
1303     ret = (socklist[i].handler.sock.outbuf != NULL);
1304     break;
1305     case SOCK_DATA_INCOMING:
1306     ret = (socklist[i].handler.sock.inbuf != NULL);
1307     break;
1308     }
1309     } else
1310     debug1("sock_has_data: could not find socket #%d, returning false.", sock);
1311     return ret;
1312     }
1313    
1314     /* flush_inbuf():
1315     * checks if there's data in the incoming buffer of an connection
1316     * and flushs the buffer if possible
1317     *
1318     * returns: -1 if the dcc entry wasn't found
1319     * -2 if dcc[idx].type->activity doesn't exist and the data couldn't
1320     * be handled
1321     * 0 if buffer was empty
1322     * otherwise length of flushed buffer
1323     */
1324     int flush_inbuf(int idx)
1325     {
1326     int i, len;
1327     char *inbuf;
1328    
1329     Assert((idx >= 0) && (idx < dcc_total));
1330     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1331     if ((dcc[idx].sock == socklist[i].sock) &&
1332     !(socklist[i].flags & SOCK_UNUSED)) {
1333     len = socklist[i].handler.sock.inbuflen;
1334     if ((len > 0) && socklist[i].handler.sock.inbuf) {
1335     if (dcc[idx].type && dcc[idx].type->activity) {
1336     inbuf = socklist[i].handler.sock.inbuf;
1337     socklist[i].handler.sock.inbuf = NULL;
1338     dcc[idx].type->activity(idx, inbuf, len);
1339     nfree(inbuf);
1340     return len;
1341     } else
1342     return -2;
1343     } else
1344     return 0;
1345     }
1346     }
1347     return -1;
1348     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23