diff options
Diffstat (limited to 'src/VBox/Devices/Network/slirp')
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; |