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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23