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

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

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


Revision 1.3 - (hide annotations) (download) (as text)
Sat Oct 9 19:31:56 1999 UTC (19 years, 9 months ago) by fabian
Branch: MAIN
Changes since 1.2: +76 -26 lines
File MIME type: text/x-chdr
Fabian's asyncdns patch

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23