/* * ---------------------------------------------------------------- * Night Light IRC Proxy - Connection Functions * ---------------------------------------------------------------- * Copyright (C) 1997-2007 Jonas Kvinge * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Last modified by: * Jonas Kvinge (24.11.2007) * */ #define CONN_CONNECTION_C #define NEED_SYS_TYPES_H 1 /* Extra types */ #define NEED_SYS_PARAM_H 1 /* Some systems need this */ #define NEED_LIMITS_H 0 /* Kernel limits */ #define NEED_STDARG_H 1 /* va_list, etc */ #define NEED_ERRNO_H 1 /* errno */ #define NEED_CTYPE_H 1 /* isdigit(), etc */ #define NEED_NETINET_IN_H 1 /* in_addr, sockaddr_in, etc */ #define NEED_ARPA_INET_H 1 /* inet_ntoa(), inet_aton(), etc */ #define NEED_STDIO_H 1 /* Standard C UNIX functions */ #define NEED_STDLIB_H 1 /* malloc(), exit(), atoi(), etc */ #define NEED_TIME_H 1 /* time(), etc */ #define NEED_SYSCTL_H 0 /* sysctl(), etc */ #define NEED_SYS_STAT_H 0 /* chmod(), mkdir(), etc */ #define NEED_SYS_UIO_H 0 /* iovec, etc */ #define NEED_FCNTL_H 1 /* open(), creat(), fcntl(), etc */ #define NEED_SYS_IOCTL_H 1 /* ioctl(), etc */ #define NEED_SYS_FILIO_H 1 /* Solaris need this for ioctl(), etc */ #define NEED_UNISTD_H 1 /* Unix standard functions */ #define NEED_STRING_H 1 /* C string functions */ #define NEED_SIGNAL_H 0 /* Signal functions */ #define NEED_SYS_SOCKET_H 1 /* Socket functions */ #define NEED_NETDB_H 1 /* Network database functions */ #define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */ #define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */ #define NEED_ARES 1 /* Functions needed for ares */ #define NEED_SSL 1 /* Needed for SSL support */ #include "includes.h" #include "irc.h" #include "conf.h" #include "access_conf.h" #include "conn_conf.h" #include "conn.h" #include "conn_io.h" #if SSL_SUPPORT #include "conn_io_ssl.h" #endif #include "conn_connection.h" #include "conn_sendq.h" #include "conn_log.h" #include "conn_parser.h" #include "conn_ignore.h" #include "client.h" #include "client_connection.h" #include "client_notice.h" #include "chan.h" #include "chan_user.h" /* VARIABLES - JONAS (31.07.2001) */ extern struct Conn_Struct *Conn_Head; extern struct Conf_Struct ConfS; extern unsigned short int Root; #if ARES extern ares_channel Ares_Channel; #endif #if SSL_SUPPORT extern SSL_CTX *IRCPROXY_SSL_CLIENT_CTX; #endif extern struct Client_Struct *Client_Head; /* CONN_CONNECT FUNCTION - JONAS (17.07.2001) */ void conn_connect(struct Conn_Struct *ConnS) { signed long int Result = 0; #if !ARES struct hostent *HostEnt = NULL; #endif assert(ConnS != NULL); if (!Conn_IsConnectProc(ConnS)) { Conn_SetConnectProc(ConnS); ConnS->ConnectProcTime = NOW; if (ConnS->ConnServerTry == NULL) { struct ConnServer_Struct *ConnServer = NULL; for (ConnServer = ConnS->Server_Head ; ConnServer != NULL ; ConnServer = ConnServer->Next) { if ((ConnS->ConnServerTry == NULL) || (ConnServer->Tries < ConnS->ConnServerTry->Tries)) { ConnS->ConnServerTry = ConnServer; } } if (ConnS->ConnServerTry == NULL) { conn_disconnect(ConnS, "Connection %s: No servers to try.", ConnS->Name); return; } } ++ConnS->ConnServerTry->Tries; ConnS->ServerHostName = strrealloc(ConnS->ServerHostName, ConnS->ConnServerTry->Host); ConnS->ServerName = strrealloc(ConnS->ServerName, ConnS->ConnServerTry->Host); ConnS->ServerPortH = ConnS->ConnServerTry->Port; ConnS->ServerPortN = htons(ConnS->ConnServerTry->Port); ConnS->ServerPass = strrealloc(ConnS->ServerPass, ConnS->ConnServerTry->Pass); ConnS->ConnServerTry = NULL; } if (!Host_IsHostToIP(ConnS->ResolveFlags)) { if (ConnS->Host[0] == '*') { #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { memset(&ConnS->INAddr6, 0, sizeof(ConnS->INAddr6)); ConnS->INAddr6 = in6addr_any; } else { #endif /* IPV6_SUPPORT */ memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr)); ConnS->INAddr.s_addr = INADDR_ANY; #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ Host_SetHostToIP(ConnS->ResolveFlags); } else { #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { memset(&ConnS->INAddr6, 0, sizeof(ConnS->INAddr6)); Result = inet_pton(AF_INET6, ConnS->Host, &ConnS->INAddr6); } else { memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr)); Result = inet_pton(AF_INET6, ConnS->Host, &ConnS->INAddr); } #else /* IPV6_SUPPORT */ memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr)); Result = inet_aton(ConnS->Host, &ConnS->INAddr); #endif /* IPV6_SUPPORT */ if (Result <= 0) { ConnS->HostName = strrealloc(ConnS->HostName, ConnS->Host); if (aerrno != AESUCCESS) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } Host_SetResolving(ConnS->ResolveFlags); client_noticealluser(ConnS->User, "Connection %s: Resolving local hostname %s to IP-address.", ConnS->Name, ConnS->HostName); #if ARES #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { ares_gethostbyname(Ares_Channel, ConnS->HostName, AF_INET6, (ares_host_callback) conn_hosttoip, ConnS); } else { #endif /* IPV6_SUPPORT */ ares_gethostbyname(Ares_Channel, ConnS->HostName, AF_INET, (ares_host_callback) conn_hosttoip, ConnS); #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ return; #else /* ARES */ #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { HostEnt = gethostbyname2(ConnS->HostName, AF_INET6); } else { HostEnt = gethostbyname2(ConnS->HostName, AF_INET); } #else /* IPV6_SUPPORT */ HostEnt = gethostbyname(ConnS->HostName); #endif /* IPV6_SUPPORT */ conn_hosttoip(ConnS, errno, HostEnt); if (!Host_IsHostToIP(ConnS->ResolveFlags)) { return; } #endif /* ARES */ } else { ConnS->HostIPS = strrealloc(ConnS->HostIPS, ConnS->Host); if (aerrno != AESUCCESS) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } ConnS->HostName = strrealloc(ConnS->HostName, ConnS->Host); if (aerrno != AESUCCESS) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } Host_SetHostToIP(ConnS->ResolveFlags); } } } Host_SetResolved(ConnS->ResolveFlags); if (!Host_IsHostToIP(ConnS->ServerResolveFlags)) { #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { memset(&ConnS->ServerINAddr6, 0, sizeof(ConnS->ServerINAddr6)); Result = inet_pton(AF_INET6, ConnS->ServerHostName, &ConnS->ServerINAddr6); } else { memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr)); Result = inet_pton(AF_INET6, ConnS->ServerHostName, &ConnS->ServerINAddr); } #else /* IPV6_SUPPORT */ memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr)); Result = inet_aton(ConnS->ServerHostName, &ConnS->ServerINAddr); #endif /* IPV6_SUPPORT */ if (Result <= 0) { Host_SetResolving(ConnS->ServerResolveFlags); client_noticealluser(ConnS->User, "Connection %s: Resolving server hostname %s to IP-address.", ConnS->Name, ConnS->ServerHostName); #if ARES #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { ares_gethostbyname(Ares_Channel, ConnS->ServerHostName, AF_INET6, (ares_host_callback) conn_serverhosttoip, ConnS); } else { #endif /* IPV6_SUPPORT */ ares_gethostbyname(Ares_Channel, ConnS->ServerHostName, AF_INET, (ares_host_callback) conn_serverhosttoip, ConnS); #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ return; #else /* ARES */ #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { HostEnt = gethostbyname2(ConnS->ServerHostName, AF_INET6); } else { HostEnt = gethostbyname2(ConnS->ServerHostName, AF_INET); } #else /* IPV6_SUPPORT */ HostEnt = gethostbyname(ConnS->ServerHostName); #endif /* IPV6_SUPPORT */ conn_serverhosttoip(ConnS, errno, HostEnt); if (!Host_IsHostToIP(ConnS->ServerResolveFlags)) { return; } #endif /* ARES */ } else { ConnS->ServerHostIPS = strrealloc(ConnS->ServerHostIPS, ConnS->ServerHostName); if (aerrno != AESUCCESS) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } Host_SetHostToIP(ConnS->ServerResolveFlags); } } Host_SetResolved(ConnS->ServerResolveFlags); if (!Conn_IsSocket(ConnS)) { #if !WIN32 sysseteuidbyuser(ConnS->User); #endif #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { Result = socket(AF_INET6, SOCK_STREAM, 0); } else { #endif Result = socket(AF_INET, SOCK_STREAM, 0); #if IPV6_SUPPORT } #endif #if !WIN32 sysseteuidnormal(); #endif if (Result <= ERROR) { conn_disconnect(ConnS, "Connection %s: Unable to create socket: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } ConnS->FD = Result; Conn_SetSocket(ConnS); #if SSL_SUPPORT if (ConnConf_IsSSL(ConnS)) { ConnS->SSL_H = SSL_new(IRCPROXY_SSL_CLIENT_CTX); if (ConnS->SSL_H == NULL) { conn_disconnect(ConnS, "Connection %s: Failed to create a new SSL structure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } SSL_set_connect_state(ConnS->SSL_H); Result = SSL_set_fd(ConnS->SSL_H, ConnS->FD); if (Result <= 0) { signed long int sslerrno = SSL_get_error(ConnS->SSL_H, Result); 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)); return; } } #endif } if (!Conn_IsSockOPT(ConnS)) { unsigned long int Flags = 0; #if defined(NBLOCK_SYSV) Flags = 1; Result = ioctl(ConnS->FD, FIONBIO, &Flags); if (Result <= ERROR) { conn_disconnect(ConnS, "Connection %s: Unable to set socket in non-blocking mode using ioctl(): [%d] %s", ConnS->Name, errno, strerror(errno)); return; } #else Result = fcntl(ConnS->FD, F_GETFL); if (Result <= ERROR) { conn_disconnect(ConnS, "Connection %s: Unable to get socket flags using fcntl(): [%d] %s", ConnS->Name, errno, strerror(errno)); return; } Flags = Result; #if defined(NBLOCK_BSD) Flags |= O_NDELAY; #elif defined(NBLOCK_POSIX) Flags |= O_NONBLOCK; #else #warning "This system does not support non-blocking sockets?" Flags |= O_NONBLOCK; #endif Result = fcntl(ConnS->FD, F_SETFL, Flags); if (Result <= ERROR) { conn_disconnect(ConnS, "Connection %s: Unable to set socket in non-blocking mode using fcntl(): [%d] %s", ConnS->Name, errno, strerror(errno)); return; } #endif Conn_SetSockOPT(ConnS); } if ((CONN_SOCKKEEPALIVEOPT == TRUE) && (!Conn_IsKeepAliveOPT(ConnS))) { unsigned long int OPT = 1; Result = setsockopt(ConnS->FD, SOL_SOCKET, SO_KEEPALIVE, &OPT, sizeof(OPT)); if (Result <= ERROR) { conn_disconnect(ConnS, "Connection %s: Unable to set Keep Alive option for socket: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } Conn_SetKeepAliveOPT(ConnS); } if (!Conn_IsBound(ConnS)) { struct sockaddr_in SockAddr = { 0 }; #if IPV6_SUPPORT struct sockaddr_in6 SockAddr6 = { 0 }; #endif #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { memset(&SockAddr6, 0, sizeof(SockAddr6)); SockAddr6.sin6_family = AF_INET6; SockAddr6.sin6_addr = ConnS->INAddr6; SockAddr6.sin6_port = 0; Result = bind(ConnS->FD, (struct sockaddr *) &SockAddr6, sizeof(SockAddr6)); } else { #endif memset(&SockAddr, 0, sizeof(SockAddr)); SockAddr.sin_family = AF_INET; SockAddr.sin_addr = ConnS->INAddr; SockAddr.sin_port = 0; Result = bind(ConnS->FD, (struct sockaddr *) &SockAddr, sizeof(SockAddr)); #if IPV6_SUPPORT } #endif if (Result <= ERROR) { conn_disconnect(ConnS, "Connection %s: Unable to bind socket to %s(%s): [%d] %s", ConnS->Name, ConnS->HostName, ConnS->HostIPS, errno, strerror(errno)); return; } Conn_SetBound(ConnS); } if (!Conn_IsConnect(ConnS)) { struct sockaddr_in SockAddr = { 0 }; #if IPV6_SUPPORT struct sockaddr_in6 SockAddr6 = { 0 }; #endif 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)" : "")); #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { memset(&SockAddr6, 0, sizeof(SockAddr6)); SockAddr6.sin6_family = AF_INET6; SockAddr6.sin6_addr = ConnS->ServerINAddr6; SockAddr6.sin6_port = ConnS->ServerPortN; Result = connect(ConnS->FD, (struct sockaddr *) &SockAddr6, sizeof(SockAddr6)); } else { #endif memset(&SockAddr, 0, sizeof(SockAddr)); SockAddr.sin_family = AF_INET; SockAddr.sin_addr = ConnS->ServerINAddr; SockAddr.sin_port = ConnS->ServerPortN; Result = connect(ConnS->FD, (struct sockaddr *) &SockAddr, sizeof(SockAddr)); #if IPV6_SUPPORT } #endif if (Result <= ERROR) { if (errno == EINPROGRESS) { Conn_SetConnecting(ConnS); ConnS->ConnectTime = NOW; conn_logon(ConnS); return; } else { 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)); return; } } else { Conn_SetConnected(ConnS); ConnS->ConnectTime = NOW; ConnS->ConnectedTime = NOW; conn_logon(ConnS); client_noticealluser(ConnS->User, "Connection %s: Socket connected to %s(%s):%ld.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH); } } if (!Conn_IsConnected(ConnS)) { int Error = 0; getsockopt_optlen_type ErrorLen = sizeof(Error); Result = getsockopt(ConnS->FD, SOL_SOCKET, SO_ERROR, &Error, &ErrorLen); if (Result <= ERROR) { 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)); return; } if (Error != SUCCESS) { 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)); return; } 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)" : "")); Conn_ClearConnecting(ConnS); Conn_SetConnected(ConnS); ConnS->ConnectedTime = NOW; } if (!Conn_IsSockName(ConnS)) { struct sockaddr_in SockAddr = { 0 }; getsockname_namelen_type SockAddrLen = sizeof(SockAddr); memset(&SockAddr, 0, sizeof(SockAddr)); Result = getsockname(ConnS->FD, (struct sockaddr *) &SockAddr, &SockAddrLen); if (Result <= ERROR) { 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)); return; } ConnS->PortN = SockAddr.sin_port; ConnS->PortH = ntohs(ConnS->PortN); Conn_SetSockName(ConnS); } #if SSL_SUPPORT if ((ConnConf_IsSSL(ConnS)) && (!Conn_IsSSLHandshake(ConnS))) { DEBUGPRINT(BITMASK_MAIN, "Connection %s: Doing SSL Handshake.", ConnS->Name); Result = SSL_connect(ConnS->SSL_H); if (Result <= 0) { signed long int sslerrno = SSL_get_error(ConnS->SSL_H, Result); if ((sslerrno == SSL_ERROR_WANT_READ) || (sslerrno == SSL_ERROR_WANT_WRITE)) { return; } 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)); return; } Conn_SetSSLHandshake(ConnS); ConnS->Cert = SSL_get_peer_certificate(ConnS->SSL_H); sysprint(BITMASK_MAIN, "Connection %s: SSL Handshake completed successfully.", ConnS->Name); } #endif Conn_ClearConnectProc(ConnS); /* MISSION COMPLETE! */ } /* CONN_DISCONNECT FUNCTION - JONAS (01.07.2000) */ void conn_disconnect(struct Conn_Struct *ConnS, const char *const LinePT, ...) { char Line[IRCNOTICELEN+1] = ""; va_list Args = { 0 }; struct Client_Struct *ClientS = NULL; assert(ConnS != NULL); assert(LinePT != NULL); va_start(Args, LinePT); vsnprintf(Line, IRCNOTICELEN+1, LinePT, Args); va_end(Args); client_noticealluser(ConnS->User, "%s", Line); if (Conn_IsWelcome(ConnS)) { for (ClientS = Client_Head ; ClientS != NULL ; ClientS = ClientS->Next) { if (ClientS->ConnS == ConnS) { client_close(ClientS, "Disconnected from attached connection %s server %s(%s):%ld.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH); } } } #if SSL_SUPPORT if (ConnConf_IsSSL(ConnS)) { if (ConnS->Cert != NULL) { X509_free(ConnS->Cert); ConnS->Cert = NULL; } if (ConnS->SSL_H != NULL) { SSL_shutdown(ConnS->SSL_H); SSL_free(ConnS->SSL_H); ConnS->SSL_H = NULL; } } #endif /* SSL_SUPPORT */ if (Conn_IsSocket(ConnS)) { close(ConnS->FD); ConnS->FD = FD_NONE; } conn_initconnection(ConnS); if (ConnS->ConnServerTry != NULL) { conn_connect(ConnS); } } /* CONN_HOSTTOIP FUNCTION - JONAS (01.03.2000) */ #if HAVE_CARES_CALLBACK_TIMEOUTS void conn_hosttoip(void *ArgPT, int ErrNo, int Timeouts, struct hostent *HostEnt) { #else void conn_hosttoip(void *ArgPT, int ErrNo, struct hostent *HostEnt) { #endif struct Conn_Struct *ConnS = ArgPT; const char *HostIPPT = NULL; #if IPV6_SUPPORT char Host[INET6_ADDRSTRLEN+1] = ""; #endif assert(ConnS != NULL); Host_ClearResolving(ConnS->ResolveFlags); if ((HostEnt == NULL) || (HostEnt->h_length < 1)) { conn_disconnect(ConnS, "Connection %s: Unable to resolve hostname %s to IP-address: [%d] %s", ConnS->Name, ConnS->HostName, ErrNo, res_strerror(ErrNo)); return; } #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { memset(&ConnS->INAddr6, 0, sizeof(ConnS->INAddr6)); memcpy(&ConnS->INAddr6, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntop(AF_INET6, &ConnS->INAddr6, Host, INET6_ADDRSTRLEN); if (HostIPPT == NULL) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } } else { memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr)); memcpy(&ConnS->INAddr, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntop(AF_INET, &ConnS->INAddr, Host, INET6_ADDRSTRLEN); if (HostIPPT == NULL) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } } #else /* IPV6_SUPPORT */ memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr)); memcpy(&ConnS->INAddr, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntoa(ConnS->INAddr); if (HostIPPT == NULL) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } #endif /* IPV6_SUPPORT */ ConnS->HostIPS = strrealloc(ConnS->HostIPS, HostIPPT); if (ConnS->HostIPS == NULL) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } client_noticealluser(ConnS->User, "Connection %s: Resolved hostname %s to IP-address %s.", ConnS->Name, ConnS->HostName, ConnS->HostIPS); Host_SetHostToIP(ConnS->ResolveFlags); #if ARES conn_connect(ConnS); #endif } /* CONN_SERVERHOSTTOIP FUNCTION - JONAS (01.03.2000) */ #if HAVE_CARES_CALLBACK_TIMEOUTS void conn_serverhosttoip(void *ArgPT, int ErrNo, int Timeouts, struct hostent *HostEnt) { #else void conn_serverhosttoip(void *ArgPT, int ErrNo, struct hostent *HostEnt) { #endif struct Conn_Struct *ConnS = ArgPT; const char *HostIPPT = NULL; #if IPV6_SUPPORT char Host[INET6_ADDRSTRLEN+1] = ""; #endif assert(ConnS != NULL); Host_ClearResolving(ConnS->ServerResolveFlags); if ((HostEnt == NULL) || (HostEnt->h_length < 1)) { conn_disconnect(ConnS, "Connection %s: Unable to resolve server hostname %s to IP-Address: [%d] %s", ConnS->Name, ConnS->ServerHostName, ErrNo, res_strerror(ErrNo)); return; } #if IPV6_SUPPORT if (ConnConf_IsIPv6(ConnS)) { memset(&ConnS->ServerINAddr6, 0, sizeof(ConnS->ServerINAddr6)); memcpy(&ConnS->ServerINAddr6, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntop(AF_INET6, &ConnS->ServerINAddr6, Host, INET6_ADDRSTRLEN); if (HostIPPT == NULL) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } } else { memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr)); memcpy(&ConnS->ServerINAddr, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntop(AF_INET, &ConnS->ServerINAddr, Host, INET6_ADDRSTRLEN); if (HostIPPT == NULL) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } } #else /* IPV6_SUPPORT */ memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr)); memcpy(&ConnS->ServerINAddr, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntoa(ConnS->ServerINAddr); if (HostIPPT == NULL) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } #endif /* IPV6_SUPPORT */ ConnS->ServerHostIPS = strrealloc(ConnS->ServerHostIPS, HostIPPT); if (ConnS->ServerHostIPS == NULL) { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); return; } client_noticealluser(ConnS->User, "Connection %s: Resolved server hostname %s to IP-address %s.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS); Host_SetHostToIP(ConnS->ServerResolveFlags); #if ARES conn_connect(ConnS); #endif } /* CONN_LOGON FUNCTION - JONAS (01.07.2000) */ void conn_logon(struct Conn_Struct *ConnS) { char *NickPT = ConnS->Nick; char *InfoPT = ConnS->Info; assert(ConnS != NULL); if (ConnS->NumClients <= 0) { NickPT = ConnS->AwayNick; Conn_SetSentAwayNick(ConnS); } else { NickPT = ConnS->Nick; Conn_SetSentNick(ConnS); } if ((ConfS.UnixPasswd == TRUE) && (Root == TRUE)) { if (strcmp(ConnS->Info, "0") == FALSE) { InfoPT = sysgetnamefromuser(ConnS->User); if (InfoPT == NULL) { InfoPT = "0"; } } } if ((ConnS->ServerPass != NULL) && (strcmp(ConnS->ServerPass, CONN_CONF_SERVERPASS_NONE) != FALSE)) { conn_addsendq(ConnS, "PASS %s", ConnS->ServerPass); } conn_addsendq(ConnS, "NICK %s", NickPT); conn_addsendq(ConnS, "USER %s 0 0 :%s", ConnS->User, InfoPT); } /* CONN_ADDSEND FUNCTION - JONAS (01.07.2000) */ void conn_addsend(struct Conn_Struct *ConnS, const char *const LinePT) { char LineCRLF[IRCMSGCRLFLEN+1] = ""; unsigned long int Len = 0; unsigned long int OldLen = 0; unsigned long int NewLen = 0; char *SendBufferPT = NULL; assert(ConnS != NULL); assert(LinePT != NULL); assert(Conn_IsSocket(ConnS)); snprintf(LineCRLF, IRCMSGCRLFLEN+1, "%s\r\n", LinePT); Len = strlen(LineCRLF); if (ConnS->SendBuffer == NULL) { OldLen = 0; } else { OldLen = strlen(ConnS->SendBuffer); } NewLen = OldLen + Len + 1; SendBufferPT = realloc(ConnS->SendBuffer, NewLen); if (SendBufferPT == NULL) { return; } ConnS->SendBuffer = SendBufferPT; SendBufferPT = SendBufferPT + OldLen; strcpy(SendBufferPT, LineCRLF); } /* CONN_QUIT FUNCTION - JONAS (09.06.2001) */ void conn_quit(struct Conn_Struct *ConnS, const char *const MessagePT, ...) { char Message[IRCQUITMSGLEN+1] = ""; va_list Args = { 0 }; assert(ConnS != NULL); assert(Conn_IsWelcome(ConnS)); assert(MessagePT != NULL); va_start(Args, MessagePT); vsnprintf(Message, IRCQUITMSGLEN+1, MessagePT, Args); va_end(Args); if (!Conn_IsSentQuit(ConnS)) { Conn_SetSentQuit(ConnS); ConnS->SentQuitTime = time(NULL); conn_initsendq(ConnS); conn_initflushl(ConnS); conn_initflushb(ConnS); conn_addsendq(ConnS, "QUIT :%s", Message); client_noticealluser(ConnS->User, "Connection %s: Quitting %s(%s):%ld \"%s\": %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, ConnS->ServerName, Message); } } /* CONN_CLOSEALL FUNCTION - JONAS (09.06.2001) */ unsigned short int conn_closeall(const char *const MessagePT, ...) { char Message[LINELEN+1] = ""; va_list Args = { 0 }; unsigned short int Count = 0; struct Conn_Struct *ConnS = NULL; assert(MessagePT != NULL); va_start(Args, MessagePT); vsnprintf(Message, LINELEN+1, MessagePT, Args); va_end(Args); for (ConnS = Conn_Head ; ConnS != NULL ; ConnS = ConnS->Next) { if (!Conn_IsRemove(ConnS)) { if ((Host_IsResolving(ConnS->ResolveFlags)) || (Host_IsResolving(ConnS->ServerResolveFlags))) { #if HAVE_ARES_CANCELQUERY ares_cancelquery(Ares_Channel, ConnS); #endif } if (Conn_IsSocket(ConnS)) { if (Conn_IsWelcome(ConnS)) { if (!Conn_IsSentQuit(ConnS)) { conn_quit(ConnS, "%s", Message); } } else { conn_disconnect(ConnS, "Connection %s: %s", ConnS->Name, Message); } } } Conn_SetRemove(ConnS); ++Count; } return(Count); }