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

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

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


Revision 1.15 - (show annotations) (download) (as text)
Fri Dec 17 02:38:45 1999 UTC (19 years, 11 months ago) by guppy
Branch: MAIN
Changes since 1.14: +12 -6 lines
File MIME type: text/x-chdr
fabian's patch

1 /*
2 * net.c -- handles:
3 * all raw network i/o
4 *
5 * $Id: net.c,v 1.14 1999/12/15 02:32:58 guppy Exp $
6 */
7 /*
8 * This is hereby released into the public domain.
9 * Robey Pointer, robey@netcom.com
10 */
11
12 #include "main.h"
13 #include <limits.h>
14 #include <string.h>
15 #include <netdb.h>
16 #include <sys/socket.h>
17 #if HAVE_SYS_SELECT_H
18 #include <sys/select.h>
19 #endif
20 #include <netinet/in.h>
21 #include <arpa/inet.h> /* is this really necessary? */
22 #include <errno.h>
23 #if HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #include <fcntl.h>
27 #include <setjmp.h>
28
29 #if !HAVE_GETDTABLESIZE
30 #ifdef FD_SETSIZE
31 #define getdtablesize() FD_SETSIZE
32 #else
33 #define getdtablesize() 200
34 #endif
35 #endif
36
37 extern int backgrd;
38 extern int use_stderr;
39 extern int resolve_timeout;
40
41 char hostname[121] = ""; /* hostname can be specified in the config
42 * file */
43 char myip[121] = ""; /* IP can be specified in the config file */
44 char firewall[121] = ""; /* socks server for firewall */
45 int firewallport = 1080; /* default port of Sock4/5 firewalls */
46 char botuser[21] = "eggdrop"; /* username of the user running the bot */
47 int dcc_sanitycheck = 0; /* we should do some sanity checking on dcc
48 * connections. */
49 sock_list *socklist = 0; /* enough to be safe */
50 int MAXSOCKS = 0;
51
52 /* types of proxy */
53 #define PROXY_SOCKS 1
54 #define PROXY_SUN 2
55
56 jmp_buf alarmret; /* env buffer for alarm() returns */
57
58 /* i need an UNSIGNED long for dcc type stuff */
59 IP my_atoul(char *s)
60 {
61 IP ret = 0;
62
63 while ((*s >= '0') && (*s <= '9')) {
64 ret *= 10;
65 ret += ((*s) - '0');
66 s++;
67 }
68 return ret;
69 }
70
71 #define my_ntohs(sh) swap_short(sh)
72 #define my_htons(sh) swap_short(sh)
73 #define my_ntohl(ln) swap_long(ln)
74 #define my_htonl(ln) swap_long(ln)
75
76 /* i read somewhere that memcpy() is broken on some machines */
77 /* it's easy to replace, so i'm not gonna take any chances, because
78 * it's pretty important that it work correctly here */
79 void my_memcpy(char *dest, char *src, int len)
80 {
81 while (len--)
82 *dest++ = *src++;
83 }
84
85 #ifndef HAVE_BZERO
86 /* bzero() is bsd-only, so here's one for non-bsd systems */
87 void bzero(char *dest, int len)
88 {
89 while (len--)
90 *dest++ = 0;
91 }
92 #endif
93
94 /* initialize the socklist */
95 void init_net()
96 {
97 int i;
98
99 for (i = 0; i < MAXSOCKS; i++) {
100 socklist[i].flags = SOCK_UNUSED;
101 }
102 }
103
104 int expmem_net()
105 {
106 int i, tot = 0;
107
108 Context;
109 for (i = 0; i < MAXSOCKS; i++) {
110 if (!(socklist[i].flags & SOCK_UNUSED)) {
111 if (socklist[i].inbuf != NULL)
112 tot += strlen(socklist[i].inbuf) + 1;
113 if (socklist[i].outbuf != NULL)
114 tot += socklist[i].outbuflen;
115 }
116 }
117 return tot;
118 }
119
120 /* get my ip number */
121 IP getmyip()
122 {
123 struct hostent *hp;
124 char s[121];
125 IP ip;
126 struct in_addr *in;
127
128 /* could be pre-defined */
129 if (myip[0]) {
130 if ((myip[strlen(myip) - 1] >= '0') && (myip[strlen(myip) - 1] <= '9'))
131 return (IP) inet_addr(myip);
132 }
133 /* also could be pre-defined */
134 if (hostname[0])
135 hp = gethostbyname(hostname);
136 else {
137 gethostname(s, 120);
138 hp = gethostbyname(s);
139 }
140 if (hp == NULL)
141 fatal("Hostname self-lookup failed.", 0);
142 in = (struct in_addr *) (hp->h_addr_list[0]);
143 ip = (IP) (in->s_addr);
144 return ip;
145 }
146
147 void neterror(char *s)
148 {
149 switch (errno) {
150 case EADDRINUSE:
151 strcpy(s, "Address already in use");
152 break;
153 case EADDRNOTAVAIL:
154 strcpy(s, "Address invalid on remote machine");
155 break;
156 case EAFNOSUPPORT:
157 strcpy(s, "Address family not supported");
158 break;
159 case EALREADY:
160 strcpy(s, "Socket already in use");
161 break;
162 case EBADF:
163 strcpy(s, "Socket descriptor is bad");
164 break;
165 case ECONNREFUSED:
166 strcpy(s, "Connection refused");
167 break;
168 case EFAULT:
169 strcpy(s, "Namespace segment violation");
170 break;
171 case EINPROGRESS:
172 strcpy(s, "Operation in progress");
173 break;
174 case EINTR:
175 strcpy(s, "Timeout");
176 break;
177 case EINVAL:
178 strcpy(s, "Invalid namespace");
179 break;
180 case EISCONN:
181 strcpy(s, "Socket already connected");
182 break;
183 case ENETUNREACH:
184 strcpy(s, "Network unreachable");
185 break;
186 case ENOTSOCK:
187 strcpy(s, "File descriptor, not a socket");
188 break;
189 case ETIMEDOUT:
190 strcpy(s, "Connection timed out");
191 break;
192 case ENOTCONN:
193 strcpy(s, "Socket is not connected");
194 break;
195 case EHOSTUNREACH:
196 strcpy(s, "Host is unreachable");
197 break;
198 case EPIPE:
199 strcpy(s, "Broken pipe");
200 break;
201 #ifdef ECONNRESET
202 case ECONNRESET:
203 strcpy(s, "Connection reset by peer");
204 break;
205 #endif
206 #ifdef EACCES
207 case EACCES:
208 strcpy(s, "Permission denied");
209 break;
210 #endif
211 case 0:
212 strcpy(s, "Error 0");
213 break;
214 default:
215 sprintf(s, "Unforseen error %d", errno);
216 break;
217 }
218 }
219
220 /* request a normal socket for i/o */
221 void setsock(int sock, int options)
222 {
223 int i;
224 int parm;
225
226 for (i = 0; i < MAXSOCKS; i++) {
227 if (socklist[i].flags & SOCK_UNUSED) {
228 /* yay! there is table space */
229 socklist[i].inbuf = socklist[i].outbuf = NULL;
230 socklist[i].outbuflen = 0;
231 socklist[i].flags = options;
232 socklist[i].sock = sock;
233 if (((sock != STDOUT) || backgrd) &&
234 !(socklist[i].flags & SOCK_NONSOCK)) {
235 parm = 1;
236 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &parm,
237 sizeof(int));
238
239 parm = 0;
240 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &parm, sizeof(int));
241 }
242 if (options & SOCK_LISTEN) {
243 /* Tris says this lets us grab the same port again next time */
244 parm = 1;
245 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &parm,
246 sizeof(int));
247 }
248 /* yay async i/o ! */
249 fcntl(sock, F_SETFL, O_NONBLOCK);
250 return;
251 }
252 }
253 fatal("Socket table is full!", 0);
254 }
255
256 int getsock(int options)
257 {
258 int sock = socket(AF_INET, SOCK_STREAM, 0);
259
260 if (sock < 0)
261 fatal("Can't open a socket at all!", 0);
262 setsock(sock, options);
263 return sock;
264 }
265
266 /* done with a socket */
267 void killsock(int sock)
268 {
269 int i;
270
271 for (i = 0; i < MAXSOCKS; i++) {
272 if ((socklist[i].sock == sock) && !(socklist[i].flags & SOCK_UNUSED)) {
273 close(socklist[i].sock);
274 if (socklist[i].inbuf != NULL) {
275 nfree(socklist[i].inbuf);
276 socklist[i].inbuf = NULL;
277 }
278 if (socklist[i].outbuf != NULL) {
279 nfree(socklist[i].outbuf);
280 socklist[i].outbuf = NULL;
281 socklist[i].outbuflen = 0;
282 }
283 socklist[i].flags = SOCK_UNUSED;
284 return;
285 }
286 }
287 putlog(LOG_MISC, "*", "Attempt to kill un-allocated socket %d !!", sock);
288 }
289
290 /* send connection request to proxy */
291 static int proxy_connect(int sock, char *host, int port, int proxy)
292 {
293 unsigned char x[10];
294 struct hostent *hp;
295 char s[30];
296 int i;
297
298 /* socks proxy */
299 if (proxy == PROXY_SOCKS) {
300 /* numeric IP? */
301 if ((host[strlen(host) - 1] >= '0') && (host[strlen(host) - 1] <= '9')) {
302 IP ip = ((IP) inet_addr(host)); /* drummer */
303 my_memcpy((char *) x, (char *) &ip, 4); /* Beige@Efnet */
304 } else {
305 /* no, must be host.domain */
306 if (!setjmp(alarmret)) {
307 alarm(resolve_timeout);
308 hp = gethostbyname(host);
309 alarm(0);
310 } else {
311 hp = NULL;
312 }
313 if (hp == NULL) {
314 killsock(sock);
315 return -2;
316 }
317 my_memcpy((char *) x, (char *) hp->h_addr, hp->h_length);
318 }
319 for (i = 0; i < MAXSOCKS; i++) {
320 if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == sock))
321 socklist[i].flags |= SOCK_PROXYWAIT; /* drummer */
322 }
323 sprintf(s, "\004\001%c%c%c%c%c%c%s", (port >> 8) % 256, (port % 256),
324 x[0], x[1], x[2], x[3], botuser);
325 tputs(sock, s, strlen(botuser) + 9); /* drummer */
326 } else if (proxy == PROXY_SUN) {
327 sprintf(s, "%s %d\n", host, port);
328 tputs(sock, s, strlen(s)); /* drummer */
329 }
330 return sock;
331 }
332
333 /* starts a connection attempt to a socket
334 * returns <0 if connection refused:
335 * -1 neterror() type error
336 * -2 can't resolve hostname */
337 int open_telnet_raw(int sock, char *server, int sport)
338 {
339 struct sockaddr_in name;
340 struct hostent *hp;
341 char host[121];
342 int i, port;
343 volatile int proxy;
344
345 /* firewall? use socks */
346 if (firewall[0]) {
347 if (firewall[0] == '!') {
348 proxy = PROXY_SUN;
349 strcpy(host, &firewall[1]);
350 } else {
351 proxy = PROXY_SOCKS;
352 strcpy(host, firewall);
353 }
354 port = firewallport;
355 } else {
356 proxy = 0;
357 strcpy(host, server);
358 port = sport;
359 }
360 /* patch by tris for multi-hosted machines: */
361 bzero((char *) &name, sizeof(struct sockaddr_in));
362
363 name.sin_family = AF_INET;
364 name.sin_addr.s_addr = (myip[0] ? getmyip() : INADDR_ANY);
365 if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0)
366 return -1;
367 bzero((char *) &name, sizeof(struct sockaddr_in));
368
369 name.sin_family = AF_INET;
370 name.sin_port = my_htons(port);
371 /* numeric IP? */
372 if ((host[strlen(host) - 1] >= '0') && (host[strlen(host) - 1] <= '9'))
373 name.sin_addr.s_addr = inet_addr(host);
374 else {
375 /* no, must be host.domain */
376 if (!setjmp(alarmret)) {
377 alarm(resolve_timeout);
378 hp = gethostbyname(host);
379 alarm(0);
380 } else {
381 hp = NULL;
382 }
383 if (hp == NULL)
384 return -2;
385 my_memcpy((char *) &name.sin_addr, hp->h_addr, hp->h_length);
386 name.sin_family = hp->h_addrtype;
387 }
388 for (i = 0; i < MAXSOCKS; i++) {
389 if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == sock))
390 socklist[i].flags |= SOCK_CONNECT;
391 }
392 if (connect(sock, (struct sockaddr *) &name,
393 sizeof(struct sockaddr_in)) < 0) {
394 if (errno == EINPROGRESS) {
395 /* firewall? announce connect attempt to proxy */
396 if (firewall[0])
397 return proxy_connect(sock, server, sport, proxy);
398 return sock; /* async success! */
399 } else
400 return -1;
401 }
402 /* synchronous? :/ */
403 if (firewall[0])
404 return proxy_connect(sock, server, sport, proxy);
405 return sock;
406 }
407
408 /* ordinary non-binary connection attempt */
409 int open_telnet(char *server, int port)
410 {
411 int sock = getsock(0),
412 ret = open_telnet_raw(sock, server, port);
413
414 if (ret < 0)
415 killsock(sock);
416 return ret;
417 }
418
419 /* returns a socket number for a listening socket that will accept any
420 * connection -- port # is returned in port */
421 int open_listen(int *port)
422 {
423 int sock, addrlen;
424 struct sockaddr_in name;
425
426 if (firewall[0]) {
427 /* FIXME: can't do listen port thru firewall yet */
428 putlog(LOG_MISC, "*", "!! Cant open a listen port (you are using a firewall)");
429 return -1;
430 }
431 sock = getsock(SOCK_LISTEN);
432 bzero((char *) &name, sizeof(struct sockaddr_in));
433
434 name.sin_family = AF_INET;
435 name.sin_port = my_htons(*port); /* 0 = just assign us a port */
436 name.sin_addr.s_addr = (myip[0] ? getmyip() : INADDR_ANY);
437 if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) {
438 killsock(sock);
439 return -1;
440 }
441 /* what port are we on? */
442 addrlen = sizeof(name);
443 if (getsockname(sock, (struct sockaddr *) &name, &addrlen) < 0) {
444 killsock(sock);
445 return -1;
446 }
447 *port = my_ntohs(name.sin_port);
448 if (listen(sock, 1) < 0) {
449 killsock(sock);
450 return -1;
451 }
452 return sock;
453 }
454
455 /* given network-style IP address, return hostname */
456 /* hostname will be "##.##.##.##" format if there was an error */
457 char *hostnamefromip(unsigned long ip)
458 {
459 struct hostent *hp;
460 unsigned long addr = ip;
461 unsigned char *p;
462 static char s[121];
463
464 if (!setjmp(alarmret)) {
465 alarm(resolve_timeout);
466 hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
467 alarm(0);
468 } else {
469 hp = NULL;
470 }
471 if (hp == NULL) {
472 p = (unsigned char *) &addr;
473 sprintf(s, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
474 return s;
475 }
476 strncpy(s, hp->h_name, 120);
477 s[120] = 0;
478 return s;
479 }
480
481 /* short routine to answer a connect received on a socket made previously
482 * by open_listen ... returns hostname of the caller & the new socket
483 * does NOT dispose of old "public" socket! */
484 int answer(int sock, char *caller, unsigned long *ip,
485 unsigned short *port, int binary)
486 {
487 int new_sock, addrlen;
488 struct sockaddr_in from;
489 addrlen = sizeof(struct sockaddr);
490
491 new_sock = accept(sock, (struct sockaddr *) &from, &addrlen);
492 if (new_sock < 0)
493 return -1;
494 if (ip != NULL) {
495 *ip = from.sin_addr.s_addr;
496 strncpy(caller, hostnamefromip(*ip), 120);
497 caller[120] = 0;
498 *ip = my_ntohl(*ip);
499 }
500 if (port != NULL)
501 *port = my_ntohs(from.sin_port);
502 /* set up all the normal socket crap */
503 setsock(new_sock, (binary ? SOCK_BINARY : 0));
504 return new_sock;
505 }
506
507 /* like open_telnet, but uses server & port specifications of dcc */
508 int open_telnet_dcc(int sock, char *server, char *port)
509 {
510 int p;
511 unsigned long addr;
512 char sv[121];
513 unsigned char c[4];
514
515 if (port != NULL)
516 p = atoi(port);
517 else
518 p = 2000;
519 if (server != NULL)
520 addr = my_atoul(server);
521 else
522 addr = 0L;
523 if (addr < (1 << 24))
524 return -3; /* fake address */
525 c[0] = (addr >> 24) & 0xff;
526 c[1] = (addr >> 16) & 0xff;
527 c[2] = (addr >> 8) & 0xff;
528 c[3] = addr & 0xff;
529 sprintf(sv, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]);
530 /* strcpy(sv,hostnamefromip(addr)); */
531 p = open_telnet_raw(sock, sv, p);
532 return p;
533 }
534
535 /* all new replacements for mtgets/mtread */
536
537 /* attempts to read from all the sockets in socklist
538 * fills s with up to 511 bytes if available, and returns the array index
539 * on EOF, returns -1, with socket in len
540 * on socket error, returns -2
541 * if nothing is ready, returns -3 */
542 static int sockread(char *s, int *len)
543 {
544 fd_set fd;
545 int fds, i, x;
546 struct timeval t;
547 int grab = 511;
548
549 fds = getdtablesize();
550 #ifdef FD_SETSIZE
551 if (fds > FD_SETSIZE)
552 fds = FD_SETSIZE; /* fixes YET ANOTHER freebsd bug!!! */
553 #endif
554 /* timeout: 1 sec */
555 t.tv_sec = 1;
556 t.tv_usec = 0;
557 FD_ZERO(&fd);
558 for (i = 0; i < MAXSOCKS; i++)
559 if (!(socklist[i].flags & SOCK_UNUSED)) {
560 if ((socklist[i].sock == STDOUT) && !backgrd)
561 FD_SET(STDIN, &fd);
562 else
563 FD_SET(socklist[i].sock, &fd);
564 }
565 #ifdef HPUX_HACKS
566 #ifndef HPUX10_HACKS
567 x = select(fds, (int *) &fd, (int *) NULL, (int *) NULL, &t);
568 #else
569 x = select(fds, &fd, NULL, NULL, &t);
570 #endif
571 #else
572 x = select(fds, &fd, NULL, NULL, &t);
573 #endif
574 if (x > 0) {
575 /* something happened */
576 for (i = 0; i < MAXSOCKS; i++) {
577 if ((!(socklist[i].flags & SOCK_UNUSED)) &&
578 ((FD_ISSET(socklist[i].sock, &fd)) ||
579 ((socklist[i].sock == STDOUT) && (!backgrd) &&
580 (FD_ISSET(STDIN, &fd))))) {
581 if (socklist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
582 /* listening socket -- don't read, just return activity */
583 /* same for connection attempt */
584 /* (for strong connections, require a read to succeed first) */
585 if (socklist[i].flags & SOCK_PROXYWAIT) { /* drummer */
586 /* hang around to get the return code from proxy */
587 grab = 10;
588 } else if (!(socklist[i].flags & SOCK_STRONGCONN)) {
589 debug1("net: connect! sock %d", socklist[i].sock);
590 s[0] = 0;
591 *len = 0;
592 return i;
593 }
594 }
595 if ((socklist[i].sock == STDOUT) && !backgrd)
596 x = read(STDIN, s, grab);
597 else
598 x = read(socklist[i].sock, s, grab);
599 if (x <= 0) { /* eof */
600 if (x == EAGAIN) {
601 s[0] = 0;
602 *len = 0;
603 return -3;
604 }
605 *len = socklist[i].sock;
606 socklist[i].flags &= ~SOCK_CONNECT;
607 debug1("net: eof!(read) socket %d", socklist[i].sock);
608 return -1;
609 }
610 s[x] = 0;
611 *len = x;
612 if (socklist[i].flags & SOCK_PROXYWAIT) {
613 debug2("net: socket: %d proxy errno: %d", socklist[i].sock, s[1]);
614 socklist[i].flags &= ~(SOCK_CONNECT | SOCK_PROXYWAIT);
615 switch (s[1]) {
616 case 90: /* success */
617 s[0] = 0;
618 *len = 0;
619 return i;
620 case 91: /* failed */
621 errno = ECONNREFUSED;
622 break;
623 case 92: /* no identd */
624 case 93: /* identd said wrong username */
625 errno = ENETUNREACH;
626 break;
627 /* a better error message would be "socks misconfigured" */
628 /* or "identd not working" but this is simplest */
629 }
630 *len = socklist[i].sock;
631 return -1;
632 }
633 return i;
634 }
635 }
636 } else if (x == -1)
637 return -2; /* socket error */
638 else {
639 s[0] = 0;
640 *len = 0;
641 }
642 return -3;
643 }
644
645 /* sockgets: buffer and read from sockets
646 *
647 * attempts to read from all registered sockets for up to one second. if
648 * after one second, no complete data has been received from any of the
649 * sockets, 's' will be empty, 'len' will be 0, and sockgets will return -3.
650 * if there is returnable data received from a socket, the data will be
651 * in 's' (null-terminated if non-binary), the length will be returned
652 * in len, and the socket number will be returned.
653 * normal sockets have their input buffered, and each call to sockgets
654 * will return one line terminated with a '\n'. binary sockets are not
655 * buffered and return whatever coems in as soon as it arrives.
656 * listening sockets will return an empty string when a connection comes in.
657 * connecting sockets will return an empty string on a successful connect,
658 * or EOF on a failed connect.
659 * if an EOF is detected from any of the sockets, that socket number will be
660 * put in len, and -1 will be returned.
661 * the maximum length of the string returned is 512 (including null)
662 */
663
664 int sockgets(char *s, int *len)
665 {
666 char xx[514], *p, *px;
667 int ret, i, data = 0;
668
669 Context;
670 for (i = 0; i < MAXSOCKS; i++) {
671 /* check for stored-up data waiting to be processed */
672 if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].inbuf != NULL)) {
673 /* look for \r too cos windows can't follow RFCs */
674 p = strchr(socklist[i].inbuf, '\n');
675 if (p == NULL)
676 p = strchr(socklist[i].inbuf, '\r');
677 if (p != NULL) {
678 *p = 0;
679 if (strlen(socklist[i].inbuf) > 510)
680 socklist[i].inbuf[510] = 0;
681 strcpy(s, socklist[i].inbuf);
682 px = (char *) nmalloc(strlen(p + 1) + 1);
683 strcpy(px, p + 1);
684 nfree(socklist[i].inbuf);
685 if (px[0])
686 socklist[i].inbuf = px;
687 else {
688 nfree(px);
689 socklist[i].inbuf = NULL;
690 }
691 /* strip CR if this was CR/LF combo */
692 if (s[strlen(s) - 1] == '\r')
693 s[strlen(s) - 1] = 0;
694 *len = strlen(s);
695 return socklist[i].sock;
696 }
697 }
698 /* also check any sockets that might have EOF'd during write */
699 if (!(socklist[i].flags & SOCK_UNUSED)
700 && (socklist[i].flags & SOCK_EOFD)) {
701 Context;
702 s[0] = 0;
703 *len = socklist[i].sock;
704 return -1;
705 }
706 }
707 /* no pent-up data of any worth -- down to business */
708 Context;
709 *len = 0;
710 ret = sockread(xx, len);
711 if (ret < 0) {
712 s[0] = 0;
713 return ret;
714 }
715 /* binary and listening sockets don't get buffered */
716 if (socklist[ret].flags & SOCK_CONNECT) {
717 if (socklist[ret].flags & SOCK_STRONGCONN) {
718 socklist[ret].flags &= ~SOCK_STRONGCONN;
719 /* buffer any data that came in, for future read */
720 socklist[ret].inbuf = (char *) nmalloc(strlen(xx) + 1);
721 strcpy(socklist[ret].inbuf, xx);
722 }
723 socklist[ret].flags &= ~SOCK_CONNECT;
724 s[0] = 0;
725 return socklist[ret].sock;
726 }
727 if (socklist[ret].flags & SOCK_BINARY) {
728 my_memcpy(s, xx, *len);
729 return socklist[ret].sock;
730 }
731 if (socklist[ret].flags & SOCK_LISTEN)
732 return socklist[ret].sock;
733 Context;
734 /* might be necessary to prepend stored-up data! */
735 if (socklist[ret].inbuf != NULL) {
736 p = socklist[ret].inbuf;
737 socklist[ret].inbuf = (char *) nmalloc(strlen(p) + strlen(xx) + 1);
738 strcpy(socklist[ret].inbuf, p);
739 strcat(socklist[ret].inbuf, xx);
740 nfree(p);
741 if (strlen(socklist[ret].inbuf) < 512) {
742 strcpy(xx, socklist[ret].inbuf);
743 nfree(socklist[ret].inbuf);
744 socklist[ret].inbuf = NULL;
745 } else {
746 p = socklist[ret].inbuf;
747 socklist[ret].inbuf = (char *) nmalloc(strlen(p) - 509);
748 strcpy(socklist[ret].inbuf, p + 510);
749 *(p + 510) = 0;
750 strcpy(xx, p);
751 nfree(p);
752 /* (leave the rest to be post-pended later) */
753 }
754 }
755 Context;
756 /* look for EOL marker; if it's there, i have something to show */
757 p = strchr(xx, '\n');
758 if (p == NULL)
759 p = strchr(xx, '\r');
760 if (p != NULL) {
761 *p = 0;
762 strcpy(s, xx);
763 strcpy(xx, p + 1);
764 if (s[strlen(s) - 1] == '\r')
765 s[strlen(s) - 1] = 0;
766 data = 1; /* DCC_CHAT may now need to process a
767 * blank line */
768 /* NO! */
769 /* if (!s[0]) strcpy(s," "); */
770 } else {
771 s[0] = 0;
772 if (strlen(xx) >= 510) {
773 /* string is too long, so just insert fake \n */
774 strcpy(s, xx);
775 xx[0] = 0;
776 data = 1;
777 }
778 }
779 Context;
780 *len = strlen(s);
781 /* anything left that needs to be saved? */
782 if (!xx[0]) {
783 if (data)
784 return socklist[ret].sock;
785 else
786 return -3;
787 }
788 Context;
789 /* prepend old data back */
790 if (socklist[ret].inbuf != NULL) {
791 Context;
792 p = socklist[ret].inbuf;
793 socklist[ret].inbuf = (char *) nmalloc(strlen(p) + strlen(xx) + 1);
794 strcpy(socklist[ret].inbuf, xx);
795 strcat(socklist[ret].inbuf, p);
796 nfree(p);
797 } else {
798 Context;
799 socklist[ret].inbuf = (char *) nmalloc(strlen(xx) + 1);
800 strcpy(socklist[ret].inbuf, xx);
801 }
802 Context;
803 if (data) {
804 Context;
805 return socklist[ret].sock;
806 } else {
807 Context;
808 return -3;
809 }
810 }
811
812 /* dump something to a socket */
813 /* DO NOT PUT CONTEXTS IN HERE IF YOU WANT DEBUG TO BE MEANINGFUL!!! */
814 void tputs(register int z, char *s, unsigned int len)
815 {
816 register int i, x;
817 char *p;
818 static int inhere = 0;
819
820 if (z < 0)
821 return; /* um... HELLO?! sanity check please! */
822 if (((z == STDOUT) || (z == STDERR)) && (!backgrd || use_stderr)) {
823 write(z, s, len);
824 return;
825 }
826 for (i = 0; i < MAXSOCKS; i++) {
827 if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == z)) {
828 if (socklist[i].outbuf != NULL) {
829 /* already queueing: just add it */
830 p = (char *) nrealloc(socklist[i].outbuf, socklist[i].outbuflen + len);
831 my_memcpy(p + socklist[i].outbuflen, s, len);
832 socklist[i].outbuf = p;
833 socklist[i].outbuflen += len;
834 return;
835 }
836 /* try. */
837 x = write(z, s, len);
838 if (x == (-1))
839 x = 0;
840 if (x < len) {
841 /* socket is full, queue it */
842 socklist[i].outbuf = (char *) nmalloc(len - x);
843 my_memcpy(socklist[i].outbuf, &s[x], len - x);
844 socklist[i].outbuflen = len - x;
845 }
846 return;
847 }
848 }
849 /* Make sure we don't cause a crash by looping here */
850 if (!inhere) {
851 inhere = 1;
852 putlog(LOG_MISC, "*", "!!! writing to nonexistent socket: %d", z);
853 s[strlen(s) - 1] = 0;
854 putlog(LOG_MISC, "*", "!-> '%s'", s);
855 inhere = 0;
856 }
857 }
858
859 /* tputs might queue data for sockets, let's dump as much of it as
860 * possible */
861 void dequeue_sockets()
862 {
863 int i, x;
864
865 for (i = 0; i < MAXSOCKS; i++) {
866 if (!(socklist[i].flags & SOCK_UNUSED) &&
867 (socklist[i].outbuf != NULL)) {
868 /* trick tputs into doing the work */
869 x = write(socklist[i].sock, socklist[i].outbuf,
870 socklist[i].outbuflen);
871 if ((x < 0) && (errno != EAGAIN)
872 #ifdef EBADSLT
873 && (errno != EBADSLT)
874 #endif
875 #ifdef ENOTCONN
876 && (errno != ENOTCONN)
877 #endif
878 ) {
879 /* this detects an EOF during writing */
880 debug3("net: eof!(write) socket %d (%s,%d)", socklist[i].sock,
881 strerror(errno), errno);
882 socklist[i].flags |= SOCK_EOFD;
883 } else if (x == socklist[i].outbuflen) {
884 /* if the whole buffer was sent, nuke it */
885 nfree(socklist[i].outbuf);
886 socklist[i].outbuf = NULL;
887 socklist[i].outbuflen = 0;
888 } else if (x > 0) {
889 char *p = socklist[i].outbuf;
890
891 /* this removes any sent bytes from the beginning of the buffer */
892 socklist[i].outbuf = (char *) nmalloc(socklist[i].outbuflen - x);
893 my_memcpy(socklist[i].outbuf, p + x, socklist[i].outbuflen - x);
894 socklist[i].outbuflen -= x;
895 nfree(p);
896 }
897 }
898 }
899 }
900
901 /* DEBUGGING STUFF */
902
903 void tell_netdebug(int idx)
904 {
905 int i;
906 char s[80];
907
908 dprintf(idx, "Open sockets:");
909 for (i = 0; i < MAXSOCKS; i++) {
910 if (!(socklist[i].flags & SOCK_UNUSED)) {
911 sprintf(s, " %d", socklist[i].sock);
912 if (socklist[i].flags & SOCK_BINARY)
913 strcat(s, " (binary)");
914 if (socklist[i].flags & SOCK_LISTEN)
915 strcat(s, " (listen)");
916 if (socklist[i].flags & SOCK_CONNECT)
917 strcat(s, " (connecting)");
918 if (socklist[i].flags & SOCK_STRONGCONN)
919 strcat(s, " (strong)");
920 if (socklist[i].flags & SOCK_NONSOCK)
921 strcat(s, " (file)");
922 if (socklist[i].inbuf != NULL)
923 sprintf(&s[strlen(s)], " (inbuf: %04X)", strlen(socklist[i].inbuf));
924 if (socklist[i].outbuf != NULL)
925 sprintf(&s[strlen(s)], " (outbuf: %06lX)", socklist[i].outbuflen);
926 strcat(s, ",");
927 dprintf(idx, "%s", s);
928 }
929 }
930 dprintf(idx, " done.\n");
931 }
932
933 /* Security-flavoured sanity checking on DCC connections of all sorts can be
934 * done with this routine. Feed it the proper information from your DCC
935 * before you attempt the connection, and this will make an attempt at
936 * figuring out if the connection is really that person, or someone screwing
937 * around. It's not foolproof, but anything that fails this check probably
938 * isn't going to work anyway due to masquerading firewalls, NAT routers,
939 * or bugs in mIRC. */
940 int sanitycheck_dcc(char *nick, char *from, char *ipaddy, char *port)
941 {
942 /* According to the latest RFC, the clients SHOULD be able to handle
943 * DNS names that are up to 255 characters long. This is not broken. */
944 char hostname[256], dnsname[256], badaddress[16];
945 IP ip = my_atoul(ipaddy);
946 int prt = atoi(port);
947
948 /* It is disabled HERE so we only have to check in *one* spot! */
949 if (!dcc_sanitycheck)
950 return 1;
951 Context; /* This should be pretty solid, but
952 * something _might_ break. */
953 sprintf(badaddress, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
954 (ip >> 8) & 0xff, ip & 0xff);
955 if (prt < 1) {
956 putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible port of %u!",
957 nick, from, prt);
958 return 0;
959 }
960 if (ip < (1 << 24)) {
961 putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible IP of %s!",
962 nick, from, badaddress);
963 return 0;
964 }
965 /* These should pad like crazy with zeros, since 120 bytes or so is
966 * where the routines providing our data currently lose interest. I'm
967 * using the n-variant in case someone changes that... */
968 strncpy(hostname, extracthostname(from), 255);
969 hostname[255] = 0;
970 /* But if they are changed one day, this might crash
971 * without [256] = 0; ++rtc
972 */
973 strncpy(dnsname, hostnamefromip(my_htonl(ip)), 255);
974 dnsname[255] = 0;
975 if (!strcasecmp(hostname, dnsname)) {
976 putlog(LOG_DEBUG, "*", "DNS information for submitted IP checks out.");
977 return 1;
978 }
979 if (!strcmp(badaddress, dnsname))
980 putlog(LOG_MISC, "*", "ALERT: (%s!%s) sent a DCC request with bogus IP information of %s port %u!",
981 nick, from, badaddress, prt);
982 else
983 return 1; /* <- usually happens when we have
984 a user with an unresolved hostmask! */
985 return 0;
986 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23