VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/slirp_dns.c@ 93115

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.6 KB
Line 
1/* $Id: slirp_dns.c 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * NAT - dns initialization.
4 */
5
6/*
7 * Copyright (C) 2012-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "slirp.h"
19#ifdef RT_OS_OS2
20# include <paths.h>
21#endif
22
23#include <iprt/errcore.h>
24#include <VBox/vmm/pdmdrv.h>
25#include <iprt/assert.h>
26#include <iprt/file.h>
27
28#ifdef RT_OS_WINDOWS
29# include <iprt/utf16.h>
30# include <Winnls.h>
31# define _WINSOCK2API_
32# include <iprt/win/iphlpapi.h>
33
34static int get_dns_addr_domain(PNATState pData)
35{
36 /*ULONG flags = GAA_FLAG_INCLUDE_PREFIX;*/ /*GAA_FLAG_INCLUDE_ALL_INTERFACES;*/ /* all interfaces registered in NDIS */
37 PIP_ADAPTER_ADDRESSES pAdapterAddr = NULL;
38 PIP_ADAPTER_ADDRESSES pAddr = NULL;
39 PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr = NULL;
40 ULONG size;
41 char *pszSuffix;
42 struct dns_domain_entry *pDomain = NULL;
43 ULONG ret = ERROR_SUCCESS;
44
45 /** @todo add SKIPing flags to get only required information */
46
47 /* determine size of buffer */
48 size = 0;
49 ret = pData->pfnGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, pAdapterAddr, &size);
50 if (ret != ERROR_BUFFER_OVERFLOW)
51 {
52 Log(("NAT: error %lu occurred on capacity detection operation\n", ret));
53 return -1;
54 }
55 if (size == 0)
56 {
57 Log(("NAT: Win socket API returns non capacity\n"));
58 return -1;
59 }
60
61 pAdapterAddr = RTMemAllocZ(size);
62 if (!pAdapterAddr)
63 {
64 Log(("NAT: No memory available\n"));
65 return -1;
66 }
67 ret = pData->pfnGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, pAdapterAddr, &size);
68 if (ret != ERROR_SUCCESS)
69 {
70 Log(("NAT: error %lu occurred on fetching adapters info\n", ret));
71 RTMemFree(pAdapterAddr);
72 return -1;
73 }
74
75 for (pAddr = pAdapterAddr; pAddr != NULL; pAddr = pAddr->Next)
76 {
77 int found;
78 if (pAddr->OperStatus != IfOperStatusUp)
79 continue;
80
81 for (pDnsAddr = pAddr->FirstDnsServerAddress; pDnsAddr != NULL; pDnsAddr = pDnsAddr->Next)
82 {
83 struct sockaddr *SockAddr = pDnsAddr->Address.lpSockaddr;
84 struct in_addr InAddr;
85 struct dns_entry *pDns;
86
87 if (SockAddr->sa_family != AF_INET)
88 continue;
89
90 InAddr = ((struct sockaddr_in *)SockAddr)->sin_addr;
91
92 /* add dns server to list */
93 pDns = RTMemAllocZ(sizeof(struct dns_entry));
94 if (!pDns)
95 {
96 Log(("NAT: Can't allocate buffer for DNS entry\n"));
97 RTMemFree(pAdapterAddr);
98 return VERR_NO_MEMORY;
99 }
100
101 Log(("NAT: adding %RTnaipv4 to DNS server list\n", InAddr));
102 if ((InAddr.s_addr & RT_H2N_U32_C(IN_CLASSA_NET)) == RT_N2H_U32_C(INADDR_LOOPBACK & IN_CLASSA_NET))
103 pDns->de_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
104 else
105 pDns->de_addr.s_addr = InAddr.s_addr;
106
107 TAILQ_INSERT_HEAD(&pData->pDnsList, pDns, de_list);
108
109 if (pAddr->DnsSuffix == NULL)
110 continue;
111
112 /* uniq */
113 RTUtf16ToUtf8(pAddr->DnsSuffix, &pszSuffix);
114 if (!pszSuffix || strlen(pszSuffix) == 0)
115 {
116 RTStrFree(pszSuffix);
117 continue;
118 }
119
120 found = 0;
121 LIST_FOREACH(pDomain, &pData->pDomainList, dd_list)
122 {
123 if ( pDomain->dd_pszDomain != NULL
124 && strcmp(pDomain->dd_pszDomain, pszSuffix) == 0)
125 {
126 found = 1;
127 RTStrFree(pszSuffix);
128 break;
129 }
130 }
131 if (!found)
132 {
133 pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
134 if (!pDomain)
135 {
136 Log(("NAT: not enough memory\n"));
137 RTStrFree(pszSuffix);
138 RTMemFree(pAdapterAddr);
139 return VERR_NO_MEMORY;
140 }
141 pDomain->dd_pszDomain = pszSuffix;
142 Log(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
143 LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
144 }
145 }
146 }
147 RTMemFree(pAdapterAddr);
148 return 0;
149}
150
151#else /* !RT_OS_WINDOWS */
152
153#include "resolv_conf_parser.h"
154
155static int get_dns_addr_domain(PNATState pData)
156{
157 struct rcp_state st;
158 int rc;
159 unsigned i;
160
161 /* XXX: perhaps IPv6 shouldn't be ignored if we're using DNS proxy */
162 st.rcps_flags = RCPSF_IGNORE_IPV6;
163 rc = rcp_parse(&st, RESOLV_CONF_FILE);
164
165 if (rc < 0)
166 return -1;
167
168 /* for historical reasons: Slirp returns -1 if no nameservers were found */
169 if (st.rcps_num_nameserver == 0)
170 return -1;
171
172
173 /* XXX: We're composing the list, but we already knows
174 * its size so we can allocate array instead (Linux guests
175 * dont like >3 servers in the list anyway)
176 * or use pre-allocated array in NATState.
177 */
178 for (i = 0; i != st.rcps_num_nameserver; ++i)
179 {
180 struct dns_entry *pDns;
181 RTNETADDRU *address = &st.rcps_nameserver[i].uAddr;
182
183 if (address->IPv4.u == INADDR_ANY)
184 {
185 /*
186 * This doesn't seem to be very well documented except for
187 * RTFS of res_init.c, but INADDR_ANY is a valid value for
188 * for "nameserver".
189 */
190 address->IPv4.u = RT_H2N_U32_C(INADDR_LOOPBACK);
191 }
192
193 if ( (address->IPv4.u & RT_H2N_U32_C(IN_CLASSA_NET))
194 == RT_N2H_U32_C(INADDR_LOOPBACK & IN_CLASSA_NET))
195 {
196 /**
197 * XXX: Note shouldn't patch the address in case of using DNS proxy,
198 * because DNS proxy we do revert it back actually.
199 */
200 if ( address->IPv4.u == RT_N2H_U32_C(INADDR_LOOPBACK)
201 && pData->fLocalhostReachable)
202 address->IPv4.u = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
203 else if (pData->fUseDnsProxy == 0) {
204 /*
205 * Either the resolver lives somewhere else on the 127/8 network or the loopback interface
206 * is blocked for access from the guest, either way switch to the DNS proxy.
207 */
208 if (pData->fLocalhostReachable)
209 LogRel(("NAT: DNS server %RTnaipv4 registration detected, switching to the DNS proxy\n", address->IPv4));
210 else
211 LogRel(("NAT: Switching to DNS proxying due to access to the loopback interface being blocked\n"));
212 pData->fUseDnsProxy = 1;
213 }
214 }
215
216 pDns = RTMemAllocZ(sizeof(struct dns_entry));
217 if (pDns == NULL)
218 {
219 slirpReleaseDnsSettings(pData);
220 return VERR_NO_MEMORY;
221 }
222
223 pDns->de_addr.s_addr = address->IPv4.u;
224 TAILQ_INSERT_HEAD(&pData->pDnsList, pDns, de_list);
225 }
226
227 if (st.rcps_domain != 0)
228 {
229 struct dns_domain_entry *pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
230 if (pDomain == NULL)
231 {
232 slirpReleaseDnsSettings(pData);
233 return -1;
234 }
235
236 pDomain->dd_pszDomain = RTStrDup(st.rcps_domain);
237 LogRel(("NAT: Adding domain name %s\n", pDomain->dd_pszDomain));
238 LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
239 }
240
241 return 0;
242}
243
244#endif /* !RT_OS_WINDOWS */
245
246int slirpInitializeDnsSettings(PNATState pData)
247{
248 int rc = VINF_SUCCESS;
249 AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
250 LogFlowFuncEnter();
251 if (!pData->fUseHostResolverPermanent)
252 {
253 TAILQ_INIT(&pData->pDnsList);
254 LIST_INIT(&pData->pDomainList);
255
256 /*
257 * Some distributions haven't got /etc/resolv.conf
258 * so we should other way to configure DNS settings.
259 */
260 if (get_dns_addr_domain(pData) < 0)
261 pData->fUseHostResolver = true;
262 else
263 {
264 pData->fUseHostResolver = false;
265 dnsproxy_init(pData);
266 }
267
268 if (!pData->fUseHostResolver)
269 {
270 struct dns_entry *pDNSEntry = NULL;
271 int cDNSListEntry = 0;
272 TAILQ_FOREACH_REVERSE(pDNSEntry, &pData->pDnsList, dns_list_head, de_list)
273 {
274 LogRel(("NAT: DNS#%i: %RTnaipv4\n", cDNSListEntry, pDNSEntry->de_addr.s_addr));
275 cDNSListEntry++;
276 }
277 }
278 }
279
280 LogFlowFuncLeaveRC(rc);
281 return rc;
282}
283
284int slirpReleaseDnsSettings(PNATState pData)
285{
286 struct dns_entry *pDns = NULL;
287 struct dns_domain_entry *pDomain = NULL;
288 int rc = VINF_SUCCESS;
289 AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
290 LogFlowFuncEnter();
291
292 while (!TAILQ_EMPTY(&pData->pDnsList))
293 {
294 pDns = TAILQ_FIRST(&pData->pDnsList);
295 TAILQ_REMOVE(&pData->pDnsList, pDns, de_list);
296 RTMemFree(pDns);
297 }
298
299 while (!LIST_EMPTY(&pData->pDomainList))
300 {
301 pDomain = LIST_FIRST(&pData->pDomainList);
302 LIST_REMOVE(pDomain, dd_list);
303 if (pDomain->dd_pszDomain != NULL)
304 RTStrFree(pDomain->dd_pszDomain);
305 RTMemFree(pDomain);
306 }
307
308 /* tell any pending dnsproxy requests their copy is expired */
309 ++pData->dnsgen;
310
311 LogFlowFuncLeaveRC(rc);
312 return rc;
313}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette