/[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.6.2.4 - (show 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 /*
2 * net.c -- handles:
3 * all raw network i/o
4 *
5 * $Id: net.c,v 1.6.2.3 2011/02/08 22:06:01 thommey 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 memcpy(&addr->addr.s4.sin_addr, hp->h_addr, hp->h_length);
177 else
178 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 memcpy(&addr->addr.s4.sin_addr, hp->h_addr, hp->h_length);
206 af = hp->h_addrtype;
207 }
208 } else
209 af = AF_INET;
210
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 #endif
216 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 #endif
231 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 }
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 #ifdef TLS
279 td->socklist[i].ssl = 0;
280 #endif
281 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 putlog(LOG_MISC, "*", _("Socket table full."));
335 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 int getsock(int af, int options)
354 {
355 int sock = socket(af, SOCK_STREAM, 0);
356
357 if (sock >= 0)
358 setsock(sock, options);
359 else
360 putlog(LOG_MISC, "*", _("Warning: Can't create new socket: %s!"),
361 strerror(errno));
362 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 #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 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 putlog(LOG_MISC, "*", _("Warning: Attempt to kill un-allocated socket %d!"),
403 sock);
404 }
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 static int proxy_connect(int sock, sockname_t *addr)
429 {
430 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 putlog(LOG_MISC, "*", _("Eggdrop doesn't support IPv6 connections "
439 "through proxies yet."));
440 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 if (proxy == PROXY_SOCKS) {
455 for (i = 0; i < threaddata()->MAXSOCKS; i++)
456 if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
457 socklist[i].flags |= SOCK_PROXYWAIT; /* drummer */
458 memcpy(host, &addr->addr.s4.sin_addr.s_addr, 4);
459 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 tputs(sock, s, strlen(botuser) + 9); /* drummer */
462 } else if (proxy == PROXY_SUN) {
463 inet_ntop(AF_INET, &addr->addr.s4.sin_addr, host, sizeof host);
464 egg_snprintf(s, sizeof s, "%s %d\n", host, port);
465 tputs(sock, s, strlen(s)); /* drummer */
466 }
467 return sock;
468 }
469
470 /* Starts a connection attempt through a socket
471 *
472 * The server address should be filled in addr by setsockname() or by the
473 * non-blocking dns functions and setsnport().
474 *
475 * returns < 0 if connection refused:
476 * -1 strerror() type error
477 */
478 int open_telnet_raw(int sock, sockname_t *addr)
479 {
480 sockname_t name;
481 int i, rc;
482
483 getvhost(&name, addr->family);
484 if (bind(sock, &name.addr.sa, name.addrlen) < 0) {
485 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 if (addr->family == AF_INET && firewall[0])
492 return proxy_connect(sock, addr);
493 rc = connect(sock, &addr->addr.sa, addr->addrlen);
494 if (rc < 0) {
495 if (errno == EINPROGRESS)
496 return sock; /* async success! */
497 else
498 return -1;
499 }
500 return sock;
501 }
502
503 /* 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 * -3: could not allocate socket
509 */
510 int open_telnet(int idx, char *server, int port)
511 {
512 int ret;
513
514 ret = setsockname(&dcc[idx].sockname, server, port, 1);
515 if (ret == AF_UNSPEC)
516 return -2;
517 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 if (ret < 0)
523 killsock(dcc[idx].sock);
524 return ret;
525 }
526
527 /* Returns a socket number for a listening socket that will accept any
528 * connection on the given address. The address can be filled in by
529 * setsockname().
530 */
531 int open_address_listen(sockname_t *addr)
532 {
533 int sock = 0;
534
535 sock = getsock(addr->family, SOCK_LISTEN);
536 if (sock < 0)
537 return -1;
538 #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 }
548
549 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 }
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 int sock;
567 sockname_t name;
568
569 (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 }
579
580 /* 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 */
585 int answer(int sock, sockname_t *caller, unsigned short *port, int binary)
586 {
587 int new_sock;
588 caller->addrlen = sizeof(caller->addr);
589 new_sock = accept(sock, &caller->addr.sa, &caller->addrlen);
590
591 if (new_sock < 0)
592 return -1;
593
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 setsock(new_sock, (binary ? SOCK_BINARY : 0));
604 return new_sock;
605 }
606
607 /* 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 */
613 int getdccaddr(sockname_t *addr, char *s, size_t l)
614 {
615 char h[121];
616 sockname_t name, *r = &name;
617
618 if (addr)
619 r = addr;
620 else
621 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 ntohl(*(IP *) &r->addr.s6.sin6_addr.s6_addr[12]));
649 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 }
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 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 #ifdef TLS
738 (slist[i].ssl && (SSL_pending(slist[i].ssl) ||
739 !SSL_is_init_finished(slist[i].ssl))) ||
740 #endif
741 ((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 #ifdef TLS
751 else if (!(slist[i].flags & SOCK_STRONGCONN) &&
752 (!(slist[i].ssl) || SSL_is_init_finished(slist[i].ssl))) {
753 #else
754 else if (!(slist[i].flags & SOCK_STRONGCONN)) {
755 #endif
756 debug1("net: connect! sock %d", slist[i].sock);
757 s[0] = 0;
758 *len = 0;
759 return i;
760 }
761 } 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 #ifdef TLS
771 {
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 #else
787 x = read(slist[i].sock, s, grab);
788 #endif
789 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 *len = slist[i].sock;
795 slist[i].flags &= ~SOCK_CONNECT;
796 debug1("net: eof!(read) socket %d", slist[i].sock);
797 return -1;
798 } else {
799 debug3("sockread EAGAIN: %d %d (%s)", slist[i].sock, errno,
800 strerror(errno));
801 continue; /* EAGAIN */
802 }
803 }
804 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 }
837 }
838 if (!tclonly) {
839 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 memcpy(s, socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
912 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 memcpy(s, socklist[i].handler.sock.inbuf, *len);
919 memcpy(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuf + *len, *len);
920 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 memcpy(socklist[ret].handler.sock.inbuf, xx, *len);
949 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 memcpy(s, xx, *len);
957 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 memcpy(socklist[ret].handler.sock.inbuf + socklist[ret].handler.sock.inbuflen, xx, *len);
967 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 memcpy(p + socklist[i].handler.sock.outbuflen, s, len);
1089 socklist[i].handler.sock.outbuf = p;
1090 socklist[i].handler.sock.outbuflen += len;
1091 return;
1092 }
1093 #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 debug2(_("%s: SSL error = %s"), "tputs()",
1103 ERR_error_string(ERR_get_error(), 0));
1104 inhere = 0;
1105 }
1106 x = -1;
1107 }
1108 } else /* not ssl, use regular write() */
1109 #endif
1110 /* 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 memcpy(socklist[i].handler.sock.outbuf, &s[x], len - x);
1118 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 putlog(LOG_MISC, "*", _("!!! writing to nonexistent socket: %d"), z);
1128 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 for (i = 0; i < threaddata()->MAXSOCKS; i++)
1157 if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
1158 (socklist[i].handler.sock.outbuf != NULL)) {
1159 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 #ifdef TLS
1177 if (socklist[i].ssl) {
1178 x = SSL_write(socklist[i].ssl, socklist[i].handler.sock.outbuf,
1179 socklist[i].handler.sock.outbuflen);
1180 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 debug2(_("%s: SSL error = %s"), "dequeue_sockets()",
1186 ERR_error_string(ERR_get_error(), 0));
1187 x = -1;
1188 }
1189 } else
1190 #endif
1191 x = write(socklist[i].sock, socklist[i].handler.sock.outbuf,
1192 socklist[i].handler.sock.outbuflen);
1193 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 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 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 #ifdef TLS
1264 if (socklist[i].ssl)
1265 strcat(s, " (TLS)");
1266 #endif
1267 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 #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 IP ip = my_atoul(ipaddy);
1304 #endif
1305 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 putlog(LOG_MISC, "*", _("ALERT: (%s!%s) specified an impossible port "
1313 "of %u!"), nick, from, from, prt);
1314 return 0;
1315 }
1316 #ifdef IPV6
1317 if (strchr(ipaddy, ':')) {
1318 if (inet_pton(AF_INET6, ipaddy, &name.addr.s6.sin6_addr) != 1) {
1319 putlog(LOG_MISC, "*", _("ALERT: (%s!%s) specified an invalid IPv6 "
1320 "address of %s!"), nick, from, ipaddy);
1321 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 putlog(LOG_MISC, "*", _("ALERT: (%s!%s) specified an impossible IP of %s!"),
1330 nick, from, badaddress);
1331 return 0;
1332 }
1333 return 1;
1334 }
1335
1336 int hostsanitycheck_dcc(char *nick, char *from, sockname_t *ip, char *dnsname,
1337 char *prt)
1338 {
1339 char badaddress[INET6_ADDRSTRLEN];
1340
1341 /* 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 char hostn[256];
1345
1346 /* It is disabled HERE so we only have to check in *one* spot! */
1347 if (!dcc_sanitycheck)
1348 return 1;
1349 strcpy(badaddress, iptostr(&ip->addr.sa));
1350 /* 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 putlog(LOG_DEBUG, "*", _("DNS information for submitted IP checks out."));
1357 return 1;
1358 }
1359 if (!strcmp(badaddress, dnsname))
1360 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 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
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