/[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.4 - (show annotations) (download) (as text)
Tue Sep 14 19:45:29 2010 UTC (8 years, 9 months ago) by pseudo
Branch: MAIN
Changes since 1.3: +3 -2 lines
File MIME type: text/x-chdr
Fixed a bug in setsockname() making it fail with IPv6 enabled due to a variable not being set.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23