/[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.1 - (show annotations) (download) (as text)
Wed Jun 23 19:51:31 1999 UTC (20 years, 5 months ago) by segfault
Branch: MAIN
Branch point for: eggdev
File MIME type: text/x-chdr
Initial revision

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23