diff options
Diffstat (limited to 'src/VBox/Devices/Network/slirp/ip_icmp.c')
-rw-r--r-- | src/VBox/Devices/Network/slirp/ip_icmp.c | 162 |
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 |