/[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.8 - (hide annotations) (download) (as text)
Tue Nov 23 16:36:23 2010 UTC (8 years, 7 months ago) by pseudo
Branch: MAIN
Changes since 1.7: +29 -14 lines
File MIME type: text/x-chdr
Fixed a problem with sharing causing starttls to fail.
Moved STARTTLS early in the bot link process and synchronized the handshake.
Made it possible for ssl handshakes to complete even without data to be sent on the channel.
Fixed an ancient bug resulting in sending uninitialized strings when sharing bot addresses.
Enabled userfile sending over ssl.

1 simple 1.1 /*
2     * net.c -- handles:
3     * all raw network i/o
4     *
5 pseudo 1.8 * $Id: net.c,v 1.7 2010/11/18 12:54:39 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     if (x > 0) {
730     /* Something happened */
731     for (i = 0; i < slistmax; i++) {
732     if (!tclonly && ((!(slist[i].flags & (SOCK_UNUSED | SOCK_TCL))) &&
733     ((FD_ISSET(slist[i].sock, &fdr)) ||
734 pseudo 1.5 #ifdef TLS
735 pseudo 1.8 (slist[i].ssl && (SSL_pending(slist[i].ssl) ||
736     !SSL_is_init_finished(slist[i].ssl))) ||
737 pseudo 1.5 #endif
738 simple 1.1 ((slist[i].sock == STDOUT) && (!backgrd) &&
739     (FD_ISSET(STDIN, &fdr)))))) {
740     if (slist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
741     /* Listening socket -- don't read, just return activity */
742     /* Same for connection attempt */
743     /* (for strong connections, require a read to succeed first) */
744     if (slist[i].flags & SOCK_PROXYWAIT) /* drummer */
745     /* Hang around to get the return code from proxy */
746     grab = 10;
747 pseudo 1.5 #ifdef TLS
748     else if (!(slist[i].flags & SOCK_STRONGCONN) &&
749 pseudo 1.8 (!(slist[i].ssl) || SSL_is_init_finished(slist[i].ssl))) {
750 pseudo 1.5 #else
751 simple 1.1 else if (!(slist[i].flags & SOCK_STRONGCONN)) {
752 pseudo 1.5 #endif
753 simple 1.1 debug1("net: connect! sock %d", slist[i].sock);
754     s[0] = 0;
755     *len = 0;
756     return i;
757     }
758     } else if (slist[i].flags & SOCK_PASS) {
759     s[0] = 0;
760     *len = 0;
761     return i;
762     }
763     errno = 0;
764     if ((slist[i].sock == STDOUT) && !backgrd)
765     x = read(STDIN, s, grab);
766     else
767 pseudo 1.5 #ifdef TLS
768     {
769     if (slist[i].ssl) {
770     x = SSL_read(slist[i].ssl, s, grab);
771     if (x < 0) {
772     int err = SSL_get_error(slist[i].ssl, x);
773     if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
774     errno = EAGAIN;
775     else
776 pseudo 1.8 debug1("sockread(): SSL error = %s",
777     ERR_error_string(ERR_get_error(), 0));
778 pseudo 1.5 x = -1;
779     }
780     } else
781     x = read(slist[i].sock, s, grab);
782     }
783     #else
784     x = read(slist[i].sock, s, grab);
785     #endif
786 simple 1.1 if (x <= 0) { /* eof */
787     if (errno != EAGAIN) { /* EAGAIN happens when the operation would
788     * block on a non-blocking socket, if the
789     * socket is going to die, it will die later,
790     * otherwise it will connect. */
791     *len = slist[i].sock;
792     slist[i].flags &= ~SOCK_CONNECT;
793     debug1("net: eof!(read) socket %d", slist[i].sock);
794     return -1;
795     } else {
796     debug3("sockread EAGAIN: %d %d (%s)", slist[i].sock, errno,
797     strerror(errno));
798     continue; /* EAGAIN */
799     }
800     }
801     s[x] = 0;
802     *len = x;
803     if (slist[i].flags & SOCK_PROXYWAIT) {
804     debug2("net: socket: %d proxy errno: %d", slist[i].sock, s[1]);
805     slist[i].flags &= ~(SOCK_CONNECT | SOCK_PROXYWAIT);
806     switch (s[1]) {
807     case 90: /* Success */
808     s[0] = 0;
809     *len = 0;
810     return i;
811     case 91: /* Failed */
812     errno = ECONNREFUSED;
813     break;
814     case 92: /* No identd */
815     case 93: /* Identd said wrong username */
816     /* A better error message would be "socks misconfigured"
817     * or "identd not working" but this is simplest.
818     */
819     errno = ENETUNREACH;
820     break;
821     }
822     *len = slist[i].sock;
823     return -1;
824     }
825     return i;
826     } else if (tclsock == -1 && (slist[i].flags & SOCK_TCL)) {
827     events = FD_ISSET(slist[i].sock, &fdr) ? TCL_READABLE : 0;
828     events |= FD_ISSET(slist[i].sock, &fdw) ? TCL_WRITABLE : 0;
829     events |= FD_ISSET(slist[i].sock, &fde) ? TCL_EXCEPTION : 0;
830     events &= slist[i].handler.tclsock.mask;
831     if (events)
832     tclsock = i;
833     }
834     }
835     } else if (x == -1)
836     return -2; /* socket error */
837     else if (!tclonly) {
838     s[0] = 0;
839     *len = 0;
840     }
841     if (tclsock != -1) {
842     (*slist[tclsock].handler.tclsock.proc)(slist[tclsock].handler.tclsock.cd,
843     events);
844     return -5;
845     }
846     return -3;
847     }
848    
849     /* sockgets: buffer and read from sockets
850     *
851     * Attempts to read from all registered sockets for up to one second. if
852     * after one second, no complete data has been received from any of the
853     * sockets, 's' will be empty, 'len' will be 0, and sockgets will return -3.
854     * if there is returnable data received from a socket, the data will be
855     * in 's' (null-terminated if non-binary), the length will be returned
856     * in len, and the socket number will be returned.
857     * normal sockets have their input buffered, and each call to sockgets
858     * will return one line terminated with a '\n'. binary sockets are not
859     * buffered and return whatever coems in as soon as it arrives.
860     * listening sockets will return an empty string when a connection comes in.
861     * connecting sockets will return an empty string on a successful connect,
862     * or EOF on a failed connect.
863     * if an EOF is detected from any of the sockets, that socket number will be
864     * put in len, and -1 will be returned.
865     * the maximum length of the string returned is 512 (including null)
866     *
867     * Returns -4 if we handled something that shouldn't be handled by the
868     * dcc functions. Simply ignore it.
869     * Returns -5 if tcl sockets are busy but not eggdrop sockets.
870     */
871    
872     int sockgets(char *s, int *len)
873     {
874     char xx[514], *p, *px;
875     int ret, i, data = 0;
876    
877     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
878     /* Check for stored-up data waiting to be processed */
879     if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL | SOCK_BUFFER)) &&
880     (socklist[i].handler.sock.inbuf != NULL)) {
881     if (!(socklist[i].flags & SOCK_BINARY)) {
882     /* look for \r too cos windows can't follow RFCs */
883     p = strchr(socklist[i].handler.sock.inbuf, '\n');
884     if (p == NULL)
885     p = strchr(socklist[i].handler.sock.inbuf, '\r');
886     if (p != NULL) {
887     *p = 0;
888     if (strlen(socklist[i].handler.sock.inbuf) > 510)
889     socklist[i].handler.sock.inbuf[510] = 0;
890     strcpy(s, socklist[i].handler.sock.inbuf);
891     px = nmalloc(strlen(p + 1) + 1);
892     strcpy(px, p + 1);
893     nfree(socklist[i].handler.sock.inbuf);
894     if (px[0])
895     socklist[i].handler.sock.inbuf = px;
896     else {
897     nfree(px);
898     socklist[i].handler.sock.inbuf = NULL;
899     }
900     /* Strip CR if this was CR/LF combo */
901     if (s[strlen(s) - 1] == '\r')
902     s[strlen(s) - 1] = 0;
903     *len = strlen(s);
904     return socklist[i].sock;
905     }
906     } else {
907     /* Handling buffered binary data (must have been SOCK_BUFFER before). */
908     if (socklist[i].handler.sock.inbuflen <= 510) {
909     *len = socklist[i].handler.sock.inbuflen;
910     egg_memcpy(s, socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
911     nfree(socklist[i].handler.sock.inbuf);
912     socklist[i].handler.sock.inbuf = NULL;
913     socklist[i].handler.sock.inbuflen = 0;
914     } else {
915     /* Split up into chunks of 510 bytes. */
916     *len = 510;
917     egg_memcpy(s, socklist[i].handler.sock.inbuf, *len);
918     egg_memcpy(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuf + *len, *len);
919     socklist[i].handler.sock.inbuflen -= *len;
920     socklist[i].handler.sock.inbuf = nrealloc(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
921     }
922     return socklist[i].sock;
923     }
924     }
925     /* Also check any sockets that might have EOF'd during write */
926     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].flags & SOCK_EOFD)) {
927     s[0] = 0;
928     *len = socklist[i].sock;
929     return -1;
930     }
931     }
932     /* No pent-up data of any worth -- down to business */
933     *len = 0;
934     ret = sockread(xx, len, socklist, threaddata()->MAXSOCKS, 0);
935     if (ret < 0) {
936     s[0] = 0;
937     return ret;
938     }
939     /* Binary, listening and passed on sockets don't get buffered. */
940     if (socklist[ret].flags & SOCK_CONNECT) {
941     if (socklist[ret].flags & SOCK_STRONGCONN) {
942     socklist[ret].flags &= ~SOCK_STRONGCONN;
943     /* Buffer any data that came in, for future read. */
944     socklist[ret].handler.sock.inbuflen = *len;
945     socklist[ret].handler.sock.inbuf = nmalloc(*len + 1);
946     /* It might be binary data. You never know. */
947     egg_memcpy(socklist[ret].handler.sock.inbuf, xx, *len);
948     socklist[ret].handler.sock.inbuf[*len] = 0;
949     }
950     socklist[ret].flags &= ~SOCK_CONNECT;
951     s[0] = 0;
952     return socklist[ret].sock;
953     }
954     if (socklist[ret].flags & SOCK_BINARY) {
955     egg_memcpy(s, xx, *len);
956     return socklist[ret].sock;
957     }
958     if (socklist[ret].flags & (SOCK_LISTEN | SOCK_PASS | SOCK_TCL)) {
959     s[0] = 0; /* for the dcc traffic counters in the mainloop */
960     return socklist[ret].sock;
961     }
962     if (socklist[ret].flags & SOCK_BUFFER) {
963     socklist[ret].handler.sock.inbuf = (char *) nrealloc(socklist[ret].handler.sock.inbuf,
964     socklist[ret].handler.sock.inbuflen + *len + 1);
965     egg_memcpy(socklist[ret].handler.sock.inbuf + socklist[ret].handler.sock.inbuflen, xx, *len);
966     socklist[ret].handler.sock.inbuflen += *len;
967     /* We don't know whether it's binary data. Make sure normal strings
968     * will be handled properly later on too. */
969     socklist[ret].handler.sock.inbuf[socklist[ret].handler.sock.inbuflen] = 0;
970     return -4; /* Ignore this one. */
971     }
972     /* Might be necessary to prepend stored-up data! */
973     if (socklist[ret].handler.sock.inbuf != NULL) {
974     p = socklist[ret].handler.sock.inbuf;
975     socklist[ret].handler.sock.inbuf = nmalloc(strlen(p) + strlen(xx) + 1);
976     strcpy(socklist[ret].handler.sock.inbuf, p);
977     strcat(socklist[ret].handler.sock.inbuf, xx);
978     nfree(p);
979     if (strlen(socklist[ret].handler.sock.inbuf) < 512) {
980     strcpy(xx, socklist[ret].handler.sock.inbuf);
981     nfree(socklist[ret].handler.sock.inbuf);
982     socklist[ret].handler.sock.inbuf = NULL;
983     socklist[ret].handler.sock.inbuflen = 0;
984     } else {
985     p = socklist[ret].handler.sock.inbuf;
986     socklist[ret].handler.sock.inbuflen = strlen(p) - 510;
987     socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
988     strcpy(socklist[ret].handler.sock.inbuf, p + 510);
989     *(p + 510) = 0;
990     strcpy(xx, p);
991     nfree(p);
992     /* (leave the rest to be post-pended later) */
993     }
994     }
995     /* Look for EOL marker; if it's there, i have something to show */
996     p = strchr(xx, '\n');
997     if (p == NULL)
998     p = strchr(xx, '\r');
999     if (p != NULL) {
1000     *p = 0;
1001     strcpy(s, xx);
1002     memmove(xx, p + 1, strlen(p + 1) + 1);
1003     if (s[strlen(s) - 1] == '\r')
1004     s[strlen(s) - 1] = 0;
1005     data = 1; /* DCC_CHAT may now need to process a blank line */
1006     /* NO! */
1007     /* if (!s[0]) strcpy(s," "); */
1008     } else {
1009     s[0] = 0;
1010     if (strlen(xx) >= 510) {
1011     /* String is too long, so just insert fake \n */
1012     strcpy(s, xx);
1013     xx[0] = 0;
1014     data = 1;
1015     }
1016     }
1017     *len = strlen(s);
1018     /* Anything left that needs to be saved? */
1019     if (!xx[0]) {
1020     if (data)
1021     return socklist[ret].sock;
1022     else
1023     return -3;
1024     }
1025     /* Prepend old data back */
1026     if (socklist[ret].handler.sock.inbuf != NULL) {
1027     p = socklist[ret].handler.sock.inbuf;
1028     socklist[ret].handler.sock.inbuflen = strlen(p) + strlen(xx);
1029     socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
1030     strcpy(socklist[ret].handler.sock.inbuf, xx);
1031     strcat(socklist[ret].handler.sock.inbuf, p);
1032     nfree(p);
1033     } else {
1034     socklist[ret].handler.sock.inbuflen = strlen(xx);
1035     socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
1036     strcpy(socklist[ret].handler.sock.inbuf, xx);
1037     }
1038     if (data)
1039     return socklist[ret].sock;
1040     else
1041     return -3;
1042     }
1043    
1044     /* Dump something to a socket
1045     *
1046     * NOTE: Do NOT put Contexts in here if you want DEBUG to be meaningful!!
1047     */
1048     void tputs(register int z, char *s, unsigned int len)
1049     {
1050     register int i, x, idx;
1051     char *p;
1052     static int inhere = 0;
1053    
1054     if (z < 0) /* um... HELLO?! sanity check please! */
1055     return;
1056    
1057     if (((z == STDOUT) || (z == STDERR)) && (!backgrd || use_stderr)) {
1058     write(z, s, len);
1059     return;
1060     }
1061    
1062     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1063     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == z)) {
1064     for (idx = 0; idx < dcc_total; idx++) {
1065     if ((dcc[idx].sock == z) && dcc[idx].type && dcc[idx].type->name) {
1066     if (!strncmp(dcc[idx].type->name, "BOT", 3))
1067     otraffic_bn_today += len;
1068     else if (!strcmp(dcc[idx].type->name, "SERVER"))
1069     otraffic_irc_today += len;
1070     else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
1071     otraffic_dcc_today += len;
1072     else if (!strncmp(dcc[idx].type->name, "FILES", 5))
1073     otraffic_filesys_today += len;
1074     else if (!strcmp(dcc[idx].type->name, "SEND"))
1075     otraffic_trans_today += len;
1076     else if (!strncmp(dcc[idx].type->name, "GET", 3))
1077     otraffic_trans_today += len;
1078     else
1079     otraffic_unknown_today += len;
1080     break;
1081     }
1082     }
1083    
1084     if (socklist[i].handler.sock.outbuf != NULL) {
1085     /* Already queueing: just add it */
1086     p = (char *) nrealloc(socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen + len);
1087     egg_memcpy(p + socklist[i].handler.sock.outbuflen, s, len);
1088     socklist[i].handler.sock.outbuf = p;
1089     socklist[i].handler.sock.outbuflen += len;
1090     return;
1091     }
1092 pseudo 1.5 #ifdef TLS
1093     if (socklist[i].ssl) {
1094     x = SSL_write(socklist[i].ssl, s, len);
1095     if (x < 0) {
1096     int err = SSL_get_error(socklist[i].ssl, x);
1097     if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ)
1098     errno = EAGAIN;
1099     else if (!inhere) { /* Out there, somewhere */
1100     inhere = 1;
1101 pseudo 1.8 debug1("tputs(): SSL error = %s",
1102     ERR_error_string(ERR_get_error(), 0));
1103 pseudo 1.5 inhere = 0;
1104     }
1105     x = -1;
1106     }
1107     } else /* not ssl, use regular write() */
1108     #endif
1109 simple 1.1 /* Try. */
1110     x = write(z, s, len);
1111     if (x == -1)
1112     x = 0;
1113     if (x < len) {
1114     /* Socket is full, queue it */
1115     socklist[i].handler.sock.outbuf = nmalloc(len - x);
1116     egg_memcpy(socklist[i].handler.sock.outbuf, &s[x], len - x);
1117     socklist[i].handler.sock.outbuflen = len - x;
1118     }
1119     return;
1120     }
1121     }
1122     /* Make sure we don't cause a crash by looping here */
1123     if (!inhere) {
1124     inhere = 1;
1125    
1126     putlog(LOG_MISC, "*", "!!! writing to nonexistent socket: %d", z);
1127     s[strlen(s) - 1] = 0;
1128     putlog(LOG_MISC, "*", "!-> '%s'", s);
1129    
1130     inhere = 0;
1131     }
1132     }
1133    
1134     /* tputs might queue data for sockets, let's dump as much of it as
1135     * possible.
1136     */
1137     void dequeue_sockets()
1138     {
1139     int i, x;
1140    
1141     int z = 0, fds;
1142     fd_set wfds;
1143     struct timeval tv;
1144    
1145     /* ^-- start poptix test code, this should avoid writes to sockets not ready to be written to. */
1146     fds = getdtablesize();
1147    
1148     #ifdef FD_SETSIZE
1149     if (fds > FD_SETSIZE)
1150     fds = FD_SETSIZE; /* Fixes YET ANOTHER freebsd bug!!! */
1151     #endif
1152     FD_ZERO(&wfds);
1153     tv.tv_sec = 0;
1154     tv.tv_usec = 0; /* we only want to see if it's ready for writing, no need to actually wait.. */
1155     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1156 pseudo 1.8 if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL))) {
1157     #ifdef TLS
1158     /* We can't rely on a transparent negotiation, because the
1159     * handshake may never finish if we don't have any data to send.
1160     */
1161     if (socklist[i].ssl && !SSL_is_init_finished(socklist[i].ssl))
1162     SSL_do_handshake(socklist[i].ssl);
1163     #endif
1164     if (socklist[i].handler.sock.outbuf != NULL) {
1165     FD_SET(socklist[i].sock, &wfds);
1166     z = 1;
1167     }
1168 simple 1.1 }
1169     }
1170     if (!z)
1171     return; /* nothing to write */
1172    
1173     select((SELECT_TYPE_ARG1) fds, SELECT_TYPE_ARG234 NULL,
1174     SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 NULL,
1175     SELECT_TYPE_ARG5 &tv);
1176    
1177     /* end poptix */
1178    
1179     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1180     if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
1181     (socklist[i].handler.sock.outbuf != NULL) && (FD_ISSET(socklist[i].sock, &wfds))) {
1182     /* Trick tputs into doing the work */
1183     errno = 0;
1184 pseudo 1.5 #ifdef TLS
1185     if (socklist[i].ssl) {
1186     x = SSL_write(socklist[i].ssl, socklist[i].handler.sock.outbuf,
1187 pseudo 1.8 socklist[i].handler.sock.outbuflen);
1188 pseudo 1.5 if (x < 0) {
1189     int err = SSL_get_error(socklist[i].ssl, x);
1190     if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ)
1191     errno = EAGAIN;
1192     else
1193 pseudo 1.8 debug1("dequeue_sockets(): SSL error = %s",
1194     ERR_error_string(ERR_get_error(), 0));
1195 pseudo 1.5 x = -1;
1196     }
1197     } else
1198     #endif
1199 pseudo 1.8 x = write(socklist[i].sock, socklist[i].handler.sock.outbuf,
1200     socklist[i].handler.sock.outbuflen);
1201 simple 1.1 if ((x < 0) && (errno != EAGAIN)
1202     #ifdef EBADSLT
1203     && (errno != EBADSLT)
1204     #endif
1205     #ifdef ENOTCONN
1206     && (errno != ENOTCONN)
1207     #endif
1208     ) {
1209     /* This detects an EOF during writing */
1210     debug3("net: eof!(write) socket %d (%s,%d)", socklist[i].sock,
1211     strerror(errno), errno);
1212     socklist[i].flags |= SOCK_EOFD;
1213     } else if (x == socklist[i].handler.sock.outbuflen) {
1214     /* If the whole buffer was sent, nuke it */
1215     nfree(socklist[i].handler.sock.outbuf);
1216     socklist[i].handler.sock.outbuf = NULL;
1217     socklist[i].handler.sock.outbuflen = 0;
1218     } else if (x > 0) {
1219     char *p = socklist[i].handler.sock.outbuf;
1220    
1221     /* This removes any sent bytes from the beginning of the buffer */
1222 pseudo 1.8 socklist[i].handler.sock.outbuf =
1223     nmalloc(socklist[i].handler.sock.outbuflen - x);
1224     egg_memcpy(socklist[i].handler.sock.outbuf, p + x,
1225     socklist[i].handler.sock.outbuflen - x);
1226 simple 1.1 socklist[i].handler.sock.outbuflen -= x;
1227     nfree(p);
1228     } else {
1229     debug3("dequeue_sockets(): errno = %d (%s) on %d", errno,
1230     strerror(errno), socklist[i].sock);
1231     }
1232     /* All queued data was sent. Call handler if one exists and the
1233     * dcc entry wants it.
1234     */
1235     if (!socklist[i].handler.sock.outbuf) {
1236     int idx = findanyidx(socklist[i].sock);
1237    
1238     if (idx > 0 && dcc[idx].type && dcc[idx].type->outdone)
1239     dcc[idx].type->outdone(idx);
1240     }
1241     }
1242     }
1243     }
1244    
1245    
1246     /*
1247     * Debugging stuff
1248     */
1249    
1250     void tell_netdebug(int idx)
1251     {
1252     int i;
1253     char s[80];
1254    
1255     dprintf(idx, "Open sockets:");
1256     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1257     if (!(socklist[i].flags & SOCK_UNUSED)) {
1258     sprintf(s, " %d", socklist[i].sock);
1259     if (socklist[i].flags & SOCK_BINARY)
1260     strcat(s, " (binary)");
1261     if (socklist[i].flags & SOCK_LISTEN)
1262     strcat(s, " (listen)");
1263     if (socklist[i].flags & SOCK_PASS)
1264     strcat(s, " (passed on)");
1265     if (socklist[i].flags & SOCK_CONNECT)
1266     strcat(s, " (connecting)");
1267     if (socklist[i].flags & SOCK_STRONGCONN)
1268     strcat(s, " (strong)");
1269     if (socklist[i].flags & SOCK_NONSOCK)
1270     strcat(s, " (file)");
1271 pseudo 1.5 #ifdef TLS
1272     if (socklist[i].ssl)
1273     strcat(s, " (TLS)");
1274     #endif
1275 simple 1.1 if (socklist[i].flags & SOCK_TCL)
1276     strcat(s, " (tcl)");
1277     if (!(socklist[i].flags & SOCK_TCL)) {
1278     if (socklist[i].handler.sock.inbuf != NULL)
1279     sprintf(&s[strlen(s)], " (inbuf: %04X)",
1280     (unsigned int) strlen(socklist[i].handler.sock.inbuf));
1281     if (socklist[i].handler.sock.outbuf != NULL)
1282     sprintf(&s[strlen(s)], " (outbuf: %06lX)", socklist[i].handler.sock.outbuflen);
1283     }
1284     strcat(s, ",");
1285     dprintf(idx, "%s", s);
1286     }
1287     }
1288     dprintf(idx, " done.\n");
1289     }
1290    
1291     /* Security-flavoured sanity checking on DCC connections of all sorts can be
1292     * done with this routine. Feed it the proper information from your DCC
1293     * before you attempt the connection, and this will make an attempt at
1294     * figuring out if the connection is really that person, or someone screwing
1295     * around. It's not foolproof, but anything that fails this check probably
1296     * isn't going to work anyway due to masquerading firewalls, NAT routers,
1297     * or bugs in mIRC.
1298     */
1299     int sanitycheck_dcc(char *nick, char *from, char *ipaddy, char *port)
1300     {
1301     /* According to the latest RFC, the clients SHOULD be able to handle
1302     * DNS names that are up to 255 characters long. This is not broken.
1303     */
1304    
1305 pseudo 1.2 #ifdef IPV6
1306     char badaddress[INET6_ADDRSTRLEN];
1307     sockname_t name;
1308     IP ip = 0;
1309     #else
1310     char badaddress[sizeof "255.255.255.255"];
1311 simple 1.1 IP ip = my_atoul(ipaddy);
1312 pseudo 1.2 #endif
1313 simple 1.1 int prt = atoi(port);
1314    
1315     /* It is disabled HERE so we only have to check in *one* spot! */
1316     if (!dcc_sanitycheck)
1317     return 1;
1318    
1319     if (prt < 1) {
1320     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible port of %u!",
1321     nick, from, prt);
1322     return 0;
1323     }
1324 pseudo 1.2 #ifdef IPV6
1325     if (strchr(ipaddy, ':')) {
1326     if (inet_pton(AF_INET6, ipaddy, &name.addr.s6.sin6_addr) != 1) {
1327     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an invalid IPv6 "
1328     "address of %s!", nick, from, ipaddy);
1329     return 0;
1330     }
1331     if (IN6_IS_ADDR_V4MAPPED(&name.addr.s6.sin6_addr))
1332     ip = ntohl(*(IP *) &name.addr.s6.sin6_addr.s6_addr[12]);
1333     }
1334     #endif
1335     if (ip && inet_ntop(AF_INET, &ip, badaddress, sizeof badaddress) &&
1336     (ip < (1 << 24))) {
1337 simple 1.1 putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible IP of %s!",
1338     nick, from, badaddress);
1339     return 0;
1340     }
1341     return 1;
1342     }
1343    
1344 pseudo 1.2 int hostsanitycheck_dcc(char *nick, char *from, sockname_t *ip, char *dnsname,
1345 simple 1.1 char *prt)
1346     {
1347 pseudo 1.2 char badaddress[INET6_ADDRSTRLEN];
1348    
1349 simple 1.1 /* According to the latest RFC, the clients SHOULD be able to handle
1350     * DNS names that are up to 255 characters long. This is not broken.
1351     */
1352 pseudo 1.2 char hostn[256];
1353 simple 1.1
1354     /* It is disabled HERE so we only have to check in *one* spot! */
1355     if (!dcc_sanitycheck)
1356     return 1;
1357 pseudo 1.2 strcpy(badaddress, iptostr(&ip->addr.sa));
1358 simple 1.1 /* These should pad like crazy with zeros, since 120 bytes or so is
1359     * where the routines providing our data currently lose interest. I'm
1360     * using the n-variant in case someone changes that...
1361     */
1362     strncpyz(hostn, extracthostname(from), sizeof hostn);
1363     if (!egg_strcasecmp(hostn, dnsname)) {
1364     putlog(LOG_DEBUG, "*", "DNS information for submitted IP checks out.");
1365     return 1;
1366     }
1367     if (!strcmp(badaddress, dnsname))
1368     putlog(LOG_MISC, "*", "ALERT: (%s!%s) sent a DCC request with bogus IP "
1369     "information of %s port %s. %s does not resolve to %s!", nick, from,
1370     badaddress, prt, from, badaddress);
1371     else
1372     return 1; /* <- usually happens when we have
1373     * a user with an unresolved hostmask! */
1374     return 0;
1375     }
1376    
1377     /* Checks wether the referenced socket has data queued.
1378     *
1379     * Returns true if the incoming/outgoing (depending on 'type') queues
1380     * contain data, otherwise false.
1381     */
1382     int sock_has_data(int type, int sock)
1383     {
1384     int ret = 0, i;
1385    
1386     for (i = 0; i < threaddata()->MAXSOCKS; i++)
1387     if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
1388     break;
1389     if (i < threaddata()->MAXSOCKS) {
1390     switch (type) {
1391     case SOCK_DATA_OUTGOING:
1392     ret = (socklist[i].handler.sock.outbuf != NULL);
1393     break;
1394     case SOCK_DATA_INCOMING:
1395     ret = (socklist[i].handler.sock.inbuf != NULL);
1396     break;
1397     }
1398     } else
1399     debug1("sock_has_data: could not find socket #%d, returning false.", sock);
1400     return ret;
1401     }
1402    
1403     /* flush_inbuf():
1404     * checks if there's data in the incoming buffer of an connection
1405     * and flushs the buffer if possible
1406     *
1407     * returns: -1 if the dcc entry wasn't found
1408     * -2 if dcc[idx].type->activity doesn't exist and the data couldn't
1409     * be handled
1410     * 0 if buffer was empty
1411     * otherwise length of flushed buffer
1412     */
1413     int flush_inbuf(int idx)
1414     {
1415     int i, len;
1416     char *inbuf;
1417    
1418     Assert((idx >= 0) && (idx < dcc_total));
1419     for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1420     if ((dcc[idx].sock == socklist[i].sock) &&
1421     !(socklist[i].flags & SOCK_UNUSED)) {
1422     len = socklist[i].handler.sock.inbuflen;
1423     if ((len > 0) && socklist[i].handler.sock.inbuf) {
1424     if (dcc[idx].type && dcc[idx].type->activity) {
1425     inbuf = socklist[i].handler.sock.inbuf;
1426     socklist[i].handler.sock.inbuf = NULL;
1427     dcc[idx].type->activity(idx, inbuf, len);
1428     nfree(inbuf);
1429     return len;
1430     } else
1431     return -2;
1432     } else
1433     return 0;
1434     }
1435     }
1436     return -1;
1437     }
1438 pseudo 1.5
1439     /* Find sock in socklist.
1440     *
1441     * Returns index in socklist or -1 if not found.
1442     */
1443     int findsock(int sock)
1444     {
1445     int i;
1446     struct threaddata *td = threaddata();
1447    
1448     for (i = 0; i < td->MAXSOCKS; i++)
1449     if (td->socklist[i].sock == sock)
1450     break;
1451     if (i == td->MAXSOCKS)
1452     return -1;
1453     return i;
1454     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23