/[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.6.2.4 - (hide annotations) (download) (as text)
Tue Feb 15 23:52:09 2011 UTC (8 years, 4 months ago) by pseudo
Branch: gettext
Changes since 1.6.2.3: +3 -2 lines
File MIME type: text/x-chdr
Fixed a bug with connecting to numeric addresses when compiled with --disable-ipv6

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23