VirtualBox

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

Last change on this file since 74950 was 71203, checked in by vboxsync, 7 years ago

NAT: Redo previous. Explicitly map nameserver 0.0.0.0 to loopback
first and let existing code remap it instead of duplicating that code.

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