2
* Copyright (C) 2004-2009 See the AUTHORS file for details.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 2 as published
6
* by the Free Software Foundation.
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)
68
// We assume that nfds is already the max. number of sockets allowed by
69
// the OS, so we don't need to update it here.
70
ares_fds(GetAres(), readfds, writefds);
71
ares_timeout(GetAres(), timeout, timeout);
73
ret = ::select(nfds, readfds, writefds, exceptfds, timeout);
75
ares_process(GetAres(), readfds, writefds);
80
void CZNCSock::ares_callback(void *lookup, int status, int timeout, struct hostent *h) {
81
struct DNSLookup *p = (struct DNSLookup *) lookup;
82
p->bLookupDone = true;
84
DEBUG("DNS lookup done for " << p->sHost);
90
p->ares_status = status;
93
if (p->family == CSSockAddr::RAF_ANY) {
95
p->family = CSSockAddr::RAF_INET6;
96
DEBUG("Retrying with AAAA");
97
p->bLookupDone = false;
98
ares_gethostbyname(GetAres(), p->sHost.c_str(), p->family,
103
if (status == ARES_SUCCESS)
104
p->ares_status = ARES_ENOTIMP;
108
if (h->h_addrtype == AF_INET && h->h_length == sizeof(in_addr)) {
109
memcpy(p->addr.GetAddr(), h->h_addr_list[0], sizeof(in_addr));
110
p->addr.SetIPv6(false);
113
else if (h->h_addrtype == AF_INET6 && h->h_length == sizeof(in6_addr)) {
114
memcpy(p->addr.GetAddr6(), h->h_addr_list[0], sizeof(in6_addr));
115
p->addr.SetIPv6(true);
119
DEBUG(__PRETTY_FUNCTION__ << ": Got unknown address with length " << h->h_length);
122
int CZNCSock::GetAddrInfo(const CS_STRING &sHostname, CSSockAddr &csSockAddr) {
123
// If this is an ip address, no lookup is necessary
125
if (inet_pton(AF_INET6, sHostname.c_str(), csSockAddr.GetAddr6()) > 0) {
126
csSockAddr.SetIPv6(true);
131
if (inet_pton(AF_INET, sHostname.c_str(), csSockAddr.GetAddr()) > 0) {
132
csSockAddr.SetIPv6(false);
138
DEBUG("New dns lookup for " << sHostname);
140
m_dns_lookup = new struct DNSLookup;
141
m_dns_lookup->bSocketDead = false;
142
m_dns_lookup->bLookupDone = false;
143
m_dns_lookup->sHost = sHostname;
144
m_dns_lookup->ares_status = 0;
145
m_dns_lookup->family = csSockAddr.GetAFRequire();
147
CSSockAddr::EAFRequire family = csSockAddr.GetAFRequire();
148
if (family == CSSockAddr::RAF_ANY) {
149
// post-1.6.0 c-ares (=current CVS versions) support
150
// lookups with AF_UNSPEC which means it first tries an
151
// AAAA lookup and then fails back to an A lookup.
152
// Older versions (= any version out there) just
153
// generate an "address family not supported" error
154
// message if you feed them, so we can't use this nice
156
family = CSSockAddr::RAF_INET;
158
ares_gethostbyname(GetAres(), sHostname.c_str(), family,
159
ares_callback, m_dns_lookup);
162
if (m_dns_lookup->sHost != sHostname)
163
// This *cannot* happen
164
DEBUG(__PRETTY_FUNCTION__ << ": Query target for an active DNS query changed!");
166
if (!m_dns_lookup->bLookupDone) {
167
DEBUG("waiting for dns on [" << sHostname << "] to finish...");
171
if (m_dns_lookup->ares_status != ARES_SUCCESS) {
172
DEBUG("Error while looking up [" << sHostname << "]: "
173
<< ares_strerror(m_dns_lookup->ares_status));
180
memcpy(csSockAddr.GetAddr6(), m_dns_lookup->addr.GetAddr6(), sizeof(in6_addr));
182
memcpy(csSockAddr.GetAddr(), m_dns_lookup->addr.GetAddr(), sizeof(in_addr));
183
csSockAddr.SetIPv6(m_dns_lookup->addr.GetIPv6());
184
SetIPv6(csSockAddr.GetIPv6());
186
DEBUG("GetAddrInfo() done for " << sHostname.c_str());
195
unsigned int CSockManager::GetAnonConnectionCount(const CString &sIP) const {
197
unsigned int ret = 0;
199
for (it = begin(); it != end(); it++) {
200
CZNCSock *pSock = *it;
201
// Logged in CClients have "USR::<username>" as their sockname
202
if (pSock->GetRemoteIP() == sIP && pSock->GetSockName().Left(5) != "USR::") {
207
DEBUG("There are [" << ret << "] clients from [" << sIP << "]");