VirtualBox

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

Last change on this file since 49482 was 49436, checked in by vboxsync, 11 years ago

slirp_dns.c: nits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1/* $Id: slirp_dns.c 49436 2013-11-11 12:07:31Z 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
154static int RTFileGets(RTFILE File, void *pvBuf, size_t cbBufSize, size_t *pcbRead)
155{
156 size_t cbRead;
157 char bTest;
158 int rc = VERR_NO_MEMORY;
159 char *pu8Buf = (char *)pvBuf;
160 *pcbRead = 0;
161
162 while ( RT_SUCCESS(rc = RTFileRead(File, &bTest, 1, &cbRead))
163 && (pu8Buf - (char *)pvBuf) < cbBufSize)
164 {
165 if (cbRead == 0)
166 return VERR_EOF;
167
168 if (bTest == '\r' || bTest == '\n')
169 {
170 *pu8Buf = 0;
171 return VINF_SUCCESS;
172 }
173 *pu8Buf = bTest;
174 pu8Buf++;
175 (*pcbRead)++;
176 }
177 return rc;
178}
179
180static int slirpOpenResolvConfFile(PRTFILE pResolvConfFile)
181{
182 int rc;
183 char buff[512];
184 char *etc = NULL;
185 char *home = NULL;
186 AssertPtrReturn(pResolvConfFile, VERR_INVALID_PARAMETER);
187 LogFlowFuncEnter();
188# ifdef RT_OS_OS2
189 /* Try various locations. */
190 NOREF(home);
191 etc = getenv("ETC");
192 if (etc)
193 {
194 RTStrmPrintf(buff, sizeof(buff), "%s/RESOLV2", etc);
195 rc = RTFileOpen(pResolvConfFile, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
196 }
197 if (RT_FAILURE(rc))
198 {
199 RTStrmPrintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
200 rc = RTFileOpen(pResolvConfFile, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
201 }
202 if (RT_FAILURE(rc))
203 {
204 RTStrmPrintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
205 rc = RTFileOpen(pResolvConfFile, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
206 }
207# else /* !RT_OS_OS2 */
208# ifndef DEBUG_vvl
209 rc = RTFileOpen(pResolvConfFile, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
210# else
211 NOREF(etc);
212 home = getenv("HOME");
213 RTStrPrintf(buff, sizeof(buff), "%s/resolv.conf", home);
214 rc = RTFileOpen(pResolvConfFile, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
215 if (RT_SUCCESS(rc))
216 Log(("NAT: DNS we're using %s\n", buff));
217 else
218 {
219 rc = RTFileOpen(pResolvConfFile, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
220 Log(("NAT: DNS we're using %s\n", buff));
221 }
222# endif
223# endif /* !RT_OS_OS2 */
224 LogFlowFuncLeaveRC(rc);
225 return rc;
226}
227static int get_dns_addr_domain(PNATState pData, const char **ppszDomain)
228{
229 char buff[256];
230 char buff2[256];
231 RTFILE ResolvConfFile;
232 int cNameserversFound = 0;
233 bool fWarnTooManyDnsServers = false;
234 struct in_addr tmp_addr;
235 int rc;
236 size_t bytes;
237
238 rc = slirpOpenResolvConfFile(&ResolvConfFile);
239 if (RT_FAILURE(rc))
240 {
241 LogRel(("NAT: there're some problems with accessing resolv.conf (or known analog), thus NAT switches to use host resolver mechanism\n"));
242 pData->fUseHostResolver = 1;
243 return VINF_SUCCESS;
244 }
245
246 if (ppszDomain)
247 *ppszDomain = NULL;
248
249 Log(("NAT: DNS Servers:\n"));
250 while ( RT_SUCCESS(rc = RTFileGets(ResolvConfFile, buff, sizeof(buff), &bytes))
251 && rc != VERR_EOF)
252 {
253 struct dns_entry *pDns = NULL;
254 if ( cNameserversFound == 4
255 && !fWarnTooManyDnsServers
256 && sscanf(buff, "nameserver%*[ \t]%255s", buff2) == 1)
257 {
258 fWarnTooManyDnsServers = true;
259 LogRel(("NAT: too many nameservers registered.\n"));
260 }
261 if ( sscanf(buff, "nameserver%*[ \t]%255s", buff2) == 1
262 && cNameserversFound < 4) /* Unix doesn't accept more than 4 name servers*/
263 {
264 if (!inet_aton(buff2, &tmp_addr))
265 continue;
266
267 /* localhost mask */
268 pDns = RTMemAllocZ(sizeof (struct dns_entry));
269 if (!pDns)
270 {
271 Log(("can't alloc memory for DNS entry\n"));
272 return -1;
273 }
274
275 /* check */
276 pDns->de_addr.s_addr = tmp_addr.s_addr;
277 if ((pDns->de_addr.s_addr & RT_H2N_U32_C(IN_CLASSA_NET)) == RT_N2H_U32_C(INADDR_LOOPBACK & IN_CLASSA_NET))
278 {
279 if ((pDns->de_addr.s_addr) == RT_N2H_U32_C(INADDR_LOOPBACK))
280 pDns->de_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
281 else if (pData->fUseDnsProxy != 1)
282 {
283 /* Modern Ubuntu register 127.0.1.1 as DNS server */
284 LogRel(("NAT: DNS server %RTnaipv4 registration detected, switching to the DNS proxy.\n",
285 pDns->de_addr.s_addr));
286 pData->fUseDnsProxy = 1;
287 pData->fUseHostResolver = 0;
288 }
289 }
290 TAILQ_INSERT_HEAD(&pData->pDnsList, pDns, de_list);
291 cNameserversFound++;
292 }
293 if (!strncmp(buff, "domain", 6) || !strncmp(buff, "search", 6))
294 {
295 char *tok;
296 char *saveptr;
297 struct dns_domain_entry *pDomain = NULL;
298 int fFoundDomain = 0;
299 tok = strtok_r(&buff[6], " \t\n", &saveptr);
300 LIST_FOREACH(pDomain, &pData->pDomainList, dd_list)
301 {
302 if ( tok != NULL
303 && strcmp(tok, pDomain->dd_pszDomain) == 0)
304 {
305 fFoundDomain = 1;
306 break;
307 }
308 }
309 if (tok != NULL && !fFoundDomain)
310 {
311 pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
312 if (!pDomain)
313 {
314 Log(("NAT: not enought memory to add domain list\n"));
315 return VERR_NO_MEMORY;
316 }
317 pDomain->dd_pszDomain = RTStrDup(tok);
318 Log(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
319 LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
320 }
321 }
322 }
323 RTFileClose(ResolvConfFile);
324 if (!cNameserversFound)
325 return -1;
326 return 0;
327}
328
329#endif /* !RT_OS_WINDOWS */
330
331int slirpInitializeDnsSettings(PNATState pData)
332{
333 int rc = VINF_SUCCESS;
334 AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
335 LogFlowFuncEnter();
336 if (!pData->fUseHostResolverPermanent)
337 {
338 TAILQ_INIT(&pData->pDnsList);
339 LIST_INIT(&pData->pDomainList);
340
341 /*
342 * Some distributions haven't got /etc/resolv.conf
343 * so we should other way to configure DNS settings.
344 */
345 if (get_dns_addr_domain(pData, NULL) < 0)
346 {
347 /* Load the DNS handler if host resolver mode was not used before. */
348 if (!pData->fUseHostResolver)
349 dns_alias_load(pData);
350 pData->fUseHostResolver = true;
351 }
352 else
353 {
354 /* Unload to not intercept in the future. */
355 if (pData->fUseHostResolver)
356 dns_alias_unload(pData);
357 pData->fUseHostResolver = false;
358 dnsproxy_init(pData);
359 }
360
361 if (!pData->fUseHostResolver)
362 {
363 struct dns_entry *pDNSEntry = NULL;
364 int cDNSListEntry = 0;
365 TAILQ_FOREACH_REVERSE(pDNSEntry, &pData->pDnsList, dns_list_head, de_list)
366 {
367 LogRel(("NAT: DNS#%i: %RTnaipv4\n", cDNSListEntry, pDNSEntry->de_addr.s_addr));
368 cDNSListEntry++;
369 }
370 }
371 }
372
373 LogFlowFuncLeaveRC(rc);
374 return rc;
375}
376
377int slirpReleaseDnsSettings(PNATState pData)
378{
379 struct dns_entry *pDns = NULL;
380 struct dns_domain_entry *pDomain = NULL;
381 int rc = VINF_SUCCESS;
382 AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
383 LogFlowFuncEnter();
384
385 while (!TAILQ_EMPTY(&pData->pDnsList))
386 {
387 pDns = TAILQ_FIRST(&pData->pDnsList);
388 TAILQ_REMOVE(&pData->pDnsList, pDns, de_list);
389 RTMemFree(pDns);
390 }
391
392 while (!LIST_EMPTY(&pData->pDomainList))
393 {
394 pDomain = LIST_FIRST(&pData->pDomainList);
395 LIST_REMOVE(pDomain, dd_list);
396 if (pDomain->dd_pszDomain != NULL)
397 RTStrFree(pDomain->dd_pszDomain);
398 RTMemFree(pDomain);
399 }
400 LogFlowFuncLeaveRC(rc);
401 return rc;
402}
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