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

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

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


Revision 1.8 - (show 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 /*
2 * net.c -- handles:
3 * all raw network i/o
4 *
5 * $Id: net.c,v 1.7 2010/11/18 12:54:39 pseudo Exp $
6 */
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 #ifdef TLS
48 # include <openssl/err.h>
49 #endif
50
51 #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 char natip[121] = ""; /* Public IPv4 to report for systems behind NAT */
66 char listen_ip[121] = ""; /* IP (or hostname) for listening sockets */
67 char vhost[121] = ""; /* IPv4 vhost for outgoing connections */
68 #ifdef IPV6
69 char vhost6[121] = ""; /* IPv6 vhost for outgoing connections */
70 int pref_af = 0; /* Prefer IPv6 over IPv4? */
71 #endif
72 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 /* 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 */
140 int setsockname(sockname_t *addr, char *src, int port, int allowres)
141 {
142 struct hostent *hp;
143 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 }
209
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 #endif
215 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 #endif
230 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 }
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 #ifdef TLS
278 td->socklist[i].ssl = 0;
279 #endif
280 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 int getsock(int af, int options)
353 {
354 int sock = socket(af, SOCK_STREAM, 0);
355
356 if (sock >= 0)
357 setsock(sock, options);
358 else
359 putlog(LOG_MISC, "*", "Warning: Can't create new socket: %s!",
360 strerror(errno));
361 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 #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 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 static int proxy_connect(int sock, sockname_t *addr)
427 {
428 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 if (proxy == PROXY_SOCKS) {
453 for (i = 0; i < threaddata()->MAXSOCKS; i++)
454 if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
455 socklist[i].flags |= SOCK_PROXYWAIT; /* drummer */
456 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 tputs(sock, s, strlen(botuser) + 9); /* drummer */
460 } else if (proxy == PROXY_SUN) {
461 inet_ntop(AF_INET, &addr->addr.s4.sin_addr, host, sizeof host);
462 egg_snprintf(s, sizeof s, "%s %d\n", host, port);
463 tputs(sock, s, strlen(s)); /* drummer */
464 }
465 return sock;
466 }
467
468 /* Starts a connection attempt through a socket
469 *
470 * The server address should be filled in addr by setsockname() or by the
471 * non-blocking dns functions and setsnport().
472 *
473 * returns < 0 if connection refused:
474 * -1 strerror() type error
475 */
476 int open_telnet_raw(int sock, sockname_t *addr)
477 {
478 sockname_t name;
479 int i, rc;
480
481 getvhost(&name, addr->family);
482 if (bind(sock, &name.addr.sa, name.addrlen) < 0) {
483 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 if (addr->family == AF_INET && firewall[0])
490 return proxy_connect(sock, addr);
491 rc = connect(sock, &addr->addr.sa, addr->addrlen);
492 if (rc < 0) {
493 if (errno == EINPROGRESS)
494 return sock; /* async success! */
495 else
496 return -1;
497 }
498 return sock;
499 }
500
501 /* 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 * -3: could not allocate socket
507 */
508 int open_telnet(int idx, char *server, int port)
509 {
510 int ret;
511
512 ret = setsockname(&dcc[idx].sockname, server, port, 1);
513 if (ret == AF_UNSPEC)
514 return -2;
515 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 if (ret < 0)
521 killsock(dcc[idx].sock);
522 return ret;
523 }
524
525 /* Returns a socket number for a listening socket that will accept any
526 * connection on the given address. The address can be filled in by
527 * setsockname().
528 */
529 int open_address_listen(sockname_t *addr)
530 {
531 int sock = 0;
532
533 sock = getsock(addr->family, SOCK_LISTEN);
534 if (sock < 0)
535 return -1;
536 #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 }
546
547 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 }
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 int sock;
565 sockname_t name;
566
567 (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 }
577
578 /* 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 */
583 int answer(int sock, sockname_t *caller, unsigned short *port, int binary)
584 {
585 int new_sock;
586 caller->addrlen = sizeof(caller->addr);
587 new_sock = accept(sock, &caller->addr.sa, &caller->addrlen);
588
589 if (new_sock < 0)
590 return -1;
591
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 setsock(new_sock, (binary ? SOCK_BINARY : 0));
602 return new_sock;
603 }
604
605 /* 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 */
611 int getdccaddr(sockname_t *addr, char *s, size_t l)
612 {
613 char h[121];
614 sockname_t name, *r = &name;
615
616 if (addr)
617 r = addr;
618 else
619 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 ntohl(*(IP *) &r->addr.s6.sin6_addr.s6_addr[12]));
647 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 }
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 #ifdef TLS
735 (slist[i].ssl && (SSL_pending(slist[i].ssl) ||
736 !SSL_is_init_finished(slist[i].ssl))) ||
737 #endif
738 ((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 #ifdef TLS
748 else if (!(slist[i].flags & SOCK_STRONGCONN) &&
749 (!(slist[i].ssl) || SSL_is_init_finished(slist[i].ssl))) {
750 #else
751 else if (!(slist[i].flags & SOCK_STRONGCONN)) {
752 #endif
753 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 #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 debug1("sockread(): SSL error = %s",
777 ERR_error_string(ERR_get_error(), 0));
778 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 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 #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 debug1("tputs(): SSL error = %s",
1102 ERR_error_string(ERR_get_error(), 0));
1103 inhere = 0;
1104 }
1105 x = -1;
1106 }
1107 } else /* not ssl, use regular write() */
1108 #endif
1109 /* 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 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 }
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 #ifdef TLS
1185 if (socklist[i].ssl) {
1186 x = SSL_write(socklist[i].ssl, socklist[i].handler.sock.outbuf,
1187 socklist[i].handler.sock.outbuflen);
1188 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 debug1("dequeue_sockets(): SSL error = %s",
1194 ERR_error_string(ERR_get_error(), 0));
1195 x = -1;
1196 }
1197 } else
1198 #endif
1199 x = write(socklist[i].sock, socklist[i].handler.sock.outbuf,
1200 socklist[i].handler.sock.outbuflen);
1201 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 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 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 #ifdef TLS
1272 if (socklist[i].ssl)
1273 strcat(s, " (TLS)");
1274 #endif
1275 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 #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 IP ip = my_atoul(ipaddy);
1312 #endif
1313 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 #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 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 int hostsanitycheck_dcc(char *nick, char *from, sockname_t *ip, char *dnsname,
1345 char *prt)
1346 {
1347 char badaddress[INET6_ADDRSTRLEN];
1348
1349 /* 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 char hostn[256];
1353
1354 /* It is disabled HERE so we only have to check in *one* spot! */
1355 if (!dcc_sanitycheck)
1356 return 1;
1357 strcpy(badaddress, iptostr(&ip->addr.sa));
1358 /* 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
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