1 /*
2  * net.c -- handles:
3  *   all raw network i/o
4  */
5 /*
6  * This is hereby released into the public domain.
7  * Robey Pointer, robey@netcom.com
8  *
9  * Changes after Feb 23, 1999 Copyright Eggheads Development Team
10  *
11  * Copyright (C) 1999 - 2021 Eggheads Development Team
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27 
28 #include <fcntl.h>
29 #include "main.h"
30 #include <limits.h>
31 #include <string.h>
32 #include <netdb.h>
33 #include <sys/socket.h>
34 #if HAVE_SYS_SELECT_H
35 #  include <sys/select.h>
36 #endif
37 #include <netinet/in.h>
38 #include <netinet/tcp.h>
39 #include <arpa/inet.h>
40 #include <errno.h>
41 #if HAVE_UNISTD_H
42 #  include <unistd.h>
43 #endif
44 #include <setjmp.h>
45 #include "mod/server.mod/server.h"
46 
47 #ifdef TLS
48 #  include <openssl/err.h>
49 #endif
50 
51 extern struct dcc_t *dcc;
52 extern int backgrd, use_stderr, resolve_timeout, dcc_total;
53 extern unsigned long otraffic_irc_today, otraffic_bn_today, otraffic_dcc_today,
54                      otraffic_filesys_today, otraffic_trans_today,
55                      otraffic_unknown_today;
56 
57 char natip[121] = "";         /* Public IPv4 to report for systems behind NAT */
58 char listen_ip[121] = "";     /* IP (or hostname) for listening sockets       */
59 char vhost[121] = "";         /* IPv4 vhost for outgoing connections          */
60 #ifdef IPV6
61 char vhost6[121] = "";        /* IPv6 vhost for outgoing connections          */
62 int pref_af = 0;              /* Prefer IPv6 over IPv4?                       */
63 #endif
64 char firewall[121] = "";      /* Socks server for firewall.                   */
65 int firewallport = 1080;      /* Default port of socks 4/5 firewalls.         */
66 char botuser[USERLEN + 1] = "eggdrop"; /* Username of the user running the bot*/
67 int dcc_sanitycheck = 0;      /* Do some sanity checking on dcc connections.  */
68 sock_list *socklist = NULL;   /* Enough to be safe.                           */
69 sigjmp_buf alarmret;          /* Env buffer for alarm() returns.              */
70 
71 /* Types of proxies */
72 #define PROXY_SOCKS   1
73 #define PROXY_SUN     2
74 
75 
76 /* I need an UNSIGNED long for dcc type stuff
77  */
my_atoul(char * s)78 IP my_atoul(char *s)
79 {
80   IP ret = 0;
81 
82   while ((*s >= '0') && (*s <= '9')) {
83     ret *= 10;
84     ret += ((*s) - '0');
85     s++;
86   }
87   return ret;
88 }
89 
expmem_net()90 int expmem_net()
91 {
92   int i, tot = 0;
93   struct threaddata *td = threaddata();
94 
95   for (i = 0; i < td->MAXSOCKS; i++) {
96     if (!(td->socklist[i].flags & (SOCK_UNUSED | SOCK_TCL))) {
97       if (td->socklist[i].handler.sock.inbuf != NULL)
98         tot += strlen(td->socklist[i].handler.sock.inbuf) + 1;
99       if (td->socklist[i].handler.sock.outbuf != NULL)
100         tot += td->socklist[i].handler.sock.outbuflen;
101     }
102   }
103   return tot;
104 }
105 
106 /* Extract the IP address from a sockaddr struct and convert it
107  * to presentation format.
108  */
iptostr(struct sockaddr * sa)109 char *iptostr(struct sockaddr *sa)
110 {
111 #ifdef IPV6
112   static char s[INET6_ADDRSTRLEN] = "";
113   if (sa->sa_family == AF_INET6)
114     inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
115               s, sizeof s);
116   else
117 #else
118   static char s[INET_ADDRSTRLEN] = "";
119 #endif
120     inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr.s_addr, s,
121               sizeof s);
122   return s;
123 }
124 
125 /* Fills in a sockname struct with the given server and port. If the string
126  * pointed by src isn't an IP address and allowres is not null, the function
127  * will assume it's a hostname and will attempt to resolve it. This is
128  * convenient, but you should use the async dns functions where possible, to
129  * avoid blocking the bot while the lookup is performed.
130  */
setsockname(sockname_t * addr,char * src,int port,int allowres)131 int setsockname(sockname_t *addr, char *src, int port, int allowres)
132 {
133   char *endptr, *src2 = src;;
134   long val;
135   IP ip;
136   struct hostent *hp;
137   volatile int af = AF_UNSPEC;
138 #ifdef IPV6
139   char ip2[INET6_ADDRSTRLEN];
140   int pref;
141 #else
142   char ip2[INET_ADDRSTRLEN];
143   int i, count;
144 #endif
145 
146   /* DCC CHAT ip is expressed as integer but inet_pton() only accepts dotted
147    * addresses */
148   val = strtol(src, &endptr, 10);
149   if (val && !*endptr) {
150     ip = htonl(val);
151     if (inet_ntop(AF_INET, &ip, ip2, sizeof ip2)) {
152       debug2("net: setsockname(): ip %s -> %s", src, ip2);
153       src2 = ip2;
154     }
155   }
156 #ifdef IPV6
157   /* Clean start */
158   egg_bzero(addr, sizeof(sockname_t));
159   pref = pref_af ? AF_INET6 : AF_INET;
160   if (pref == AF_INET) {
161     if (inet_pton(AF_INET, src2, &addr->addr.s4.sin_addr) == 1)
162       af = AF_INET;
163     else if (inet_pton(AF_INET6, src2, &addr->addr.s6.sin6_addr) == 1)
164       af = AF_INET6;
165     else
166       af = AF_UNSPEC;
167   } else {
168     if (inet_pton(AF_INET6, src2, &addr->addr.s6.sin6_addr) == 1)
169       af = AF_INET6;
170     else if (inet_pton(AF_INET, src2, &addr->addr.s4.sin_addr) == 1)
171       af = AF_INET;
172     else
173       af = AF_UNSPEC;
174   }
175 
176   if (af == AF_UNSPEC && allowres && *src) {
177     /* src is a hostname. Attempt to resolve it.. */
178     if (!sigsetjmp(alarmret, 1)) {
179       alarm(resolve_timeout);
180       hp = gethostbyname2(src, pref_af ? AF_INET6 : AF_INET);
181       if (!hp)
182         hp = gethostbyname2(src, pref_af ? AF_INET : AF_INET6);
183       alarm(0);
184     } else
185       hp = NULL;
186     if (hp) {
187       if (hp->h_addrtype == AF_INET)
188         memcpy(&addr->addr.s4.sin_addr, hp->h_addr_list[0], hp->h_length);
189       else
190         memcpy(&addr->addr.s6.sin6_addr, hp->h_addr_list[0], hp->h_length);
191       af = hp->h_addrtype;
192     }
193   }
194 
195   addr->family = (af == AF_UNSPEC) ? pref : af;
196   addr->addr.sa.sa_family = addr->family;
197   if (addr->family == AF_INET6) {
198     addr->addrlen = sizeof(struct sockaddr_in6);
199     addr->addr.s6.sin6_port = htons(port);
200     addr->addr.s6.sin6_family = AF_INET6;
201   } else {
202     addr->addrlen = sizeof(struct sockaddr_in);
203     addr->addr.s4.sin_port = htons(port);
204     addr->addr.s4.sin_family = AF_INET;
205   }
206 #else
207   egg_bzero(addr, sizeof(sockname_t));
208 
209 /* If it's not an IPv4 address, check if its IPv6 (so it can fail/error
210  * appropriately). If it's not, and allowres is 1, use gethostbyname()
211  * to try and resolve. If allowres is 0, return AF_UNSPEC to allow
212  * dns.mod to do it's thing.
213 
214  * Also, because we can't be sure inet_pton exists on the system, we
215  * have to resort to hackishly counting :s to see if its IPv6 or not.
216  * Go internet.
217  */
218   if (!inet_pton(AF_INET, src2, &addr->addr.s4.sin_addr)) {
219     /* Boring way to count :s */
220     count = 0;
221     for (i = 0; src[i]; i++) {
222       if (src[i] == ':') {
223         count++;
224         if (count == 2)
225           break;
226       }
227     }
228     if (count > 1) {
229       putlog(LOG_MISC, "*", "ERROR: This looks like an IPv6 address, \
230 but this Eggdrop was not compiled with IPv6 support.");
231       af = AF_UNSPEC;
232     }
233     else if (allowres) {
234     /* src is a hostname. Attempt to resolve it.. */
235       if (!sigsetjmp(alarmret, 1)) {
236         alarm(resolve_timeout);
237         hp = gethostbyname(src);
238         alarm(0);
239       } else
240         hp = NULL;
241       if (hp) {
242         memcpy(&addr->addr.s4.sin_addr, hp->h_addr_list[0], hp->h_length);
243         af = hp->h_addrtype;
244       }
245     } else
246         af = AF_UNSPEC;
247   } else
248       af = AF_INET;
249 
250   addr->family = addr->addr.s4.sin_family = AF_INET;
251   addr->addr.sa.sa_family = addr->family;
252   addr->addrlen = sizeof(struct sockaddr_in);
253   addr->addr.s4.sin_port = htons(port);
254 #endif
255   return af;
256 }
257 
258 /* Get socket address to bind to for outbound connections
259  */
getvhost(sockname_t * addr,int af)260 void getvhost(sockname_t *addr, int af)
261 {
262   char *h = NULL;
263 
264   if (af == AF_INET)
265     h = vhost;
266 #ifdef IPV6
267   else
268     h = vhost6;
269 #endif
270   if (!h || !h[0] || setsockname(addr, (h ? h : ""), 0, 1) != af)
271     setsockname(addr, (af == AF_INET ? "0.0.0.0" : "::"), 0, 0);
272   /* Remember this 'self-lookup failed' thingie?
273      I have good news - you won't see it again ;) */
274 }
275 
276 /* Sets/Unsets options for a specific socket.
277  *
278  * Returns:  0   - on success
279  *           -1  - socket not found
280  *           -2  - illegal operation
281  */
sockoptions(int sock,int operation,int sock_options)282 int sockoptions(int sock, int operation, int sock_options)
283 {
284   int i;
285   struct threaddata *td = threaddata();
286 
287   for (i = 0; i < td->MAXSOCKS; i++)
288     if ((td->socklist[i].sock == sock) &&
289         !(td->socklist[i].flags & SOCK_UNUSED)) {
290       if (operation == EGG_OPTION_SET)
291         td->socklist[i].flags |= sock_options;
292       else if (operation == EGG_OPTION_UNSET)
293         td->socklist[i].flags &= ~sock_options;
294       else
295         return -2;
296       return 0;
297     }
298   return -1;
299 }
300 
301 /* Return a free entry in the socket entry
302  */
allocsock(int sock,int options)303 int allocsock(int sock, int options)
304 {
305   int i;
306   struct threaddata *td = threaddata();
307 
308   for (i = 0; i < td->MAXSOCKS; i++) {
309     if (td->socklist[i].flags & SOCK_UNUSED) {
310       /* yay!  there is table space */
311       td->socklist[i].handler.sock.inbuf = NULL;
312       td->socklist[i].handler.sock.outbuf = NULL;
313       td->socklist[i].handler.sock.inbuflen = 0;
314       td->socklist[i].handler.sock.outbuflen = 0;
315       td->socklist[i].flags = options;
316       td->socklist[i].sock = sock;
317 #ifdef TLS
318       td->socklist[i].ssl = 0;
319 #endif
320       return i;
321     }
322   }
323   /* Try again if enlarging socketlist works */
324   if (increase_socks_max())
325     return -1;
326   else
327     return allocsock(sock, options);
328 }
329 
330 /* Return a free entry in the socket entry for a tcl socket
331  *
332  * alloctclsock() can be called by Tcl threads
333  */
alloctclsock(int sock,int mask,Tcl_FileProc * proc,ClientData cd)334 int alloctclsock(int sock, int mask, Tcl_FileProc *proc, ClientData cd)
335 {
336   int f = -1;
337   int i;
338   struct threaddata *td = threaddata();
339 
340   for (i = 0; i < td->MAXSOCKS; i++) {
341     if (td->socklist[i].flags & SOCK_UNUSED) {
342       if (f == -1)
343         f = i;
344     } else if ((td->socklist[i].flags & SOCK_TCL) &&
345                td->socklist[i].sock == sock) {
346       f = i;
347       break;
348     }
349   }
350   if (f != -1) {
351     td->socklist[f].sock = sock;
352     td->socklist[f].flags = SOCK_TCL;
353     td->socklist[f].handler.tclsock.mask = mask;
354     td->socklist[f].handler.tclsock.proc = proc;
355     td->socklist[f].handler.tclsock.cd = cd;
356     return f;
357   }
358   /* Try again if enlarging socketlist works */
359   if (increase_socks_max())
360     return -1;
361   else
362     return alloctclsock(sock, mask, proc, cd);
363 }
364 
365 /* Request a normal socket for i/o
366  */
setsock(int sock,int options)367 void setsock(int sock, int options)
368 {
369   int i = allocsock(sock, options), parm = 1;
370   struct threaddata *td = threaddata();
371   struct linger linger = {0};
372 
373   if (i == -1) {
374     putlog(LOG_MISC, "*", "Sockettable full.");
375     return;
376   }
377   if (((sock != STDOUT) || backgrd) && !(td->socklist[i].flags & SOCK_NONSOCK)) {
378     if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &parm, sizeof parm))
379       debug2("net: setsock(): setsockopt() s %i level SOL_SOCKET optname SO_KEEPALIVE error %s", sock, strerror(errno));
380     if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger)))
381       debug2("net: setsock(): setsockopt() s %i level SOL_SOCKET optname SO_LINGER error %s", sock, strerror(errno));
382     /* Turn off Nagle's algorithm, see man tcp */
383     if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &parm, sizeof parm))
384       debug2("net: setsock(): setsockopt() s %i level IPPROTO_TCP optname TCP_NODELAY error %s", sock, strerror(errno));
385   }
386   if (options & SOCK_LISTEN) {
387     /* Tris says this lets us grab the same port again next time */
388     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &parm, sizeof parm))
389       debug2("net: setsock(): setsockopt() s %i level SOL_SOCKET optname SO_REUSEADDR error %s", sock, strerror(errno));
390   }
391   /* Yay async i/o ! */
392   if ((sock != STDOUT) || backgrd)
393     fcntl(sock, F_SETFL, O_NONBLOCK);
394 }
395 
getsock(int af,int options)396 int getsock(int af, int options)
397 {
398   int sock = socket(af, SOCK_STREAM, 0);
399 
400   if (sock >= 0)
401     setsock(sock, options);
402   else
403     putlog(LOG_MISC, "*", "Warning: Can't create new socket: %s!",
404            strerror(errno));
405   return sock;
406 }
407 
408 /* Done with a socket
409  */
killsock(int sock)410 void killsock(int sock)
411 {
412   int i;
413   struct threaddata *td = threaddata();
414 
415   /* Ignore invalid sockets.  */
416   if (sock < 0)
417     return;
418 
419   for (i = 0; i < td->MAXSOCKS; i++) {
420     if ((td->socklist[i].sock == sock) && !(td->socklist[i].flags & SOCK_UNUSED)) {
421       if (!(td->socklist[i].flags & SOCK_TCL)) { /* nothing to free for tclsocks */
422 #ifdef TLS
423         if (td->socklist[i].ssl) {
424           SSL_shutdown(td->socklist[i].ssl);
425           nfree(SSL_get_app_data(td->socklist[i].ssl));
426           SSL_free(td->socklist[i].ssl);
427           td->socklist[i].ssl = NULL;
428         }
429 #endif
430         close(td->socklist[i].sock);
431         if (td->socklist[i].handler.sock.inbuf != NULL) {
432           nfree(td->socklist[i].handler.sock.inbuf);
433           td->socklist[i].handler.sock.inbuf = NULL;
434         }
435         if (td->socklist[i].handler.sock.outbuf != NULL) {
436           nfree(td->socklist[i].handler.sock.outbuf);
437           td->socklist[i].handler.sock.outbuf = NULL;
438           td->socklist[i].handler.sock.outbuflen = 0;
439         }
440       }
441       td->socklist[i].flags = SOCK_UNUSED;
442       return;
443     }
444   }
445   putlog(LOG_MISC, "*", "Warning: Attempt to kill un-allocated socket %d!", sock);
446 }
447 
448 /* Done with a tcl socket
449  *
450  * killtclsock() can be called by Tcl threads
451  */
killtclsock(int sock)452 void killtclsock(int sock)
453 {
454   int i;
455   struct threaddata *td = threaddata();
456 
457   if (sock < 0)
458     return;
459 
460   for (i = 0; i < td->MAXSOCKS; i++) {
461     if ((td->socklist[i].flags & SOCK_TCL) && td->socklist[i].sock == sock) {
462       td->socklist[i].flags = SOCK_UNUSED;
463       return;
464     }
465   }
466 }
467 
468 /* Send connection request to proxy
469  */
proxy_connect(int sock,sockname_t * addr)470 static int proxy_connect(int sock, sockname_t *addr)
471 {
472   sockname_t name;
473   char host[121], s[256];
474   int i, port, proxy;
475 
476   if (!firewall[0])
477     return -2;
478 #ifdef IPV6
479   if (addr->family == AF_INET6) {
480     putlog(LOG_MISC, "*", "Eggdrop doesn't support IPv6 connections "
481            "through proxies yet.");
482     return -1;
483   }
484 #endif
485   if (firewall[0] == '!') {
486     proxy = PROXY_SUN;
487     strlcpy(host, &firewall[1], sizeof host);
488   } else {
489     proxy = PROXY_SOCKS;
490     strcpy(host, firewall);
491   }
492   port = addr->addr.s4.sin_port;
493   setsockname(&name, host, firewallport, 1);
494   if (connect(sock, &name.addr.sa, name.addrlen) < 0 && errno != EINPROGRESS)
495     return -1;
496   if (proxy == PROXY_SOCKS) {
497     for (i = 0; i < threaddata()->MAXSOCKS; i++)
498       if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
499         socklist[i].flags |= SOCK_PROXYWAIT;    /* drummer */
500     memcpy(host, &addr->addr.s4.sin_addr.s_addr, 4);
501     egg_snprintf(s, sizeof s, "\004\001%c%c%c%c%c%c%s", port % 256,
502                  (port >> 8) % 256, host[0], host[1], host[2], host[3], botuser);
503     tputs(sock, s, strlen(botuser) + 9);        /* drummer */
504   } else if (proxy == PROXY_SUN) {
505     inet_ntop(AF_INET, &addr->addr.s4.sin_addr, host, sizeof host);
506     egg_snprintf(s, sizeof s, "%s %d\n", host, port);
507     tputs(sock, s, strlen(s));  /* drummer */
508   }
509   return sock;
510 }
511 
512 /* FIXME: if we can break compatibility for 1.9 or 2.0, we can replace this
513  * workaround with an additional port parameter for functions in need
514  */
get_port_from_addr(const sockname_t * addr)515 static int get_port_from_addr(const sockname_t *addr)
516 {
517 #ifdef IPV6
518   return ntohs((addr->family == AF_INET) ? addr->addr.s4.sin_port : addr->addr.s6.sin6_port);
519 #else
520   return ntohs(addr->addr.s4.sin_port);
521 #endif
522 }
523 
524 /* Starts a connection attempt through a socket
525  *
526  * The server address should be filled in addr by setsockname() or by the
527  * non-blocking dns functions and setsnport().
528  *
529  * returns < 0 if connection refused:
530  *   -1  strerror() type error
531  */
open_telnet_raw(int sock,sockname_t * addr)532 int open_telnet_raw(int sock, sockname_t *addr)
533 {
534   sockname_t name;
535   socklen_t res_len;
536   fd_set sockset;
537   struct timeval tv;
538   int i, j, rc, res;
539 
540   for (i = 0; i < dcc_total; i++)
541     if (dcc[i].sock == sock) { /* Got idx from sock ? */
542 #ifdef TLS
543       debug5("net: open_telnet_raw(): idx %i host %s ip %s port %i ssl %i",
544              i, dcc[i].host, iptostr(&addr->addr.sa), dcc[i].port, dcc[i].ssl);
545 #else
546       debug4("net: open_telnet_raw(): idx %i host %s ip %s port %i",
547              i, dcc[i].host, iptostr(&addr->addr.sa), dcc[i].port);
548 #endif
549       break;
550     }
551   getvhost(&name, addr->family);
552   if (bind(sock, &name.addr.sa, name.addrlen) < 0) {
553     return -1;
554   }
555   for (j = 0; j < threaddata()->MAXSOCKS; j++) {
556     if (!(socklist[j].flags & SOCK_UNUSED) && (socklist[j].sock == sock))
557       socklist[j].flags = (socklist[j].flags & ~SOCK_VIRTUAL) | SOCK_CONNECT;
558   }
559   if (addr->family == AF_INET && firewall[0])
560     return proxy_connect(sock, addr);
561   rc = connect(sock, &addr->addr.sa, addr->addrlen);
562   /* To minimize a proven race condition, call ident here (especially when
563    * rc < 0 and errno == EINPROGRESS)
564    */
565   if (dcc[i].status & STAT_SERV) {
566     check_tcl_event("ident");
567   }
568   if (rc < 0) {
569     if (errno == EINPROGRESS) {
570       /* Async connection... don't return socket descriptor
571        * until after we confirm if it was successful or not */
572       tv.tv_sec = 1;
573       tv.tv_usec = 0;
574       FD_ZERO(&sockset);
575       FD_SET(sock, &sockset);
576       select(sock + 1, &sockset, NULL, NULL, &tv);
577       res_len = sizeof(res);
578       getsockopt(sock, SOL_SOCKET, SO_ERROR, &res, &res_len);
579       if (res == EINPROGRESS) /* Operation now in progress */
580         return sock; /* This could probably fail somewhere */
581       if (res == ECONNREFUSED) { /* Connection refused */
582         debug2("net: attempted socket connection refused: %s:%i",
583                iptostr(&addr->addr.sa), get_port_from_addr(addr));
584         errno = res;
585         return -4;
586       }
587       if (res != 0) {
588         debug1("net: getsockopt error %d", res);
589         return -1;
590       }
591       return sock; /* async success! */
592     }
593     else {
594       return -1;
595     }
596   }
597   return sock;
598 }
599 
600 /* Ordinary non-binary connection attempt
601  * Return values:
602  *   >=0: connect successful, returned is the socket number
603  *    -1: look at errno or use strerror()
604  *    -2: lookup failed or server is not a valid IP string
605  *    -3: could not allocate socket
606  *    -4: connection failed
607  */
open_telnet(int idx,char * server,int port)608 int open_telnet(int idx, char *server, int port)
609 {
610   int ret;
611 
612   ret = setsockname(&dcc[idx].sockname, server, port, 1);
613   if (ret == AF_UNSPEC)
614     return -2;
615   dcc[idx].port = port;
616   dcc[idx].sock = getsock(ret, 0);
617   if (dcc[idx].sock < 0)
618     return -3;
619   ret = open_telnet_raw(dcc[idx].sock, &dcc[idx].sockname);
620   if (ret < 0) {
621     if (findidx(dcc[idx].sock) >= 0) {
622       killsock(dcc[idx].sock);
623     }
624   }
625   return ret;
626 }
627 
628 /* Returns a socket number for a listening socket that will accept any
629  * connection on the given address. The address can be filled in by
630  * setsockname().
631  */
open_address_listen(sockname_t * addr)632 int open_address_listen(sockname_t *addr)
633 {
634   int sock = 0;
635 
636   sock = getsock(addr->family, SOCK_LISTEN);
637   if (sock < 0)
638     return -1;
639 #if defined IPV6 && IPV6_V6ONLY
640   if (addr->family == AF_INET6) {
641     int on = 0;
642     setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, sizeof(on));
643   }
644 #endif
645   if (bind(sock, &addr->addr.sa, addr->addrlen) < 0) {
646     killsock(sock);
647     return -2;
648   }
649 
650   if (getsockname(sock, &addr->addr.sa, &addr->addrlen) < 0) {
651     killsock(sock);
652     return -1;
653   }
654   if (listen(sock, 1) < 0) {
655     killsock(sock);
656     return -1;
657   }
658 
659   return sock;
660 }
661 
662 /* Returns a socket number for a listening socket that will accept any
663  * connection -- port # is returned in port
664  */
open_listen(int * port)665 int open_listen(int *port)
666 {
667   int sock;
668   sockname_t name;
669 
670   (void) setsockname(&name, listen_ip, *port, 1);
671   sock = open_address_listen(&name);
672   if (name.addr.sa.sa_family == AF_INET)
673     *port = ntohs(name.addr.s4.sin_port);
674 #ifdef IPV6
675   else
676     *port = ntohs(name.addr.s6.sin6_port);
677 #endif
678   return sock;
679 }
680 
681 /* Short routine to answer a connect received on a listening socket.
682  * Returned is the new socket.
683  * If port is not NULL, it points to an integer to hold the port number
684  * of the caller.
685  */
answer(int sock,sockname_t * caller,uint16_t * port,int binary)686 int answer(int sock, sockname_t *caller, uint16_t *port, int binary)
687 {
688   int new_sock;
689   caller->addrlen = sizeof(caller->addr);
690   new_sock = accept(sock, &caller->addr.sa, &caller->addrlen);
691 
692   if (new_sock < 0)
693     return -1;
694 
695   caller->family = caller->addr.sa.sa_family;
696   if (port) {
697     if (caller->family == AF_INET)
698       *port = ntohs(caller->addr.s4.sin_port);
699 #ifdef IPV6
700     else
701       *port = ntohs(caller->addr.s6.sin6_port);
702 #endif
703   }
704   setsock(new_sock, (binary ? SOCK_BINARY : 0));
705   return new_sock;
706 }
707 
getdccaddr(sockname_t * addr,char * s,size_t l)708 int getdccaddr(sockname_t *addr, char *s, size_t l)
709 {
710   return getdccfamilyaddr(addr, s, l, AF_UNSPEC);
711 }
712 
713 /* Get DCC compatible address for a client to connect (e.g. 1660944385)
714  * If addr is not NULL, it should point to the listening socket's address.
715  * Otherwise, this function will try to figure out the public address of the
716  * machine, using listen_ip and natip. If restrict_af is set, it will limit
717  * the possible IPs to the specified family. The result is a string usable
718  * for DCC requests
719  */
getdccfamilyaddr(sockname_t * addr,char * s,size_t l,int restrict_af)720 int getdccfamilyaddr(sockname_t *addr, char *s, size_t l, int restrict_af)
721 {
722   char h[121];
723   sockname_t name, *r = &name;
724   int af = AF_UNSPEC;
725 #ifdef IPV6
726   IP ip = 0;
727 #endif
728 
729   if (addr)
730     r = addr;
731   else
732     setsockname(r, listen_ip, 0, 1);
733   if (
734 #ifdef IPV6
735       ((r->family == AF_INET6) &&
736       IN6_IS_ADDR_UNSPECIFIED(&r->addr.s6.sin6_addr)) ||
737 #endif
738       (r->family == AF_INET && !r->addr.s4.sin_addr.s_addr)) {
739       /* We can't send :: or 0.0.0.0 for dcc, so try
740          to figure out some real address */
741 #ifdef IPV6
742      /* If it's listening on an IPv6 :: address,
743         try using vhost6 as the source IP */
744     if (r->family == AF_INET6 && restrict_af != AF_INET) {
745       if (inet_pton(AF_INET6, vhost6, &r->addr.s6.sin6_addr) != 1) {
746         r = &name;
747         gethostname(h, sizeof h);
748         setsockname(r, h, 0, 1);
749         if (r->family == AF_INET) {
750         /* setsockname tries to resolve both ipv4 and ipv6. ipv4 dns
751            resolution comes later in precedence, so if we get an ipv4
752            back, reset it to the original addr struct and try
753            again */
754           if (addr) {
755             r = addr;
756           } else {
757             setsockname(r, listen_ip, 0, 1);
758           }
759         } else
760           af = AF_INET6;
761       }
762     }
763 #endif
764      /* If IPv6 didn't work or is disabled, or it's listening on an IPv4
765         0.0.0.0 address, try using vhost4 as the source */
766     if (!af
767 #ifdef IPV6
768         && restrict_af != AF_INET6
769 #endif
770        ) {
771       if (inet_pton(AF_INET, vhost, &r->addr.s4.sin_addr) != 1) {
772         /* And if THAT fails, try DNS resolution of hostname */
773         r = &name;
774         gethostname(h, sizeof h);
775         setsockname(r, h, 0, 1);
776       }
777     }
778   }
779 
780   if (
781 #ifdef IPV6
782       ((r->family == AF_INET6) &&
783       IN6_IS_ADDR_UNSPECIFIED(&r->addr.s6.sin6_addr)) ||
784       ((r->family == AF_INET6) && (restrict_af == AF_INET)) ||
785       ((r->family == AF_INET) && (restrict_af == AF_INET6)) ||
786 #endif
787       (!natip[0] && (r->family == AF_INET) && !r->addr.s4.sin_addr.s_addr))
788     return 0;
789 
790 #ifdef IPV6
791   if (r->family == AF_INET6) {
792     if (IN6_IS_ADDR_V4MAPPED(&r->addr.s6.sin6_addr) ||
793         IN6_IS_ADDR_UNSPECIFIED(&r->addr.s6.sin6_addr)) {
794       memcpy(&ip, r->addr.s6.sin6_addr.s6_addr + 12, sizeof ip);
795       egg_snprintf(s, l, "%lu", natip[0] ? iptolong(inet_addr(natip)) :
796                ntohl(ip));
797     } else
798       inet_ntop(AF_INET6, &r->addr.s6.sin6_addr, s, l);
799   } else
800 #endif
801   egg_snprintf(s, l, "%lu", natip[0] ? iptolong(inet_addr(natip)) :
802              ntohl(r->addr.s4.sin_addr.s_addr));
803   return 1;
804 }
805 
806 /* Builds the fd_sets for select(). Eggdrop only cares about readable
807  * sockets, but tcl also cares for writable/exceptions.
808  * preparefdset() can be called by Tcl Threads
809  */
preparefdset(fd_set * fds,sock_list * slist,int slistmax,int tclonly,int tclmask)810 static int preparefdset(fd_set *fds, sock_list *slist, int slistmax, int tclonly, int tclmask)
811 {
812   int fd, i, nfds = 0;
813 
814   FD_ZERO(fds);
815   for (i = 0; i < slistmax; i++) {
816     if (!(slist[i].flags & (SOCK_UNUSED | SOCK_VIRTUAL))) {
817       if ((slist[i].sock == STDOUT) && !backgrd)
818         fd = STDIN;
819       else
820         fd = slist[i].sock;
821       /*
822        * Looks like that having more than a call, in the same
823        * program, to the FD_SET macro, triggers a bug in gcc.
824        * SIGBUS crashing binaries used to be produced on a number
825        * (prolly all?) of 64 bits architectures.
826        * Make your best to avoid to make it happen again.
827        *
828        * ITE
829        */
830       if (slist[i].flags & SOCK_TCL) {
831         if (!(slist[i].handler.tclsock.mask & tclmask))
832           continue;
833       } else if (tclonly)
834         continue;
835       if (fd > nfds)
836         nfds = fd;
837       FD_SET(fd, fds);
838     }
839   }
840   return nfds;
841 }
842 
843 /* A safer version of write() that deals with partial writes. */
safe_write(int fd,const void * buf,size_t count)844 void safe_write(int fd, const void *buf, size_t count)
845 {
846   const char *bytes = buf;
847   ssize_t ret;
848   static int inhere = 0;
849 
850   do {
851     if ((ret = write(fd, bytes, count)) == -1 && errno != EINTR) {
852       if (!inhere) {
853         inhere = 1;
854         putlog(LOG_MISC, "*", "Unexpected write() failure on attempt to write %zd bytes to fd %d: %s.", count, fd, strerror(errno));
855         inhere = 0;
856       }
857       break;
858     }
859   } while ((bytes += ret, count -= ret));
860 }
861 
862 /* Attempts to read from all sockets in slist (upper array boundary slistmax-1)
863  * fills s with up to 511 bytes if available, and returns the array index
864  * Also calls all handler procs for Tcl sockets
865  * sockread() can be called by Tcl threads
866  *
867  *              on EOF:  returns -1, with socket in len
868  *     on socket error:  returns -2
869  * if nothing is ready:  returns -3
870  *    tcl sockets busy:  returns -5
871  */
sockread(char * s,int * len,sock_list * slist,int slistmax,int tclonly)872 int sockread(char *s, int *len, sock_list *slist, int slistmax, int tclonly)
873 {
874   struct timeval t;
875   fd_set fdr, fdw, fde;
876   int i, x, nfds_r, nfds_w, nfds_e;
877   int grab = 511, tclsock = -1, events = 0;
878   struct threaddata *td = threaddata();
879   int nfds;
880 #ifdef EGG_TDNS
881   int fd;
882   struct dns_thread_node *dtn, *dtn_prev;
883 #endif
884 
885   nfds_r = preparefdset(&fdr, slist, slistmax, tclonly, TCL_READABLE);
886 #ifdef EGG_TDNS
887   for (dtn = dns_thread_head->next; dtn; dtn = dtn->next) {
888     fd = dtn->fildes[0];
889     FD_SET(fd, &fdr);
890     if (fd > nfds_r)
891       nfds_r = fd;
892   }
893 #endif
894   nfds_w = preparefdset(&fdw, slist, slistmax, 1, TCL_WRITABLE);
895   nfds_e = preparefdset(&fde, slist, slistmax, 1, TCL_EXCEPTION);
896 
897   nfds = nfds_r;
898   if (nfds_w > nfds)
899     nfds = nfds_w;
900   if (nfds_e > nfds)
901     nfds = nfds_e;
902 
903   /* select() may modify the timeval argument - copy it */
904   t.tv_sec = td->blocktime.tv_sec;
905   t.tv_usec = td->blocktime.tv_usec;
906 
907   x = select((SELECT_TYPE_ARG1) nfds + 1,
908              SELECT_TYPE_ARG234 (nfds_r ? &fdr : NULL),
909              SELECT_TYPE_ARG234 (nfds_w ? &fdw : NULL),
910              SELECT_TYPE_ARG234 (nfds_e ? &fde : NULL),
911              SELECT_TYPE_ARG5 &t);
912   if (x == -1)
913     return -2;                  /* socket error */
914 
915   for (i = 0; i < slistmax; i++) {
916     if (!tclonly && ((!(slist[i].flags & (SOCK_UNUSED | SOCK_TCL))) &&
917         ((FD_ISSET(slist[i].sock, &fdr)) ||
918 #ifdef TLS
919         (slist[i].ssl && (SSL_pending(slist[i].ssl) ||
920          !SSL_is_init_finished(slist[i].ssl))) ||
921 #endif
922         ((slist[i].sock == STDOUT) && (!backgrd) &&
923          (FD_ISSET(STDIN, &fdr)))))) {
924       if (slist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
925         /* Listening socket -- don't read, just return activity */
926         /* Same for connection attempt */
927         /* (for strong connections, require a read to succeed first) */
928         if (slist[i].flags & SOCK_PROXYWAIT) /* drummer */
929           /* Hang around to get the return code from proxy */
930           grab = 10;
931 #ifdef TLS
932         else if (!(slist[i].flags & SOCK_STRONGCONN) &&
933                  (!(slist[i].ssl) || SSL_is_init_finished(slist[i].ssl))) {
934 #else
935         else if (!(slist[i].flags & SOCK_STRONGCONN)) {
936 #endif
937           debug1("net: connect! sock %d", slist[i].sock);
938           s[0] = 0;
939           *len = 0;
940           return i;
941         }
942       } else if (slist[i].flags & SOCK_PASS) {
943         s[0] = 0;
944         *len = 0;
945         return i;
946       }
947       errno = 0;
948       if ((slist[i].sock == STDOUT) && !backgrd)
949         x = read(STDIN, s, grab);
950       else
951 #ifdef TLS
952       {
953         if (slist[i].ssl) {
954           x = SSL_read(slist[i].ssl, s, grab);
955           if (x < 0) {
956             int err = SSL_get_error(slist[i].ssl, x);
957             if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
958               errno = EAGAIN;
959             else if (err == SSL_ERROR_SYSCALL) {
960               debug0("net: sockread(): SSL_read() SSL_ERROR_SYSCALL");
961               putlog(LOG_MISC, "*", "NET: SSL read failed. Non-SSL connection?");
962             }
963             else
964               debug2("net: sockread(): SSL_read() error = %s (%i)",
965                      ERR_error_string(ERR_get_error(), 0), err);
966             x = -1;
967           }
968         } else
969           x = read(slist[i].sock, s, grab);
970       }
971 #else
972         x = read(slist[i].sock, s, grab);
973 #endif
974       if (x <= 0) {           /* eof */
975         if (errno != EAGAIN) { /* EAGAIN happens when the operation would
976                                 * block on a non-blocking socket, if the
977                                 * socket is going to die, it will die later,
978                                 * otherwise it will connect. */
979           *len = slist[i].sock;
980           slist[i].flags &= ~SOCK_CONNECT;
981           debug1("net: eof!(read) socket %d", slist[i].sock);
982           return -1;
983         } else {
984           debug3("sockread EAGAIN: %d %d (%s)", slist[i].sock, errno,
985                  strerror(errno));
986           continue;           /* EAGAIN */
987         }
988       }
989       s[x] = 0;
990       *len = x;
991       if (slist[i].flags & SOCK_PROXYWAIT) {
992         debug2("net: socket: %d proxy errno: %d", slist[i].sock, s[1]);
993         slist[i].flags &= ~(SOCK_CONNECT | SOCK_PROXYWAIT);
994         switch (s[1]) {
995         case 90:             /* Success */
996           s[0] = 0;
997           *len = 0;
998           return i;
999         case 91:             /* Failed */
1000           errno = ECONNREFUSED;
1001           break;
1002         case 92:             /* No identd */
1003         case 93:             /* Identd said wrong username */
1004           /* A better error message would be "socks misconfigured"
1005            * or "identd not working" but this is simplest.
1006            */
1007           errno = ENETUNREACH;
1008           break;
1009         }
1010         *len = slist[i].sock;
1011         return -1;
1012       }
1013       return i;
1014     } else if (tclsock == -1 && (slist[i].flags & SOCK_TCL)) {
1015       events = FD_ISSET(slist[i].sock, &fdr) ? TCL_READABLE : 0;
1016       events |= FD_ISSET(slist[i].sock, &fdw) ? TCL_WRITABLE : 0;
1017       events |= FD_ISSET(slist[i].sock, &fde) ? TCL_EXCEPTION : 0;
1018       events &= slist[i].handler.tclsock.mask;
1019       if (events)
1020         tclsock = i;
1021     }
1022   }
1023   if (!tclonly) {
1024     s[0] = 0;
1025     *len = 0;
1026   }
1027   if (tclsock != -1) {
1028     (*slist[tclsock].handler.tclsock.proc)(slist[tclsock].handler.tclsock.cd,
1029                                            events);
1030     return -5;
1031   }
1032 #ifdef EGG_TDNS
1033   dtn_prev = dns_thread_head;
1034   for (dtn = dtn_prev->next; dtn; dtn = dtn->next) {
1035     fd = dtn->fildes[0];
1036     if (FD_ISSET(fd, &fdr)) {
1037       if (dtn->type == DTN_TYPE_HOSTBYIP)
1038         call_hostbyip(&dtn->addr, dtn->host, dtn->ok);
1039       else
1040         call_ipbyhost(dtn->host, &dtn->addr, dtn->ok);
1041       close(dtn->fildes[0]);
1042       dtn_prev->next = dtn->next;
1043       nfree(dtn);
1044       dtn = dtn_prev;
1045     }
1046     dtn_prev = dtn;
1047   }
1048 #endif
1049   return -3;
1050 }
1051 
1052 /* sockgets: buffer and read from sockets
1053  *
1054  * Attempts to read from all registered sockets for up to one second.  if
1055  * after one second, no complete data has been received from any of the
1056  * sockets, 's' will be empty, 'len' will be 0, and sockgets will return -3.
1057  * if there is returnable data received from a socket, the data will be
1058  * in 's' (null-terminated if non-binary), the length will be returned
1059  * in len, and the socket number will be returned.
1060  * normal sockets have their input buffered, and each call to sockgets
1061  * will return one line terminated with a '\n'.  binary sockets are not
1062  * buffered and return whatever coems in as soon as it arrives.
1063  * listening sockets will return an empty string when a connection comes in.
1064  * connecting sockets will return an empty string on a successful connect,
1065  * or EOF on a failed connect.
1066  * if an EOF is detected from any of the sockets, that socket number will be
1067  * put in len, and -1 will be returned.
1068  * the maximum length of the string returned is 512 (including null)
1069  *
1070  * Returns -4 if we handled something that shouldn't be handled by the
1071  * dcc functions. Simply ignore it.
1072  * Returns -5 if tcl sockets are busy but not eggdrop sockets.
1073  */
1074 
1075 int sockgets(char *s, int *len)
1076 {
1077   char xx[RECVLINEMAX], *p, *px, *p2;
1078   int ret, i, data = 0;
1079   size_t len2;
1080 
1081   for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1082     /* Check for stored-up data waiting to be processed */
1083     if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL | SOCK_BUFFER)) &&
1084         (socklist[i].handler.sock.inbuf != NULL)) {
1085       if (!(socklist[i].flags & SOCK_BINARY)) {
1086         /* IRC messages are always lines of characters terminated with a CR-LF
1087          * (Carriage Return - Line Feed) pair.
1088          */
1089         p = strpbrk(socklist[i].handler.sock.inbuf, "\r\n");
1090         if (p != NULL) {
1091 
1092           /* this function is used not only for irc connections. dont remove
1093            * empty lines for they could be important like for example for http
1094            * header termination.
1095            */
1096           p2 = p;
1097           if (*p == '\r')
1098             p++;
1099           if (*p == '\n')
1100             p++;
1101           *p2 = 0;
1102 
1103           strlcpy(s, socklist[i].handler.sock.inbuf, RECVLINEMAX-1);
1104           if (*p) {
1105             len2 = strlen(p) + 1;
1106             px = nmalloc(len2);
1107             memcpy(px, p, len2);
1108             nfree(socklist[i].handler.sock.inbuf);
1109             socklist[i].handler.sock.inbuf = px;
1110           } else {
1111             nfree(socklist[i].handler.sock.inbuf);
1112             socklist[i].handler.sock.inbuf = NULL;
1113           }
1114           *len = strlen(s);
1115           return socklist[i].sock;
1116         }
1117       } else {
1118         /* Handling buffered binary data (must have been SOCK_BUFFER before). */
1119         if (socklist[i].handler.sock.inbuflen <= RECVLINEMAX-2) {
1120           *len = socklist[i].handler.sock.inbuflen;
1121           memcpy(s, socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
1122           nfree(socklist[i].handler.sock.inbuf);
1123           socklist[i].handler.sock.inbuf = NULL;
1124           socklist[i].handler.sock.inbuflen = 0;
1125         } else {
1126           /* Split up into chunks of RECVLINEMAX-2 bytes. */
1127           *len = RECVLINEMAX-2;
1128           memcpy(s, socklist[i].handler.sock.inbuf, *len);
1129           memcpy(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuf + *len, *len);
1130           socklist[i].handler.sock.inbuflen -= *len;
1131           socklist[i].handler.sock.inbuf = nrealloc(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
1132         }
1133         return socklist[i].sock;
1134       }
1135     }
1136     /* Also check any sockets that might have EOF'd during write */
1137     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].flags & SOCK_EOFD)) {
1138       s[0] = 0;
1139       *len = socklist[i].sock;
1140       return -1;
1141     }
1142   }
1143   /* No pent-up data of any worth -- down to business */
1144   *len = 0;
1145   ret = sockread(xx, len, socklist, threaddata()->MAXSOCKS, 0);
1146   if (ret < 0) {
1147     s[0] = 0;
1148     return ret;
1149   }
1150   /* sockread can return binary data while socket still has connectflag, process first */
1151   if (socklist[ret].flags & SOCK_BINARY && *len > 0) {
1152     socklist[ret].flags &= ~SOCK_CONNECT;
1153     memcpy(s, xx, *len);
1154     return socklist[ret].sock;
1155   }
1156   /* Binary, listening and passed on sockets don't get buffered. */
1157   if (socklist[ret].flags & SOCK_CONNECT) {
1158     if (socklist[ret].flags & SOCK_STRONGCONN) {
1159       socklist[ret].flags &= ~SOCK_STRONGCONN;
1160       /* Buffer any data that came in, for future read. */
1161       socklist[ret].handler.sock.inbuflen = *len;
1162       socklist[ret].handler.sock.inbuf = nmalloc(*len + 1);
1163       /* It might be binary data. You never know. */
1164       memcpy(socklist[ret].handler.sock.inbuf, xx, *len);
1165       socklist[ret].handler.sock.inbuf[*len] = 0;
1166     }
1167     socklist[ret].flags &= ~SOCK_CONNECT;
1168     s[0] = 0;
1169     return socklist[ret].sock;
1170   }
1171   if (socklist[ret].flags & (SOCK_LISTEN | SOCK_PASS | SOCK_TCL)) {
1172     s[0] = 0; /* for the dcc traffic counters in the mainloop */
1173     return socklist[ret].sock;
1174   }
1175   if (socklist[ret].flags & SOCK_BUFFER) {
1176     socklist[ret].handler.sock.inbuf = (char *) nrealloc(socklist[ret].handler.sock.inbuf,
1177                                             socklist[ret].handler.sock.inbuflen + *len + 1);
1178     memcpy(socklist[ret].handler.sock.inbuf + socklist[ret].handler.sock.inbuflen, xx, *len);
1179     socklist[ret].handler.sock.inbuflen += *len;
1180     /* We don't know whether it's binary data. Make sure normal strings
1181      * will be handled properly later on too. */
1182     socklist[ret].handler.sock.inbuf[socklist[ret].handler.sock.inbuflen] = 0;
1183     return -4;                  /* Ignore this one. */
1184   }
1185   /* Might be necessary to prepend stored-up data! */
1186   if (socklist[ret].handler.sock.inbuf != NULL) {
1187     p = socklist[ret].handler.sock.inbuf;
1188     socklist[ret].handler.sock.inbuf = nmalloc(strlen(p) + strlen(xx) + 1);
1189     strcpy(socklist[ret].handler.sock.inbuf, p);
1190     strcat(socklist[ret].handler.sock.inbuf, xx);
1191     nfree(p);
1192     if (strlen(socklist[ret].handler.sock.inbuf) < RECVLINEMAX) {
1193       strcpy(xx, socklist[ret].handler.sock.inbuf);
1194       nfree(socklist[ret].handler.sock.inbuf);
1195       socklist[ret].handler.sock.inbuf = NULL;
1196       socklist[ret].handler.sock.inbuflen = 0;
1197     } else {
1198       p = socklist[ret].handler.sock.inbuf;
1199       socklist[ret].handler.sock.inbuflen = strlen(p) - RECVLINEMAX-2;
1200       socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
1201       strcpy(socklist[ret].handler.sock.inbuf, p + RECVLINEMAX-2);
1202       *(p + RECVLINEMAX-2) = 0;
1203       strcpy(xx, p);
1204       nfree(p);
1205       /* (leave the rest to be post-pended later) */
1206     }
1207   }
1208   /* Look for EOL marker; if it's there, i have something to show */
1209   for (p = xx; *p != 0 ; p++) {
1210     if ((*p == '\r') || (*p == '\n')) {
1211       memcpy(s, xx, p - xx);
1212       s[p - xx] = 0;
1213       for (p++; (*p == '\r') || (*p == '\n'); p++);
1214       memmove(xx, p, strlen(p) + 1);
1215       data = 1; /* DCC_CHAT may now need to process a blank line */
1216       break;
1217     }
1218   }
1219 /* NO! */
1220 /* if (!s[0]) strcpy(s," ");  */
1221   if (!data) {
1222     s[0] = 0;
1223     if (strlen(xx) >= RECVLINEMAX-2) {
1224       /* String is too long, so just insert fake \n */
1225       strcpy(s, xx);
1226       xx[0] = 0;
1227       data = 1;
1228     }
1229   }
1230   *len = strlen(s);
1231   /* Anything left that needs to be saved? */
1232   if (!xx[0]) {
1233     if (data)
1234       return socklist[ret].sock;
1235     else
1236       return -3;
1237   }
1238   /* Prepend old data back */
1239   if (socklist[ret].handler.sock.inbuf != NULL) {
1240     p = socklist[ret].handler.sock.inbuf;
1241     socklist[ret].handler.sock.inbuflen = strlen(p) + strlen(xx);
1242     socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
1243     strcpy(socklist[ret].handler.sock.inbuf, xx);
1244     strcat(socklist[ret].handler.sock.inbuf, p);
1245     nfree(p);
1246   } else {
1247     socklist[ret].handler.sock.inbuflen = strlen(xx);
1248     len2 = socklist[ret].handler.sock.inbuflen + 1;
1249     socklist[ret].handler.sock.inbuf = nmalloc(len2);
1250     memcpy(socklist[ret].handler.sock.inbuf, xx, len2);
1251   }
1252   if (data)
1253     return socklist[ret].sock;
1254   else
1255     return -3;
1256 }
1257 
1258 /* Dump something to a socket
1259  *
1260  * NOTE: Do NOT put Contexts in here if you want DEBUG to be meaningful!!
1261  */
1262 void tputs(int z, char *s, unsigned int len)
1263 {
1264   int i, x, idx;
1265   char *p;
1266   static int inhere = 0;
1267 
1268   if (z < 0) /* um... HELLO?! sanity check please! */
1269     return;
1270 
1271   if (((z == STDOUT) || (z == STDERR)) && (!backgrd || use_stderr)) {
1272     safe_write(z, s, len);
1273     return;
1274   }
1275 
1276   for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1277     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == z)) {
1278       for (idx = 0; idx < dcc_total; idx++) {
1279         if ((dcc[idx].sock == z) && dcc[idx].type && dcc[idx].type->name) {
1280           if (!strncmp(dcc[idx].type->name, "BOT", 3))
1281             otraffic_bn_today += len;
1282           else if (!strcmp(dcc[idx].type->name, "SERVER"))
1283             otraffic_irc_today += len;
1284           else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
1285             otraffic_dcc_today += len;
1286           else if (!strncmp(dcc[idx].type->name, "FILES", 5))
1287             otraffic_filesys_today += len;
1288           else if (!strcmp(dcc[idx].type->name, "SEND"))
1289             otraffic_trans_today += len;
1290           else if (!strcmp(dcc[idx].type->name, "FORK_SEND"))
1291             otraffic_trans_today += len;
1292           else if (!strncmp(dcc[idx].type->name, "GET", 3))
1293             otraffic_trans_today += len;
1294           else
1295             otraffic_unknown_today += len;
1296           break;
1297         }
1298       }
1299 
1300       if (socklist[i].handler.sock.outbuf != NULL) {
1301         /* Already queueing: just add it */
1302         p = (char *) nrealloc(socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen + len);
1303         memcpy(p + socklist[i].handler.sock.outbuflen, s, len);
1304         socklist[i].handler.sock.outbuf = p;
1305         socklist[i].handler.sock.outbuflen += len;
1306         return;
1307       }
1308 #ifdef TLS
1309       if (socklist[i].ssl) {
1310         x = SSL_write(socklist[i].ssl, s, len);
1311         if (x < 0) {
1312           int err = SSL_get_error(socklist[i].ssl, x);
1313           if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ)
1314             errno = EAGAIN;
1315           else if (!inhere) { /* Out there, somewhere */
1316             inhere = 1;
1317             debug1("tputs(): SSL error = %s",
1318                    ERR_error_string(ERR_get_error(), 0));
1319             inhere = 0;
1320           }
1321           x = -1;
1322         }
1323       } else /* not ssl, use regular write() */
1324 #endif
1325       /* Try. */
1326       x = write(z, s, len);
1327       if (x == -1)
1328         x = 0;
1329       if (x < len) {
1330         /* Socket is full, queue it */
1331         socklist[i].handler.sock.outbuf = nmalloc(len - x);
1332         memcpy(socklist[i].handler.sock.outbuf, &s[x], len - x);
1333         socklist[i].handler.sock.outbuflen = len - x;
1334       }
1335       return;
1336     }
1337   }
1338   /* Make sure we don't cause a crash by looping here */
1339   if (!inhere) {
1340     inhere = 1;
1341 
1342     putlog(LOG_MISC, "*", "!!! writing to nonexistent socket: %d", z);
1343     s[strlen(s) - 1] = 0;
1344     putlog(LOG_MISC, "*", "!-> '%s'", s);
1345 
1346     inhere = 0;
1347   }
1348 }
1349 
1350 /* tputs might queue data for sockets, let's dump as much of it as
1351  * possible.
1352  */
1353 void dequeue_sockets()
1354 {
1355   int i, x;
1356   int z = 0;
1357   fd_set wfds;
1358   struct timeval tv;
1359   int nfds = 0;
1360 
1361 /* ^-- start poptix test code, this should avoid writes to sockets not ready to be written to. */
1362 
1363   FD_ZERO(&wfds);
1364   tv.tv_sec = 0;
1365   tv.tv_usec = 0;               /* we only want to see if it's ready for writing, no need to actually wait.. */
1366   for (i = 0; i < threaddata()->MAXSOCKS; i++)
1367     if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
1368         (socklist[i].handler.sock.outbuf != NULL)) {
1369       if (socklist[i].sock > nfds)
1370         nfds = socklist[i].sock;
1371       FD_SET(socklist[i].sock, &wfds);
1372       z = 1;
1373     }
1374   if (!z)
1375     return;                     /* nothing to write */
1376 
1377   select((SELECT_TYPE_ARG1) nfds + 1, SELECT_TYPE_ARG234 NULL,
1378          SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 NULL,
1379          SELECT_TYPE_ARG5 &tv);
1380 
1381 /* end poptix */
1382 
1383   for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1384     if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
1385         (socklist[i].handler.sock.outbuf != NULL) && (FD_ISSET(socklist[i].sock, &wfds))) {
1386       /* Trick tputs into doing the work */
1387       errno = 0;
1388 #ifdef TLS
1389       if (socklist[i].ssl) {
1390         x = SSL_write(socklist[i].ssl, socklist[i].handler.sock.outbuf,
1391                       socklist[i].handler.sock.outbuflen);
1392         if (x < 0) {
1393           int err = SSL_get_error(socklist[i].ssl, x);
1394           if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ)
1395             errno = EAGAIN;
1396           else
1397             debug1("dequeue_sockets(): SSL error = %s",
1398                    ERR_error_string(ERR_get_error(), 0));
1399           x = -1;
1400         }
1401       } else
1402 #endif
1403       x = write(socklist[i].sock, socklist[i].handler.sock.outbuf,
1404                 socklist[i].handler.sock.outbuflen);
1405       if ((x < 0) && (errno != EAGAIN)
1406 #ifdef EBADSLT
1407           && (errno != EBADSLT)
1408 #endif
1409 #ifdef ENOTCONN
1410           && (errno != ENOTCONN)
1411 #endif
1412         ) {
1413         /* This detects an EOF during writing */
1414         debug3("net: eof!(write) socket %d (%s,%d)", socklist[i].sock,
1415                strerror(errno), errno);
1416         socklist[i].flags |= SOCK_EOFD;
1417       } else if (x == socklist[i].handler.sock.outbuflen) {
1418         /* If the whole buffer was sent, nuke it */
1419         nfree(socklist[i].handler.sock.outbuf);
1420         socklist[i].handler.sock.outbuf = NULL;
1421         socklist[i].handler.sock.outbuflen = 0;
1422       } else if (x > 0) {
1423         char *p = socklist[i].handler.sock.outbuf;
1424 
1425         /* This removes any sent bytes from the beginning of the buffer */
1426         socklist[i].handler.sock.outbuf =
1427                             nmalloc(socklist[i].handler.sock.outbuflen - x);
1428         memcpy(socklist[i].handler.sock.outbuf, p + x,
1429                    socklist[i].handler.sock.outbuflen - x);
1430         socklist[i].handler.sock.outbuflen -= x;
1431         nfree(p);
1432       } else {
1433         debug3("dequeue_sockets(): errno = %d (%s) on %d", errno,
1434                strerror(errno), socklist[i].sock);
1435       }
1436       /* All queued data was sent. Call handler if one exists and the
1437        * dcc entry wants it.
1438        */
1439       if (!socklist[i].handler.sock.outbuf) {
1440         int idx = findanyidx(socklist[i].sock);
1441 
1442         if (idx > 0 && dcc[idx].type && dcc[idx].type->outdone)
1443           dcc[idx].type->outdone(idx);
1444       }
1445     }
1446   }
1447 }
1448 
1449 
1450 /*
1451  *      Debugging stuff
1452  */
1453 
1454 void tell_netdebug(int idx)
1455 {
1456   int i;
1457   char s[80];
1458 
1459   dprintf(idx, "Open sockets:");
1460   for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1461     if (!(socklist[i].flags & SOCK_UNUSED)) {
1462       sprintf(s, " %d", socklist[i].sock);
1463       if (socklist[i].flags & SOCK_BINARY)
1464         strcat(s, " (binary)");
1465       if (socklist[i].flags & SOCK_LISTEN)
1466         strcat(s, " (listen)");
1467       if (socklist[i].flags & SOCK_PASS)
1468         strcat(s, " (passed on)");
1469       if (socklist[i].flags & SOCK_CONNECT)
1470         strcat(s, " (connecting)");
1471       if (socklist[i].flags & SOCK_STRONGCONN)
1472         strcat(s, " (strong)");
1473       if (socklist[i].flags & SOCK_NONSOCK)
1474         strcat(s, " (file)");
1475 #ifdef TLS
1476       if (socklist[i].ssl)
1477         strcat(s, " (TLS)");
1478 #endif
1479       if (socklist[i].flags & SOCK_TCL)
1480         strcat(s, " (tcl)");
1481       if (!(socklist[i].flags & SOCK_TCL)) {
1482         if (socklist[i].handler.sock.inbuf != NULL)
1483           sprintf(&s[strlen(s)], " (inbuf: %04X)",
1484                   (unsigned int) strlen(socklist[i].handler.sock.inbuf));
1485         if (socklist[i].handler.sock.outbuf != NULL)
1486           sprintf(&s[strlen(s)], " (outbuf: %06lX)", socklist[i].handler.sock.outbuflen);
1487       }
1488       strcat(s, ",");
1489       dprintf(idx, "%s", s);
1490     }
1491   }
1492   dprintf(idx, " done.\n");
1493 }
1494 
1495 /* Security-flavoured sanity checking on DCC connections of all sorts can be
1496  * done with this routine.  Feed it the proper information from your DCC
1497  * before you attempt the connection, and this will make an attempt at
1498  * figuring out if the connection is really that person, or someone screwing
1499  * around.  It's not foolproof, but anything that fails this check probably
1500  * isn't going to work anyway due to masquerading firewalls, NAT routers,
1501  * or bugs in mIRC.
1502  */
1503 int sanitycheck_dcc(char *nick, char *from, char *ipaddy, char *port)
1504 {
1505   /* According to the latest RFC, the clients SHOULD be able to handle
1506    * DNS names that are up to 255 characters long.  This is not broken.
1507    */
1508 
1509 #ifdef IPV6
1510   char badaddress[INET6_ADDRSTRLEN];
1511   sockname_t name;
1512   IP ip = 0;
1513 #else
1514   char badaddress[INET_ADDRSTRLEN];
1515   IP ip = my_atoul(ipaddy);
1516 #endif
1517   int prt = atoi(port);
1518 
1519   /* It is disabled HERE so we only have to check in *one* spot! */
1520   if (!dcc_sanitycheck)
1521     return 1;
1522 
1523   if (prt < 1) {
1524     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible port of %u!",
1525            nick, from, prt);
1526     return 0;
1527   }
1528 #ifdef IPV6
1529   if (strchr(ipaddy, ':')) {
1530     if (inet_pton(AF_INET6, ipaddy, &name.addr.s6.sin6_addr) != 1) {
1531       putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an invalid IPv6 "
1532              "address of %s!", nick, from, ipaddy);
1533       return 0;
1534     }
1535     if (IN6_IS_ADDR_V4MAPPED(&name.addr.s6.sin6_addr)) {
1536       memcpy(&ip, name.addr.s6.sin6_addr.s6_addr + 12, sizeof ip);
1537       ip = ntohl(ip);
1538     }
1539   }
1540 #endif
1541   if (ip && inet_ntop(AF_INET, &ip, badaddress, sizeof badaddress) &&
1542       (ip < (1 << 24))) {
1543     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible IP of %s!",
1544            nick, from, badaddress);
1545     return 0;
1546   }
1547   return 1;
1548 }
1549 
1550 int hostsanitycheck_dcc(char *nick, char *from, sockname_t *ip, char *dnsname,
1551                         char *prt)
1552 {
1553   char badaddress[INET6_ADDRSTRLEN];
1554 
1555   /* According to the latest RFC, the clients SHOULD be able to handle
1556    * DNS names that are up to 255 characters long.  This is not broken.
1557    */
1558   char hostn[256];
1559 
1560   /* It is disabled HERE so we only have to check in *one* spot! */
1561   if (!dcc_sanitycheck)
1562     return 1;
1563   strcpy(badaddress, iptostr(&ip->addr.sa));
1564   /* These should pad like crazy with zeros, since 120 bytes or so is
1565    * where the routines providing our data currently lose interest. I'm
1566    * using the n-variant in case someone changes that...
1567    */
1568   strlcpy(hostn, extracthostname(from), sizeof hostn);
1569   if (!strcasecmp(hostn, dnsname)) {
1570     putlog(LOG_DEBUG, "*", "DNS information for submitted IP checks out.");
1571     return 1;
1572   }
1573   if (!strcmp(badaddress, dnsname))
1574     putlog(LOG_MISC, "*", "ALERT: (%s!%s) sent a DCC request with bogus IP "
1575            "information of %s port %s. %s does not resolve to %s!", nick, from,
1576            badaddress, prt, from, badaddress);
1577   else
1578     return 1;                   /* <- usually happens when we have
1579                                  * a user with an unresolved hostmask! */
1580   return 0;
1581 }
1582 
1583 /* Checks whether the referenced socket has data queued.
1584  *
1585  * Returns true if the incoming/outgoing (depending on 'type') queues
1586  * contain data, otherwise false.
1587  */
1588 int sock_has_data(int type, int sock)
1589 {
1590   int ret = 0, i;
1591 
1592   for (i = 0; i < threaddata()->MAXSOCKS; i++)
1593     if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
1594       break;
1595   if (i < threaddata()->MAXSOCKS) {
1596     switch (type) {
1597     case SOCK_DATA_OUTGOING:
1598       ret = (socklist[i].handler.sock.outbuf != NULL);
1599       break;
1600     case SOCK_DATA_INCOMING:
1601       ret = (socklist[i].handler.sock.inbuf != NULL);
1602       break;
1603     }
1604   } else
1605     debug1("sock_has_data: could not find socket #%d, returning false.", sock);
1606   return ret;
1607 }
1608 
1609 /* flush_inbuf():
1610  * checks if there's data in the incoming buffer of an connection
1611  * and flushes the buffer if possible
1612  *
1613  * returns: -1 if the dcc entry wasn't found
1614  *          -2 if dcc[idx].type->activity doesn't exist and the data couldn't
1615  *             be handled
1616  *          0 if buffer was empty
1617  *          otherwise length of flushed buffer
1618  */
1619 int flush_inbuf(int idx)
1620 {
1621   int i, len;
1622   char *inbuf;
1623 
1624   Assert((idx >= 0) && (idx < dcc_total));
1625   for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1626     if ((dcc[idx].sock == socklist[i].sock) &&
1627         !(socklist[i].flags & SOCK_UNUSED)) {
1628       len = socklist[i].handler.sock.inbuflen;
1629       if ((len > 0) && socklist[i].handler.sock.inbuf) {
1630         if (dcc[idx].type && dcc[idx].type->activity) {
1631           inbuf = socklist[i].handler.sock.inbuf;
1632           socklist[i].handler.sock.inbuf = NULL;
1633           dcc[idx].type->activity(idx, inbuf, len);
1634           nfree(inbuf);
1635           return len;
1636         } else
1637           return -2;
1638       } else
1639         return 0;
1640     }
1641   }
1642   return -1;
1643 }
1644 
1645 /* Find sock in socklist.
1646  *
1647  * Returns index in socklist or -1 if not found.
1648  */
1649 int findsock(int sock)
1650 {
1651   int i;
1652   struct threaddata *td = threaddata();
1653 
1654   for (i = 0; i < td->MAXSOCKS; i++)
1655     if (td->socklist[i].sock == sock)
1656       break;
1657   if (i == td->MAXSOCKS)
1658     return -1;
1659   return i;
1660 }
1661 
1662 /* Trace on my-ip and my-hostname variable to handle transition into vhost4/vhost6/listen-addr.
1663  */
1664 char *traced_myiphostname(ClientData cd, Tcl_Interp *irp, EGG_CONST char *name1, EGG_CONST char *name2, int flags)
1665 {
1666   const char *value;
1667 
1668   if (flags & TCL_INTERP_DESTROYED)
1669     return NULL;
1670   /* Recover trace in case of unset. */
1671   if (flags & TCL_TRACE_DESTROYED) {
1672     Tcl_TraceVar2(irp, name1, name2, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, traced_myiphostname, cd);
1673     return NULL;
1674   }
1675 
1676   value = Tcl_GetVar2(irp, name1, name2, TCL_GLOBAL_ONLY);
1677   strlcpy(vhost, value, sizeof vhost);
1678   strlcpy(listen_ip, value, sizeof listen_ip);
1679   putlog(LOG_MISC, "*", "WARNING: You are using the DEPRECATED variable '%s' in your config file.\n", name1);
1680   putlog(LOG_MISC, "*", "    To prevent future incompatibility, please use the vhost4/listen-addr variables instead.\n");
1681   putlog(LOG_MISC, "*", "    More information on this subject can be found in the eggdrop/doc/IPV6 file, or\n");
1682   putlog(LOG_MISC, "*", "    in the comments above those settings in the example eggdrop.conf that is included with Eggdrop.\n");
1683   return NULL;
1684 }
1685