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

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

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


Revision 1.10 - (hide annotations) (download) (as text)
Sat Oct 9 22:24:15 1999 UTC (20 years, 2 months ago) by guppy
Branch: MAIN
Changes since 1.9: +1 -1 lines
File MIME type: text/x-chdr
blah ... I need a drink

1 segfault 1.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 guppy 1.8 if ((socklist[i].sock == sock) && !(socklist[i].flags & SOCK_UNUSED)) {
270 segfault 1.1 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 poptix 1.4 int i;
294 segfault 1.1
295     /* socks proxy */
296     if (proxy == PROXY_SOCKS) {
297     /* numeric IP? */
298     if ((host[strlen(host) - 1] >= '0') && (host[strlen(host) - 1] <= '9')) {
299 guppy 1.2 IP ip = ((IP) inet_addr(host)); /* drummer */
300 segfault 1.1 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 poptix 1.4 for (i = 0; i < MAXSOCKS; i++) {
317     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == sock))
318     socklist[i].flags |= SOCK_PROXYWAIT; /* drummer */
319     }
320 segfault 1.1 sprintf(s, "\004\001%c%c%c%c%c%c%s", (port >> 8) % 256, (port % 256),
321     x[0], x[1], x[2], x[3], botuser);
322 guppy 1.5 tputs(sock, s, strlen(botuser) + 9); /* drummer */
323 segfault 1.1 } else if (proxy == PROXY_SUN) {
324     sprintf(s, "%s %d\n", host, port);
325 guppy 1.5 tputs(sock, s, strlen(s)); /* drummer */
326 segfault 1.1 }
327     return sock;
328     }
329    
330     /* starts a connection attempt to a socket
331     * returns <0 if connection refused:
332     * -1 neterror() type error
333     * -2 can't resolve hostname */
334     int open_telnet_raw(int sock, char *server, int sport)
335     {
336     struct sockaddr_in name;
337     struct hostent *hp;
338     char host[121];
339     int i, port;
340     volatile int proxy;
341    
342     /* firewall? use socks */
343     if (firewall[0]) {
344     if (firewall[0] == '!') {
345     proxy = PROXY_SUN;
346     strcpy(host, &firewall[1]);
347     } else {
348     proxy = PROXY_SOCKS;
349     strcpy(host, firewall);
350     }
351     port = firewallport;
352     } else {
353     proxy = 0;
354     strcpy(host, server);
355     port = sport;
356     }
357     /* patch by tris for multi-hosted machines: */
358     bzero((char *) &name, sizeof(struct sockaddr_in));
359    
360     name.sin_family = AF_INET;
361     name.sin_addr.s_addr = (myip[0] ? getmyip() : INADDR_ANY);
362 guppy 1.9 if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0)
363 segfault 1.1 return -1;
364     bzero((char *) &name, sizeof(struct sockaddr_in));
365    
366     name.sin_family = AF_INET;
367     name.sin_port = my_htons(port);
368     /* numeric IP? */
369     if ((host[strlen(host) - 1] >= '0') && (host[strlen(host) - 1] <= '9'))
370     name.sin_addr.s_addr = inet_addr(host);
371     else {
372     /* no, must be host.domain */
373     if (!setjmp(alarmret)) {
374     alarm(resolve_timeout);
375     hp = gethostbyname(host);
376     alarm(0);
377     } else {
378     hp = NULL;
379     }
380 guppy 1.9 if (hp == NULL)
381 segfault 1.1 return -2;
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 guppy 1.9 } else
397 segfault 1.1 return -1;
398     }
399     /* synchronous? :/ */
400     if (firewall[0])
401     return proxy_connect(sock, server, sport, proxy);
402     return sock;
403     }
404    
405     /* ordinary non-binary connection attempt */
406     int open_telnet(char *server, int port)
407     {
408 guppy 1.9 int sock = getsock(0),
409     ret = open_telnet_raw(sock, server, port);
410    
411     if (ret < 0)
412     killsock(sock);
413     return ret;
414 segfault 1.1 }
415    
416     /* returns a socket number for a listening socket that will accept any
417     * connection -- port # is returned in port */
418     int open_listen(int *port)
419     {
420     int sock, addrlen;
421     struct sockaddr_in name;
422    
423     if (firewall[0]) {
424     /* FIXME: can't do listen port thru firewall yet */
425 guppy 1.10 putlog(LOG_MISC, "*", "!! Cant open a listen port (you are using a firewall)");
426 segfault 1.1 return -1;
427     }
428     sock = getsock(SOCK_LISTEN);
429     bzero((char *) &name, sizeof(struct sockaddr_in));
430    
431     name.sin_family = AF_INET;
432     name.sin_port = my_htons(*port); /* 0 = just assign us a port */
433     name.sin_addr.s_addr = (myip[0] ? getmyip() : INADDR_ANY);
434     if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) {
435     killsock(sock);
436     return -1;
437     }
438     /* what port are we on? */
439     addrlen = sizeof(name);
440     if (getsockname(sock, (struct sockaddr *) &name, &addrlen) < 0) {
441     killsock(sock);
442     return -1;
443     }
444     *port = my_ntohs(name.sin_port);
445     if (listen(sock, 1) < 0) {
446     killsock(sock);
447     return -1;
448     }
449     return sock;
450     }
451    
452     /* given network-style IP address, return hostname */
453     /* hostname will be "##.##.##.##" format if there was an error */
454     char *hostnamefromip(unsigned long ip)
455     {
456     struct hostent *hp;
457     unsigned long addr = ip;
458     unsigned char *p;
459     static char s[121];
460    
461     if (!setjmp(alarmret)) {
462     alarm(resolve_timeout);
463     hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
464     alarm(0);
465     } else {
466     hp = NULL;
467     }
468     if (hp == NULL) {
469     p = (unsigned char *) &addr;
470     sprintf(s, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
471     return s;
472     }
473     strncpy(s, hp->h_name, 120);
474     s[120] = 0;
475     return s;
476     }
477    
478     /* short routine to answer a connect received on a socket made previously
479     * by open_listen ... returns hostname of the caller & the new socket
480     * does NOT dispose of old "public" socket! */
481     int answer(int sock, char *caller, unsigned long *ip,
482     unsigned short *port, int binary)
483     {
484     int new_sock, addrlen;
485     struct sockaddr_in from;
486     addrlen = sizeof(struct sockaddr);
487    
488     new_sock = accept(sock, (struct sockaddr *) &from, &addrlen);
489     if (new_sock < 0)
490     return -1;
491     if (ip != NULL) {
492     *ip = from.sin_addr.s_addr;
493     strncpy(caller, hostnamefromip(*ip), 120);
494     caller[120] = 0;
495     *ip = my_ntohl(*ip);
496     }
497     if (port != NULL)
498     *port = my_ntohs(from.sin_port);
499     /* set up all the normal socket crap */
500     setsock(new_sock, (binary ? SOCK_BINARY : 0));
501     return new_sock;
502     }
503    
504     /* like open_telnet, but uses server & port specifications of dcc */
505     int open_telnet_dcc(int sock, char *server, char *port)
506     {
507     int p;
508     unsigned long addr;
509     char sv[121];
510     unsigned char c[4];
511    
512     if (port != NULL)
513     p = atoi(port);
514     else
515     p = 2000;
516     if (server != NULL)
517     addr = my_atoul(server);
518     else
519     addr = 0L;
520     if (addr < (1 << 24))
521     return -3; /* fake address */
522     c[0] = (addr >> 24) & 0xff;
523     c[1] = (addr >> 16) & 0xff;
524     c[2] = (addr >> 8) & 0xff;
525     c[3] = addr & 0xff;
526     sprintf(sv, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]);
527     /* strcpy(sv,hostnamefromip(addr)); */
528     p = open_telnet_raw(sock, sv, p);
529     return p;
530     }
531    
532     /* all new replacements for mtgets/mtread */
533    
534     /* attempts to read from all the sockets in socklist
535     * fills s with up to 511 bytes if available, and returns the array index
536     * on EOF, returns -1, with socket in len
537     * on socket error, returns -2
538     * if nothing is ready, returns -3 */
539     static int sockread(char *s, int *len)
540     {
541     fd_set fd;
542     int fds, i, x;
543     struct timeval t;
544     int grab = 511;
545    
546     fds = getdtablesize();
547     #ifdef FD_SETSIZE
548     if (fds > FD_SETSIZE)
549     fds = FD_SETSIZE; /* fixes YET ANOTHER freebsd bug!!! */
550     #endif
551     /* timeout: 1 sec */
552     t.tv_sec = 1;
553     t.tv_usec = 0;
554     FD_ZERO(&fd);
555     for (i = 0; i < MAXSOCKS; i++)
556     if (!(socklist[i].flags & SOCK_UNUSED)) {
557     if ((socklist[i].sock == STDOUT) && !backgrd)
558     FD_SET(STDIN, &fd);
559     else
560     FD_SET(socklist[i].sock, &fd);
561     }
562     #ifdef HPUX_HACKS
563     #ifndef HPUX10_HACKS
564     x = select(fds, (int *) &fd, (int *) NULL, (int *) NULL, &t);
565     #else
566     x = select(fds, &fd, NULL, NULL, &t);
567     #endif
568     #else
569     x = select(fds, &fd, NULL, NULL, &t);
570     #endif
571     if (x > 0) {
572     /* something happened */
573     for (i = 0; i < MAXSOCKS; i++) {
574     if ((!(socklist[i].flags & SOCK_UNUSED)) &&
575     ((FD_ISSET(socklist[i].sock, &fd)) ||
576     ((socklist[i].sock == STDOUT) && (!backgrd) &&
577     (FD_ISSET(STDIN, &fd))))) {
578     if (socklist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
579     /* listening socket -- don't read, just return activity */
580     /* same for connection attempt */
581     /* (for strong connections, require a read to succeed first) */
582 poptix 1.4 if (socklist[i].flags & SOCK_PROXYWAIT) { /* drummer */
583 segfault 1.1 /* hang around to get the return code from proxy */
584 guppy 1.5 grab = 10;
585 segfault 1.1 } else if (!(socklist[i].flags & SOCK_STRONGCONN)) {
586     debug1("net: connect! sock %d", socklist[i].sock);
587     s[0] = 0;
588     *len = 0;
589     return i;
590     }
591     }
592     if ((socklist[i].sock == STDOUT) && !backgrd)
593     x = read(STDIN, s, grab);
594     else
595     x = read(socklist[i].sock, s, grab);
596     if (x <= 0) { /* eof */
597     if (x == EAGAIN) {
598     s[0] = 0;
599     *len = 0;
600     return -3;
601     }
602     *len = socklist[i].sock;
603     socklist[i].flags &= ~SOCK_CONNECT;
604     debug1("net: eof!(read) socket %d", socklist[i].sock);
605     return -1;
606     }
607     s[x] = 0;
608     *len = x;
609 poptix 1.4 if (socklist[i].flags & SOCK_PROXYWAIT) {
610     debug2("net: socket: %d proxy errno: %d", socklist[i].sock, s[1]);
611     socklist[i].flags &= ~(SOCK_CONNECT | SOCK_PROXYWAIT);
612 segfault 1.1 switch (s[1]) {
613     case 90: /* success */
614     s[0] = 0;
615     *len = 0;
616     return i;
617     case 91: /* failed */
618     errno = ECONNREFUSED;
619     break;
620     case 92: /* no identd */
621     case 93: /* identd said wrong username */
622     errno = ENETUNREACH;
623     break;
624     /* a better error message would be "socks misconfigured" */
625     /* or "identd not working" but this is simplest */
626     }
627     *len = socklist[i].sock;
628     return -1;
629     }
630     return i;
631     }
632     }
633     } else if (x == -1)
634     return -2; /* socket error */
635     else {
636     s[0] = 0;
637     *len = 0;
638     }
639     return -3;
640     }
641    
642     /* sockgets: buffer and read from sockets
643     *
644     * attempts to read from all registered sockets for up to one second. if
645     * after one second, no complete data has been received from any of the
646     * sockets, 's' will be empty, 'len' will be 0, and sockgets will return -3.
647     * if there is returnable data received from a socket, the data will be
648     * in 's' (null-terminated if non-binary), the length will be returned
649     * in len, and the socket number will be returned.
650     * normal sockets have their input buffered, and each call to sockgets
651     * will return one line terminated with a '\n'. binary sockets are not
652     * buffered and return whatever coems in as soon as it arrives.
653     * listening sockets will return an empty string when a connection comes in.
654     * connecting sockets will return an empty string on a successful connect,
655     * or EOF on a failed connect.
656     * if an EOF is detected from any of the sockets, that socket number will be
657     * put in len, and -1 will be returned.
658     * the maximum length of the string returned is 512 (including null)
659     */
660    
661     int sockgets(char *s, int *len)
662     {
663     char xx[514], *p, *px;
664     int ret, i, data = 0;
665    
666     context;
667     for (i = 0; i < MAXSOCKS; i++) {
668     /* check for stored-up data waiting to be processed */
669     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].inbuf != NULL)) {
670     /* look for \r too cos windows can't follow RFCs */
671     p = strchr(socklist[i].inbuf, '\n');
672     if (p == NULL)
673     p = strchr(socklist[i].inbuf, '\r');
674     if (p != NULL) {
675     *p = 0;
676     if (strlen(socklist[i].inbuf) > 510)
677     socklist[i].inbuf[510] = 0;
678     strcpy(s, socklist[i].inbuf);
679     px = (char *) nmalloc(strlen(p + 1) + 1);
680     strcpy(px, p + 1);
681     nfree(socklist[i].inbuf);
682     if (px[0])
683     socklist[i].inbuf = px;
684     else {
685     nfree(px);
686     socklist[i].inbuf = NULL;
687     }
688     /* strip CR if this was CR/LF combo */
689     if (s[strlen(s) - 1] == '\r')
690     s[strlen(s) - 1] = 0;
691     *len = strlen(s);
692     return socklist[i].sock;
693     }
694     }
695     /* also check any sockets that might have EOF'd during write */
696     if (!(socklist[i].flags & SOCK_UNUSED)
697     && (socklist[i].flags & SOCK_EOFD)) {
698     context;
699     s[0] = 0;
700     *len = socklist[i].sock;
701     return -1;
702     }
703     }
704     /* no pent-up data of any worth -- down to business */
705     context;
706     *len = 0;
707     ret = sockread(xx, len);
708     if (ret < 0) {
709     s[0] = 0;
710     return ret;
711     }
712     /* binary and listening sockets don't get buffered */
713     if (socklist[ret].flags & SOCK_CONNECT) {
714     if (socklist[ret].flags & SOCK_STRONGCONN) {
715     socklist[ret].flags &= ~SOCK_STRONGCONN;
716     /* buffer any data that came in, for future read */
717     socklist[ret].inbuf = (char *) nmalloc(strlen(xx) + 1);
718     strcpy(socklist[ret].inbuf, xx);
719     }
720     socklist[ret].flags &= ~SOCK_CONNECT;
721     s[0] = 0;
722     return socklist[ret].sock;
723     }
724     if (socklist[ret].flags & SOCK_BINARY) {
725     my_memcpy(s, xx, *len);
726     return socklist[ret].sock;
727     }
728     if (socklist[ret].flags & SOCK_LISTEN)
729     return socklist[ret].sock;
730     context;
731     /* might be necessary to prepend stored-up data! */
732     if (socklist[ret].inbuf != NULL) {
733     p = socklist[ret].inbuf;
734     socklist[ret].inbuf = (char *) nmalloc(strlen(p) + strlen(xx) + 1);
735     strcpy(socklist[ret].inbuf, p);
736     strcat(socklist[ret].inbuf, xx);
737     nfree(p);
738     if (strlen(socklist[ret].inbuf) < 512) {
739     strcpy(xx, socklist[ret].inbuf);
740     nfree(socklist[ret].inbuf);
741     socklist[ret].inbuf = NULL;
742     } else {
743     p = socklist[ret].inbuf;
744     socklist[ret].inbuf = (char *) nmalloc(strlen(p) - 509);
745     strcpy(socklist[ret].inbuf, p + 510);
746     *(p + 510) = 0;
747     strcpy(xx, p);
748     nfree(p);
749     /* (leave the rest to be post-pended later) */
750     }
751     }
752     context;
753     /* look for EOL marker; if it's there, i have something to show */
754     p = strchr(xx, '\n');
755     if (p == NULL)
756     p = strchr(xx, '\r');
757     if (p != NULL) {
758     *p = 0;
759     strcpy(s, xx);
760     strcpy(xx, p + 1);
761     if (s[strlen(s) - 1] == '\r')
762     s[strlen(s) - 1] = 0;
763     data = 1; /* DCC_CHAT may now need to process a
764     * blank line */
765     /* NO! */
766     /* if (!s[0]) strcpy(s," "); */
767     } else {
768     s[0] = 0;
769     if (strlen(xx) >= 510) {
770     /* string is too long, so just insert fake \n */
771     strcpy(s, xx);
772     xx[0] = 0;
773     data = 1;
774     }
775     }
776     context;
777     *len = strlen(s);
778     /* anything left that needs to be saved? */
779     if (!xx[0]) {
780     if (data)
781     return socklist[ret].sock;
782     else
783     return -3;
784     }
785     context;
786     /* prepend old data back */
787     if (socklist[ret].inbuf != NULL) {
788 arthur2 1.6 context;
789 segfault 1.1 p = socklist[ret].inbuf;
790     socklist[ret].inbuf = (char *) nmalloc(strlen(p) + strlen(xx) + 1);
791     strcpy(socklist[ret].inbuf, xx);
792     strcat(socklist[ret].inbuf, p);
793     nfree(p);
794     } else {
795 arthur2 1.6 context;
796 segfault 1.1 socklist[ret].inbuf = (char *) nmalloc(strlen(xx) + 1);
797     strcpy(socklist[ret].inbuf, xx);
798     }
799 arthur2 1.6 context;
800 segfault 1.1 if (data) {
801 arthur2 1.6 context;
802 segfault 1.1 return socklist[ret].sock;
803     } else {
804 arthur2 1.6 context;
805 segfault 1.1 return -3;
806     }
807     }
808    
809     /* dump something to a socket */
810     /* DO NOT PUT CONTEXTS IN HERE IF YOU WANT DEBUG TO BE MEANINGFUL!!! */
811     void tputs(int z, char *s, unsigned int len)
812     {
813     int i, x;
814     char *p;
815    
816     if (z < 0)
817     return; /* um... HELLO?! sanity check please! */
818     if (((z == STDOUT) || (z == STDERR)) && (!backgrd || use_stderr)) {
819     write(z, s, len);
820     return;
821     }
822     for (i = 0; i < MAXSOCKS; i++) {
823     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == z)) {
824 guppy 1.5 if (socklist[i].outbuf != NULL) {
825     /* already queueing: just add it */
826     p = (char *) nrealloc(socklist[i].outbuf, socklist[i].outbuflen + len);
827 segfault 1.1 my_memcpy(p + socklist[i].outbuflen, s, len);
828     socklist[i].outbuf = p;
829     socklist[i].outbuflen += len;
830     return;
831     }
832     /* try. */
833     x = write(z, s, len);
834     if (x == (-1))
835     x = 0;
836     if (x < len) {
837     /* socket is full, queue it */
838     socklist[i].outbuf = (char *) nmalloc(len - x);
839     my_memcpy(socklist[i].outbuf, &s[x], len - x);
840     socklist[i].outbuflen = len - x;
841     }
842     return;
843     }
844     }
845     putlog(LOG_MISC, "*", "!!! writing to nonexistent socket: %d", z);
846     s[strlen(s) - 1] = 0;
847     putlog(LOG_MISC, "*", "!-> '%s'", s);
848     }
849    
850     /* tputs might queue data for sockets, let's dump as much of it as
851     * possible */
852     void dequeue_sockets()
853     {
854     int i, x;
855    
856 guppy 1.5 for (i = 0; i < MAXSOCKS; i++) {
857     if (!(socklist[i].flags & SOCK_UNUSED) &&
858 segfault 1.1 (socklist[i].outbuf != NULL)) {
859     /* trick tputs into doing the work */
860     x = write(socklist[i].sock, socklist[i].outbuf,
861     socklist[i].outbuflen);
862     if ((x < 0) && (errno != EAGAIN)
863     #ifdef EBADSLT
864     && (errno != EBADSLT)
865     #endif
866     #ifdef ENOTCONN
867     && (errno != ENOTCONN)
868     #endif
869     ) {
870     /* this detects an EOF during writing */
871     debug3("net: eof!(write) socket %d (%s,%d)", socklist[i].sock,
872     strerror(errno), errno);
873     socklist[i].flags |= SOCK_EOFD;
874     } else if (x == socklist[i].outbuflen) {
875     /* if the whole buffer was sent, nuke it */
876     nfree(socklist[i].outbuf);
877     socklist[i].outbuf = NULL;
878     socklist[i].outbuflen = 0;
879     } else if (x > 0) {
880     char *p = socklist[i].outbuf;
881    
882     /* this removes any sent bytes from the beginning of the buffer */
883     socklist[i].outbuf = (char *) nmalloc(socklist[i].outbuflen - x);
884     my_memcpy(socklist[i].outbuf, p + x, socklist[i].outbuflen - x);
885     socklist[i].outbuflen -= x;
886     nfree(p);
887     }
888     }
889     }
890     }
891    
892     /* DEBUGGING STUFF */
893    
894     void tell_netdebug(int idx)
895     {
896     int i;
897     char s[80];
898    
899     dprintf(idx, "Open sockets:");
900     for (i = 0; i < MAXSOCKS; i++) {
901     if (!(socklist[i].flags & SOCK_UNUSED)) {
902     sprintf(s, " %d", socklist[i].sock);
903     if (socklist[i].flags & SOCK_BINARY)
904     strcat(s, " (binary)");
905     if (socklist[i].flags & SOCK_LISTEN)
906     strcat(s, " (listen)");
907     if (socklist[i].flags & SOCK_CONNECT)
908     strcat(s, " (connecting)");
909     if (socklist[i].flags & SOCK_STRONGCONN)
910     strcat(s, " (strong)");
911     if (socklist[i].flags & SOCK_NONSOCK)
912     strcat(s, " (file)");
913     if (socklist[i].inbuf != NULL)
914     sprintf(&s[strlen(s)], " (inbuf: %04X)", strlen(socklist[i].inbuf));
915     if (socklist[i].outbuf != NULL)
916     sprintf(&s[strlen(s)], " (outbuf: %06lX)", socklist[i].outbuflen);
917     strcat(s, ",");
918     dprintf(idx, "%s", s);
919     }
920     }
921     dprintf(idx, " done.\n");
922     }
923    
924     /* Security-flavoured sanity checking on DCC connections of all sorts can be
925     * done with this routine. Feed it the proper information from your DCC
926     * before you attempt the connection, and this will make an attempt at
927     * figuring out if the connection is really that person, or someone screwing
928     * around. It's not foolproof, but anything that fails this check probably
929     * isn't going to work anyway due to masquerading firewalls, NAT routers,
930     * or bugs in mIRC. */
931     int sanitycheck_dcc(char *nick, char *from, char *ipaddy, char *port)
932     {
933     /* According to the latest RFC, the clients SHOULD be able to handle
934     * DNS names that are up to 255 characters long. This is not broken. */
935     char hostname[256], dnsname[256], badaddress[16];
936     IP ip = my_atoul(ipaddy);
937     int prt = atoi(port);
938    
939     /* It is disabled HERE so we only have to check in *one* spot! */
940     if (!dcc_sanitycheck)
941     return 1;
942     context; /* This should be pretty solid, but
943     * something _might_ break. */
944     sprintf(badaddress, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
945     (ip >> 8) & 0xff, ip & 0xff);
946     if (prt < 1) {
947     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible port of %u!",
948     nick, from, prt);
949     return 0;
950     }
951     if (ip < (1 << 24)) {
952     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible IP of %s!",
953     nick, from, badaddress);
954     return 0;
955     }
956     /* These should pad like crazy with zeros, since 120 bytes or so is
957     * where the routines providing our data currently lose interest. I'm
958     * using the n-variant in case someone changes that... */
959     strncpy(hostname, extracthostname(from), 256);
960     strncpy(dnsname, hostnamefromip(my_htonl(ip)), 256);
961     if (!strcasecmp(hostname, dnsname)) {
962     putlog(LOG_DEBUG, "*", "DNS information for submitted IP checks out.");
963     return 1;
964     }
965     if (!strcmp(badaddress, dnsname))
966     putlog(LOG_MISC, "*", "ALERT: (%s!%s) sent a DCC request with bogus IP information of %s port %u!",
967     nick, from, badaddress, prt);
968     else
969 segfault 1.3 return 1; /* <- usually happens when we have
970     a user with an unresolved hostmask! */
971 segfault 1.1 return 0;
972     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23