VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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