/*
* ----------------------------------------------------------------
* Night Light IRC Proxy - Connection Functions
* ----------------------------------------------------------------
* Copyright (C) 1997-2007 Jonas Kvinge <jonas@night-light.net>
* 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);
}
syntax highlighted by Code2HTML, v. 0.9.1