/[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.7 - (show annotations) (download) (as text)
Thu Nov 18 12:54:39 2010 UTC (8 years, 11 months ago) by pseudo
Branch: MAIN
Changes since 1.6: +2 -3 lines
File MIME type: text/x-chdr
Fixed a problem with resolving hostnames when compiled with IPv6 disabled.
Made server.mod report connection failures properly.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23