/[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.10 - (hide annotations) (download) (as text)
Thu Feb 3 15:44:11 2011 UTC (8 years, 8 months ago) by pseudo
Branch: MAIN
Changes since 1.9: +92 -93 lines
File MIME type: text/x-chdr
Check for pending data on SSL sockets even when select reports the descriptor's not readable.
Allow moving write buffers for SSL sockets.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23