summaryrefslogtreecommitdiffstats
path: root/tap-win32/tapdrvr.c
diff options
context:
space:
mode:
Diffstat (limited to 'tap-win32/tapdrvr.c')
-rwxr-xr-xtap-win32/tapdrvr.c331
1 files changed, 299 insertions, 32 deletions
diff --git a/tap-win32/tapdrvr.c b/tap-win32/tapdrvr.c
index 7eecca7..0997bd5 100755
--- a/tap-win32/tapdrvr.c
+++ b/tap-win32/tapdrvr.c
@@ -35,7 +35,8 @@
// By default we operate as a "tap" virtual ethernet
// 802.3 interface, but we can emulate a "tun"
// interface (point-to-point IPv4) through the
-// TAP_IOCTL_CONFIG_POINT_TO_POINT ioctl.
+// TAP_IOCTL_CONFIG_POINT_TO_POINT or
+// TAP_IOCTL_CONFIG_TUN ioctl.
//======================================================
#define NDIS_MINIPORT_DRIVER
@@ -46,11 +47,27 @@
#define NTSTRSAFE_LIB
// Debug info output
-#define ALSO_DBGPRINT 1
-#define DEBUGP_AT_DISPATCH 0
+#define ALSO_DBGPRINT 1
+#define DEBUGP_AT_DISPATCH 0
+
+//========================================================
+// Check for truncated IPv4 packets, log errors if found.
+//========================================================
+#define PACKET_TRUNCATION_CHECK 1 // JYFIXME
+
+//========================================================
+// EXPERIMENTAL -- Configure TAP device object to be
+// accessible from non-administrative accounts, based
+// on an advanced properties setting.
+//
+// Duplicates the functionality of OpenVPN's
+// --allow-nonadmin directive.
+//========================================================
+#define ENABLE_NONADMIN 1 // JYFIXME
#include <ndis.h>
#include <ntstrsafe.h>
+#include <ntddk.h>
#include "lock.h"
#include "constants.h"
@@ -274,6 +291,10 @@ NDIS_STATUS AdapterCreate
UINT l_Index;
NDIS_STATUS status;
+#if ENABLE_NONADMIN
+ BOOLEAN enable_non_admin = FALSE;
+#endif
+
//====================================
// Make sure adapter type is supported
//====================================
@@ -410,6 +431,25 @@ NDIS_STATUS AdapterCreate
}
}
+#if ENABLE_NONADMIN
+ /* Read AllowNonAdmin setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("AllowNonAdmin");
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterInteger);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterInteger)
+ {
+ if (parm->ParameterData.IntegerData)
+ {
+ enable_non_admin = TRUE;
+ }
+ }
+ }
+ }
+#endif
+
/* Read optional MAC setting from registry */
{
NDIS_STRING key = NDIS_STRING_CONST("MAC");
@@ -479,6 +519,11 @@ NDIS_STATUS AdapterCreate
l_Adapter->m_InterfaceIsRunning = TRUE;
+#if ENABLE_NONADMIN
+ if (enable_non_admin)
+ AllowNonAdmin (&l_Adapter->m_Extension);
+#endif
+
return NDIS_STATUS_SUCCESS;
}
@@ -1011,7 +1056,7 @@ NDIS_STATUS AdapterQuery
break;
case OID_GEN_LINK_SPEED:
- l_Query.m_Long = 100000;
+ l_Query.m_Long = 100000; // rate / 100 bps
break;
case OID_802_3_PERMANENT_ADDRESS:
@@ -1348,19 +1393,40 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
__try
{
- for (l_Index = 0; l_NDIS_Buffer && l_Index < l_PacketLength;
- l_Index += l_BufferLength)
+ l_Index = 0;
+ while (l_NDIS_Buffer && l_Index < l_PacketLength)
{
+ ULONG newlen;
NdisQueryBuffer (l_NDIS_Buffer, (PVOID *) & l_Buffer,
&l_BufferLength);
+ newlen = l_Index + l_BufferLength;
+ if (newlen > l_PacketLength)
+ {
+ NOTE_ERROR ();
+ goto no_queue; /* overflow */
+ }
NdisMoveMemory (l_PacketBuffer->m_Data + l_Index, l_Buffer,
l_BufferLength);
+ l_Index = newlen;
NdisGetNextBuffer (l_NDIS_Buffer, &l_NDIS_Buffer);
}
+ if (l_Index != l_PacketLength)
+ {
+ NOTE_ERROR ();
+ goto no_queue; /* underflow */
+ }
DUMP_PACKET ("AdapterTransmit", l_PacketBuffer->m_Data, l_PacketLength);
//=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify (l_PacketBuffer->m_Data, l_PacketLength, FALSE, "TX", &l_Adapter->m_TxTrunc);
+#endif
+
+ //=====================================================
// Are we running in DHCP server masquerade mode?
//
// If so, catch both DHCP requests and ARP queries
@@ -1381,6 +1447,7 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
(PARP_PACKET) l_PacketBuffer->m_Data,
l_Adapter->m_dhcp_addr,
l_Adapter->m_dhcp_server_ip,
+ ~0,
l_Adapter->m_dhcp_server_mac))
goto no_queue;
}
@@ -1417,7 +1484,7 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
// In Point-To-Point mode, check to see whether
// packet is ARP or IPv4 (if neither, then drop).
//===============================================
- if (l_Adapter->m_PointToPoint)
+ if (l_Adapter->m_tun)
{
ETH_HEADER *e;
@@ -1438,7 +1505,8 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
ProcessARP (l_Adapter,
(PARP_PACKET) l_PacketBuffer->m_Data,
l_Adapter->m_localIP,
- l_Adapter->m_remoteIP,
+ l_Adapter->m_remoteNetwork,
+ l_Adapter->m_remoteNetmask,
l_Adapter->m_TapToUser.dest);
default:
@@ -1458,7 +1526,7 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
goto no_queue;
// Packet looks like IPv4, queue it.
- l_PacketBuffer->m_SizeFlags |= TP_POINT_TO_POINT;
+ l_PacketBuffer->m_SizeFlags |= TP_TUN;
}
}
@@ -1669,15 +1737,25 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
NULL,
NULL,
STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
+#if PACKET_TRUNCATION_CHECK
+ "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d]",
+#else
"State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d]",
+#endif
state,
g_LastErrorFilename,
g_LastErrorLineNumber,
(int)l_Adapter->m_Extension.m_NumTapOpens,
(int)l_Adapter->m_Tx,
(int)l_Adapter->m_TxErr,
+#if PACKET_TRUNCATION_CHECK
+ (int)l_Adapter->m_TxTrunc,
+#endif
(int)l_Adapter->m_Rx,
(int)l_Adapter->m_RxErr,
+#if PACKET_TRUNCATION_CHECK
+ (int)l_Adapter->m_RxTrunc,
+#endif
(int)l_Adapter->m_Extension.m_IrpQueue->size,
(int)l_Adapter->m_Extension.m_IrpQueue->max_size,
(int)IRP_QUEUE_SIZE,
@@ -1708,21 +1786,65 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
}
#endif
- case TAP_IOCTL_CONFIG_POINT_TO_POINT:
+ case TAP_IOCTL_CONFIG_TUN:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ (sizeof (IPADDR) * 3))
+ {
+ MACADDR dest;
+
+ l_Adapter->m_tun = FALSE;
+
+ GenerateRelatedMAC (dest, l_Adapter->m_MAC, 1);
+
+ l_Adapter->m_localIP = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ l_Adapter->m_remoteNetwork = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1];
+ l_Adapter->m_remoteNetmask = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[2];
+
+ // sanity check on network/netmask
+ if ((l_Adapter->m_remoteNetwork & l_Adapter->m_remoteNetmask) != l_Adapter->m_remoteNetwork)
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ COPY_MAC (l_Adapter->m_TapToUser.src, l_Adapter->m_MAC);
+ COPY_MAC (l_Adapter->m_TapToUser.dest, dest);
+ COPY_MAC (l_Adapter->m_UserToTap.src, dest);
+ COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
+
+ l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
+
+ l_Adapter->m_tun = TRUE;
+
+ CheckIfDhcpAndTunMode (l_Adapter);
+
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ case TAP_IOCTL_CONFIG_POINT_TO_POINT: // Obsoleted by TAP_IOCTL_CONFIG_TUN
{
if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
(sizeof (IPADDR) * 2))
{
MACADDR dest;
- l_Adapter->m_PointToPoint = FALSE;
+ l_Adapter->m_tun = FALSE;
GenerateRelatedMAC (dest, l_Adapter->m_MAC, 1);
- l_Adapter->m_localIP =
- ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0];
- l_Adapter->m_remoteIP =
- ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1];
+ l_Adapter->m_localIP = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ l_Adapter->m_remoteNetwork = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1];
+ l_Adapter->m_remoteNetmask = ~0;
COPY_MAC (l_Adapter->m_TapToUser.src, l_Adapter->m_MAC);
COPY_MAC (l_Adapter->m_TapToUser.dest, dest);
@@ -1731,9 +1853,9 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
- l_Adapter->m_PointToPoint = TRUE;
+ l_Adapter->m_tun = TRUE;
- CheckIfDhcpAndPointToPointMode (l_Adapter);
+ CheckIfDhcpAndTunMode (l_Adapter);
p_IRP->IoStatus.Information = 1; // Simple boolean value
}
@@ -1791,7 +1913,7 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
l_Adapter->m_dhcp_enabled = TRUE;
l_Adapter->m_dhcp_server_arp = TRUE;
- CheckIfDhcpAndPointToPointMode (l_Adapter);
+ CheckIfDhcpAndTunMode (l_Adapter);
p_IRP->IoStatus.Information = 1; // Simple boolean value
}
@@ -1979,7 +2101,7 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
p_IRP->IoStatus.Information = 0;
}
- else if (!l_Adapter->m_PointToPoint && ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
+ else if (!l_Adapter->m_tun && ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
{
__try
{
@@ -1989,6 +2111,18 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
(unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
l_IrpSp->Parameters.Write.Length);
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify ((unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length,
+ FALSE,
+ "RX",
+ &l_Adapter->m_RxTrunc);
+#endif
+
NdisMEthIndicateReceive
(l_Adapter->m_MiniportAdapterHandle,
(NDIS_HANDLE) l_Adapter,
@@ -2011,7 +2145,7 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
p_IRP->IoStatus.Information = 0;
}
}
- else if (l_Adapter->m_PointToPoint && ((l_IrpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
+ else if (l_Adapter->m_tun && ((l_IrpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
{
__try
{
@@ -2022,6 +2156,18 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
(unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
l_IrpSp->Parameters.Write.Length);
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify ((unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length,
+ TRUE,
+ "RX",
+ &l_Adapter->m_RxTrunc);
+#endif
+
NdisMEthIndicateReceive
(l_Adapter->m_MiniportAdapterHandle,
(NDIS_HANDLE) l_Adapter,
@@ -2197,7 +2343,7 @@ CompleteIRP (IN PIRP p_IRP,
// component.
//-------------------------------------------
- if (p_PacketBuffer->m_SizeFlags & TP_POINT_TO_POINT)
+ if (p_PacketBuffer->m_SizeFlags & TP_TUN)
{
offset = ETHERNET_HEADER_SIZE;
len = (int) (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE;
@@ -2379,16 +2525,16 @@ SetMediaStatus (TapAdapterPointer p_Adapter, BOOLEAN state)
//======================================================
-// If DHCP mode is used together with Point-to-point
-// mode, consider the fact that the P2P remote endpoint
-// might be equal to the DHCP masq server address.
+// If DHCP mode is used together with tun
+// mode, consider the fact that the P2P remote subnet
+// might enclose the DHCP masq server address.
//======================================================
VOID
-CheckIfDhcpAndPointToPointMode (TapAdapterPointer p_Adapter)
+CheckIfDhcpAndTunMode (TapAdapterPointer p_Adapter)
{
- if (p_Adapter->m_PointToPoint && p_Adapter->m_dhcp_enabled)
+ if (p_Adapter->m_tun && p_Adapter->m_dhcp_enabled)
{
- if (p_Adapter->m_dhcp_server_ip == p_Adapter->m_remoteIP)
+ if ((p_Adapter->m_dhcp_server_ip & p_Adapter->m_remoteNetmask) == p_Adapter->m_remoteNetwork)
{
COPY_MAC (p_Adapter->m_dhcp_server_mac, p_Adapter->m_TapToUser.dest);
p_Adapter->m_dhcp_server_arp = FALSE;
@@ -2404,7 +2550,8 @@ BOOLEAN
ProcessARP (TapAdapterPointer p_Adapter,
const PARP_PACKET src,
const IPADDR adapter_ip,
- const IPADDR ip,
+ const IPADDR ip_network,
+ const IPADDR ip_netmask,
const MACADDR mac)
{
//-----------------------------------------------
@@ -2420,7 +2567,8 @@ ProcessARP (TapAdapterPointer p_Adapter,
&& src->m_PROTO_AddressType == htons (ETH_P_IP)
&& src->m_PROTO_AddressSize == sizeof (IPADDR)
&& src->m_ARP_IP_Source == adapter_ip
- && src->m_ARP_IP_Destination == ip)
+ && (src->m_ARP_IP_Destination & ip_netmask) == ip_network
+ && src->m_ARP_IP_Destination != adapter_ip)
{
ARP_PACKET *arp = (ARP_PACKET *) MemAlloc (sizeof (ARP_PACKET), TRUE);
if (arp)
@@ -2442,7 +2590,7 @@ ProcessARP (TapAdapterPointer p_Adapter,
COPY_MAC (arp->m_MAC_Destination, p_Adapter->m_MAC);
COPY_MAC (arp->m_ARP_MAC_Source, mac);
COPY_MAC (arp->m_ARP_MAC_Destination, p_Adapter->m_MAC);
- arp->m_ARP_IP_Source = ip;
+ arp->m_ARP_IP_Source = src->m_ARP_IP_Destination;
arp->m_ARP_IP_Destination = adapter_ip;
DUMP_PACKET ("ProcessARP",
@@ -2508,9 +2656,10 @@ InjectPacket (TapAdapterPointer p_Adapter,
VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
{
// Point-To-Point
- p_Adapter->m_PointToPoint = FALSE;
+ p_Adapter->m_tun = FALSE;
p_Adapter->m_localIP = 0;
- p_Adapter->m_remoteIP = 0;
+ p_Adapter->m_remoteNetwork = 0;
+ p_Adapter->m_remoteNetmask = 0;
NdisZeroMemory (&p_Adapter->m_TapToUser, sizeof (p_Adapter->m_TapToUser));
NdisZeroMemory (&p_Adapter->m_UserToTap, sizeof (p_Adapter->m_UserToTap));
@@ -2526,6 +2675,124 @@ VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
p_Adapter->m_dhcp_bad_requests = 0;
NdisZeroMemory (p_Adapter->m_dhcp_server_mac, sizeof (MACADDR));
}
+
+#if ENABLE_NONADMIN
+
+//===================================================================
+// Set TAP device handle to be accessible without admin privileges.
+//===================================================================
+VOID AllowNonAdmin (TapExtensionPointer p_Extension)
+{
+ NTSTATUS stat;
+ SECURITY_DESCRIPTOR sd;
+ OBJECT_ATTRIBUTES oa;
+ IO_STATUS_BLOCK isb;
+ HANDLE hand = NULL;
+
+ NdisZeroMemory (&sd, sizeof (sd));
+ NdisZeroMemory (&oa, sizeof (oa));
+ NdisZeroMemory (&isb, sizeof (isb));
+
+ if (!p_Extension->m_CreatedUnicodeLinkName)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: UnicodeLinkName is uninitialized\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: RtlCreateSecurityDescriptor failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ InitializeObjectAttributes (
+ &oa,
+ &p_Extension->m_UnicodeLinkName,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
+
+ stat = ZwOpenFile (
+ &hand,
+ WRITE_DAC,
+ &oa,
+ &isb,
+ 0,
+ 0
+ );
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwOpenFile failed, status=0x%08x\n", (unsigned int)stat));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = ZwSetSecurityObject (hand, DACL_SECURITY_INFORMATION, &sd);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwSetSecurityObject failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = ZwClose (hand);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwClose failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ DEBUGP (("[TAP] AllowNonAdmin: SUCCEEDED\n"));
+}
+
+#endif
+
+#if PACKET_TRUNCATION_CHECK
+
+VOID
+IPv4PacketSizeVerify (const UCHAR *data, ULONG length, BOOLEAN tun, const char *prefix, LONG *counter)
+{
+ const IPHDR *ip;
+ int len = length;
+
+ if (tun)
+ {
+ ip = (IPHDR *) data;
+ }
+ else
+ {
+ if (length >= sizeof (ETH_HEADER))
+ {
+ const ETH_HEADER *eth = (ETH_HEADER *) data;
+
+ if (eth->proto != htons (ETH_P_IP))
+ return;
+
+ ip = (IPHDR *) (data + sizeof (ETH_HEADER));
+ len -= sizeof (ETH_HEADER);
+ }
+ else
+ return;
+ }
+
+ if (len >= sizeof (IPHDR))
+ {
+ const int totlen = ntohs (ip->tot_len);
+
+ DEBUGP (("[TAP] IPv4PacketSizeVerify %s len=%d totlen=%d\n", prefix, len, totlen));
+
+ if (len != totlen)
+ ++(*counter);
+ }
+}
+
+#endif
+
//======================================================================
// End of Source
//======================================================================