summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/Network/slirp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Network/slirp')
-rw-r--r--src/VBox/Devices/Network/slirp/bootp.c7
-rw-r--r--src/VBox/Devices/Network/slirp/debug.c2
-rw-r--r--src/VBox/Devices/Network/slirp/debug.h2
-rw-r--r--src/VBox/Devices/Network/slirp/dnsproxy/dnsproxy.c375
-rw-r--r--src/VBox/Devices/Network/slirp/dnsproxy/hash.c2
-rw-r--r--src/VBox/Devices/Network/slirp/ext.h2
-rw-r--r--src/VBox/Devices/Network/slirp/ip_icmp.c162
-rw-r--r--src/VBox/Devices/Network/slirp/ip_icmp.h2
-rw-r--r--src/VBox/Devices/Network/slirp/ip_input.c2
-rw-r--r--src/VBox/Devices/Network/slirp/ip_output.c2
-rw-r--r--src/VBox/Devices/Network/slirp/libalias/alias_dns.c2
-rw-r--r--src/VBox/Devices/Network/slirp/libalias/alias_mod.c10
-rw-r--r--src/VBox/Devices/Network/slirp/libslirp.h20
-rw-r--r--src/VBox/Devices/Network/slirp/misc.c2
-rw-r--r--src/VBox/Devices/Network/slirp/misc.h2
-rw-r--r--src/VBox/Devices/Network/slirp/queue.h2
-rw-r--r--src/VBox/Devices/Network/slirp/resolv_conf_parser.c539
-rw-r--r--src/VBox/Devices/Network/slirp/resolv_conf_parser.h109
-rw-r--r--src/VBox/Devices/Network/slirp/sbuf.c2
-rw-r--r--src/VBox/Devices/Network/slirp/slirp.c32
-rw-r--r--src/VBox/Devices/Network/slirp/slirp.h2
-rw-r--r--src/VBox/Devices/Network/slirp/slirp_dns.c84
-rw-r--r--src/VBox/Devices/Network/slirp/slirp_state.h10
-rw-r--r--src/VBox/Devices/Network/slirp/socket.c14
-rw-r--r--src/VBox/Devices/Network/slirp/socket.h2
-rw-r--r--src/VBox/Devices/Network/slirp/tcp_input.c2
-rw-r--r--src/VBox/Devices/Network/slirp/tcp_output.c2
-rw-r--r--src/VBox/Devices/Network/slirp/tcp_subr.c2
-rw-r--r--src/VBox/Devices/Network/slirp/tcp_timer.c2
-rw-r--r--src/VBox/Devices/Network/slirp/tcp_timer.h2
-rw-r--r--src/VBox/Devices/Network/slirp/tftp.c19
-rw-r--r--src/VBox/Devices/Network/slirp/tftp.h2
-rw-r--r--src/VBox/Devices/Network/slirp/udp.c6
-rw-r--r--src/VBox/Devices/Network/slirp/udp.h2
-rw-r--r--src/VBox/Devices/Network/slirp/zone.h2
35 files changed, 1128 insertions, 303 deletions
diff --git a/src/VBox/Devices/Network/slirp/bootp.c b/src/VBox/Devices/Network/slirp/bootp.c
index 31d434c2..6cf126bd 100644
--- a/src/VBox/Devices/Network/slirp/bootp.c
+++ b/src/VBox/Devices/Network/slirp/bootp.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -697,9 +697,10 @@ static void dhcp_decode(PNATState pData, struct bootp_t *bp, const uint8_t *buf,
* We're going update dns list at least once per DHCP transaction (!not on every operation
* within transaction), assuming that transaction can't be longer than 1 min.
*/
- if ( !pData->fUseHostResolver
+ if ( !pData->fUseHostResolverPermanent
&& ( pData->dnsLastUpdate == 0
- || curtime - pData->dnsLastUpdate > 60 * 1000)) /* one minute*/
+ || curtime - pData->dnsLastUpdate > 60 * 1000
+ || pData->fUseHostResolver)) /* one minute*/
{
uint8_t i = 2; /* i = 0 - tag, i == 1 - length */
parameter_list = dhcp_find_option(&bp->bp_vend[0], RFC2132_PARAM_LIST);
diff --git a/src/VBox/Devices/Network/slirp/debug.c b/src/VBox/Devices/Network/slirp/debug.c
index 14c29295..22284b72 100644
--- a/src/VBox/Devices/Network/slirp/debug.c
+++ b/src/VBox/Devices/Network/slirp/debug.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/debug.h b/src/VBox/Devices/Network/slirp/debug.h
index 0a2ae900..8cedf5e5 100644
--- a/src/VBox/Devices/Network/slirp/debug.h
+++ b/src/VBox/Devices/Network/slirp/debug.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/dnsproxy/dnsproxy.c b/src/VBox/Devices/Network/slirp/dnsproxy/dnsproxy.c
index 7f3d742e..ca69bdf9 100644
--- a/src/VBox/Devices/Network/slirp/dnsproxy/dnsproxy.c
+++ b/src/VBox/Devices/Network/slirp/dnsproxy/dnsproxy.c
@@ -1,4 +1,17 @@
/* $Id: dnsproxy.c $ */
+
+/*
+ * Copyright (C) 2009-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
/*
* Copyright (c) 2003,2004,2005 Armin Wolfermann
*
@@ -104,64 +117,70 @@ timeout(PNATState pData, struct socket *so, void *arg)
{
struct request *req = (struct request *)arg;
struct dns_entry *de;
+ /* be paranoid */
+ AssertPtrReturnVoid(arg);
+
de = TAILQ_PREV(req->dns_server, dns_list_head, de_list);
- /* here we should check if we reached the end of the DNS server list */
+
if (de == NULL)
{
hash_remove_request(pData, req);
RTMemFree(req);
++removed_queries;
+ /* the rest of clean up at the end of the method. */
}
else
{
struct ip *ip;
struct udphdr *udp;
int iphlen;
- struct socket *so1 = socreate();
struct mbuf *m = NULL;
char *data;
- if (so1 == NULL)
- {
- LogRel(("NAT: can't create DNS socket\n"));
- return;
- }
- if(udp_attach(pData, so1) == -1)
- {
- LogRel(("NAT: can't attach udp socket\n"));
- sofree(pData, so1);
- return;
- }
+
m = slirpDnsMbufAlloc(pData);
if (m == NULL)
{
LogRel(("NAT: Can't allocate mbuf\n"));
- udp_detach(pData, so1);
- return;
+ goto socket_clean_up;
}
+
/* mbuf initialization */
m->m_data += if_maxlinkhdr;
+
ip = mtod(m, struct ip *);
udp = (struct udphdr *)&ip[1]; /* ip attributes */
data = (char *)&udp[1];
iphlen = sizeof(struct ip);
+
m->m_len += sizeof(struct ip);
m->m_len += sizeof(struct udphdr);
m->m_len += req->nbyte;
+
ip->ip_src.s_addr = so->so_laddr.s_addr;
ip->ip_dst.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_DNS);
udp->uh_dport = ntohs(53);
udp->uh_sport = so->so_lport;
+
memcpy(data, req->byte, req->nbyte); /* coping initial req */
- so1->so_laddr = so->so_laddr;
- so1->so_lport = so->so_lport;
- so1->so_faddr = so->so_faddr;
- so1->so_fport = so->so_fport;
+ /* req points to so->so_timeout_arg */
req->dns_server = de;
- so1->so_timeout_arg = req;
- so1->so_timeout = timeout;
- dnsproxy_query(pData, so1, m, iphlen);
+
+ /* expiration will be bumped in dnsproxy_query */
+
+ dnsproxy_query(pData, so, m, iphlen);
+ /* should we free so->so_m ? */
+ return;
}
+
+ socket_clean_up:
+ /* This socket (so) will be detached, so we need to remove timeout(&_arg) references
+ * before leave
+ */
+ so->so_timeout = NULL;
+ so->so_timeout_arg = NULL;
+ return;
+
}
#endif /* VBOX */
@@ -216,19 +235,6 @@ dnsproxy_query(PNATState pData, struct socket *so, struct mbuf *m, int iphlen)
++dropped_queries;
return;
}
-#else
- ip = mtod(m, struct ip *);
- udp = (struct udphdr *)(m->m_data + iphlen);
-
- fromaddr.sin_addr.s_addr = ip->ip_src.s_addr;
- fromaddr.sin_port = udp->uh_sport;
- fromaddr.sin_family = AF_INET;
-
- iphlen += sizeof (struct udphdr);
- byte = m->m_len - iphlen; /* size of IP header + udp header size */
- /* the validness of ip and udp header has been already checked so we shouldn't care if */
- buf = m->m_data + iphlen;
-#endif
/* check for minimum dns packet length */
if (byte < 12) {
@@ -237,7 +243,6 @@ dnsproxy_query(PNATState pData, struct socket *so, struct mbuf *m, int iphlen)
return;
}
-#ifndef VBOX
/* allocate new request */
if ((req = calloc(1, sizeof(struct request))) == NULL) {
LogRel(("calloc failed\n"));
@@ -248,49 +253,7 @@ dnsproxy_query(PNATState pData, struct socket *so, struct mbuf *m, int iphlen)
req->id = QUERYID;
memcpy(&req->client, &fromaddr, sizeof(struct sockaddr_in));
memcpy(&req->clientid, &buf[0], 2);
-#else
- /* allocate new request */
- req = so->so_timeout_arg; /* in slirp we might re-send the query*/
- if (req == NULL)
- {
- if ((req = RTMemAllocZ(sizeof(struct request) + byte)) == NULL) {
- LogRel(("calloc failed\n"));
- ++dropped_queries;
- return;
- }
- }
- /* fill the request structure */
- if (so->so_timeout_arg == NULL)
- {
- req->id = QUERYID;
- memcpy(&req->client, &fromaddr, sizeof(struct sockaddr_in));
- memcpy(&req->clientid, &buf[0], 2);
- req->dns_server = TAILQ_LAST(&pData->pDnsList, dns_list_head);
- if (req->dns_server == NULL)
- {
- static int fail_counter = 0;
- RTMemFree(req);
- if (fail_counter == 0)
- LogRel(("NAT/dnsproxy: Empty DNS entry (suppressed 100 times)\n"));
- else
- fail_counter = (fail_counter == 100 ? 0 : fail_counter + 1);
- return;
-
- }
- retransmit = 0;
- so->so_timeout = timeout;
- so->so_timeout_arg = req;
- req->nbyte = byte;
- memcpy(req->byte, buf, byte); /* copying original request */
- }
- else
- {
- retransmit = 1;
- }
-#endif
-
-#ifndef VBOX
/* where is this query coming from? */
if (is_internal(pData, fromaddr.sin_addr)) {
req->recursion = RD(buf);
@@ -303,17 +266,10 @@ dnsproxy_query(PNATState pData, struct socket *so, struct mbuf *m, int iphlen)
/* insert it into the hash table */
hash_add_request(pData, req);
-#else
- req->recursion = 0;
- DPRINTF(("External query RD=%d\n", RD(buf)));
- if (retransmit == 0)
- hash_add_request(pData, req);
-#endif
/* overwrite the original query id */
memcpy(&buf[0], &req->id, 2);
-#ifndef VBOX
if (req->recursion) {
/* recursive queries timeout in 90s */
@@ -347,30 +303,141 @@ dnsproxy_query(PNATState pData, struct socket *so, struct mbuf *m, int iphlen)
++dropped_queries;
return;
}
+ ++authoritative_queries;
+ }
-#else
- so->so_expire = curtime + recursive_timeout * 1000; /* let's slirp to care about expiration */
- memset(&addr, 0, sizeof(struct sockaddr_in));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = req->dns_server->de_addr.s_addr;
- addr.sin_port = htons(53);
- so->so_expire = curtime + recursive_timeout * 1000; /* let's slirp to care about expiration */
- /* send it to our authoritative server */
- Log2(("NAT: request will be sent to %RTnaipv4 on %R[natsock]\n", addr.sin_addr, so));
- if ((byte = sendto(so->s, buf, (unsigned int)byte, 0,
- (struct sockaddr *)&addr,
- sizeof(struct sockaddr_in))) == -1) {
- LogRel(("sendto failed: %s\n", strerror(errno)));
+#else /* VBOX */
+ AssertPtr(pData);
+
+ /* m->m_data points to IP header */
+#if 0
+ /* XXX: for some reason it make gdb ill,
+ * it good to have this assert here with assumption above.
+ */
+ M_ASSERTPKTHDR(m);
+#endif
+
+ ip = mtod(m, struct ip *);
+ udp = (struct udphdr *)(m->m_data + iphlen);
+
+ fromaddr.sin_addr.s_addr = ip->ip_src.s_addr;
+ fromaddr.sin_port = udp->uh_sport;
+ fromaddr.sin_family = AF_INET;
+
+ /* iphlen equals to lenght of ip header */
+ Assert(iphlen == sizeof(struct ip));
+ iphlen += sizeof (struct udphdr);
+
+ byte = m->m_len - iphlen;
+ buf = m->m_data + iphlen;
+
+ /* check for minimum dns packet length */
+ if (byte < 12) {
+ LogRel(("query too short from %RTnaipv4\n", fromaddr.sin_addr));
+ ++dropped_queries;
+ return;
+ }
+
+
+ req = so->so_timeout_arg;
+
+ if (!req)
+ {
+
+ Assert(!so->so_timeout_arg);
+
+ if ((req = RTMemAllocZ(sizeof(struct request) + byte)) == NULL)
+ {
+ LogRel(("calloc failed\n"));
++dropped_queries;
return;
}
- so->so_state = SS_ISFCONNECTED; /* now it's selected */
- Log2(("NAT: request was sent to %RTnaipv4 on %R[natsock]\n", addr.sin_addr, so));
-#endif
- ++authoritative_queries;
-#ifndef VBOX
+
+ req->id = QUERYID;
+ memcpy(&req->client, &fromaddr, sizeof(struct sockaddr_in));
+ memcpy(&req->clientid, &buf[0], 2);
+ req->dns_server = TAILQ_LAST(&pData->pDnsList, dns_list_head);
+ if (req->dns_server == NULL)
+ {
+ static int fail_counter = 0;
+ RTMemFree(req);
+ /** @todo: This is completely bogus, fail_counter will always be 0. */
+ if (fail_counter == 0)
+ LogRel(("NAT/dnsproxy: Empty DNS entry (suppressed 100 times)\n"));
+ else
+ fail_counter = (fail_counter == 100 ? 0 : fail_counter + 1);
+ return;
+
+ }
+ retransmit = 0;
+ so->so_timeout = timeout;
+ so->so_timeout_arg = req;
+ req->nbyte = byte;
+ memcpy(req->byte, buf, byte); /* copying original request */
}
-#endif
+ else
+ {
+ retransmit = 1;
+ }
+
+ req->recursion = 0;
+
+ DPRINTF(("External query RD=%d\n", RD(buf)));
+
+ if (retransmit == 0)
+ hash_add_request(pData, req);
+
+
+ /* overwrite the original query id */
+ memcpy(&buf[0], &req->id, 2);
+
+ /* let's slirp to care about expiration */
+ so->so_expire = curtime + recursive_timeout * 1000;
+
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ if (req->dns_server->de_addr.s_addr == (pData->special_addr.s_addr | RT_H2N_U32_C(CTL_ALIAS))) {
+ /* undo loopback remapping done in get_dns_addr_domain() */
+ addr.sin_addr.s_addr = RT_N2H_U32_C(INADDR_LOOPBACK);
+ }
+ else {
+ addr.sin_addr.s_addr = req->dns_server->de_addr.s_addr;
+ }
+ addr.sin_port = htons(53);
+
+ /* send it to our authoritative server */
+ Log2(("NAT: request will be sent to %RTnaipv4 on %R[natsock]\n", addr.sin_addr, so));
+
+ byte = sendto(so->s, buf, (unsigned int)byte, 0,
+ (struct sockaddr *)&addr,
+ sizeof(struct sockaddr_in));
+ if (byte == -1)
+ {
+ /* XXX: is it really enough? */
+ LogRel(("sendto failed: %s\n", strerror(errno)));
+ ++dropped_queries;
+ return;
+ }
+
+ so->so_state = SS_ISFCONNECTED; /* now it's selected */
+ Log2(("NAT: request was sent to %RTnaipv4 on %R[natsock]\n", addr.sin_addr, so));
+
+ ++authoritative_queries;
+
+# if 0
+ /* XXX: this stuff for _debugging_ only,
+ * first enforce guest to send next request
+ * and second for faster getting timeout callback
+ * other option is adding couple entries in resolv.conf with
+ * invalid nameservers.
+ *
+ * For testing purposes could be used
+ * namebench -S -q 10000 -m random or -m chunk
+ */
+ /* RTThreadSleep(3000); */
+ /* curtime += 300; */
+# endif
+#endif /* VBOX */
}
/* do_answer -- Process a packet coming from our authoritative or recursive
@@ -404,13 +471,6 @@ dnsproxy_answer(PNATState pData, struct socket *so, struct mbuf *m)
++dropped_answers;
return;
}
-#else
- char *buf;
- int byte;
- struct request *query = NULL;
- byte = m->m_len;
- buf = mtod(m, char *);
-#endif
/* check for minimum dns packet length */
if (byte < 12) {
@@ -420,51 +480,91 @@ dnsproxy_answer(PNATState pData, struct socket *so, struct mbuf *m)
}
/* find corresponding query */
-#ifdef VBOX
- if ((query = hash_find_request(pData, *((unsigned short *)buf))) == NULL) {
- ++late_answers;
- /* Probably, this request wasn't serviced by
- * dnsproxy so we won't care about it here*/
- so->so_expire = curtime + SO_EXPIREFAST;
- Log2(("NAT: query wasn't found\n"));
- return;
- }
- so->so_timeout = NULL;
- so->so_timeout_arg = NULL;
-#else
if ((query = hash_find_request(pData, *((unsigned short *)&buf))) == NULL) {
++late_answers;
return;
}
event_del(&query->timeout);
-#endif
+
hash_remove_request(pData, query);
/* restore original query id */
memcpy(&buf[0], &query->clientid, 2);
-#ifndef VBOX
- /* Slirp: will send mbuf to guest by itself */
- /* send answer back to querying host */
if (sendto(sock_query, buf, (unsigned int)byte, 0,
(struct sockaddr *)&query->client,
sizeof(struct sockaddr_in)) == -1) {
LogRel(("sendto failed: %s\n", strerror(errno)));
++dropped_answers;
- } else
+ }
+ else
++answered_queries;
free(query);
-#else
+#else /* VBOX */
+
+ char *buf = NULL;
+ int byte = 0;
+ struct request *query = NULL;
+
+ AssertPtr(pData);
+
+ /* XXX: mbuf->data points to ??? */
+ byte = m->m_len;
+ buf = mtod(m, char *);
+
+ /* check for minimum dns packet length */
+ if (byte < 12) {
+ LogRel(("answer too short\n"));
+ ++dropped_answers;
+ return;
+ }
+
+ query = hash_find_request(pData, *((unsigned short *)buf));
+
+ /* find corresponding query */
+ if (query == NULL)
+ {
+ /* XXX: if we haven't found anything for this request ...
+ * What we are expecting later?
+ */
+ ++late_answers;
+ so->so_expire = curtime + SO_EXPIREFAST;
+ Log2(("NAT: query wasn't found\n"));
+ return;
+ }
+
+ so->so_timeout = NULL;
+ so->so_timeout_arg = NULL;
+
+ hash_remove_request(pData, query);
+
+ /* restore original query id */
+ memcpy(&buf[0], &query->clientid, 2);
+
++answered_queries;
RTMemFree(query);
-#endif
+#endif /* VBOX */
}
+
+#ifdef VBOX
+int
+dnsproxy_init(PNATState pData)
+{
+ /* globals initialization */
+ authoritative_port = 53;
+ authoritative_timeout = 10;
+ recursive_port = 53;
+ recursive_timeout = 2;
+ stats_timeout = 3600;
+ dns_port = 53;
+ return 0;
+}
+#else /* !VBOX */
/* main -- dnsproxy main function
*/
-#ifndef VBOX
int
main(int argc, char *argv[])
{
@@ -624,17 +724,4 @@ main(int argc, char *argv[])
return 0;
}
-#else
-int
-dnsproxy_init(PNATState pData)
-{
- /* globals initialization */
- authoritative_port = 53;
- authoritative_timeout = 10;
- recursive_port = 53;
- recursive_timeout = 2;
- stats_timeout = 3600;
- dns_port = 53;
- return 0;
-}
#endif
diff --git a/src/VBox/Devices/Network/slirp/dnsproxy/hash.c b/src/VBox/Devices/Network/slirp/dnsproxy/hash.c
index 0d007d05..0de6cbea 100644
--- a/src/VBox/Devices/Network/slirp/dnsproxy/hash.c
+++ b/src/VBox/Devices/Network/slirp/dnsproxy/hash.c
@@ -29,7 +29,7 @@
#define HASH(id) (id & ((1 << HASHSIZE) - 1))
static struct request *request_hash[1 << HASHSIZE];
-#else
+#else /* VBOX */
# include "slirp.h"
#endif
diff --git a/src/VBox/Devices/Network/slirp/ext.h b/src/VBox/Devices/Network/slirp/ext.h
index e18285ae..3248f559 100644
--- a/src/VBox/Devices/Network/slirp/ext.h
+++ b/src/VBox/Devices/Network/slirp/ext.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/ip_icmp.c b/src/VBox/Devices/Network/slirp/ip_icmp.c
index e924372d..b760cdd3 100644
--- a/src/VBox/Devices/Network/slirp/ip_icmp.c
+++ b/src/VBox/Devices/Network/slirp/ip_icmp.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -56,8 +56,9 @@
#include "slirp.h"
#include "ip_icmp.h"
#ifdef RT_OS_WINDOWS
-#include <Icmpapi.h>
-#include <Iphlpapi.h>
+# include <Icmpapi.h>
+# include <Iphlpapi.h>
+# include <iprt/ldr.h>
#endif
/* The message sent when emulating PING */
@@ -115,54 +116,52 @@ icmp_init(PNATState pData, int iIcmpCacheLimit)
}
fd_nonblock(pData->icmp_socket.s);
NSOCK_INC();
+
#else /* RT_OS_WINDOWS */
- pData->hmIcmpLibrary = LoadLibrary("Iphlpapi.dll");
- if (pData->hmIcmpLibrary != NULL)
+ /* Resolve symbols we need. */
{
- pData->pfIcmpParseReplies = (long (WINAPI *)(void *, long))
- GetProcAddress(pData->hmIcmpLibrary, "IcmpParseReplies");
- pData->pfIcmpCloseHandle = (BOOL (WINAPI *)(HANDLE))
- GetProcAddress(pData->hmIcmpLibrary, "IcmpCloseHandle");
- pData->pfGetAdaptersAddresses = (ULONG (WINAPI *)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG))
- GetProcAddress(pData->hmIcmpLibrary, "GetAdaptersAddresses");
- if (pData->pfGetAdaptersAddresses == NULL)
+ RTLDRMOD hLdrMod;
+ int rc = RTLdrLoadSystem("Iphlpapi.dll", true /*fNoUnload*/, &hLdrMod);
+ if (RT_SUCCESS(rc))
{
- LogRel(("NAT: Can't find GetAdapterAddresses in Iphlpapi.dll\n"));
+ pData->pfIcmpParseReplies = (long (WINAPI *)(void *, long))RTLdrGetFunction(hLdrMod, "IcmpParseReplies");
+ pData->pfIcmpCloseHandle = (BOOL (WINAPI *)(HANDLE))RTLdrGetFunction(hLdrMod, "IcmpCloseHandle");
+ rc = RTLdrGetSymbol(hLdrMod, "GetAdaptersAddresses", (void **)&pData->pfGetAdaptersAddresses);
+ if (RT_FAILURE(rc))
+ LogRel(("NAT: Can't find GetAdapterAddresses in Iphlpapi.dll\n"));
+ RTLdrClose(hLdrMod);
}
- }
- if (pData->pfIcmpParseReplies == NULL)
- {
- if(pData->pfGetAdaptersAddresses == NULL)
- FreeLibrary(pData->hmIcmpLibrary);
- pData->hmIcmpLibrary = LoadLibrary("Icmp.dll");
- if (pData->hmIcmpLibrary == NULL)
+ if (pData->pfIcmpParseReplies == NULL)
{
- LogRel(("NAT: Icmp.dll could not be loaded\n"));
- return 1;
+ int rc = RTLdrLoadSystem("Icmp.dll", true /*fNoUnload*/, &hLdrMod);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("NAT: Icmp.dll could not be loaded: %Rrc\n", rc));
+ return 1;
+ }
+ pData->pfIcmpParseReplies = (long (WINAPI *)(void *, long))RTLdrGetFunction(hLdrMod, "IcmpParseReplies");
+ pData->pfIcmpCloseHandle = (BOOL (WINAPI *)(HANDLE))RTLdrGetFunction(hLdrMod, "IcmpCloseHandle");
+ RTLdrClose(hLdrMod);
}
- pData->pfIcmpParseReplies = (long (WINAPI *)(void *, long))
- GetProcAddress(pData->hmIcmpLibrary, "IcmpParseReplies");
- pData->pfIcmpCloseHandle = (BOOL (WINAPI *)(HANDLE))
- GetProcAddress(pData->hmIcmpLibrary, "IcmpCloseHandle");
}
if (pData->pfIcmpParseReplies == NULL)
{
LogRel(("NAT: Can't find IcmpParseReplies symbol\n"));
- FreeLibrary(pData->hmIcmpLibrary);
return 1;
}
if (pData->pfIcmpCloseHandle == NULL)
{
LogRel(("NAT: Can't find IcmpCloseHandle symbol\n"));
- FreeLibrary(pData->hmIcmpLibrary);
return 1;
}
+
pData->icmp_socket.sh = IcmpCreateFile();
pData->phEvents[VBOX_ICMP_EVENT_INDEX] = CreateEvent(NULL, FALSE, FALSE, NULL);
- pData->szIcmpBuffer = sizeof(ICMP_ECHO_REPLY) * 10;
- pData->pvIcmpBuffer = RTMemAlloc(pData->szIcmpBuffer);
+ pData->cbIcmpBuffer = sizeof(ICMP_ECHO_REPLY) * 10;
+ pData->pvIcmpBuffer = RTMemAlloc(pData->cbIcmpBuffer);
#endif /* RT_OS_WINDOWS */
+
LIST_INIT(&pData->icmp_msg_head);
return 0;
}
@@ -176,7 +175,6 @@ icmp_finit(PNATState pData)
icmp_cache_clean(pData, -1);
#ifdef RT_OS_WINDOWS
pData->pfIcmpCloseHandle(pData->icmp_socket.sh);
- FreeLibrary(pData->hmIcmpLibrary);
RTMemFree(pData->pvIcmpBuffer);
#else
closesocket(pData->icmp_socket.s);
@@ -450,7 +448,9 @@ icmp_input(PNATState pData, struct mbuf *m, int hlen)
case ICMP_ECHO:
ip->ip_len += hlen; /* since ip_input subtracts this */
dst = ip->ip_dst.s_addr;
- if (dst == alias_addr.s_addr)
+ if ( CTL_CHECK(dst, CTL_ALIAS)
+ || CTL_CHECK(dst, CTL_DNS)
+ || CTL_CHECK(dst, CTL_TFTP))
{
icp->icmp_type = ICMP_ECHOREPLY;
ip->ip_dst.s_addr = ip->ip_src.s_addr;
@@ -526,7 +526,7 @@ icmp_input(PNATState pData, struct mbuf *m, int hlen)
icmplen - ICMP_MINLEN /*=RequestSize*/,
&ipopt /*=RequestOptions*/,
pData->pvIcmpBuffer /*=ReplyBuffer*/,
- pData->szIcmpBuffer /*=ReplySize*/,
+ pData->cbIcmpBuffer /*=ReplySize*/,
1 /*=Timeout in ms*/);
error = GetLastError();
if ( status != 0
@@ -601,17 +601,19 @@ done:
* be fully correct and in host byte order.
* ICMP fragmentation is illegal. All machines must accept 576 bytes in one
* packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
+ * @note: implementation note: MSIZE is 256 bytes (minimal buffer), m_getjcl we allocate two mbufs on: clust_zone
+ * and mbuf_zone. the maximum payload 256 - 14 (Ethernet header) - 20 (IPv4 hdr) - 8 (ICMPv4 header) = 214
*
* @note This function will free msrc!
*/
-#define ICMP_MAXDATALEN (IP_MSS-28)
void icmp_error(PNATState pData, struct mbuf *msrc, u_char type, u_char code, int minsize, const char *message)
{
unsigned hlen, shlen, s_ip_len;
register struct ip *ip;
register struct icmp *icp;
register struct mbuf *m;
+ int new_ip_size = 0;
int new_m_size = 0;
int size = 0;
@@ -652,70 +654,80 @@ void icmp_error(PNATState pData, struct mbuf *msrc, u_char type, u_char code, in
goto end_error;
}
- new_m_size = sizeof(struct ip) + ICMP_MINLEN + msrc->m_len + ICMP_MAXDATALEN;
- if (new_m_size < MSIZE)
- size = MCLBYTES;
- else if (new_m_size < MCLBYTES)
- size = MCLBYTES;
- else if(new_m_size < MJUM9BYTES)
- size = MJUM9BYTES;
- else if (new_m_size < MJUM16BYTES)
- size = MJUM16BYTES;
- else
- AssertMsgFailed(("Unsupported size"));
- m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, size);
+ m = m_gethdr(pData, M_NOWAIT, MT_HEADER);
if (!m)
goto end_error;
+ m->m_flags |= M_SKIP_FIREWALL;
m->m_data += if_maxlinkhdr;
m->m_pkthdr.header = mtod(m, void *);
- memcpy(m->m_data, msrc->m_data, msrc->m_len);
- m->m_len = msrc->m_len; /* copy msrc to m */
+ memcpy(m->m_pkthdr.header, ip, shlen); /* initialize respond IP header with data from original one. */
- /* make the header of the reply packet */
- ip = mtod(m, struct ip *);
- hlen = sizeof(struct ip); /* no options in reply */
+ ip = mtod(m, struct ip *); /* ip points to new IP header */
+ hlen = sizeof(struct ip); /* trim the IP header no options in reply */
/* fill in icmp */
- m->m_data += hlen;
- m->m_len -= hlen;
-
- icp = mtod(m, struct icmp *);
-
- if (minsize)
- s_ip_len = shlen+ICMP_MINLEN; /* return header+8b only */
- else if (s_ip_len > ICMP_MAXDATALEN) /* maximum size */
- s_ip_len = ICMP_MAXDATALEN;
-
- m->m_len = ICMP_MINLEN + s_ip_len; /* 8 bytes ICMP header */
-
- /* min. size = 8+sizeof(struct ip)+8 */
+ m->m_data += hlen; /* shifts m_data to ICMP header */
+ icp = mtod(m, struct icmp *); /* _icp_: points to the ICMP header */
+ m->m_data += RT_OFFSETOF(struct icmp, icmp_ip); /* shifts m_data to IP header payload */
icp->icmp_type = type;
icp->icmp_code = code;
icp->icmp_id = 0;
icp->icmp_seq = 0;
- memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */
-
HTONS(icp->icmp_ip.ip_len);
HTONS(icp->icmp_ip.ip_id);
HTONS(icp->icmp_ip.ip_off);
+ memcpy(mtod(m, void *), mtod(msrc, void *), shlen); /* copy original IP header (with options) */
+ msrc->m_data += shlen; /* _msrc_: shifts m_data of original mbuf to the end of original IP header */
+ msrc->m_len -= shlen; /* _msrc_: alter m_len to size of original IP datagram payload */
+ m->m_data += shlen; /* _m_: shifts m_data to the end of reported IP datagram */
+ /* initialize reported payload of original datagram with MUST size RFC792 or with rest of allocated mbuf */
+ s_ip_len = minsize ? 8 : M_TRAILINGSPACE(m);
+ /* trims original IP datagram's payload to the lenght of its mbuf size or already reserved space if it's smaller */
+ s_ip_len = RT_MIN(s_ip_len, msrc->m_len);
+ memcpy(mtod(m, void *), mtod(msrc, void *), s_ip_len);
+
#if DEBUG
if (message)
{
- /* DEBUG : append message to ICMP packet */
- int message_len;
+
+ size_t message_len;
+ /**
+ * Trim reported payload to first eight bytes (RFC792) to let sniffering tools do
+ * their audit duties, and add hint message to the tail of mandatory piece.
+ */
+ s_ip_len = 8;
+ /**
+ * _m_: shifts m_data to the end of mandatory 8b piece to let M_TRAILINGSPACE
+ * to returns available space with counting mandatory region.
+ */
+ m->m_data += s_ip_len;
message_len = strlen(message);
- if (message_len > ICMP_MAXDATALEN)
- message_len = ICMP_MAXDATALEN;
- m_append(pData, m, message_len, message);
+ if (message_len > M_TRAILINGSPACE(m))
+ message_len = M_TRAILINGSPACE(m);
+
+ /**
+ * m->m_data points to the end of 8 bytes payload, and m->m_len is length of appended
+ * message.
+ */
+ m_append(pData, m, (int)message_len, message);
+ m->m_data -= s_ip_len; /* now we're ready for further processing, with pointing to mandatory payload */
}
#else
NOREF(message);
#endif
+
+ m->m_data -= shlen + RT_OFFSETOF(struct icmp, icmp_ip); /* _m_: shifts m_data to the start of ICMP header */
+ m->m_len += s_ip_len + shlen + RT_OFFSETOF(struct icmp, icmp_ip); /* _m_: m_len counts bytes in IP payload */
+
+ /**
+ * It asserts if calculation above is wrong.
+ */
+ Assert(icp == mtod(m, struct icmp*));
icp->icmp_cksum = 0;
icp->icmp_cksum = cksum(m, m->m_len);
@@ -734,6 +746,11 @@ void icmp_error(PNATState pData, struct mbuf *msrc, u_char type, u_char code, in
/* returns pointer back. */
m->m_data -= hlen;
m->m_len += hlen;
+
+ /**
+ * paranoid. if something goes wrong previous assert should be triggered.
+ */
+ Assert(ip == mtod(m, struct ip*));
(void) ip_output0(pData, (struct socket *)NULL, m, 1);
icmpstat.icps_reflect++;
@@ -748,7 +765,7 @@ end_error:
/*
* clear source datagramm in case if some of requirement haven't been met.
*/
- if (!msrc)
+ if (msrc)
m_freem(pData, msrc);
{
@@ -761,7 +778,6 @@ end_error:
}
LogFlowFuncLeave();
}
-#undef ICMP_MAXDATALEN
/*
* Reflect the ip packet back to the source
diff --git a/src/VBox/Devices/Network/slirp/ip_icmp.h b/src/VBox/Devices/Network/slirp/ip_icmp.h
index eb3715f5..eb26aed8 100644
--- a/src/VBox/Devices/Network/slirp/ip_icmp.h
+++ b/src/VBox/Devices/Network/slirp/ip_icmp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/ip_input.c b/src/VBox/Devices/Network/slirp/ip_input.c
index db485f8d..6b4d48c1 100644
--- a/src/VBox/Devices/Network/slirp/ip_input.c
+++ b/src/VBox/Devices/Network/slirp/ip_input.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/ip_output.c b/src/VBox/Devices/Network/slirp/ip_output.c
index 654e3ce2..56257183 100644
--- a/src/VBox/Devices/Network/slirp/ip_output.c
+++ b/src/VBox/Devices/Network/slirp/ip_output.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/libalias/alias_dns.c b/src/VBox/Devices/Network/slirp/libalias/alias_dns.c
index d255457a..d451d9c1 100644
--- a/src/VBox/Devices/Network/slirp/libalias/alias_dns.c
+++ b/src/VBox/Devices/Network/slirp/libalias/alias_dns.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/libalias/alias_mod.c b/src/VBox/Devices/Network/slirp/libalias/alias_mod.c
index 2c4fda33..4da99393 100644
--- a/src/VBox/Devices/Network/slirp/libalias/alias_mod.c
+++ b/src/VBox/Devices/Network/slirp/libalias/alias_mod.c
@@ -141,7 +141,7 @@ _attach_handler(PNATState pData, struct proto_handler *p)
_attach_handler(struct proto_handler *p)
#endif
{
- struct proto_handler *b = NULL;
+ struct proto_handler *b = NULL, *handler_chain_tail = NULL;
LIBALIAS_WLOCK_ASSERT();
LIST_FOREACH(b, &handler_chain, entries) {
@@ -153,10 +153,14 @@ _attach_handler(struct proto_handler *p)
LIST_INSERT_BEFORE(b, p, entries);
return (0);
}
+
+ /* If the conditions above do not work, we should keep the last
+ * element of the list in order to insert *p right after it. */
+ handler_chain_tail = b;
}
/* End of list or found right position, inserts here. */
- if (b)
- LIST_INSERT_AFTER(b, p, entries);
+ if (handler_chain_tail)
+ LIST_INSERT_AFTER(handler_chain_tail, p, entries);
else
LIST_INSERT_HEAD(&handler_chain, p, entries);
return (0);
diff --git a/src/VBox/Devices/Network/slirp/libslirp.h b/src/VBox/Devices/Network/slirp/libslirp.h
index e67dfcee..c00071c6 100644
--- a/src/VBox/Devices/Network/slirp/libslirp.h
+++ b/src/VBox/Devices/Network/slirp/libslirp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -37,7 +37,6 @@ int inet_aton(const char *cp, struct in_addr *ia);
#endif
#include <VBox/types.h>
-#include <VBox/vmm/dbgf.h>
typedef struct NATState *PNATState;
struct mbuf;
@@ -93,9 +92,24 @@ void slirp_set_tcp_sndspace(PNATState pData, int kilobytes);
int slirp_set_binding_address(PNATState, char *addr);
void slirp_set_mtu(PNATState, int);
-void slirp_info(PNATState pData, PCDBGFINFOHLP pHlp, const char *pszArgs);
+void slirp_info(PNATState pData, const void *pvArg, const char *pszArgs);
void slirp_set_somaxconn(PNATState pData, int iSoMaxConn);
+/**
+ * This method help DrvNAT to select strategy: about VMRESUMEREASON_HOST_RESUME:
+ * - proceed with link termination (we let guest track host DNS settings)
+ * VBOX_NAT_HNCE_EXPOSED_NAME_RESOLVING_INFO
+ * - enforce internal DNS update (we are using dnsproxy and track but don't export DNS host settings)
+ * VBOX_NAT_HNCE_DNSPROXY
+ * - ignore (NAT configured to use hostresolver - we aren't track any host DNS changes)
+ * VBOX_NAT_HNCE_HOSTRESOLVER
+ * @note: It's safe to call this method from any thread, because settings we're checking
+ * are immutable at runtime.
+ */
+#define VBOX_NAT_HNCE_EXSPOSED_NAME_RESOLUTION_INFO 0
+#define VBOX_NAT_HNCE_DNSPROXY 1
+#define VBOX_NAT_HNCE_HOSTRESOLVER 2
+int slirp_host_network_configuration_change_strategy_selector(const PNATState);
#if defined(RT_OS_WINDOWS)
diff --git a/src/VBox/Devices/Network/slirp/misc.c b/src/VBox/Devices/Network/slirp/misc.c
index 578a6207..f785a6eb 100644
--- a/src/VBox/Devices/Network/slirp/misc.c
+++ b/src/VBox/Devices/Network/slirp/misc.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/misc.h b/src/VBox/Devices/Network/slirp/misc.h
index 64601eda..940df28d 100644
--- a/src/VBox/Devices/Network/slirp/misc.h
+++ b/src/VBox/Devices/Network/slirp/misc.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/queue.h b/src/VBox/Devices/Network/slirp/queue.h
index 20535fab..5d7f0cc3 100644
--- a/src/VBox/Devices/Network/slirp/queue.h
+++ b/src/VBox/Devices/Network/slirp/queue.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/resolv_conf_parser.c b/src/VBox/Devices/Network/slirp/resolv_conf_parser.c
new file mode 100644
index 00000000..dd5fb825
--- /dev/null
+++ b/src/VBox/Devices/Network/slirp/resolv_conf_parser.c
@@ -0,0 +1,539 @@
+/* $Id: resolv_conf_parser.c $ */
+/** @file
+ * resolv_conf_parser.c - parser of resolv.conf resolver(5)
+ */
+
+/*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/net.h>
+#include <iprt/string.h>
+#include <iprt/stream.h>
+#include <iprt/thread.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+
+#include "resolv_conf_parser.h"
+
+enum RCP_TOKEN
+{
+ tok_eof = -1, /* EOF */
+ tok_string = -2, /* string */
+ tok_number = -3, /* number */
+ tok_ipv4 = -4, /* ipv4 */
+ tok_ipv4_port = -5, /* ipv4 port */
+ tok_ipv6 = -6, /* ipv6 */
+ tok_ipv6_port = -7, /* ipv6 port */
+ tok_nameserver = -8, /* nameserver */
+ tok_port = -9, /* port, Mac OSX specific */
+ tok_domain = -10, /* domain */
+ tok_search = -11, /* search */
+ tok_search_order = -12, /* search order */
+ tok_sortlist = -13, /* sortlist */
+ tok_timeout = -14, /* timeout */
+ tok_options = -15, /* options */
+ tok_option = -16, /* option */
+ tok_comment = -17, /* comment */
+ tok_error = -20
+};
+
+#define RCP_BUFFER_SIZE 256
+
+
+struct rcp_parser
+{
+ enum RCP_TOKEN rcpp_token;
+ char rcpp_str_buffer[RCP_BUFFER_SIZE];
+ struct rcp_state *rcpp_state;
+ PRTSTREAM rcpp_stream;
+};
+
+
+#define GETCHAR(parser) (RTStrmGetCh((parser)->rcpp_stream))
+#define EOF (-1)
+
+
+#define PARSER_STOP(tok, parser, ptr) ( (tok) != EOF \
+ && (((ptr) - (parser)->rcpp_str_buffer) != (RCP_BUFFER_SIZE - 1)))
+#define PARSER_BUFFER_EXCEEDED(parser, ptr) \
+ do { \
+ if (((ptr) - (parser)->rcpp_str_buffer) == (RCP_BUFFER_SIZE - 1)) { \
+ return tok_error; \
+ } \
+ }while(0);
+
+static int rcp_get_token(struct rcp_parser *parser)
+{
+ char tok = ' ';
+ char *ptr;
+ size_t ptr_len;
+
+ while (isspace(tok))
+ tok = GETCHAR(parser);
+
+ ptr = parser->rcpp_str_buffer;
+
+ /* tok can't be ipv4 */
+ if (isalnum(tok)) {
+ int xdigit, digit, dot_number;
+ RT_ZERO(parser->rcpp_str_buffer);
+
+ dot_number = 0;
+ xdigit = 1;
+ digit = 1;
+ do {
+ *ptr++ = tok;
+ tok = GETCHAR(parser);
+
+ if (!isalnum(tok) && tok != ':' && tok != '.' && tok != '-' && tok != '_')
+ break;
+
+ /**
+ * if before ':' there were only [0-9][a-f][A-F],
+ * then it can't be option.
+ */
+ xdigit &= (isxdigit(tok) || (tok == ':'));
+ /**
+ * We want hint to differ ipv4 and network name.
+ */
+ digit &= (isdigit(tok) || (tok == '.'));
+
+ if (tok == ':')
+ {
+ if (xdigit == 1)
+ {
+ int port = 0;
+ do
+ {
+ *ptr++ = tok;
+ tok = GETCHAR(parser);
+
+ if (tok == '.')
+ port++;
+
+ } while(PARSER_STOP(tok, parser, ptr) && (tok == ':' || tok == '.' || isxdigit(tok)));
+
+ PARSER_BUFFER_EXCEEDED(parser, ptr);
+
+ if (port == 0)
+ return tok_ipv6;
+ else if (port == 1)
+ return tok_ipv6_port;
+ else
+ {
+ /* eats rest of the token */
+ do
+ {
+ *ptr++ = tok;
+ tok = GETCHAR(parser);
+ } while( PARSER_STOP(tok, parser, ptr)
+ && (isalnum(tok) || tok == '.' || tok == '_' || tok == '-'));
+
+ PARSER_BUFFER_EXCEEDED(parser, ptr);
+
+ return tok_string;
+ }
+ }
+ else {
+ /* XXX: need further experiments */
+ return tok_option; /* option with value */
+ }
+ }
+
+ if (tok == '.')
+ {
+ do {
+ if (tok == '.') dot_number++;
+
+ *ptr++ = tok;
+ digit &= (isdigit(tok) || (tok == '.'));
+ tok = GETCHAR(parser);
+ } while( PARSER_STOP(tok, parser, ptr)
+ && (isalnum(tok) || tok == '.' || tok == '_' || tok == '-'));
+
+ PARSER_BUFFER_EXCEEDED(parser, ptr);
+
+ if (dot_number == 3 && digit)
+ return tok_ipv4;
+ else if (dot_number == 4 && digit)
+ return tok_ipv4_port;
+ else
+ return tok_string;
+ }
+ } while( PARSER_STOP(tok, parser, ptr)
+ && (isalnum(tok) || tok == ':' || tok == '.' || tok == '-' || tok == '_'));
+
+ PARSER_BUFFER_EXCEEDED(parser, ptr);
+
+ if (digit || xdigit)
+ return tok_number;
+ if (RTStrCmp(parser->rcpp_str_buffer, "nameserver") == 0)
+ return tok_nameserver;
+ if (RTStrCmp(parser->rcpp_str_buffer, "port") == 0)
+ return tok_port;
+ if (RTStrCmp(parser->rcpp_str_buffer, "domain") == 0)
+ return tok_domain;
+ if (RTStrCmp(parser->rcpp_str_buffer, "search") == 0)
+ return tok_search;
+ if (RTStrCmp(parser->rcpp_str_buffer, "search_order") == 0)
+ return tok_search_order;
+ if (RTStrCmp(parser->rcpp_str_buffer, "sortlist") == 0)
+ return tok_sortlist;
+ if (RTStrCmp(parser->rcpp_str_buffer, "timeout") == 0)
+ return tok_timeout;
+ if (RTStrCmp(parser->rcpp_str_buffer, "options") == 0)
+ return tok_options;
+
+ return tok_string;
+ }
+
+ if (tok == EOF) return tok_eof;
+
+ if (tok == '#')
+ {
+ do{
+ tok = GETCHAR(parser);
+ } while (tok != EOF && tok != '\r' && tok != '\n');
+
+ if (tok == EOF) return tok_eof;
+
+ return tok_comment;
+ }
+ return tok;
+}
+
+#undef PARSER_STOP
+#undef PARSER_BUFFER_EXCEEDED
+
+/**
+ * nameserverexpr ::= 'nameserver' ip+
+ * @note: resolver(5) ip ::= (ipv4|ipv6)(.number)?
+ */
+static enum RCP_TOKEN rcp_parse_nameserver(struct rcp_parser *parser)
+{
+ enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'nameserver' */
+
+ if ( ( tok != tok_ipv4
+ && tok != tok_ipv4_port
+ && tok != tok_ipv6
+ && tok != tok_ipv6_port)
+ || tok == EOF)
+ return tok_error;
+
+ while ( tok == tok_ipv4
+ || tok == tok_ipv4_port
+ || tok == tok_ipv6
+ || tok == tok_ipv6_port)
+ {
+ struct rcp_state *st;
+ RTNETADDR *address;
+ char *str_address;
+
+ Assert(parser->rcpp_state);
+
+ st = parser->rcpp_state;
+
+ /* It's still valid resolv.conf file, just rest of the nameservers should be ignored */
+ if (st->rcps_num_nameserver >= RCPS_MAX_NAMESERVERS)
+ return rcp_get_token(parser);
+
+ address = &st->rcps_nameserver[st->rcps_num_nameserver];
+ str_address = &st->rcps_nameserver_str_buffer[st->rcps_num_nameserver * RCPS_IPVX_SIZE];
+
+#ifdef RT_OS_DARWIN
+ if ( tok == tok_ipv4_port
+ || ( tok == tok_ipv6_port
+ && (st->rcps_flags & RCPSF_IGNORE_IPV6) == 0))
+ {
+ char *ptr = &parser->rcpp_str_buffer[strlen(parser->rcpp_str_buffer)];
+ while (*(--ptr) != '.');
+ *ptr = '\0';
+ address->uPort = RTStrToUInt16(ptr + 1);
+
+ if (address->uPort == 0) return tok_error;
+ }
+#endif
+ /**
+ * if we on Darwin upper code will cut off port if it's.
+ */
+ if ((st->rcps_flags & RCPSF_NO_STR2IPCONV) != 0)
+ {
+ if (strlen(parser->rcpp_str_buffer) > RCPS_IPVX_SIZE)
+ return tok_error;
+
+ strcpy(str_address, parser->rcpp_str_buffer);
+
+ st->rcps_str_nameserver[st->rcps_num_nameserver] = str_address;
+
+ goto loop_prolog;
+ }
+
+ switch (tok)
+ {
+ case tok_ipv4:
+ case tok_ipv4_port:
+ {
+ int rc = RTNetStrToIPv4Addr(parser->rcpp_str_buffer, &address->uAddr.IPv4);
+ if (RT_FAILURE(rc)) return tok_error;
+
+ address->enmType = RTNETADDRTYPE_IPV4;
+ }
+
+ break;
+ case tok_ipv6:
+ case tok_ipv6_port:
+ {
+ int rc;
+
+ if ((st->rcps_flags & RCPSF_IGNORE_IPV6) != 0)
+ return rcp_get_token(parser);
+
+ rc = inet_pton(AF_INET6, parser->rcpp_str_buffer,
+ &address->uAddr.IPv6);
+ if (rc == -1)
+ return tok_error;
+
+ address->enmType = RTNETADDRTYPE_IPV6;
+ }
+
+ break;
+ default: /* loop condition doesn't let enter enything */
+ AssertMsgFailed(("shouldn't ever happen tok:%d, %s", tok,
+ isprint(tok) ? parser->rcpp_str_buffer : "#"));
+ break;
+ }
+
+ loop_prolog:
+ st->rcps_num_nameserver++;
+ tok = rcp_get_token(parser);
+ }
+ return tok;
+}
+
+/**
+ * portexpr ::= 'port' [0-9]+
+ */
+static enum RCP_TOKEN rcp_parse_port(struct rcp_parser *parser)
+{
+ struct rcp_state *st;
+ enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'port' */
+
+ Assert(parser->rcpp_state);
+ st = parser->rcpp_state;
+
+ if ( tok != tok_number
+ || tok == tok_eof)
+ return tok_error;
+
+ st->rcps_port = RTStrToUInt16(parser->rcpp_str_buffer);
+
+ if (st->rcps_port == 0)
+ return tok_error;
+
+ return rcp_get_token(parser);
+}
+
+/**
+ * domainexpr ::= 'domain' string
+ */
+static enum RCP_TOKEN rcp_parse_domain(struct rcp_parser *parser)
+{
+ struct rcp_state *st;
+ enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'domain' */
+
+ Assert(parser->rcpp_state);
+ st = parser->rcpp_state;
+
+ /**
+ * It's nowhere specified how resolver should react on dublicats
+ * of 'domain' declarations, let's assume that resolv.conf is broken.
+ */
+ if ( tok == tok_eof
+ || tok == tok_error
+ || st->rcps_domain != NULL)
+ return tok_error;
+
+ strcpy(st->rcps_domain_buffer, parser->rcpp_str_buffer);
+ /**
+ * We initialize this pointer in place, just make single pointer check
+ * in 'domain'-less resolv.conf.
+ */
+ st->rcps_domain = st->rcps_domain_buffer;
+
+ return rcp_get_token(parser);
+}
+
+/**
+ * searchexpr ::= 'search' (string)+
+ * @note: resolver (5) Mac OSX:
+ * "The search list is currently limited to six domains with a total of 256 characters."
+ * @note: resolv.conf (5) Linux:
+ * "The search list is currently limited to six domains with a total of 256 characters."
+ */
+static enum RCP_TOKEN rcp_parse_search(struct rcp_parser *parser)
+{
+ unsigned i, len, trailing;
+ char *ptr;
+ struct rcp_state *st;
+ enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'search' */
+
+ Assert(parser->rcpp_state);
+ st = parser->rcpp_state;
+
+ /**
+ * We asume that duplication of search list in resolv.conf isn't correct.
+ */
+ if ( tok == tok_eof
+ || tok == tok_error
+ || tok != tok_string
+ || st->rcps_searchlist[0] != NULL)
+ return tok_error;
+
+ i = 0;
+ trailing = RCPS_BUFFER_SIZE;
+ do {
+ len = strlen(parser->rcpp_str_buffer);
+
+ if (len + 1 > trailing)
+ break; /* not enough room for new entry */
+
+ ptr = st->rcps_searchlist_buffer + RCPS_BUFFER_SIZE - trailing;
+ strcpy(ptr, parser->rcpp_str_buffer);
+
+ trailing -= len + 1; /* 1 reserved for '\0' */
+
+ st->rcps_searchlist[i] = ptr;
+
+ } while( (tok = rcp_get_token(parser)) == tok_string
+ && ++i != RCPS_MAX_SEARCHLIST);
+
+ st->rcps_num_searchlist = i;
+
+ return tok;
+}
+
+/**
+ * expr ::= nameserverexpr | expr
+ * ::= portexpr | expr
+ * ::= domainexpr | expr
+ * ::= searchexpr | expr
+ * ::= searchlistexpr | expr
+ * ::= search_orderexpr | expr
+ * ::= timeoutexpr | expr
+ * ::= optionsexpr | expr
+ */
+static int rcp_parse_primary(struct rcp_parser *parser)
+{
+ enum RCP_TOKEN tok;
+ tok = rcp_get_token(parser);
+
+ while( tok != tok_eof
+ && tok != tok_error)
+ {
+ switch (tok)
+ {
+ case tok_nameserver:
+ tok = rcp_parse_nameserver(parser);
+ break;
+ case tok_port:
+ tok = rcp_parse_port(parser);
+ break;
+ case tok_domain:
+ tok = rcp_parse_domain(parser);
+ break;
+ case tok_search:
+ tok = rcp_parse_search(parser);
+ break;
+ default:
+ tok = rcp_get_token(parser);
+ }
+ }
+
+ if (tok == tok_error)
+ return -1;
+
+ return 0;
+}
+
+
+int rcp_parse(struct rcp_state* state, const char *filename)
+{
+ unsigned i;
+ uint32_t flags;
+ int rc;
+ struct rcp_parser parser;
+ flags = state->rcps_flags;
+
+ RT_ZERO(parser);
+ RT_ZERO(*state);
+
+ state->rcps_flags = flags;
+
+ parser.rcpp_state = state;
+
+ /**
+ * for debugging need: with RCP_STANDALONE it's possible
+ * to run simplefied scenarious like
+ *
+ * # cat /etc/resolv.conf | rcp-test-0
+ * or in lldb
+ * # process launch -i /etc/resolv.conf
+ */
+#ifdef RCP_STANDALONE
+ if (filename == NULL)
+ parser.rcpp_stream = g_pStdIn;
+#else
+ if (filename == NULL)
+ return -1;
+#endif
+ else
+ {
+ rc = RTStrmOpen(filename, "r", &parser.rcpp_stream);
+ if (RT_FAILURE(rc)) return -1;
+ }
+
+ rc = rcp_parse_primary(&parser);
+
+ if (filename != NULL)
+ RTStrmClose(parser.rcpp_stream);
+
+ if (rc == -1)
+ return -1;
+
+#ifdef RT_OS_DARWIN
+ /**
+ * port recolv.conf's option and IP.port are Mac OSX extentions, there're no need to care on
+ * other hosts.
+ */
+ if (state->rcps_port == 0)
+ state->rcps_port = 53;
+
+ for(i = 0; (state->rcps_flags & RCPSF_NO_STR2IPCONV) == 0
+ && i != RCPS_MAX_NAMESERVERS; ++i)
+ {
+ RTNETADDR *addr = &state->rcps_nameserver[i];
+
+ if (addr->uPort == 0)
+ addr->uPort = state->rcps_port;
+ }
+#endif
+
+ if ( state->rcps_domain == NULL
+ && state->rcps_searchlist[0] != NULL)
+ state->rcps_domain = state->rcps_searchlist[0];
+
+ return 0;
+}
diff --git a/src/VBox/Devices/Network/slirp/resolv_conf_parser.h b/src/VBox/Devices/Network/slirp/resolv_conf_parser.h
new file mode 100644
index 00000000..21353fe9
--- /dev/null
+++ b/src/VBox/Devices/Network/slirp/resolv_conf_parser.h
@@ -0,0 +1,109 @@
+/* $Id: resolv_conf_parser.h $ */
+/** @file
+ * resolv_conf_parser.h - interface to parser of resolv.conf resolver(5)
+ */
+
+/*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __RESOLV_CONF_PARSER_H__
+#define __RESOLV_CONF_PARSER_H__
+
+#include <iprt/cdefs.h>
+#include <iprt/net.h>
+
+RT_C_DECLS_BEGIN
+
+#define RCPS_MAX_NAMESERVERS 3
+#define RCPS_MAX_SEARCHLIST 10
+#define RCPS_BUFFER_SIZE 256
+#define RCPS_IPVX_SIZE 47
+/**
+ * In Slirp we don't need IPv6 for general case (only for dnsproxy mode
+ * it's potentially acceptable)
+ */
+#define RCPSF_IGNORE_IPV6 RT_BIT(0)
+/**
+ * In Main, we perhaps don't need parsed IPv6 and IPv4, because parsed values are
+ * used in Network services.
+ */
+#define RCPSF_NO_STR2IPCONV RT_BIT(1)
+
+struct rcp_state
+{
+ uint16_t rcps_port;
+ /**
+ * Filling of this array ommited iff RCPSF_NO_STR2IPCONF in rcp_state::rcps_flags set.
+ */
+ RTNETADDR rcps_nameserver[RCPS_MAX_NAMESERVERS];
+ /**
+ * this array contains non-NULL (pointing to rcp_state::rcps_nameserver_str_buffer) iff
+ * RCPSF_NO_STR2IPCONF in rcp_state::rcps_flags set.
+ */
+ char *rcps_str_nameserver[RCPS_MAX_NAMESERVERS];
+ unsigned rcps_num_nameserver;
+ /**
+ * Shortcuts to storage, note that domain is optional
+ * and if it's missed in resolv.conf rcps_domain should be equal
+ * to rcps_search_list[0]
+ */
+ char *rcps_domain;
+ char *rcps_searchlist[RCPS_MAX_SEARCHLIST];
+ unsigned rcps_num_searchlist;
+
+ uint32_t rcps_flags;
+
+ char rcps_domain_buffer[RCPS_BUFFER_SIZE];
+ char rcps_searchlist_buffer[RCPS_BUFFER_SIZE];
+ char rcps_nameserver_str_buffer[RCPS_MAX_NAMESERVERS * RCPS_IPVX_SIZE];
+};
+
+
+/**
+ * This function parses specified file (expected to conform resolver (5) Mac OSX or resolv.conf (3) Linux)
+ * and fills the structure.
+ * @return 0 - on success
+ * -1 - on fail.
+ * <code>
+ * struct rcp_state state;
+ * int rc;
+ *
+ * rc = rcp_parse(&state, "/etc/resolv.conf");
+ * for(i = 0; rc == 0 && i != state.rcps_num_nameserver; ++i)
+ * {
+ * if ((state.rcps_flags & RCPSF_NO_STR2IPCONV) == 0)
+ * {
+ * const RTNETADDR *addr = &state.rcps_nameserver[i];
+ *
+ * switch (state.rcps_nameserver[i].enmType)
+ * {
+ * case RTNETADDRTYPE_IPV4:
+ * RTPrintf("nameserver[%d]: [%RTnaipv4]:%d\n", i, addr->uAddr.IPv4, addr->uPort);
+ * break;
+ * case RTNETADDRTYPE_IPV6:
+ * RTPrintf("nameserver[%d]: [%RTnaipv6]:%d\n", i, &addr->uAddr.IPv6, addr->uPort);
+ * break;
+ * default:
+ * break;
+ * }
+ * }
+ * else
+ * RTPrintf("nameserver[%d]: %s\n", i, state.rcps_str_nameserver[i]);
+ * }
+ * </code>
+ *
+ */
+int rcp_parse(struct rcp_state *, const char *);
+
+RT_C_DECLS_END
+
+#endif
diff --git a/src/VBox/Devices/Network/slirp/sbuf.c b/src/VBox/Devices/Network/slirp/sbuf.c
index 1f8c8b4c..45babcee 100644
--- a/src/VBox/Devices/Network/slirp/sbuf.c
+++ b/src/VBox/Devices/Network/slirp/sbuf.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/slirp.c b/src/VBox/Devices/Network/slirp/slirp.c
index 35215f37..2a7ecfd3 100644
--- a/src/VBox/Devices/Network/slirp/slirp.c
+++ b/src/VBox/Devices/Network/slirp/slirp.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -47,6 +47,7 @@
#endif
#include <VBox/err.h>
+#include <VBox/vmm/dbgf.h>
#include <VBox/vmm/pdmdrv.h>
#include <iprt/assert.h>
#include <iprt/file.h>
@@ -303,6 +304,7 @@ int slirp_init(PNATState *ppData, uint32_t u32NetAddr, uint32_t u32Netmask,
return VERR_NO_MEMORY;
pData->fPassDomain = !fUseHostResolver ? fPassDomain : false;
pData->fUseHostResolver = fUseHostResolver;
+ pData->fUseHostResolverPermanent = fUseHostResolver;
pData->pvUser = pvUser;
pData->netmask = u32Netmask;
@@ -351,8 +353,13 @@ int slirp_init(PNATState *ppData, uint32_t u32NetAddr, uint32_t u32Netmask,
/* set default addresses */
inet_aton("127.0.0.1", &loopback_addr);
- rc = slirpInitializeDnsSettings(pData);
- AssertRCReturn(rc, VINF_NAT_DNS);
+
+ if (!fUseHostResolver)
+ {
+ rc = slirpInitializeDnsSettings(pData);
+ AssertRCReturn(rc, VINF_NAT_DNS);
+ }
+
rc = slirpTftpInit(pData);
AssertRCReturn(rc, VINF_NAT_DNS);
@@ -736,7 +743,15 @@ void slirp_select_fill(PNATState pData, int *pnfds, struct pollfd *polls)
Log2(("NAT: %R[natsock] expired\n", so));
if (so->so_timeout != NULL)
{
+ /* so_timeout - might change the so_expire value or
+ * drop so_timeout* from so.
+ */
so->so_timeout(pData, so, so->so_timeout_arg);
+ /* on 4.2 so->
+ */
+ if ( so_next->so_prev != so /* so_timeout freed the socket */
+ || so->so_timeout) /* so_timeout just freed so_timeout */
+ CONTINUE_NO_UNLOCK(udp);
}
UDP_DETACH(pData, so, so_next);
CONTINUE_NO_UNLOCK(udp);
@@ -1976,11 +1991,12 @@ void slirp_set_mtu(PNATState pData, int mtu)
/**
* Info handler.
*/
-void slirp_info(PNATState pData, PCDBGFINFOHLP pHlp, const char *pszArgs)
+void slirp_info(PNATState pData, const void *pvArg, const char *pszArgs)
{
struct socket *so, *so_next;
struct arp_cache_entry *ac;
struct port_forward_rule *rule;
+ PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvArg;
NOREF(pszArgs);
pHlp->pfnPrintf(pHlp, "NAT parameters: MTU=%d\n", if_mtu);
@@ -2011,3 +2027,11 @@ void slirp_info(PNATState pData, PCDBGFINFOHLP pHlp, const char *pszArgs)
rule->activated ? ' ' : '*');
}
}
+
+
+int slirp_host_network_configuration_change_strategy_selector(const PNATState pData)
+{
+ if (pData->fUseHostResolver) return VBOX_NAT_HNCE_HOSTRESOLVER;
+ if (pData->fUseDnsProxy) return VBOX_NAT_HNCE_DNSPROXY;
+ return VBOX_NAT_HNCE_EXSPOSED_NAME_RESOLUTION_INFO;
+}
diff --git a/src/VBox/Devices/Network/slirp/slirp.h b/src/VBox/Devices/Network/slirp/slirp.h
index 5e37af66..7b5a06a6 100644
--- a/src/VBox/Devices/Network/slirp/slirp.h
+++ b/src/VBox/Devices/Network/slirp/slirp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/slirp_dns.c b/src/VBox/Devices/Network/slirp/slirp_dns.c
index 13e4c40e..9ff44c1a 100644
--- a/src/VBox/Devices/Network/slirp/slirp_dns.c
+++ b/src/VBox/Devices/Network/slirp/slirp_dns.c
@@ -177,59 +177,77 @@ static int RTFileGets(RTFILE File, void *pvBuf, size_t cbBufSize, size_t *pcbRea
return rc;
}
-static int get_dns_addr_domain(PNATState pData, const char **ppszDomain)
+static int slirpOpenResolvConfFile(PRTFILE pResolvConfFile)
{
- char buff[512];
- char buff2[256];
- RTFILE f;
- int cNameserversFound = 0;
- bool fWarnTooManyDnsServers = false;
- struct in_addr tmp_addr;
int rc;
- size_t bytes;
-
+ char buff[512];
+ char *etc = NULL;
+ char *home = NULL;
+ AssertPtrReturn(pResolvConfFile, VERR_INVALID_PARAMETER);
+ LogFlowFuncEnter();
# ifdef RT_OS_OS2
/* Try various locations. */
- char *etc = getenv("ETC");
+ NOREF(home);
+ etc = getenv("ETC");
if (etc)
{
RTStrmPrintf(buff, sizeof(buff), "%s/RESOLV2", etc);
- rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
+ rc = RTFileOpen(pResolvConfFile, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
}
if (RT_FAILURE(rc))
{
RTStrmPrintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
- rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
+ rc = RTFileOpen(pResolvConfFile, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
}
if (RT_FAILURE(rc))
{
RTStrmPrintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
- rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
+ rc = RTFileOpen(pResolvConfFile, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
}
# else /* !RT_OS_OS2 */
# ifndef DEBUG_vvl
- rc = RTFileOpen(&f, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
+ rc = RTFileOpen(pResolvConfFile, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
# else
- char *home = getenv("HOME");
+ NOREF(etc);
+ home = getenv("HOME");
RTStrPrintf(buff, sizeof(buff), "%s/resolv.conf", home);
- rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
+ rc = RTFileOpen(pResolvConfFile, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
if (RT_SUCCESS(rc))
Log(("NAT: DNS we're using %s\n", buff));
else
{
- rc = RTFileOpen(&f, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
+ rc = RTFileOpen(pResolvConfFile, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
Log(("NAT: DNS we're using %s\n", buff));
}
# endif
# endif /* !RT_OS_OS2 */
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+static int get_dns_addr_domain(PNATState pData, const char **ppszDomain)
+{
+ char buff[256];
+ char buff2[256];
+ RTFILE ResolvConfFile;
+ int cNameserversFound = 0;
+ bool fWarnTooManyDnsServers = false;
+ struct in_addr tmp_addr;
+ int rc;
+ size_t bytes;
+
+ rc = slirpOpenResolvConfFile(&ResolvConfFile);
if (RT_FAILURE(rc))
- return -1;
+ {
+ LogRel(("NAT: there're some problems with accessing resolv.conf (or known analog), thus NAT switches to use host resolver mechanism\n"));
+ pData->fUseHostResolver = 1;
+ return VINF_SUCCESS;
+ }
if (ppszDomain)
*ppszDomain = NULL;
Log(("NAT: DNS Servers:\n"));
- while ( RT_SUCCESS(rc = RTFileGets(f, buff, sizeof(buff), &bytes))
+ while ( RT_SUCCESS(rc = RTFileGets(ResolvConfFile, buff, sizeof(buff), &bytes))
&& rc != VERR_EOF)
{
struct dns_entry *pDns = NULL;
@@ -260,16 +278,13 @@ static int get_dns_addr_domain(PNATState pData, const char **ppszDomain)
{
if ((pDns->de_addr.s_addr) == RT_N2H_U32_C(INADDR_LOOPBACK))
pDns->de_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
- else
+ else if (pData->fUseDnsProxy != 1)
{
/* Modern Ubuntu register 127.0.1.1 as DNS server */
- LogRel(("NAT: DNS server %RTnaipv4 registration detected, switching to the host resolver.\n",
+ LogRel(("NAT: DNS server %RTnaipv4 registration detected, switching to the DNS proxy.\n",
pDns->de_addr.s_addr));
- RTMemFree(pDns);
- /* Releasing fetched DNS information. */
- slirpReleaseDnsSettings(pData);
- pData->fUseHostResolver = 1;
- return VINF_SUCCESS;
+ pData->fUseDnsProxy = 1;
+ pData->fUseHostResolver = 0;
}
}
TAILQ_INSERT_HEAD(&pData->pDnsList, pDns, de_list);
@@ -305,7 +320,7 @@ static int get_dns_addr_domain(PNATState pData, const char **ppszDomain)
}
}
}
- RTFileClose(f);
+ RTFileClose(ResolvConfFile);
if (!cNameserversFound)
return -1;
return 0;
@@ -318,7 +333,7 @@ int slirpInitializeDnsSettings(PNATState pData)
int rc = VINF_SUCCESS;
AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
LogFlowFuncEnter();
- if (!pData->fUseHostResolver)
+ if (!pData->fUseHostResolverPermanent)
{
TAILQ_INIT(&pData->pDnsList);
LIST_INIT(&pData->pDomainList);
@@ -327,9 +342,20 @@ int slirpInitializeDnsSettings(PNATState pData)
* so we should other way to configure DNS settings.
*/
if (get_dns_addr_domain(pData, NULL) < 0)
- pData->fUseHostResolver = 1;
+ {
+ /* Load the DNS handler if host resolver mode was not used before. */
+ if (!pData->fUseHostResolver)
+ dns_alias_load(pData);
+ pData->fUseHostResolver = true;
+ }
else
+ {
+ /* Unload to not intercept in the future. */
+ if (pData->fUseHostResolver)
+ dns_alias_unload(pData);
+ pData->fUseHostResolver = false;
dnsproxy_init(pData);
+ }
if (!pData->fUseHostResolver)
{
diff --git a/src/VBox/Devices/Network/slirp/slirp_state.h b/src/VBox/Devices/Network/slirp/slirp_state.h
index 1164b6f6..ffab722a 100644
--- a/src/VBox/Devices/Network/slirp/slirp_state.h
+++ b/src/VBox/Devices/Network/slirp/slirp_state.h
@@ -201,13 +201,12 @@ typedef struct NATState
int iIcmpCacheLimit;
# ifdef RT_OS_WINDOWS
void *pvIcmpBuffer;
- size_t szIcmpBuffer;
- /* Accordin MSDN specification IcmpParseReplies
- * function should be detected in runtime
+ uint32_t cbIcmpBuffer;
+ /* According MSDN specification IcmpParseReplies
+ * function should be detected at runtime.
*/
long (WINAPI * pfIcmpParseReplies)(void *, long);
BOOL (WINAPI * pfIcmpCloseHandle)(HANDLE);
- HMODULE hmIcmpLibrary;
# endif
#if defined(RT_OS_WINDOWS)
# define VBOX_SOCKET_EVENT (pData->phEvents[VBOX_SOCKET_EVENT_INDEX])
@@ -247,6 +246,9 @@ typedef struct NATState
#endif
uma_zone_t zone_ext_refcnt;
bool fUseHostResolver;
+ /** Flag whether using the host resolver mode is permanent
+ * because the user configured it that way. */
+ bool fUseHostResolverPermanent;
/* from dnsproxy/dnsproxy.h*/
unsigned int authoritative_port;
unsigned int authoritative_timeout;
diff --git a/src/VBox/Devices/Network/slirp/socket.c b/src/VBox/Devices/Network/slirp/socket.c
index 05d122bb..d1e7e2a0 100644
--- a/src/VBox/Devices/Network/slirp/socket.c
+++ b/src/VBox/Devices/Network/slirp/socket.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -195,6 +195,9 @@ sofree(PNATState pData, struct socket *so)
* Check that we don't freeng socket with tcbcb
*/
Assert(!sototcpcb(so));
+ /* udp checks */
+ Assert(!so->so_timeout);
+ Assert(!so->so_timeout_arg);
if (so == tcp_last_so)
tcp_last_so = &tcb;
else if (so == udp_last_so)
@@ -1137,9 +1140,10 @@ solisten(PNATState pData, u_int32_t bind_addr, u_int port, u_int32_t laddr, u_in
#else
int tmperrno = errno; /* Don't clobber the real reason we failed */
close(s);
- QSOCKET_LOCK(tcb);
- sofree(pData, so);
- QSOCKET_UNLOCK(tcb);
+ if (sototcpcb(so))
+ tcp_close(pData, sototcpcb(so));
+ else
+ sofree(pData, so);
/* Restore the real errno */
errno = tmperrno;
#endif
@@ -1474,7 +1478,7 @@ sorecvfrom_icmp_win(PNATState pData, struct socket *so)
int out_len;
int size;
- len = pData->pfIcmpParseReplies(pData->pvIcmpBuffer, pData->szIcmpBuffer);
+ len = pData->pfIcmpParseReplies(pData->pvIcmpBuffer, pData->cbIcmpBuffer);
if (len < 0)
{
LogRel(("NAT: Error (%d) occurred on ICMP receiving\n", GetLastError()));
diff --git a/src/VBox/Devices/Network/slirp/socket.h b/src/VBox/Devices/Network/slirp/socket.h
index 42e34976..d97afd5b 100644
--- a/src/VBox/Devices/Network/slirp/socket.h
+++ b/src/VBox/Devices/Network/slirp/socket.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/tcp_input.c b/src/VBox/Devices/Network/slirp/tcp_input.c
index b9a34f8e..0c4eb219 100644
--- a/src/VBox/Devices/Network/slirp/tcp_input.c
+++ b/src/VBox/Devices/Network/slirp/tcp_input.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/tcp_output.c b/src/VBox/Devices/Network/slirp/tcp_output.c
index 2a8a50d8..07a1d910 100644
--- a/src/VBox/Devices/Network/slirp/tcp_output.c
+++ b/src/VBox/Devices/Network/slirp/tcp_output.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/tcp_subr.c b/src/VBox/Devices/Network/slirp/tcp_subr.c
index 5fb68c6d..be5ef847 100644
--- a/src/VBox/Devices/Network/slirp/tcp_subr.c
+++ b/src/VBox/Devices/Network/slirp/tcp_subr.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/tcp_timer.c b/src/VBox/Devices/Network/slirp/tcp_timer.c
index f378b547..90a2ccd4 100644
--- a/src/VBox/Devices/Network/slirp/tcp_timer.c
+++ b/src/VBox/Devices/Network/slirp/tcp_timer.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/tcp_timer.h b/src/VBox/Devices/Network/slirp/tcp_timer.h
index a9edba86..dd0a33aa 100644
--- a/src/VBox/Devices/Network/slirp/tcp_timer.h
+++ b/src/VBox/Devices/Network/slirp/tcp_timer.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/tftp.c b/src/VBox/Devices/Network/slirp/tftp.c
index 42e25690..2e3ef8e8 100644
--- a/src/VBox/Devices/Network/slirp/tftp.c
+++ b/src/VBox/Devices/Network/slirp/tftp.c
@@ -433,7 +433,7 @@ DECLINLINE(int) tftpSessionEvaluateOptions(PNATState pData, PTFTPSESSION pTftpSe
rc = pftpSessionOpenFile(pData, pTftpSession, &hSessionFile);
if (RT_FAILURE(rc))
{
- LogFlowFuncLeave();
+ LogFlowFuncLeaveRC(rc);
return rc;
}
@@ -441,13 +441,13 @@ DECLINLINE(int) tftpSessionEvaluateOptions(PNATState pData, PTFTPSESSION pTftpSe
RTFileClose(hSessionFile);
if (RT_FAILURE(rc))
{
- LogFlowFuncLeave();
+ LogFlowFuncLeaveRC(rc);
return rc;
}
if (pTftpSession->OptionTSize.fRequested)
{
- pTftpSession->OptionTSize.u64Value = cbSessionFile;
+ pTftpSession->OptionTSize.u64Value = cbSessionFile;
}
if ( !pTftpSession->OptionBlkSize.u64Value
&& !pTftpSession->OptionBlkSize.fRequested)
@@ -546,7 +546,7 @@ DECLINLINE(int) tftpAddOptionToOACK(PNATState pData, struct mbuf *pMBuf, const c
RT_ZERO(aszOptionBuffer);
iOptLength += RTStrPrintf(aszOptionBuffer, 256 , "%s", pszOptName) + 1;
- iOptLength += RTStrPrintf(aszOptionBuffer + iOptLength, 256 - iOptLength , "%u", u64OptValue) + 1;
+ iOptLength += RTStrPrintf(aszOptionBuffer + iOptLength, 256 - iOptLength , "%llu", u64OptValue) + 1;
if (iOptLength > M_TRAILINGSPACE(pMBuf))
rc = VERR_BUFFER_OVERFLOW; /* buffer too small */
else
@@ -569,7 +569,7 @@ DECLINLINE(int) tftpSendOACK(PNATState pData,
rc = tftpSessionEvaluateOptions(pData, pTftpSession);
if (RT_FAILURE(rc))
{
- tftpSendError(pData, pTftpSession, 2, "Internal Error (blksize evaluation)", pcTftpIpHeaderRecv);
+ tftpSendError(pData, pTftpSession, 2, "Option negotiation failure (file not found or inaccessible?)", pcTftpIpHeaderRecv);
LogFlowFuncLeave();
return -1;
}
@@ -578,8 +578,6 @@ DECLINLINE(int) tftpSendOACK(PNATState pData,
if (!m)
return -1;
-
-
m->m_data += if_maxlinkhdr;
m->m_pkthdr.header = mtod(m, void *);
pTftpIpHeader = mtod(m, PTFTPIPHDR);
@@ -756,9 +754,10 @@ static void tftpProcessACK(PNATState pData, PTFTPIPHDR pTftpIpHeader)
if (RT_FAILURE(rc))
return;
- AssertReturnVoid(tftpSendData(pData,
- pTftpSession,
- RT_N2H_U16(pTftpIpHeader->Core.u16TftpOpCode), pTftpIpHeader) == 0);
+ if (tftpSendData(pData, pTftpSession,
+ RT_N2H_U16(pTftpIpHeader->Core.u16TftpOpCode),
+ pTftpIpHeader))
+ LogRel(("NAT TFTP: failure\n"));
}
int slirpTftpInit(PNATState pData)
diff --git a/src/VBox/Devices/Network/slirp/tftp.h b/src/VBox/Devices/Network/slirp/tftp.h
index 690e5d62..e3460b2b 100644
--- a/src/VBox/Devices/Network/slirp/tftp.h
+++ b/src/VBox/Devices/Network/slirp/tftp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/udp.c b/src/VBox/Devices/Network/slirp/udp.c
index 10685f95..e8ec3056 100644
--- a/src/VBox/Devices/Network/slirp/udp.c
+++ b/src/VBox/Devices/Network/slirp/udp.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -123,7 +123,6 @@ udp_input(PNATState pData, register struct mbuf *m, int iphlen)
* If not enough data to reflect UDP length, drop.
*/
len = RT_N2H_U16((u_int16_t)uh->uh_ulen);
- Assert((ip->ip_len == len));
Assert((ip->ip_len + iphlen == m_length(m, NULL)));
if (ip->ip_len != len)
@@ -132,6 +131,7 @@ udp_input(PNATState pData, register struct mbuf *m, int iphlen)
{
udpstat.udps_badlen++;
Log3(("NAT: IP(id: %hd) has bad size\n", ip->ip_id));
+ goto bad_free_mbuf;
}
m_adj(m, len - ip->ip_len);
ip->ip_len = len;
@@ -277,7 +277,7 @@ udp_input(PNATState pData, register struct mbuf *m, int iphlen)
* DNS proxy
*/
if ( pData->fUseDnsProxy
- && (ip->ip_dst.s_addr == RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_DNS))
+ && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS)
&& (uh->uh_dport == RT_H2N_U16_C(53)))
{
dnsproxy_query(pData, so, m, iphlen);
diff --git a/src/VBox/Devices/Network/slirp/udp.h b/src/VBox/Devices/Network/slirp/udp.h
index a5c0bf2f..e9aa69df 100644
--- a/src/VBox/Devices/Network/slirp/udp.h
+++ b/src/VBox/Devices/Network/slirp/udp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Network/slirp/zone.h b/src/VBox/Devices/Network/slirp/zone.h
index 9372901e..089f0419 100644
--- a/src/VBox/Devices/Network/slirp/zone.h
+++ b/src/VBox/Devices/Network/slirp/zone.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;