VirtualBox

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

Last change on this file since 53448 was 53448, checked in by vboxsync, 10 years ago

NAT: trac ticket 13630 - use generation numbers as poor man's weak
references to prevent dnsproxy from using stale request::dns_server.

This commit has some extra LogRel() for the user to confirm the fix,
which are to be changed to Log2.

XXX: TOO: Clean up in dnsproxy_query() needs more investigation.
Existing code just punts with an "XXX" comment on sendto() failure,
which doesn't doesn't look right.

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