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
29using Poco::Environment;
30using Poco::NumberFormatter;
31using Poco::IOException;
32
33
34namespace Poco {
35namespace Net {
36
37
38#if defined(POCO_HAVE_LIBRESOLV)
39static Poco::RWLock resolverLock;
40#endif
41
42
43HostEntry 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
87HostEntry 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
142HostEntry 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
152IPAddress 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
162HostEntry DNS::thisHost()
163{
164 return hostByName(hostName());
165}
166
167
168void DNS::reload()
169{
170#if defined(POCO_HAVE_LIBRESOLV)
171 Poco::ScopedWriteRWLock writeLock(resolverLock);
172 res_init();
173#endif
174}
175
176
177void DNS::flushCache()
178{
179}
180
181
182std::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
193int 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
205void 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
227void 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