pxping_win.c revision 1c08b0ec28ca5c600c21c0ab5a53cae73f1c821d
/* -*- indent-tabs-mode: nil; -*- */
#define LOG_GROUP LOG_GROUP_NAT_SERVICE
#include "winutils.h"
#include "proxy.h"
#include "pxremap.h"
#include "lwip/inet_chksum.h"
/* XXX: lwIP names conflict with winsock <iphlpapi.h> */
#include <winternl.h> /* for PIO_APC_ROUTINE &c */
#include <iphlpapi.h>
#include <icmpapi.h>
#include <stdio.h>
struct pxping {
/*
* We use single ICMP handle for all pings. This means that all
* proxied pings will have the same id and share single sequence
* of sequence numbers.
*/
/*
* 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.
*/
void *callback4;
void *callback6;
};
struct pong4 {
struct icmp_echo_hdr reqicmph;
};
struct pong6 {
struct icmp6_echo_hdr reqicmph;
};
{
int status;
if (status == 0) {
return ERR_ARG;
}
}
else {
}
}
else {
}
}
else {
}
{
return ERR_ARG;
}
return ERR_OK;
}
/**
* ICMP Echo Request in pbuf "p" is to be proxied.
*/
static void
{
const struct icmp_echo_hdr *icmph;
int mapped;
int ttl;
void *reqdata;
int status;
goto out;
}
goto out;
}
if (mapped == PXREMAP_ASIS) {
}
goto out;
}
--ttl;
}
if (RT_UNLIKELY(status != 0)) {
goto out;
}
goto out;
}
/* single pbuf can be directly used as request data source */
}
else {
/* data from pbuf chain must be concatenated */
}
opts.OptionsSize = 0;
opts.OptionsData = 0;
5 * 1000 /* ms */);
if (RT_UNLIKELY(status != 0)) {
goto out;
}
int code;
switch (status) {
code = ICMP_DUR_NET;
break;
case ERROR_HOST_UNREACHABLE:
break;
default:
code = -1;
break;
}
if (code != -1) {
/* move payload back to IP header */
icmp_dest_unreach(p, code);
}
}
goto out;
}
out:
}
pbuf_free(p);
}
{
}
}
pxping_icmp4_callback_old(void *ctx)
{
}
}
static void
{
struct pbuf *p;
struct icmp_echo_hdr *icmph;
int mapped;
if (nreplies <= 0) {
if (error == IP_REQ_TIMED_OUT) {
}
else {
DPRINTF(("pong4: %p: IcmpParseReplies: error %d\n",
}
return;
}
return;
}
if (mapped == PXREMAP_FAILED) {
return;
}
if (mapped == PXREMAP_ASIS) {
return;
}
}
{
return;
}
if (RT_UNLIKELY(p == NULL)) {
return;
}
}
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;
}
if (RT_UNLIKELY(p == NULL)) {
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).
*/
}
ip_output_if(p, &src,
pbuf_free(p);
}
static void
{
struct icmp6_echo_hdr *icmph;
int mapped;
void *reqdata;
int hopl;
int status;
goto out;
}
if (mapped == PXREMAP_ASIS) {
}
goto out;
}
--hopl;
}
if (RT_UNLIKELY(status != 0)) {
goto out;
}
goto out;
}
/* single pbuf can be directly used as request data source */
}
else {
/* data from pbuf chain must be concatenated */
}
5 * 1000 /* ms */);
if (RT_UNLIKELY(status != 0)) {
goto out;
}
int code;
switch (status) {
case ERROR_HOST_UNREACHABLE:
break;
default:
code = -1;
break;
}
if (code != -1) {
/* move payload back to IP header */
+ ip_current_header_tot_len()));
icmp6_dest_unreach(p, code);
}
}
goto out;
}
out:
}
pbuf_free(p);
}
{
}
}
pxping_icmp6_callback_old(void *ctx)
{
}
}
static void
{
struct pbuf *p;
struct icmp6_echo_hdr *icmph;
int mapped;
if (nreplies <= 0) {
if (error == IP_REQ_TIMED_OUT) {
}
else {
DPRINTF(("pong6: %p: Icmp6ParseReplies: error %d\n",
}
return;
}
if (mapped == PXREMAP_FAILED) {
return;
}
/*
* Reply data follows ICMPV6_ECHO_REPLY structure in memory, but
* it doesn't tell us its size. Assume it's equal the size of the
* request.
*/
if (RT_UNLIKELY(p == NULL)) {
return;
}
pbuf_free(p);
}