1 /*
2  * ----------------------------------------------------------------
3  * ircproxy - Connection Functions
4  * ----------------------------------------------------------------
5  * Copyright (C) 1997-2009 Jonas Kvinge
6  *
7  * This file is part of ircproxy.
8  *
9  * ircproxy is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * ircproxy is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with ircproxy.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * Additional permission under GNU GPL version 3 section 7
23  *
24  * If you modify ircproxy, or any covered work, by linking or
25  * combining it with openssl (or a modified version of that library),
26  * containing parts covered by the terms of the OpenSSL License and the
27  * SSLeay License, the licensors of ircproxy grant you additional
28  * permission to convey the resulting work.
29  *
30  * $Id: conn_connection.c 54 2009-03-18 18:23:29Z jonasio $
31  *
32  */
33 
34 #define CONN_CONNECTION_C
35 
36 #define NEED_SYS_TYPES_H 1		/* Extra types */
37 #define NEED_SYS_PARAM_H 1		/* Some systems need this */
38 #define NEED_LIMITS_H 0			/* Kernel limits */
39 #define NEED_STDARG_H 1			/* va_list, etc */
40 #define NEED_ERRNO_H 1			/* errno */
41 #define NEED_CTYPE_H 1			/* isdigit(), etc */
42 #define NEED_NETINET_IN_H 1		/* in_addr, sockaddr_in, etc */
43 #define NEED_ARPA_INET_H 1		/* inet_ntoa(), inet_aton(), etc */
44 #define NEED_STDIO_H 1			/* Standard C UNIX functions */
45 #define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
46 #define NEED_TIME_H 1			/* time(), etc */
47 #define NEED_SYSCTL_H 0			/* sysctl(), etc */
48 #define NEED_SYS_STAT_H 0		/* chmod(), mkdir(), etc */
49 #define NEED_SYS_UIO_H 0		/* iovec, etc */
50 #define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
51 #define NEED_SYS_IOCTL_H 1		/* ioctl(), etc */
52 #define NEED_SYS_FILIO_H 1		/* Solaris need this for ioctl(), etc */
53 #define NEED_UNISTD_H 1			/* Unix standard functions */
54 #define NEED_STRING_H 1			/* C string functions */
55 #define NEED_SIGNAL_H 0			/* Signal functions */
56 #define NEED_SYS_SOCKET_H 1		/* Socket functions */
57 #define NEED_NETDB_H 1			/* Network database functions */
58 #define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
59 #define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */
60 #define NEED_ARES 1			/* Functions needed for ares */
61 #define NEED_SSL 1			/* Needed for SSL support */
62 
63 #include "includes.h"
64 #include "irc.h"
65 
66 #include "conf.h"
67 #include "access_conf.h"
68 #include "conn_conf.h"
69 
70 #include "conn.h"
71 #include "conn_io.h"
72 #if SSL_SUPPORT
73   #include "conn_io_ssl.h"
74 #endif
75 #include "conn_connection.h"
76 #include "conn_sendq.h"
77 #include "conn_log.h"
78 #include "conn_parser.h"
79 #include "conn_ignore.h"
80 
81 #include "client.h"
82 #include "client_connection.h"
83 #include "client_notice.h"
84 
85 #include "chan.h"
86 #include "chan_user.h"
87 
88 /* VARIABLES - JONAS (31.07.2001) */
89 
90 extern struct Conn_Struct *Conn_Head;
91 
92 extern struct Conf_Struct ConfS;
93 extern unsigned short int Root;
94 
95 #if ARES
96   extern ares_channel Ares_Channel;
97 #endif
98 
99 #if SSL_SUPPORT
100   extern SSL_CTX *IRCPROXY_SSL_CLIENT_CTX;
101 #endif
102 
103 extern struct Client_Struct *Client_Head;
104 
105 /* CONN_CONNECT FUNCTION - JONAS (17.07.2001) */
106 
conn_connect(struct Conn_Struct * ConnS)107 void conn_connect(struct Conn_Struct *ConnS) {
108 
109   signed long int Result = 0;
110 #if !ARES
111     struct hostent *HostEnt = NULL;
112 #endif
113 
114   assert(ConnS != NULL);
115 
116   if (!Conn_IsConnectProc(ConnS)) {
117 
118     Conn_SetConnectProc(ConnS);
119     ConnS->ConnectProcTime = NOW;
120 
121     if (ConnS->ConnServerTry == NULL) {
122 
123       struct ConnServer_Struct *ConnServer = NULL;
124 
125       for (ConnServer = ConnS->Server_Head ; ConnServer != NULL ; ConnServer = ConnServer->Next) {
126         if ((ConnS->ConnServerTry == NULL) || (ConnServer->Tries < ConnS->ConnServerTry->Tries)) { ConnS->ConnServerTry = ConnServer; }
127       }
128       if (ConnS->ConnServerTry == NULL) { conn_disconnect(ConnS, "Connection %s: No servers to try.", ConnS->Name); return; }
129     }
130 
131     ++ConnS->ConnServerTry->Tries;
132     ConnS->ServerHostName = strrealloc(ConnS->ServerHostName, ConnS->ConnServerTry->Host);
133     ConnS->ServerName = strrealloc(ConnS->ServerName, ConnS->ConnServerTry->Host);
134     ConnS->ServerPortH = ConnS->ConnServerTry->Port;
135     ConnS->ServerPortN = htons(ConnS->ConnServerTry->Port);
136     ConnS->ServerPass = strrealloc(ConnS->ServerPass, ConnS->ConnServerTry->Pass);
137     ConnS->ConnServerTry = NULL;
138 
139   }
140 
141   if (!Host_IsHostToIP(ConnS->ResolveFlags)) {
142 
143     if (ConnS->Host[0] == '*') {
144 #if IPV6_SUPPORT
145       if (ConnConf_IsIPv6(ConnS)) {
146         memset(&ConnS->INAddr6, 0, sizeof(ConnS->INAddr6));
147         ConnS->INAddr6 = in6addr_any;
148       }
149       else {
150 #endif /* IPV6_SUPPORT */
151         memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr));
152         ConnS->INAddr.s_addr = INADDR_ANY;
153 #if IPV6_SUPPORT
154       }
155 #endif /* IPV6_SUPPORT */
156       Host_SetHostToIP(ConnS->ResolveFlags);
157     }
158     else {
159 #if IPV6_SUPPORT
160       if (ConnConf_IsIPv6(ConnS)) {
161         memset(&ConnS->INAddr6, 0, sizeof(ConnS->INAddr6));
162         Result = inet_pton(AF_INET6, ConnS->Host, &ConnS->INAddr6);
163       }
164       else {
165         memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr));
166         Result = inet_pton(AF_INET, ConnS->Host, &ConnS->INAddr);
167       }
168 #else /* IPV6_SUPPORT */
169       memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr));
170       Result = inet_aton(ConnS->Host, &ConnS->INAddr);
171 #endif /* IPV6_SUPPORT */
172       if (Result <= 0) {
173         ConnS->HostName = strrealloc(ConnS->HostName, ConnS->Host);
174         if (aerrno != AESUCCESS) {
175           conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
176           return;
177         }
178         Host_SetResolving(ConnS->ResolveFlags);
179         client_noticealluser(ConnS->User, "Connection %s: Resolving local hostname %s to IP-address.", ConnS->Name, ConnS->HostName);
180 #if ARES
181 #if IPV6_SUPPORT
182         if (ConnConf_IsIPv6(ConnS)) { ares_gethostbyname(Ares_Channel, ConnS->HostName, AF_INET6, (ares_host_callback) conn_hosttoip, ConnS); }
183         else {
184 #endif /* IPV6_SUPPORT */
185           ares_gethostbyname(Ares_Channel, ConnS->HostName, AF_INET, (ares_host_callback) conn_hosttoip, ConnS);
186 #if IPV6_SUPPORT
187         }
188 #endif /* IPV6_SUPPORT */
189         return;
190 #else /* ARES */
191 #if IPV6_SUPPORT
192         if (ConnConf_IsIPv6(ConnS)) { HostEnt = gethostbyname2(ConnS->HostName, AF_INET6); }
193         else { HostEnt = gethostbyname2(ConnS->HostName, AF_INET); }
194 #else /* IPV6_SUPPORT */
195         HostEnt = gethostbyname(ConnS->HostName);
196 #endif /* IPV6_SUPPORT */
197         conn_hosttoip(ConnS, errno, HostEnt);
198         if (!Host_IsHostToIP(ConnS->ResolveFlags)) { return; }
199 #endif /* ARES */
200       }
201       else {
202         ConnS->HostIPS = strrealloc(ConnS->HostIPS, ConnS->Host);
203         if (aerrno != AESUCCESS) {
204           conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
205           return;
206         }
207         ConnS->HostName = strrealloc(ConnS->HostName, ConnS->Host);
208         if (aerrno != AESUCCESS) {
209           conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
210           return;
211         }
212         Host_SetHostToIP(ConnS->ResolveFlags);
213       }
214     }
215   }
216   Host_SetResolved(ConnS->ResolveFlags);
217 
218  if (!Host_IsHostToIP(ConnS->ServerResolveFlags)) {
219 #if IPV6_SUPPORT
220     if (ConnConf_IsIPv6(ConnS)) {
221       memset(&ConnS->ServerINAddr6, 0, sizeof(ConnS->ServerINAddr6));
222       Result = inet_pton(AF_INET6, ConnS->ServerHostName, &ConnS->ServerINAddr6);
223     }
224     else {
225       memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr));
226       Result = inet_pton(AF_INET, ConnS->ServerHostName, &ConnS->ServerINAddr);
227     }
228 #else /* IPV6_SUPPORT */
229     memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr));
230     Result = inet_aton(ConnS->ServerHostName, &ConnS->ServerINAddr);
231 #endif /* IPV6_SUPPORT */
232     if (Result <= 0) {
233       Host_SetResolving(ConnS->ServerResolveFlags);
234       client_noticealluser(ConnS->User, "Connection %s: Resolving server hostname %s to IP-address.", ConnS->Name, ConnS->ServerHostName);
235 #if ARES
236 #if IPV6_SUPPORT
237       if (ConnConf_IsIPv6(ConnS)) { ares_gethostbyname(Ares_Channel, ConnS->ServerHostName, AF_INET6, (ares_host_callback) conn_serverhosttoip, ConnS); }
238       else {
239 #endif /* IPV6_SUPPORT */
240         ares_gethostbyname(Ares_Channel, ConnS->ServerHostName, AF_INET, (ares_host_callback) conn_serverhosttoip, ConnS);
241 #if IPV6_SUPPORT
242       }
243 #endif /* IPV6_SUPPORT */
244       return;
245 #else /* ARES */
246 #if IPV6_SUPPORT
247       if (ConnConf_IsIPv6(ConnS)) { HostEnt = gethostbyname2(ConnS->ServerHostName, AF_INET6); }
248       else { HostEnt = gethostbyname2(ConnS->ServerHostName, AF_INET); }
249 #else /* IPV6_SUPPORT */
250       HostEnt = gethostbyname(ConnS->ServerHostName);
251 #endif /* IPV6_SUPPORT */
252       conn_serverhosttoip(ConnS, errno, HostEnt);
253       if (!Host_IsHostToIP(ConnS->ServerResolveFlags)) { return; }
254 #endif /* ARES */
255     }
256     else {
257       ConnS->ServerHostIPS = strrealloc(ConnS->ServerHostIPS, ConnS->ServerHostName);
258       if (aerrno != AESUCCESS) {
259         conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
260         return;
261       }
262       Host_SetHostToIP(ConnS->ServerResolveFlags);
263     }
264   }
265   Host_SetResolved(ConnS->ServerResolveFlags);
266 
267   if (!Conn_IsSocket(ConnS)) {
268 
269 #if !WIN32
270     sysseteuidbyuser(ConnS->User);
271 #endif
272 #if IPV6_SUPPORT
273     if (ConnConf_IsIPv6(ConnS)) { Result = socket(AF_INET6, SOCK_STREAM, 0); }
274     else {
275 #endif
276       Result = socket(AF_INET, SOCK_STREAM, 0);
277 
278 #if IPV6_SUPPORT
279     }
280 #endif
281 #if !WIN32
282     sysseteuidnormal();
283 #endif
284     if (Result <= ERROR) {
285       conn_disconnect(ConnS, "Connection %s: Unable to create socket: [%d] %s", ConnS->Name, errno, strerror(errno));
286       return;
287     }
288     ConnS->FD = Result;
289     Conn_SetSocket(ConnS);
290 
291 #if SSL_SUPPORT
292     if (ConnConf_IsSSL(ConnS)) {
293       ConnS->SSL_H = SSL_new(IRCPROXY_SSL_CLIENT_CTX);
294       if (ConnS->SSL_H == NULL) {
295         conn_disconnect(ConnS, "Connection %s: Failed to create a new SSL structure: [%d] %s", ConnS->Name, errno, strerror(errno));
296         return;
297       }
298 
299       SSL_set_connect_state(ConnS->SSL_H);
300 
301       Result = SSL_set_fd(ConnS->SSL_H, ConnS->FD);
302       if (Result <= 0) {
303         signed long int sslerrno = SSL_get_error(ConnS->SSL_H, Result);
304         conn_disconnect(ConnS, "Connection %s: Unable to connect the SSL object with the file descriptor: [%ld] %s", ConnS->Name, sslerrno, ERR_error_string(sslerrno, NULL));
305         return;
306       }
307 
308     }
309 #endif
310 
311   }
312 
313   if (!Conn_IsSockOPT(ConnS)) {
314 
315     unsigned long int Flags = 0;
316 
317 #if defined(NBLOCK_SYSV)
318     Flags = 1;
319     Result = ioctl(ConnS->FD, FIONBIO, &Flags);
320     if (Result <= ERROR) {
321       conn_disconnect(ConnS, "Connection %s: Unable to set socket in non-blocking mode using ioctl(): [%d] %s", ConnS->Name, errno, strerror(errno));
322       return;
323     }
324 #else
325     Result = fcntl(ConnS->FD, F_GETFL);
326     if (Result <= ERROR) {
327       conn_disconnect(ConnS, "Connection %s: Unable to get socket flags using fcntl(): [%d] %s", ConnS->Name, errno, strerror(errno));
328       return;
329     }
330     Flags = Result;
331 #if defined(NBLOCK_BSD)
332     Flags |= O_NDELAY;
333 #elif defined(NBLOCK_POSIX)
334     Flags |= O_NONBLOCK;
335 #else
336     #warning "This system does not support non-blocking sockets?"
337     Flags |= O_NONBLOCK;
338 #endif
339     Result = fcntl(ConnS->FD, F_SETFL, Flags);
340     if (Result <= ERROR) {
341       conn_disconnect(ConnS, "Connection %s: Unable to set socket in non-blocking mode using fcntl(): [%d] %s", ConnS->Name, errno, strerror(errno));
342       return;
343     }
344 #endif
345 
346     Conn_SetSockOPT(ConnS);
347 
348   }
349 
350   if ((CONN_SOCKKEEPALIVEOPT == TRUE) && (!Conn_IsKeepAliveOPT(ConnS))) {
351 
352     unsigned long int OPT = 1;
353 
354     Result = setsockopt(ConnS->FD, SOL_SOCKET, SO_KEEPALIVE, &OPT, sizeof(OPT));
355     if (Result <= ERROR) {
356       conn_disconnect(ConnS, "Connection %s: Unable to set Keep Alive option for socket: [%d] %s", ConnS->Name, errno, strerror(errno));
357       return;
358     }
359 
360     Conn_SetKeepAliveOPT(ConnS);
361 
362   }
363 
364   if (!Conn_IsBound(ConnS)) {
365 
366     struct sockaddr_in SockAddr = { 0 };
367 #if IPV6_SUPPORT
368     struct sockaddr_in6 SockAddr6 = { 0 };
369 #endif
370 
371 #if IPV6_SUPPORT
372     if (ConnConf_IsIPv6(ConnS)) {
373       memset(&SockAddr6, 0, sizeof(SockAddr6));
374       SockAddr6.sin6_family = AF_INET6;
375       SockAddr6.sin6_addr = ConnS->INAddr6;
376       SockAddr6.sin6_port = 0;
377       Result = bind(ConnS->FD, (struct sockaddr *) &SockAddr6, sizeof(SockAddr6));
378     }
379     else {
380 #endif
381       memset(&SockAddr, 0, sizeof(SockAddr));
382       SockAddr.sin_family = AF_INET;
383       SockAddr.sin_addr = ConnS->INAddr;
384       SockAddr.sin_port = 0;
385       Result = bind(ConnS->FD, (struct sockaddr *) &SockAddr, sizeof(SockAddr));
386 #if IPV6_SUPPORT
387     }
388 #endif
389     if (Result <= ERROR) {
390       conn_disconnect(ConnS, "Connection %s: Unable to bind socket to %s(%s): [%d] %s", ConnS->Name, ConnS->HostName, ConnS->HostIPS, errno, strerror(errno));
391       return;
392     }
393     Conn_SetBound(ConnS);
394 
395   }
396 
397   if (!Conn_IsConnect(ConnS)) {
398 
399     struct sockaddr_in SockAddr = { 0 };
400 #if IPV6_SUPPORT
401     struct sockaddr_in6 SockAddr6 = { 0 };
402 #endif
403 
404     client_noticealluser(ConnS->User, "Connection %s: Connecting to server %s(%s):%ld%s.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, (ConnConf_IsSSL(ConnS) ? " (SSL)" : ""));
405 
406 #if IPV6_SUPPORT
407     if (ConnConf_IsIPv6(ConnS)) {
408       memset(&SockAddr6, 0, sizeof(SockAddr6));
409       SockAddr6.sin6_family = AF_INET6;
410       SockAddr6.sin6_addr = ConnS->ServerINAddr6;
411       SockAddr6.sin6_port = ConnS->ServerPortN;
412       Result = connect(ConnS->FD, (struct sockaddr *) &SockAddr6, sizeof(SockAddr6));
413     }
414     else {
415 #endif
416       memset(&SockAddr, 0, sizeof(SockAddr));
417       SockAddr.sin_family = AF_INET;
418       SockAddr.sin_addr = ConnS->ServerINAddr;
419       SockAddr.sin_port = ConnS->ServerPortN;
420       Result = connect(ConnS->FD, (struct sockaddr *) &SockAddr, sizeof(SockAddr));
421 #if IPV6_SUPPORT
422     }
423 #endif
424     if (Result <= ERROR) {
425       if (errno == EINPROGRESS) {
426         Conn_SetConnecting(ConnS);
427         ConnS->ConnectTime = NOW;
428         conn_logon(ConnS);
429         return;
430       }
431       else {
432         conn_disconnect(ConnS, "Connection %s: Unable to connect to %s(%s):%ld%s: [%d] %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, (ConnConf_IsSSL(ConnS) ? " (SSL)" : ""), errno, strerror(errno));
433         return;
434       }
435     }
436     else {
437       Conn_SetConnected(ConnS);
438       ConnS->ConnectTime = NOW;
439       ConnS->ConnectedTime = NOW;
440       conn_logon(ConnS);
441       client_noticealluser(ConnS->User, "Connection %s: Socket connected to %s(%s):%ld.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH);
442     }
443   }
444 
445   if (!Conn_IsConnected(ConnS)) {
446 
447     int Error = 0;
448     getsockopt_optlen_type ErrorLen = sizeof(Error);
449 
450     Result = getsockopt(ConnS->FD, SOL_SOCKET, SO_ERROR, &Error, &ErrorLen);
451     if (Result <= ERROR) {
452       conn_disconnect(ConnS, "Connection %s: Unable to get connection result for %s(%s):%ld%s: [%d] %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, (ConnConf_IsSSL(ConnS) ? " (SSL)" : ""), errno, strerror(errno));
453       return;
454     }
455     if (Error != SUCCESS) {
456       conn_disconnect(ConnS, "Connection %s: Unable to connect to %s(%s):%ld%s: [%d] %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, (ConnConf_IsSSL(ConnS) ? " (SSL)" : ""), Error, strerror(Error));
457       return;
458     }
459 
460     client_noticealluser(ConnS->User, "Connection %s: Socket connected to %s(%s):%ld%s.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, (ConnConf_IsSSL(ConnS) ? " (SSL)" : ""));
461     Conn_ClearConnecting(ConnS);
462     Conn_SetConnected(ConnS);
463     ConnS->ConnectedTime = NOW;
464 
465   }
466 
467   if (!Conn_IsSockName(ConnS)) {
468 
469     struct sockaddr_in SockAddr = { 0 };
470     getsockname_namelen_type SockAddrLen = sizeof(SockAddr);
471 
472     memset(&SockAddr, 0, sizeof(SockAddr));
473     Result = getsockname(ConnS->FD, (struct sockaddr *) &SockAddr, &SockAddrLen);
474     if (Result <= ERROR) {
475       conn_disconnect(ConnS, "Connection %s: Unable to get socket name for %s(%s):%ld%s: [%d] %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, (ConnConf_IsSSL(ConnS) ? " (SSL)" : ""), errno, strerror(errno));
476       return;
477     }
478 
479     ConnS->PortN = SockAddr.sin_port;
480     ConnS->PortH = ntohs(ConnS->PortN);
481     Conn_SetSockName(ConnS);
482 
483   }
484 
485 #if SSL_SUPPORT
486 
487   if ((ConnConf_IsSSL(ConnS)) && (!Conn_IsSSLHandshake(ConnS))) {
488     DEBUGPRINT(BITMASK_MAIN, "Connection %s: Doing SSL Handshake.", ConnS->Name);
489     Result = SSL_connect(ConnS->SSL_H);
490     if (Result <= 0) {
491       signed long int sslerrno = SSL_get_error(ConnS->SSL_H, Result);
492       if ((sslerrno == SSL_ERROR_WANT_READ) || (sslerrno == SSL_ERROR_WANT_WRITE)) { return; }
493       conn_disconnect(ConnS, "Connection %s: Failed SSL Handshake for %s(%s):%ld: [%ld] %s.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, sslerrno, ERR_error_string(sslerrno, NULL));
494       return;
495     }
496     Conn_SetSSLHandshake(ConnS);
497     ConnS->Cert = SSL_get_peer_certificate(ConnS->SSL_H);
498     sysprint(BITMASK_MAIN, "Connection %s: SSL Handshake completed successfully.", ConnS->Name);
499   }
500 
501 #endif
502 
503   Conn_ClearConnectProc(ConnS); /* MISSION COMPLETE! */
504 
505 }
506 
507 /* CONN_DISCONNECT FUNCTION - JONAS (01.07.2000) */
508 
conn_disconnect(struct Conn_Struct * ConnS,const char * const LinePT,...)509 void conn_disconnect(struct Conn_Struct *ConnS, const char *const LinePT, ...) {
510 
511   char Line[IRC_NOTICELEN+1] = "";
512   va_list Args;
513   struct Client_Struct *ClientS = NULL;
514 
515   assert(ConnS != NULL);
516   assert(LinePT != NULL);
517 
518   va_start(Args, LinePT);
519   vsnprintf(Line, IRC_NOTICELEN+1, LinePT, Args);
520   va_end(Args);
521 
522   client_noticealluser(ConnS->User, "%s", Line);
523 
524   if (Conn_IsWelcome(ConnS)) {
525     for (ClientS = Client_Head ; ClientS != NULL ; ClientS = ClientS->Next) {
526       if (ClientS->ConnS == ConnS) { client_close(ClientS, "Disconnected from attached connection %s server %s(%s):%ld.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH); }
527     }
528   }
529 
530 #if SSL_SUPPORT
531   if (ConnConf_IsSSL(ConnS)) {
532     if (ConnS->Cert != NULL) {
533       X509_free(ConnS->Cert);
534       ConnS->Cert = NULL;
535     }
536     if (ConnS->SSL_H != NULL) {
537       SSL_shutdown(ConnS->SSL_H);
538       SSL_free(ConnS->SSL_H);
539       ConnS->SSL_H = NULL;
540     }
541   }
542 #endif /* SSL_SUPPORT */
543 
544   if (Conn_IsSocket(ConnS)) {
545     close(ConnS->FD);
546     ConnS->FD = FD_NONE;
547   }
548 
549   conn_initconnection(ConnS);
550 
551   if (ConnS->ConnServerTry != NULL) { conn_connect(ConnS); }
552 
553 }
554 
555 /* CONN_HOSTTOIP FUNCTION - JONAS (01.03.2000) */
556 
557 #if HAVE_CARES_CALLBACK_TIMEOUTS
conn_hosttoip(void * ArgPT,int ErrNo,int Timeouts,struct hostent * HostEnt)558 void conn_hosttoip(void *ArgPT, int ErrNo, int Timeouts, struct hostent *HostEnt) {
559 #else
560 void conn_hosttoip(void *ArgPT, int ErrNo, struct hostent *HostEnt) {
561 #endif
562 
563   struct Conn_Struct *ConnS = ArgPT;
564   const char *HostIPPT = NULL;
565 #if IPV6_SUPPORT
566   char Host[INET6_ADDRSTRLEN+1] = "";
567 #endif
568 
569   assert(ConnS != NULL);
570 
571   Host_ClearResolving(ConnS->ResolveFlags);
572 
573   if ((HostEnt == NULL) || (HostEnt->h_length < 1)) {
574     conn_disconnect(ConnS, "Connection %s: Unable to resolve hostname %s to IP-address: [%d] %s", ConnS->Name, ConnS->HostName, ErrNo, res_strerror(ErrNo));
575     return;
576   }
577 #if IPV6_SUPPORT
578   if (ConnConf_IsIPv6(ConnS)) {
579     memset(&ConnS->INAddr6, 0, sizeof(ConnS->INAddr6));
580     memcpy(&ConnS->INAddr6, HostEnt->h_addr, HostEnt->h_length);
581     HostIPPT = inet_ntop(AF_INET6, &ConnS->INAddr6, Host, INET6_ADDRSTRLEN);
582     if (HostIPPT == NULL) {
583       conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
584       return;
585     }
586   }
587   else {
588     memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr));
589     memcpy(&ConnS->INAddr, HostEnt->h_addr, HostEnt->h_length);
590     HostIPPT = inet_ntop(AF_INET, &ConnS->INAddr, Host, INET6_ADDRSTRLEN);
591     if (HostIPPT == NULL) {
592       conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
593       return;
594     }
595   }
596 #else /* IPV6_SUPPORT */
597   memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr));
598   memcpy(&ConnS->INAddr, HostEnt->h_addr, HostEnt->h_length);
599   HostIPPT = inet_ntoa(ConnS->INAddr);
600   if (HostIPPT == NULL) {
601     conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
602     return;
603   }
604 #endif /* IPV6_SUPPORT */
605   ConnS->HostIPS = strrealloc(ConnS->HostIPS, HostIPPT);
606   if (ConnS->HostIPS == NULL) {
607     conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
608     return;
609   }
610 
611   client_noticealluser(ConnS->User, "Connection %s: Resolved hostname %s to IP-address %s.", ConnS->Name, ConnS->HostName, ConnS->HostIPS);
612 
613   Host_SetHostToIP(ConnS->ResolveFlags);
614 
615 #if ARES
616   conn_connect(ConnS);
617 #endif
618 
619 }
620 
621 /* CONN_SERVERHOSTTOIP FUNCTION - JONAS (01.03.2000) */
622 
623 #if HAVE_CARES_CALLBACK_TIMEOUTS
624 void conn_serverhosttoip(void *ArgPT, int ErrNo, int Timeouts, struct hostent *HostEnt) {
625 #else
626 void conn_serverhosttoip(void *ArgPT, int ErrNo, struct hostent *HostEnt) {
627 #endif
628 
629   struct Conn_Struct *ConnS = ArgPT;
630   const char *HostIPPT = NULL;
631 #if IPV6_SUPPORT
632   char Host[INET6_ADDRSTRLEN+1] = "";
633 #endif
634 
635   assert(ConnS != NULL);
636 
637   Host_ClearResolving(ConnS->ServerResolveFlags);
638 
639   if ((HostEnt == NULL) || (HostEnt->h_length < 1)) {
640     conn_disconnect(ConnS, "Connection %s: Unable to resolve server hostname %s to IP-Address: [%d] %s", ConnS->Name, ConnS->ServerHostName, ErrNo, res_strerror(ErrNo));
641     return;
642   }
643 
644 #if IPV6_SUPPORT
645   if (ConnConf_IsIPv6(ConnS)) {
646     memset(&ConnS->ServerINAddr6, 0, sizeof(ConnS->ServerINAddr6));
647     memcpy(&ConnS->ServerINAddr6, HostEnt->h_addr, HostEnt->h_length);
648     HostIPPT = inet_ntop(AF_INET6, &ConnS->ServerINAddr6, Host, INET6_ADDRSTRLEN);
649     if (HostIPPT == NULL) {
650       conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
651       return;
652     }
653   }
654   else {
655     memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr));
656     memcpy(&ConnS->ServerINAddr, HostEnt->h_addr, HostEnt->h_length);
657     HostIPPT = inet_ntop(AF_INET, &ConnS->ServerINAddr, Host, INET6_ADDRSTRLEN);
658     if (HostIPPT == NULL) {
659       conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
660       return;
661     }
662   }
663 #else /* IPV6_SUPPORT */
664   memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr));
665   memcpy(&ConnS->ServerINAddr, HostEnt->h_addr, HostEnt->h_length);
666   HostIPPT = inet_ntoa(ConnS->ServerINAddr);
667   if (HostIPPT == NULL) {
668     conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
669     return;
670   }
671 #endif /* IPV6_SUPPORT */
672   ConnS->ServerHostIPS = strrealloc(ConnS->ServerHostIPS, HostIPPT);
673   if (ConnS->ServerHostIPS == NULL) {
674     conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
675     return;
676   }
677 
678   client_noticealluser(ConnS->User, "Connection %s: Resolved server hostname %s to IP-address %s.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS);
679 
680   Host_SetHostToIP(ConnS->ServerResolveFlags);
681 
682 #if ARES
683   conn_connect(ConnS);
684 #endif
685 
686 }
687 
688 /* CONN_LOGON FUNCTION - JONAS (01.07.2000) */
689 
690 void conn_logon(struct Conn_Struct *ConnS) {
691 
692   char *NickPT = ConnS->Nick;
693   char *InfoPT = ConnS->Info;
694 
695   assert(ConnS != NULL);
696 
697   if (ConnS->NumClients <= 0) {
698     NickPT = ConnS->AwayNick;
699     Conn_SetSentAwayNick(ConnS);
700   }
701   else {
702     NickPT = ConnS->Nick;
703     Conn_SetSentNick(ConnS);
704   }
705 
706 if ((ConfS.UnixPasswd == TRUE) && (Root == TRUE)) {
707   if (strcmp(ConnS->Info, "0") == FALSE) {
708     InfoPT = sysgetnamefromuser(ConnS->User);
709     if (InfoPT == NULL) { InfoPT = "0"; }
710   }
711 }
712 
713   if ((ConnS->ServerPass != NULL) && (strcmp(ConnS->ServerPass, CONN_CONF_SERVERPASS_NONE) != FALSE)) {
714     conn_addsendq(ConnS, "PASS %s", ConnS->ServerPass);
715   }
716   conn_addsendq(ConnS, "NICK %s", NickPT);
717   conn_addsendq(ConnS, "USER %s 0 0 :%s", ConnS->User, InfoPT);
718 
719 }
720 
721 /* CONN_ADDSEND FUNCTION - JONAS (01.07.2000) */
722 
723 void conn_addsend(struct Conn_Struct *ConnS, const char *const LinePT) {
724 
725   char LineCRLF[IRC_MSGCRLFLEN+1] = "";
726   unsigned long int Len = 0;
727   unsigned long int OldLen = 0;
728   unsigned long int NewLen = 0;
729   char *SendBufferPT = NULL;
730 
731   assert(ConnS != NULL);
732   assert(LinePT != NULL);
733   assert(Conn_IsSocket(ConnS));
734 
735   snprintf(LineCRLF, IRC_MSGCRLFLEN+1, "%s\r\n", LinePT);
736 
737   Len = strlen(LineCRLF);
738   if (ConnS->SendBuffer == NULL) { OldLen = 0; }
739   else { OldLen = strlen(ConnS->SendBuffer); }
740   NewLen = OldLen + Len + 1;
741   SendBufferPT = realloc(ConnS->SendBuffer, NewLen);
742   if (SendBufferPT == NULL) { return; }
743   ConnS->SendBuffer = SendBufferPT;
744   SendBufferPT = SendBufferPT + OldLen;
745   strcpy(SendBufferPT, LineCRLF);
746 
747   DEBUGPRINT(BITMASK_DEBUG_CONN_SEND, "Connection %s: Server: %s: Send: %s", ConnS->Name, ConnS->ServerHostName, LinePT);
748 
749 }
750 
751 /* CONN_QUIT FUNCTION - JONAS (09.06.2001) */
752 
753 void conn_quit(struct Conn_Struct *ConnS, const char *const MessagePT, ...) {
754 
755   char Message[IRC_QUITMSGLEN+1] = "";
756   va_list Args;
757 
758   assert(ConnS != NULL);
759   assert(Conn_IsWelcome(ConnS));
760   assert(MessagePT != NULL);
761 
762   va_start(Args, MessagePT);
763   vsnprintf(Message, IRC_QUITMSGLEN+1, MessagePT, Args);
764   va_end(Args);
765 
766   if (!Conn_IsSentQuit(ConnS)) {
767     Conn_SetSentQuit(ConnS);
768     ConnS->SentQuitTime = time(NULL);
769     conn_initsendq(ConnS);
770     conn_initflushl(ConnS);
771     conn_initflushb(ConnS);
772     conn_addsendq(ConnS, "QUIT :%s", Message);
773     client_noticealluser(ConnS->User, "Connection %s: Quitting %s(%s):%ld \"%s\": %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, ConnS->ServerName, Message);
774   }
775 
776 }
777 
778 /* CONN_CLOSEALL FUNCTION - JONAS (09.06.2001) */
779 
780 unsigned short int conn_closeall(const char *const MessagePT, ...) {
781 
782   char Message[LINELEN+1] = "";
783   va_list Args;
784   unsigned short int Count = 0;
785   struct Conn_Struct *ConnS = NULL;
786 
787   assert(MessagePT != NULL);
788 
789   va_start(Args, MessagePT);
790   vsnprintf(Message, LINELEN+1, MessagePT, Args);
791   va_end(Args);
792 
793   for (ConnS = Conn_Head ; ConnS != NULL ; ConnS = ConnS->Next) {
794     if ((Host_IsResolving(ConnS->ResolveFlags)) || (Host_IsResolving(ConnS->ServerResolveFlags))) {
795 #if HAVE_ARES_CANCELQUERY
796       ares_cancelquery(Ares_Channel, ConnS);
797 #endif
798     }
799     if (Conn_IsSocket(ConnS)) {
800       if (Conn_IsWelcome(ConnS)) {
801         if (!Conn_IsSentQuit(ConnS)) { conn_quit(ConnS, "%s", Message); }
802       }
803       else {
804         conn_disconnect(ConnS, "Connection %s: %s", ConnS->Name, Message);
805       }
806     }
807     Conn_SetRemove(ConnS);
808     ++Count;
809   }
810 
811   return(Count);
812 
813 }
814