1 | // |
2 | // DNS.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: NetCore |
6 | // Module: DNS |
7 | // |
8 | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Net/DNS.h" |
16 | #include "Poco/Net/NetException.h" |
17 | #include "Poco/Net/SocketAddress.h" |
18 | #include "Poco/Environment.h" |
19 | #include "Poco/NumberFormatter.h" |
20 | #include "Poco/RWLock.h" |
21 | #include <cstring> |
22 | |
23 | |
24 | #if defined(POCO_HAVE_LIBRESOLV) |
25 | #include <resolv.h> |
26 | #endif |
27 | |
28 | |
29 | using Poco::Environment; |
30 | using Poco::NumberFormatter; |
31 | using Poco::IOException; |
32 | |
33 | |
34 | namespace Poco { |
35 | namespace Net { |
36 | |
37 | |
38 | #if defined(POCO_HAVE_LIBRESOLV) |
39 | static Poco::RWLock resolverLock; |
40 | #endif |
41 | |
42 | |
43 | HostEntry DNS::hostByName(const std::string& hostname, unsigned |
44 | #ifdef POCO_HAVE_ADDRINFO |
45 | hintFlags |
46 | #endif |
47 | ) |
48 | { |
49 | #if defined(POCO_HAVE_LIBRESOLV) |
50 | Poco::ScopedReadRWLock readLock(resolverLock); |
51 | #endif |
52 | |
53 | #if defined(POCO_HAVE_ADDRINFO) |
54 | struct addrinfo* pAI; |
55 | struct addrinfo hints; |
56 | std::memset(&hints, 0, sizeof(hints)); |
57 | hints.ai_flags = hintFlags; |
58 | int rc = getaddrinfo(hostname.c_str(), NULL, &hints, &pAI); |
59 | if (rc == 0) |
60 | { |
61 | HostEntry result(pAI); |
62 | freeaddrinfo(pAI); |
63 | return result; |
64 | } |
65 | else |
66 | { |
67 | aierror(rc, hostname); |
68 | } |
69 | #elif defined(POCO_VXWORKS) |
70 | int addr = hostGetByName(const_cast<char*>(hostname.c_str())); |
71 | if (addr != ERROR) |
72 | { |
73 | return HostEntry(hostname, IPAddress(&addr, sizeof(addr))); |
74 | } |
75 | #else |
76 | struct hostent* he = gethostbyname(hostname.c_str()); |
77 | if (he) |
78 | { |
79 | return HostEntry(he); |
80 | } |
81 | #endif |
82 | error(lastError(), hostname); // will throw an appropriate exception |
83 | throw NetException(); // to silence compiler |
84 | } |
85 | |
86 | |
87 | HostEntry DNS::hostByAddress(const IPAddress& address, unsigned |
88 | #ifdef POCO_HAVE_ADDRINFO |
89 | hintFlags |
90 | #endif |
91 | ) |
92 | { |
93 | #if defined(POCO_HAVE_LIBRESOLV) |
94 | Poco::ScopedReadRWLock readLock(resolverLock); |
95 | #endif |
96 | |
97 | #if defined(POCO_HAVE_ADDRINFO) |
98 | SocketAddress sa(address, 0); |
99 | static char fqname[1024]; |
100 | int rc = getnameinfo(sa.addr(), sa.length(), fqname, sizeof(fqname), NULL, 0, NI_NAMEREQD); |
101 | if (rc == 0) |
102 | { |
103 | struct addrinfo* pAI; |
104 | struct addrinfo hints; |
105 | std::memset(&hints, 0, sizeof(hints)); |
106 | hints.ai_flags = hintFlags; |
107 | rc = getaddrinfo(fqname, NULL, &hints, &pAI); |
108 | if (rc == 0) |
109 | { |
110 | HostEntry result(pAI); |
111 | freeaddrinfo(pAI); |
112 | return result; |
113 | } |
114 | else |
115 | { |
116 | aierror(rc, address.toString()); |
117 | } |
118 | } |
119 | else |
120 | { |
121 | aierror(rc, address.toString()); |
122 | } |
123 | #elif defined(POCO_VXWORKS) |
124 | char name[MAXHOSTNAMELEN + 1]; |
125 | if (hostGetByAddr(*reinterpret_cast<const int*>(address.addr()), name) == OK) |
126 | { |
127 | return HostEntry(std::string(name), address); |
128 | } |
129 | #else |
130 | struct hostent* he = gethostbyaddr(reinterpret_cast<const char*>(address.addr()), address.length(), address.af()); |
131 | if (he) |
132 | { |
133 | return HostEntry(he); |
134 | } |
135 | #endif |
136 | int err = lastError(); |
137 | error(err, address.toString()); // will throw an appropriate exception |
138 | throw NetException(); // to silence compiler |
139 | } |
140 | |
141 | |
142 | HostEntry DNS::resolve(const std::string& address) |
143 | { |
144 | IPAddress ip; |
145 | if (IPAddress::tryParse(address, ip)) |
146 | return hostByAddress(ip); |
147 | else |
148 | return hostByName(address); |
149 | } |
150 | |
151 | |
152 | IPAddress DNS::resolveOne(const std::string& address) |
153 | { |
154 | const HostEntry& entry = resolve(address); |
155 | if (!entry.addresses().empty()) |
156 | return entry.addresses()[0]; |
157 | else |
158 | throw NoAddressFoundException(address); |
159 | } |
160 | |
161 | |
162 | HostEntry DNS::thisHost() |
163 | { |
164 | return hostByName(hostName()); |
165 | } |
166 | |
167 | |
168 | void DNS::reload() |
169 | { |
170 | #if defined(POCO_HAVE_LIBRESOLV) |
171 | Poco::ScopedWriteRWLock writeLock(resolverLock); |
172 | res_init(); |
173 | #endif |
174 | } |
175 | |
176 | |
177 | void DNS::flushCache() |
178 | { |
179 | } |
180 | |
181 | |
182 | std::string DNS::hostName() |
183 | { |
184 | char buffer[256]; |
185 | int rc = gethostname(buffer, sizeof(buffer)); |
186 | if (rc == 0) |
187 | return std::string(buffer); |
188 | else |
189 | throw NetException("Cannot get host name" ); |
190 | } |
191 | |
192 | |
193 | int DNS::lastError() |
194 | { |
195 | #if defined(_WIN32) |
196 | return GetLastError(); |
197 | #elif defined(POCO_VXWORKS) |
198 | return errno; |
199 | #else |
200 | return h_errno; |
201 | #endif |
202 | } |
203 | |
204 | |
205 | void DNS::error(int code, const std::string& arg) |
206 | { |
207 | switch (code) |
208 | { |
209 | case POCO_ESYSNOTREADY: |
210 | throw NetException("Net subsystem not ready" ); |
211 | case POCO_ENOTINIT: |
212 | throw NetException("Net subsystem not initialized" ); |
213 | case POCO_HOST_NOT_FOUND: |
214 | throw HostNotFoundException(arg); |
215 | case POCO_TRY_AGAIN: |
216 | throw DNSException("Temporary DNS error while resolving" , arg); |
217 | case POCO_NO_RECOVERY: |
218 | throw DNSException("Non recoverable DNS error while resolving" , arg); |
219 | case POCO_NO_DATA: |
220 | throw NoAddressFoundException(arg); |
221 | default: |
222 | throw IOException(NumberFormatter::format(code)); |
223 | } |
224 | } |
225 | |
226 | |
227 | void DNS::aierror(int code, const std::string& arg) |
228 | { |
229 | #if defined(POCO_HAVE_IPv6) || defined(POCO_HAVE_ADDRINFO) |
230 | switch (code) |
231 | { |
232 | case EAI_AGAIN: |
233 | throw DNSException("Temporary DNS error while resolving" , arg); |
234 | case EAI_FAIL: |
235 | throw DNSException("Non recoverable DNS error while resolving" , arg); |
236 | #if !defined(_WIN32) // EAI_NODATA and EAI_NONAME have the same value |
237 | #if defined(EAI_NODATA) // deprecated in favor of EAI_NONAME on FreeBSD |
238 | case EAI_NODATA: |
239 | throw NoAddressFoundException(arg); |
240 | #endif |
241 | #endif |
242 | case EAI_NONAME: |
243 | throw HostNotFoundException(arg); |
244 | #if defined(EAI_SYSTEM) |
245 | case EAI_SYSTEM: |
246 | error(lastError(), arg); |
247 | break; |
248 | #endif |
249 | #if defined(_WIN32) |
250 | case WSANO_DATA: // may happen on XP |
251 | throw HostNotFoundException(arg); |
252 | #endif |
253 | default: |
254 | throw DNSException("EAI" , NumberFormatter::format(code)); |
255 | } |
256 | #endif // POCO_HAVE_IPv6 || defined(POCO_HAVE_ADDRINFO) |
257 | } |
258 | |
259 | |
260 | } } // namespace Poco::Net |
261 | |