18
// When both of the above are true, this struct can be freed
22
CSSockAddr::EAFRequire family;
29
static ares_channel& GetAres() {
30
static ares_channel m_ares;
35
CZNCSock::~CZNCSock() {
38
m_dns_lookup->bSocketDead = true;
39
if (m_dns_lookup->bLookupDone)
46
CSockManager::CSockManager() : TSocketManager<CZNCSock>() {
48
int i = ares_init(&GetAres());
49
if (i != ARES_SUCCESS) {
50
CUtils::PrintError("Could not initialize c-ares: " + CString(ares_strerror(i)));
53
DEBUG("Successfully initialized c-ares");
57
CSockManager::~CSockManager() {
59
ares_destroy(GetAres());
64
int CSockManager::Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
69
// Csocket sometimes can use NULL for writefds and c-ares doesn't like NULLs here
76
// We assume that nfds is already the max. number of sockets allowed by
77
// the OS, so we don't need to update it here.
78
ares_fds(GetAres(), readfds, writefds);
79
ares_timeout(GetAres(), timeout, timeout);
81
ret = ::select(nfds, readfds, writefds, exceptfds, timeout);
83
ares_process(GetAres(), readfds, writefds);
88
void CZNCSock::ares_callback(void *lookup, int status, int timeout, struct hostent *h) {
89
struct DNSLookup *p = (struct DNSLookup *) lookup;
90
p->bLookupDone = true;
92
DEBUG("DNS lookup done for " << p->sHost);
98
p->ares_status = status;
101
if (p->family == CSSockAddr::RAF_ANY) {
102
// Try an AAAA lookup
103
p->family = CSSockAddr::RAF_INET6;
104
DEBUG("Retrying with AAAA");
105
p->bLookupDone = false;
106
ares_gethostbyname(GetAres(), p->sHost.c_str(), p->family,
111
if (status == ARES_SUCCESS)
112
p->ares_status = ARES_ENOTIMP;
116
if (h->h_addrtype == AF_INET && h->h_length == sizeof(in_addr)) {
117
memcpy(p->addr.GetAddr(), h->h_addr_list[0], sizeof(in_addr));
118
p->addr.SetIPv6(false);
121
else if (h->h_addrtype == AF_INET6 && h->h_length == sizeof(in6_addr)) {
122
memcpy(p->addr.GetAddr6(), h->h_addr_list[0], sizeof(in6_addr));
123
p->addr.SetIPv6(true);
127
DEBUG(__PRETTY_FUNCTION__ << ": Got unknown address with length " << h->h_length);
130
int CZNCSock::GetAddrInfo(const CS_STRING &sHostname, CSSockAddr &csSockAddr) {
131
// If this is an ip address, no lookup is necessary
133
if (inet_pton(AF_INET6, sHostname.c_str(), csSockAddr.GetAddr6()) > 0) {
134
csSockAddr.SetIPv6(true);
139
if (inet_pton(AF_INET, sHostname.c_str(), csSockAddr.GetAddr()) > 0) {
140
csSockAddr.SetIPv6(false);
146
DEBUG("New dns lookup for " << sHostname);
148
m_dns_lookup = new struct DNSLookup;
149
m_dns_lookup->bSocketDead = false;
150
m_dns_lookup->bLookupDone = false;
151
m_dns_lookup->sHost = sHostname;
152
m_dns_lookup->ares_status = 0;
153
m_dns_lookup->family = csSockAddr.GetAFRequire();
155
CSSockAddr::EAFRequire family = csSockAddr.GetAFRequire();
156
if (family == CSSockAddr::RAF_ANY) {
157
// post-1.6.0 c-ares (=current CVS versions) support
158
// lookups with AF_UNSPEC which means it first tries an
159
// AAAA lookup and then fails back to an A lookup.
160
// Older versions (= any version out there) just
161
// generate an "address family not supported" error
162
// message if you feed them, so we can't use this nice
164
family = CSSockAddr::RAF_INET;
166
ares_gethostbyname(GetAres(), sHostname.c_str(), family,
167
ares_callback, m_dns_lookup);
170
if (m_dns_lookup->sHost != sHostname)
171
// This *cannot* happen
172
DEBUG(__PRETTY_FUNCTION__ << ": Query target for an active DNS query changed!");
174
if (!m_dns_lookup->bLookupDone) {
175
DEBUG("waiting for dns on [" << sHostname << "] to finish...");
179
if (m_dns_lookup->ares_status != ARES_SUCCESS) {
180
DEBUG("Error while looking up [" << sHostname << "]: "
181
<< ares_strerror(m_dns_lookup->ares_status));
188
memcpy(csSockAddr.GetAddr6(), m_dns_lookup->addr.GetAddr6(), sizeof(in6_addr));
190
memcpy(csSockAddr.GetAddr(), m_dns_lookup->addr.GetAddr(), sizeof(in_addr));
191
csSockAddr.SetIPv6(m_dns_lookup->addr.GetIPv6());
192
SetIPv6(csSockAddr.GetIPv6());
194
DEBUG("GetAddrInfo() done for " << sHostname.c_str());
203
14
unsigned int CSockManager::GetAnonConnectionCount(const CString &sIP) const {
204
15
const_iterator it;
205
16
unsigned int ret = 0;
207
for (it = begin(); it != end(); it++) {
18
for (it = begin(); it != end(); ++it) {
208
19
CZNCSock *pSock = *it;
209
20
// Logged in CClients have "USR::<username>" as their sockname
210
if (pSock->GetRemoteIP() == sIP && pSock->GetSockName().Left(5) != "USR::") {
21
if (pSock->GetType() == Csock::INBOUND && pSock->GetRemoteIP() == sIP
22
&& pSock->GetSockName().Left(5) != "USR::") {
32
CS_STRING CZNCSock::ConvertAddress(void *addr, bool ipv6) {
33
CString sRet = Csock::ConvertAddress(addr, ipv6);
34
sRet.TrimPrefix("::ffff:");
38
/////////////////// CSocket ///////////////////
39
CSocket::CSocket(CModule* pModule) : CZNCSock() {
41
m_pModule->AddSocket(this);
43
SetMaxBufferThreshold(10240);
46
CSocket::CSocket(CModule* pModule, const CString& sHostname, unsigned short uPort, int iTimeout) : CZNCSock(sHostname, uPort, iTimeout) {
48
m_pModule->AddSocket(this);
50
SetMaxBufferThreshold(10240);
56
// CWebSock could cause us to have a NULL pointer here
58
pUser = m_pModule->GetUser();
59
m_pModule->UnlinkSocket(this);
62
if (pUser && !m_pModule->IsGlobal()) {
63
pUser->AddBytesWritten(GetBytesWritten());
64
pUser->AddBytesRead(GetBytesRead());
66
CZNC::Get().AddBytesWritten(GetBytesWritten());
67
CZNC::Get().AddBytesRead(GetBytesRead());
71
void CSocket::ReachedMaxBuffer() {
72
DEBUG(GetSockName() << " == ReachedMaxBuffer()");
73
PutModule("Some socket reached its max buffer limit and was closed!");
77
void CSocket::SockError(int iErrno) {
78
DEBUG(GetSockName() << " == SockError(" << strerror(iErrno) << ")");
79
if (iErrno == EMFILE) {
80
// We have too many open fds, this can cause a busy loop.
85
bool CSocket::ConnectionFrom(const CString& sHost, unsigned short uPort) {
86
return CZNC::Get().AllowConnectionFrom(sHost);
89
bool CSocket::Connect(const CString& sHostname, unsigned short uPort, bool bSSL, unsigned int uTimeout) {
90
CUser* pUser = m_pModule->GetUser();
91
CString sSockName = "MOD::C::" + m_pModule->GetModName();
95
sSockName += "::" + pUser->GetUserName();
96
sVHost = m_pModule->GetUser()->GetVHost();
99
// Don't overwrite the socket name if one is already set
100
if (!GetSockName().empty()) {
101
sSockName = GetSockName();
104
return m_pModule->GetManager()->Connect(sHostname, uPort, sSockName, uTimeout, bSSL, sVHost, this);
107
bool CSocket::Listen(unsigned short uPort, bool bSSL, unsigned int uTimeout) {
108
CUser* pUser = m_pModule->GetUser();
109
CString sSockName = "MOD::L::" + m_pModule->GetModName();
112
sSockName += "::" + pUser->GetUserName();
114
// Don't overwrite the socket name if one is already set
115
if (!GetSockName().empty()) {
116
sSockName = GetSockName();
119
return m_pModule->GetManager()->ListenAll(uPort, sSockName, bSSL, SOMAXCONN, this);
122
bool CSocket::PutIRC(const CString& sLine) {
123
return (m_pModule) ? m_pModule->PutIRC(sLine) : false;
126
bool CSocket::PutUser(const CString& sLine) {
127
return (m_pModule) ? m_pModule->PutUser(sLine) : false;
130
bool CSocket::PutStatus(const CString& sLine) {
131
return (m_pModule) ? m_pModule->PutStatus(sLine) : false;
134
bool CSocket::PutModule(const CString& sLine, const CString& sIdent, const CString& sHost) {
135
return (m_pModule) ? m_pModule->PutModule(sLine, sIdent, sHost) : false;
137
bool CSocket::PutModNotice(const CString& sLine, const CString& sIdent, const CString& sHost) {
138
return (m_pModule) ? m_pModule->PutModNotice(sLine, sIdent, sHost) : false;
141
void CSocket::SetModule(CModule* p) { m_pModule = p; }
142
CModule* CSocket::GetModule() const { return m_pModule; }
143
/////////////////// !CSocket ///////////////////