ip_icmpwin.c revision 5f83ab060c98132ab115599b8f2fb5fbc819ed1d
/* $Id$ */
/** @file
* NAT - Windows ICMP API based ping proxy.
*/
/*
* Copyright (C) 2006-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;
* 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 "slirp.h"
#include "ip_icmp.h"
#include <winternl.h> /* for PIO_APC_ROUTINE &c */
#include <iphlpapi.h>
#include <icmpapi.h>
/*
* A header of ICMP ECHO. Intended for storage, unlike struct icmp
* which is intended to be overlayed onto a buffer.
*/
struct icmp_echo {
};
struct pong {
};
/*
* On Windows XP and Windows Server 2003 IcmpSendEcho2() callback
* is FARPROC, but starting from Vista it's PIO_APC_ROUTINE with
* two extra arguments. Callbacks use WINAPI (stdcall) calling
* convention with callee responsible for popping the arguments,
* so to avoid stack corruption we check windows version at run
* time and provide correct callback.
*
* XXX: this is system-wide, but what about multiple NAT threads?
*/
static void *pfIcmpCallback;
int
{
if (pfIcmpCallback == NULL)
{
int status;
if (status == 0)
return 1;
else
}
return 0;
}
void
{
}
/*
* Outgoing ping from guest.
*/
void
{
void *reqdata;
int status;
--ttl;
return;
{
/* already in single contiguous buffer */
}
else
{
/* use reply buffer as temporary storage */
}
opts.OptionsSize = 0;
opts.OptionsData = 0;
5 * 1000 /* ms */);
if (RT_UNLIKELY(status != 0))
{
}
{
int code;
switch (status) {
break;
case ERROR_HOST_UNREACHABLE:
break;
default:
code = -1;
break;
}
{
{
}
}
}
else /* success */
{
Log2(("NAT: pong %p for ping %RTnaipv4 id 0x%04x seq %d len %d\n",
reqsize));
}
}
{
{
}
}
icmpwin_callback_old(void *ctx)
{
{
}
}
/*
* Actual callback code for IcmpSendEcho2(). OS version specific
* trampoline will free "pong" argument for us.
*/
static void
{
struct mbuf *m;
if (nreplies == 0)
{
if (error == IP_REQ_TIMED_OUT)
else
Log2(("NAT: ping %p: IcmpParseReplies: error %d\n",
return;
}
{
return;
/* need to remap &reply->Address ? */
if (/* not a mapped loopback */ 1)
{
return;
}
return;
if (m == NULL)
return;
/* fill in ip (ip_output0() does the boilerplate for us) */
icmp->icmp_cksum = 0;
}
else {
case IP_DEST_NET_UNREACHABLE:
break;
case IP_DEST_HOST_UNREACHABLE:
break;
case IP_DEST_PROT_UNREACHABLE:
break;
case IP_PACKET_TOO_BIG:
break;
case IP_SOURCE_QUENCH:
break;
case IP_TTL_EXPIRED_TRANSIT:
break;
case IP_TTL_EXPIRED_REASSEM:
break;
default:
return;
}
/*
* XXX: we don't know the TTL of the request at the time this
* ICMP error was generated (we can guess it was 1 for ttl
* exceeded, but don't bother faking it).
*/
if (m == NULL)
return;
}
}
/*
* IP source must be filled by the caller.
*/
static struct mbuf *
{
struct mbuf *m;
if (m == NULL)
return NULL;
icmp->icmp_cksum = 0;
icmp->icmp_echo_id = 0;
icmp->icmp_echo_seq = 0;
return m;
}
/*
* Replacing original simple slirp mbufs with real mbufs from freebsd
* was a bit messy since assumption are different. This leads to
* rather ugly code at times. Hide the gore here.
*/
static struct mbuf *
{
struct mbuf *m;
reqsize += if_maxlinkhdr;
/* good pings come in small packets */
else
if (m == NULL)
return NULL;
m->m_flags |= M_SKIP_FIREWALL;
return m;
}