/[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.2 - (hide annotations) (download) (as text)
Sat Oct 9 15:46:35 1999 UTC (20 years, 1 month ago) by fabian
Branch: MAIN
Changes since 1.1: +2 -2 lines
File MIME type: text/x-chdr
all changes to the 1.3 tree merged with 1.4

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23