summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/Network/slirp/ip_icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Network/slirp/ip_icmp.c')
-rw-r--r--src/VBox/Devices/Network/slirp/ip_icmp.c162
1 files changed, 89 insertions, 73 deletions
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