You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
398 lines
9.9 KiB
398 lines
9.9 KiB
/* |
|
* TAP-Windows -- A kernel driver to provide virtual tap |
|
* device functionality on Windows. |
|
* |
|
* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. |
|
* |
|
* This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., |
|
* and is released under the GPL version 2 (see below). |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License version 2 |
|
* as published by the Free Software Foundation. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program (see the file COPYING included with this |
|
* distribution); if not, write to the Free Software Foundation, Inc., |
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
*/ |
|
|
|
#include "tap.h" |
|
|
|
//----------------- |
|
// DEBUGGING OUTPUT |
|
//----------------- |
|
|
|
const char *g_LastErrorFilename; |
|
int g_LastErrorLineNumber; |
|
|
|
#if DBG |
|
|
|
DebugOutput g_Debug; |
|
|
|
BOOLEAN |
|
NewlineExists (const char *str, int len) |
|
{ |
|
while (len-- > 0) |
|
{ |
|
const char c = *str++; |
|
if (c == '\n') |
|
return TRUE; |
|
else if (c == '\0') |
|
break; |
|
} |
|
return FALSE; |
|
} |
|
|
|
VOID |
|
MyDebugInit (unsigned int bufsiz) |
|
{ |
|
NdisZeroMemory (&g_Debug, sizeof (g_Debug)); |
|
g_Debug.text = (char *) MemAlloc (bufsiz, FALSE); |
|
|
|
if (g_Debug.text) |
|
{ |
|
g_Debug.capacity = bufsiz; |
|
} |
|
} |
|
|
|
VOID |
|
MyDebugFree () |
|
{ |
|
if (g_Debug.text) |
|
{ |
|
MemFree (g_Debug.text, g_Debug.capacity); |
|
} |
|
|
|
NdisZeroMemory (&g_Debug, sizeof (g_Debug)); |
|
} |
|
|
|
VOID |
|
MyDebugPrint (const unsigned char* format, ...) |
|
{ |
|
if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT) |
|
{ |
|
BOOLEAN owned; |
|
ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned); |
|
if (owned) |
|
{ |
|
const int remaining = (int)g_Debug.capacity - (int)g_Debug.out; |
|
|
|
if (remaining > 0) |
|
{ |
|
va_list args; |
|
NTSTATUS status; |
|
char *end; |
|
|
|
#ifdef DBG_PRINT |
|
va_start (args, format); |
|
vDbgPrintEx (DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, format, args); |
|
va_end (args); |
|
#endif |
|
va_start (args, format); |
|
status = RtlStringCchVPrintfExA (g_Debug.text + g_Debug.out, |
|
remaining, |
|
&end, |
|
NULL, |
|
STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS, |
|
format, |
|
args); |
|
va_end (args); |
|
va_start (args, format); |
|
vDbgPrintEx(DPFLTR_IHVDRIVER_ID , 1, format, args); |
|
va_end (args); |
|
if (status == STATUS_SUCCESS) |
|
g_Debug.out = (unsigned int) (end - g_Debug.text); |
|
else |
|
g_Debug.error = TRUE; |
|
} |
|
else |
|
g_Debug.error = TRUE; |
|
|
|
RELEASE_MUTEX (&g_Debug.lock); |
|
} |
|
else |
|
g_Debug.error = TRUE; |
|
} |
|
} |
|
|
|
BOOLEAN |
|
GetDebugLine ( |
|
__in char *buf, |
|
__in const int len |
|
) |
|
{ |
|
static const char *truncated = "[OUTPUT TRUNCATED]\n"; |
|
BOOLEAN ret = FALSE; |
|
|
|
NdisZeroMemory (buf, len); |
|
|
|
if (g_Debug.text && g_Debug.capacity > 0) |
|
{ |
|
BOOLEAN owned; |
|
ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned); |
|
if (owned) |
|
{ |
|
int i = 0; |
|
|
|
if (g_Debug.error || NewlineExists (g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in)) |
|
{ |
|
while (i < (len - 1) && g_Debug.in < g_Debug.out) |
|
{ |
|
const char c = g_Debug.text[g_Debug.in++]; |
|
if (c == '\n') |
|
break; |
|
buf[i++] = c; |
|
} |
|
if (i < len) |
|
buf[i] = '\0'; |
|
} |
|
|
|
if (!i) |
|
{ |
|
if (g_Debug.in == g_Debug.out) |
|
{ |
|
g_Debug.in = g_Debug.out = 0; |
|
if (g_Debug.error) |
|
{ |
|
const unsigned int tlen = strlen (truncated); |
|
if (tlen < g_Debug.capacity) |
|
{ |
|
NdisMoveMemory (g_Debug.text, truncated, tlen+1); |
|
g_Debug.out = tlen; |
|
} |
|
g_Debug.error = FALSE; |
|
} |
|
} |
|
} |
|
else |
|
ret = TRUE; |
|
|
|
RELEASE_MUTEX (&g_Debug.lock); |
|
} |
|
} |
|
return ret; |
|
} |
|
|
|
VOID |
|
PrMac (const MACADDR mac) |
|
{ |
|
DEBUGP (("%x:%x:%x:%x:%x:%x", |
|
mac[0], mac[1], mac[2], |
|
mac[3], mac[4], mac[5])); |
|
} |
|
|
|
VOID |
|
PrIP (IPADDR ip_addr) |
|
{ |
|
const unsigned char *ip = (const unsigned char *) &ip_addr; |
|
|
|
DEBUGP (("%d.%d.%d.%d", |
|
ip[0], ip[1], ip[2], ip[3])); |
|
} |
|
|
|
const char * |
|
PrIPProto (int proto) |
|
{ |
|
switch (proto) |
|
{ |
|
case IPPROTO_UDP: |
|
return "UDP"; |
|
|
|
case IPPROTO_TCP: |
|
return "TCP"; |
|
|
|
case IPPROTO_ICMP: |
|
return "ICMP"; |
|
|
|
case IPPROTO_IGMP: |
|
return "IGMP"; |
|
|
|
default: |
|
return "???"; |
|
} |
|
} |
|
|
|
VOID |
|
DumpARP (const char *prefix, const ARP_PACKET *arp) |
|
{ |
|
DEBUGP (("%s ARP src=", prefix)); |
|
PrMac (arp->m_MAC_Source); |
|
DEBUGP ((" dest=")); |
|
PrMac (arp->m_MAC_Destination); |
|
DEBUGP ((" OP=0x%04x", |
|
(int)ntohs(arp->m_ARP_Operation))); |
|
DEBUGP ((" M=0x%04x(%d)", |
|
(int)ntohs(arp->m_MAC_AddressType), |
|
(int)arp->m_MAC_AddressSize)); |
|
DEBUGP ((" P=0x%04x(%d)", |
|
(int)ntohs(arp->m_PROTO_AddressType), |
|
(int)arp->m_PROTO_AddressSize)); |
|
|
|
DEBUGP ((" MacSrc=")); |
|
PrMac (arp->m_ARP_MAC_Source); |
|
DEBUGP ((" MacDest=")); |
|
PrMac (arp->m_ARP_MAC_Destination); |
|
|
|
DEBUGP ((" IPSrc=")); |
|
PrIP (arp->m_ARP_IP_Source); |
|
DEBUGP ((" IPDest=")); |
|
PrIP (arp->m_ARP_IP_Destination); |
|
|
|
DEBUGP (("\n")); |
|
} |
|
|
|
struct ethpayload |
|
{ |
|
ETH_HEADER eth; |
|
UCHAR payload[DEFAULT_PACKET_LOOKAHEAD]; |
|
}; |
|
|
|
#ifdef ALLOW_PACKET_DUMP |
|
|
|
VOID |
|
DumpPacket2( |
|
__in const char *prefix, |
|
__in const ETH_HEADER *eth, |
|
__in const unsigned char *data, |
|
__in unsigned int len |
|
) |
|
{ |
|
struct ethpayload *ep = (struct ethpayload *) MemAlloc (sizeof (struct ethpayload), TRUE); |
|
if (ep) |
|
{ |
|
if (len > DEFAULT_PACKET_LOOKAHEAD) |
|
len = DEFAULT_PACKET_LOOKAHEAD; |
|
ep->eth = *eth; |
|
NdisMoveMemory (ep->payload, data, len); |
|
DumpPacket (prefix, (unsigned char *) ep, sizeof (ETH_HEADER) + len); |
|
MemFree (ep, sizeof (struct ethpayload)); |
|
} |
|
} |
|
|
|
VOID |
|
DumpPacket( |
|
__in const char *prefix, |
|
__in const unsigned char *data, |
|
__in unsigned int len |
|
) |
|
{ |
|
const ETH_HEADER *eth = (const ETH_HEADER *) data; |
|
const IPHDR *ip = (const IPHDR *) (data + sizeof (ETH_HEADER)); |
|
|
|
if (len < sizeof (ETH_HEADER)) |
|
{ |
|
DEBUGP (("%s TRUNCATED PACKET LEN=%d\n", prefix, len)); |
|
return; |
|
} |
|
|
|
// ARP Packet? |
|
if (len >= sizeof (ARP_PACKET) && eth->proto == htons (ETH_P_ARP)) |
|
{ |
|
DumpARP (prefix, (const ARP_PACKET *) data); |
|
return; |
|
} |
|
|
|
// IPv4 packet? |
|
if (len >= (sizeof (IPHDR) + sizeof (ETH_HEADER)) |
|
&& eth->proto == htons (ETH_P_IP) |
|
&& IPH_GET_VER (ip->version_len) == 4) |
|
{ |
|
const int hlen = IPH_GET_LEN (ip->version_len); |
|
const int blen = len - sizeof (ETH_HEADER); |
|
BOOLEAN did = FALSE; |
|
|
|
DEBUGP (("%s IPv4 %s[%d]", prefix, PrIPProto (ip->protocol), len)); |
|
|
|
if (!(ntohs (ip->tot_len) == blen && hlen <= blen)) |
|
{ |
|
DEBUGP ((" XXX")); |
|
return; |
|
} |
|
|
|
// TCP packet? |
|
if (ip->protocol == IPPROTO_TCP |
|
&& blen - hlen >= (sizeof (TCPHDR))) |
|
{ |
|
const TCPHDR *tcp = (TCPHDR *) (data + sizeof (ETH_HEADER) + hlen); |
|
DEBUGP ((" ")); |
|
PrIP (ip->saddr); |
|
DEBUGP ((":%d", ntohs (tcp->source))); |
|
DEBUGP ((" -> ")); |
|
PrIP (ip->daddr); |
|
DEBUGP ((":%d", ntohs (tcp->dest))); |
|
did = TRUE; |
|
} |
|
|
|
// UDP packet? |
|
else if ((ntohs (ip->frag_off) & IP_OFFMASK) == 0 |
|
&& ip->protocol == IPPROTO_UDP |
|
&& blen - hlen >= (sizeof (UDPHDR))) |
|
{ |
|
const UDPHDR *udp = (UDPHDR *) (data + sizeof (ETH_HEADER) + hlen); |
|
|
|
// DHCP packet? |
|
if ((udp->dest == htons (BOOTPC_PORT) || udp->dest == htons (BOOTPS_PORT)) |
|
&& blen - hlen >= (sizeof (UDPHDR) + sizeof (DHCP))) |
|
{ |
|
const DHCP *dhcp = (DHCP *) (data |
|
+ hlen |
|
+ sizeof (ETH_HEADER) |
|
+ sizeof (UDPHDR)); |
|
|
|
int optlen = len |
|
- sizeof (ETH_HEADER) |
|
- hlen |
|
- sizeof (UDPHDR) |
|
- sizeof (DHCP); |
|
|
|
if (optlen < 0) |
|
optlen = 0; |
|
|
|
DumpDHCP (eth, ip, udp, dhcp, optlen); |
|
did = TRUE; |
|
} |
|
|
|
if (!did) |
|
{ |
|
DEBUGP ((" ")); |
|
PrIP (ip->saddr); |
|
DEBUGP ((":%d", ntohs (udp->source))); |
|
DEBUGP ((" -> ")); |
|
PrIP (ip->daddr); |
|
DEBUGP ((":%d", ntohs (udp->dest))); |
|
did = TRUE; |
|
} |
|
} |
|
|
|
if (!did) |
|
{ |
|
DEBUGP ((" ipproto=%d ", ip->protocol)); |
|
PrIP (ip->saddr); |
|
DEBUGP ((" -> ")); |
|
PrIP (ip->daddr); |
|
} |
|
|
|
DEBUGP (("\n")); |
|
return; |
|
} |
|
|
|
{ |
|
DEBUGP (("%s ??? src=", prefix)); |
|
PrMac (eth->src); |
|
DEBUGP ((" dest=")); |
|
PrMac (eth->dest); |
|
DEBUGP ((" proto=0x%04x len=%d\n", |
|
(int) ntohs(eth->proto), |
|
len)); |
|
} |
|
} |
|
|
|
#endif // ALLOW_PACKET_DUMP |
|
|
|
#endif
|
|
|