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