~vanhoof/+junk/znc

« back to all changes in this revision

Viewing changes to Socket.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Matthäi
  • Date: 2009-07-24 13:46:00 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20090724134600-uaxedj9f92i72ru1
Tags: 0.074-1
* New upstream release.
  - Bump urgency to high. This release fixes an high-impact directory
    traversal buf, where unpriviliged users can save about DCC SEND files on
    the server with the rights of the znc process. The attacker could also
    use the exploit to get a shell on the server.
    Closes: #537977
  - Use c-ares for DNS resolving, add libc-ares-dev and pkg-config as
    build-dependency.
* Merge 0.058-2+lenny2, 0.058-2+lenny3, 0.070-1~bpo40+1 and 0.070-1~bpo50+1
  changelog.
* Bump Standards-Version to 3.8.2 (no changes needed).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2004-2009  See the AUTHORS file for details.
 
3
 *
 
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.
 
7
 */
 
8
 
 
9
#include "Socket.h"
 
10
#ifdef HAVE_ARES
 
11
#include <ares.h>
 
12
#endif
 
13
 
 
14
#ifdef HAVE_ARES
 
15
struct DNSLookup {
 
16
        bool bSocketDead;
 
17
        bool bLookupDone;
 
18
        // When both of the above are true, this struct can be freed
 
19
 
 
20
        // Query
 
21
        CString sHost;
 
22
        CSSockAddr::EAFRequire family;
 
23
 
 
24
        // Result
 
25
        int ares_status;
 
26
        CSSockAddr addr;
 
27
};
 
28
 
 
29
static ares_channel& GetAres() {
 
30
        static ares_channel m_ares;
 
31
        return m_ares;
 
32
}
 
33
#endif
 
34
 
 
35
CZNCSock::~CZNCSock() {
 
36
#ifdef HAVE_ARES
 
37
        if (m_dns_lookup) {
 
38
                m_dns_lookup->bSocketDead = true;
 
39
                if (m_dns_lookup->bLookupDone)
 
40
                        delete m_dns_lookup;
 
41
                m_dns_lookup = NULL;
 
42
        }
 
43
#endif
 
44
}
 
45
 
 
46
CSockManager::CSockManager() : TSocketManager<CZNCSock>() {
 
47
#ifdef HAVE_ARES
 
48
        int i = ares_init(&GetAres());
 
49
        if (i != ARES_SUCCESS) {
 
50
                CUtils::PrintError("Could not initialize c-ares: " + CString(ares_strerror(i)));
 
51
                exit(0);
 
52
        }
 
53
        DEBUG("Successfully initialized c-ares");
 
54
#endif
 
55
}
 
56
 
 
57
CSockManager::~CSockManager() {
 
58
#ifdef HAVE_ARES
 
59
        ares_destroy(GetAres());
 
60
#endif
 
61
}
 
62
 
 
63
#ifdef HAVE_ARES
 
64
int CSockManager::Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
 
65
{
 
66
        int ret;
 
67
 
 
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);
 
72
 
 
73
        ret = ::select(nfds, readfds, writefds, exceptfds, timeout);
 
74
 
 
75
        ares_process(GetAres(), readfds, writefds);
 
76
 
 
77
        return ret;
 
78
}
 
79
 
 
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;
 
83
 
 
84
        DEBUG("DNS lookup done for " << p->sHost);
 
85
        if (p->bSocketDead) {
 
86
                delete p;
 
87
                return;
 
88
        }
 
89
 
 
90
        p->ares_status = status;
 
91
        if (!h) {
 
92
#ifdef HAVE_IPV6
 
93
                if (p->family == CSSockAddr::RAF_ANY) {
 
94
                        // Try an AAAA lookup
 
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,
 
99
                                        ares_callback, p);
 
100
                        return;
 
101
                }
 
102
#endif
 
103
                if (status == ARES_SUCCESS)
 
104
                        p->ares_status = ARES_ENOTIMP;
 
105
                return;
 
106
        }
 
107
 
 
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);
 
111
        }
 
112
#ifdef HAVE_IPV6
 
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);
 
116
        }
 
117
#endif
 
118
        else
 
119
                DEBUG(__PRETTY_FUNCTION__ << ": Got unknown address with length " << h->h_length);
 
120
}
 
121
 
 
122
int CZNCSock::GetAddrInfo(const CS_STRING &sHostname, CSSockAddr &csSockAddr) {
 
123
        // If this is an ip address, no lookup is necessary
 
124
#ifdef HAVE_IPV6
 
125
        if (inet_pton(AF_INET6, sHostname.c_str(), csSockAddr.GetAddr6()) > 0) {
 
126
                csSockAddr.SetIPv6(true);
 
127
                SetIPv6(true);
 
128
                return 0;
 
129
        }
 
130
#endif
 
131
        if (inet_pton(AF_INET, sHostname.c_str(), csSockAddr.GetAddr()) > 0) {
 
132
                csSockAddr.SetIPv6(false);
 
133
                SetIPv6(false);
 
134
                return 0;
 
135
        }
 
136
 
 
137
        if (!m_dns_lookup) {
 
138
                DEBUG("New dns lookup for " << sHostname);
 
139
 
 
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();
 
146
 
 
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
 
155
                        // feature for now.
 
156
                        family = CSSockAddr::RAF_INET;
 
157
                }
 
158
                ares_gethostbyname(GetAres(), sHostname.c_str(), family,
 
159
                                ares_callback, m_dns_lookup);
 
160
        }
 
161
 
 
162
        if (m_dns_lookup->sHost != sHostname)
 
163
                // This *cannot* happen
 
164
                DEBUG(__PRETTY_FUNCTION__ << ": Query target for an active DNS query changed!");
 
165
 
 
166
        if (!m_dns_lookup->bLookupDone) {
 
167
                DEBUG("waiting for dns on [" << sHostname << "] to finish...");
 
168
                return EAGAIN;
 
169
        }
 
170
 
 
171
        if (m_dns_lookup->ares_status != ARES_SUCCESS) {
 
172
                DEBUG("Error while looking up [" << sHostname << "]: "
 
173
                                << ares_strerror(m_dns_lookup->ares_status));
 
174
                delete m_dns_lookup;
 
175
                m_dns_lookup = NULL;
 
176
                return ETIMEDOUT;
 
177
        }
 
178
 
 
179
#ifdef HAVE_IPV6
 
180
        memcpy(csSockAddr.GetAddr6(), m_dns_lookup->addr.GetAddr6(), sizeof(in6_addr));
 
181
#endif
 
182
        memcpy(csSockAddr.GetAddr(), m_dns_lookup->addr.GetAddr(), sizeof(in_addr));
 
183
        csSockAddr.SetIPv6(m_dns_lookup->addr.GetIPv6());
 
184
        SetIPv6(csSockAddr.GetIPv6());
 
185
 
 
186
        DEBUG("GetAddrInfo() done for " << sHostname.c_str());
 
187
 
 
188
        delete m_dns_lookup;
 
189
        m_dns_lookup = NULL;
 
190
 
 
191
        return 0;
 
192
}
 
193
#endif
 
194
 
 
195
unsigned int CSockManager::GetAnonConnectionCount(const CString &sIP) const {
 
196
        const_iterator it;
 
197
        unsigned int ret = 0;
 
198
 
 
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::") {
 
203
                        ret++;
 
204
                }
 
205
        }
 
206
 
 
207
        DEBUG("There are [" << ret << "] clients from [" << sIP << "]");
 
208
 
 
209
        return ret;
 
210
}