From 1f7304870ca843775c8a6ccf94620c1d16aea937 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Gardou?= Date: Wed, 21 Jan 2015 15:55:00 +0000 Subject: [PATCH] [TCPIP_DRVTEST] - Add quite a lot of tests for IOCTL_TCP_QUERY_INFORMATION_EX This IOCTL is quite important because that's how iphlpapi gets data from it. Also, this can be used as a viewer for quite a lot SNMP info as described here: http://www.oidview.com/mibs/0/RFC1213-MIB.html svn path=/trunk/; revision=66070 --- rostests/drivers/tcpip/CMakeLists.txt | 1 + rostests/drivers/tcpip/tcp_info.c | 580 ++++++++++++++++++++++++++ rostests/drivers/tcpip/testlist.c | 2 + 3 files changed, 583 insertions(+) create mode 100644 rostests/drivers/tcpip/tcp_info.c diff --git a/rostests/drivers/tcpip/CMakeLists.txt b/rostests/drivers/tcpip/CMakeLists.txt index 06f14f093b5..b20297133e9 100644 --- a/rostests/drivers/tcpip/CMakeLists.txt +++ b/rostests/drivers/tcpip/CMakeLists.txt @@ -3,6 +3,7 @@ include_directories(../../apitests/include) list(APPEND SOURCE InterfaceInfo.c + tcp_info.c testlist.c) add_executable(tcpip_drvtest ${SOURCE}) diff --git a/rostests/drivers/tcpip/tcp_info.c b/rostests/drivers/tcpip/tcp_info.c new file mode 100644 index 00000000000..b76f196ecc5 --- /dev/null +++ b/rostests/drivers/tcpip/tcp_info.c @@ -0,0 +1,580 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Tests for IOCTL_TCP_QUERY_INFORMATION_EX + * PROGRAMMER: Jérôme Gardou + */ + +#include + +#include + +#include +#include +#include +#include +#include + +/* Route info */ +typedef struct IPRouteEntry { + unsigned long ire_dest; + unsigned long ire_index; + unsigned long ire_metric1; + unsigned long ire_metric2; + unsigned long ire_metric3; + unsigned long ire_metric4; + unsigned long ire_nexthop; + unsigned long ire_type; + unsigned long ire_proto; + unsigned long ire_age; + unsigned long ire_mask; + unsigned long ire_metric5; + unsigned long ire_context; +} IPRouteEntry; + +/* Present in headers for Vista+, but there in WinXP/2k3 ntdll */ +NTSYSAPI +PSTR +NTAPI +RtlIpv4AddressToStringA( + _In_ const struct in_addr *Addr, + _Out_writes_(16) PSTR S); + + +static HANDLE TcpFileHandle; + +static ULONG IndentationLevel = 0; + +static +char* +dbg_print_physaddr(const unsigned char* addr, unsigned long addr_len) +{ + static char buffer[24]; + + char* dest = buffer; + *dest = '\0'; + + while (addr_len--) + { + dest += sprintf(dest, "%02x", *addr); + addr++; + if (addr_len) + *dest++ = ':'; + } + + return buffer; +} + +static +int +__cdecl +indent_printf(const char* format, ...) +{ + ULONG Indent = IndentationLevel; + int ret; + va_list args; + + while(Indent--) + printf("\t"); + + va_start(args, format); + ret = vprintf(format, args); + va_end(args); + + ret += IndentationLevel; + + return ret; +} + +static +void +test_IF_MIB_STATS( + TDIEntityID Id, + ULONG EntityType) +{ + IFEntry* IfEntry; + TCP_REQUEST_QUERY_INFORMATION_EX Request; + ULONG BufferSize = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1; + BOOL Result; + + /* Not valid for other entity types */ + if (EntityType != IF_MIB) + return; + + IfEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize); + ok(IfEntry != NULL, "\n"); + + ZeroMemory(&Request, sizeof(Request)); + Request.ID.toi_entity = Id; + Request.ID.toi_class = INFO_CLASS_PROTOCOL; + Request.ID.toi_type = INFO_TYPE_PROVIDER; + Request.ID.toi_id = IF_MIB_STATS_ID; + + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + IfEntry, + BufferSize, + &BufferSize, + NULL); + ok(Result, "DeviceIoControl failed.\n"); + + /* Dump it */ + indent_printf("IF_MIB Statistics:\n"); + IndentationLevel++; + indent_printf("if_index: %lu\n", IfEntry->if_index); + indent_printf("if_type: %lu\n", IfEntry->if_type); + indent_printf("if_mtu: %lu\n", IfEntry->if_mtu); + indent_printf("if_speed: %lu\n", IfEntry->if_speed); + indent_printf("if_physaddr: %s\n", dbg_print_physaddr(IfEntry->if_physaddr, IfEntry->if_physaddrlen)); + indent_printf("if_adminstatus: %lu\n", IfEntry->if_adminstatus); + indent_printf("if_operstatus: %lu\n", IfEntry->if_operstatus); + indent_printf("if_lastchange: %lu\n", IfEntry->if_lastchange); + indent_printf("if_inoctets: %lu\n", IfEntry->if_inoctets); + indent_printf("if_inucastpkts: %lu\n", IfEntry->if_inucastpkts); + indent_printf("if_innucastpkts: %lu\n", IfEntry->if_innucastpkts); + indent_printf("if_indiscards: %lu\n", IfEntry->if_indiscards); + indent_printf("if_inerrors: %lu\n", IfEntry->if_inerrors); + indent_printf("if_inunknownprotos: %lu\n", IfEntry->if_inunknownprotos); + indent_printf("if_outoctets: %lu\n", IfEntry->if_outoctets); + indent_printf("if_outucastpkts: %lu\n", IfEntry->if_outucastpkts); + indent_printf("if_outnucastpkts: %lu\n", IfEntry->if_outnucastpkts); + indent_printf("if_outdiscards: %lu\n", IfEntry->if_outdiscards); + indent_printf("if_outerrors: %lu\n", IfEntry->if_outerrors); + indent_printf("if_outqlen: %lu\n", IfEntry->if_outqlen); + indent_printf("if_descr: %*s\n", IfEntry->if_descrlen, IfEntry->if_descr); + IndentationLevel--; + + HeapFree(GetProcessHeap(), 0, IfEntry); +} + +static +void +test_IP_MIB_STATS( + TDIEntityID Id, + ULONG EntityType) +{ + IPSNMPInfo IpSnmpInfo; + TCP_REQUEST_QUERY_INFORMATION_EX Request; + ULONG BufferSize = 0; + BOOL Result; + + /* Not valid for other entity types */ + if (EntityType != CL_NL_IP) + return; + + ZeroMemory(&IpSnmpInfo, sizeof(IpSnmpInfo)); + + ZeroMemory(&Request, sizeof(Request)); + Request.ID.toi_entity = Id; + Request.ID.toi_class = INFO_CLASS_PROTOCOL; + Request.ID.toi_type = INFO_TYPE_PROVIDER; + Request.ID.toi_id = IP_MIB_STATS_ID; + + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + &IpSnmpInfo, + sizeof(IpSnmpInfo), + &BufferSize, + NULL); + ok(Result, "DeviceIoControl failed.\n"); + + /* Dump it */ + indent_printf("IP_MIB Statistics:\n"); + IndentationLevel++; + indent_printf("ipsi_forwarding: %lu\n", IpSnmpInfo.ipsi_forwarding); + indent_printf("ipsi_defaultttl: %lu\n", IpSnmpInfo.ipsi_defaultttl); + indent_printf("ipsi_inreceives: %lu\n", IpSnmpInfo.ipsi_inreceives); + indent_printf("ipsi_inhdrerrors: %lu\n", IpSnmpInfo.ipsi_inhdrerrors); + indent_printf("ipsi_inaddrerrors: %lu\n", IpSnmpInfo.ipsi_inaddrerrors); + indent_printf("ipsi_forwdatagrams: %lu\n", IpSnmpInfo.ipsi_forwdatagrams); + indent_printf("ipsi_inunknownprotos: %lu\n", IpSnmpInfo.ipsi_inunknownprotos); + indent_printf("ipsi_indiscards: %lu\n", IpSnmpInfo.ipsi_indiscards); + indent_printf("ipsi_indelivers: %lu\n", IpSnmpInfo.ipsi_indelivers); + indent_printf("ipsi_outrequests: %lu\n", IpSnmpInfo.ipsi_outrequests); + indent_printf("ipsi_routingdiscards: %lu\n", IpSnmpInfo.ipsi_routingdiscards); + indent_printf("ipsi_outdiscards: %lu\n", IpSnmpInfo.ipsi_outdiscards); + indent_printf("ipsi_outnoroutes: %lu\n", IpSnmpInfo.ipsi_outnoroutes); + indent_printf("ipsi_reasmtimeout: %lu\n", IpSnmpInfo.ipsi_reasmtimeout); + indent_printf("ipsi_reasmreqds: %lu\n", IpSnmpInfo.ipsi_reasmreqds); + indent_printf("ipsi_reasmoks: %lu\n", IpSnmpInfo.ipsi_reasmoks); + indent_printf("ipsi_reasmfails: %lu\n", IpSnmpInfo.ipsi_reasmfails); + indent_printf("ipsi_fragoks: %lu\n", IpSnmpInfo.ipsi_fragoks); + indent_printf("ipsi_fragfails: %lu\n", IpSnmpInfo.ipsi_fragfails); + indent_printf("ipsi_fragcreates: %lu\n", IpSnmpInfo.ipsi_fragcreates); + indent_printf("ipsi_numif: %lu\n", IpSnmpInfo.ipsi_numif); + indent_printf("ipsi_numaddr: %lu\n", IpSnmpInfo.ipsi_numaddr); + indent_printf("ipsi_numroutes: %lu\n", IpSnmpInfo.ipsi_numroutes); + + if (IpSnmpInfo.ipsi_numaddr != 0) + { + IPAddrEntry* AddrEntries; + ULONG i; + + AddrEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0])); + ok(AddrEntries != NULL, "\n"); + + ZeroMemory(&Request, sizeof(Request)); + Request.ID.toi_entity = Id; + Request.ID.toi_class = INFO_CLASS_PROTOCOL; + Request.ID.toi_type = INFO_TYPE_PROVIDER; + Request.ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID; + + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + AddrEntries, + IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]), + &BufferSize, + NULL); + ok(Result, "DeviceIoControl failed.\n"); + ok_long(BufferSize, IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0])); + + for(i = 0; i < IpSnmpInfo.ipsi_numaddr; i++) + { + CHAR AddressString[16]; + struct in_addr Addr; + + Addr.S_un.S_addr = AddrEntries[i].iae_addr; + RtlIpv4AddressToStringA(&Addr, AddressString); + + indent_printf("Address %lu: %s\n", i, AddressString); + + IndentationLevel++; + + indent_printf("iae_addr: %lx\n", AddrEntries[i].iae_addr); + indent_printf("iae_index: %lu\n", AddrEntries[i].iae_index); + Addr.S_un.S_addr = AddrEntries[i].iae_mask; + RtlIpv4AddressToStringA(&Addr, AddressString); + indent_printf("iae_mask: %lx (%s)\n", AddrEntries[i].iae_mask, AddressString); + indent_printf("iae_bcastaddr: %lu\n", AddrEntries[i].iae_bcastaddr); + indent_printf("iae_reasmsize: %lu\n", AddrEntries[i].iae_reasmsize); + indent_printf("iae_context: %u\n", AddrEntries[i].iae_context); + + { + IPInterfaceInfo* InterfaceInfo; + + /* Get the interface info */ + BufferSize = sizeof(IPInterfaceInfo) + MAX_PHYSADDR_SIZE; + InterfaceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize); + ok(InterfaceInfo != NULL, "\n"); + + Request.ID.toi_id = IP_INTFC_INFO_ID; + Request.Context[0] = AddrEntries[i].iae_addr; + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + InterfaceInfo, + BufferSize, + &BufferSize, + NULL); + ok(Result, "DeviceIoControl failed.\n"); + + indent_printf("Interface info:\n"); + IndentationLevel++; + + indent_printf("iii_flags: %lu\n", InterfaceInfo->iii_flags); + indent_printf("iii_mtu : %lu\n", InterfaceInfo->iii_mtu); + indent_printf("iii_speed: %lu\n", InterfaceInfo->iii_speed); + indent_printf("iii_physaddr: %s\n", dbg_print_physaddr(InterfaceInfo->iii_addr, InterfaceInfo->iii_addrlength)); + + IndentationLevel--; + } + + IndentationLevel--; + } + + HeapFree(GetProcessHeap(), 0, AddrEntries); + } + + /* See for the routes */ + if (IpSnmpInfo.ipsi_numroutes) + { + IPRouteEntry* RouteEntries; + ULONG i; + + RouteEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0])); + ok(RouteEntries != NULL, "\n"); + + ZeroMemory(&Request, sizeof(Request)); + Request.ID.toi_entity = Id; + Request.ID.toi_class = INFO_CLASS_PROTOCOL; + Request.ID.toi_type = INFO_TYPE_PROVIDER; + Request.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID; + + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + RouteEntries, + IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0]), + &BufferSize, + NULL); + ok(Result, "DeviceIoControl failed.\n"); + ok_long(BufferSize, IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0])); + + for (i = 0; i < IpSnmpInfo.ipsi_numroutes; i++) + { + CHAR AddressString[16]; + struct in_addr Addr; + + Addr.S_un.S_addr = RouteEntries[i].ire_dest; + RtlIpv4AddressToStringA(&Addr, AddressString); + + indent_printf("Route %lu:\n", i); + + IndentationLevel++; + + indent_printf("ire_dest: %s (%lx)\n", AddressString, RouteEntries[i].ire_dest); + indent_printf("ire_index: %lu\n", RouteEntries[i].ire_index); + indent_printf("ire_metric1: %#lx\n", RouteEntries[i].ire_metric1); + indent_printf("ire_metric2: %#lx\n", RouteEntries[i].ire_metric2); + indent_printf("ire_metric3: %#lx\n", RouteEntries[i].ire_metric3); + indent_printf("ire_metric4: %#lx\n", RouteEntries[i].ire_metric4); + Addr.S_un.S_addr = RouteEntries[i].ire_nexthop; + RtlIpv4AddressToStringA(&Addr, AddressString); + indent_printf("ire_nexthop: %s (%lx)\n", AddressString, RouteEntries[i].ire_nexthop); + indent_printf("ire_type: %lu\n", RouteEntries[i].ire_type); + indent_printf("ire_proto: %lu\n", RouteEntries[i].ire_proto); + indent_printf("ire_age: %lu\n", RouteEntries[i].ire_age); + Addr.S_un.S_addr = RouteEntries[i].ire_mask; + RtlIpv4AddressToStringA(&Addr, AddressString); + indent_printf("ire_mask: %s (%lx)\n", AddressString, RouteEntries[i].ire_mask); + indent_printf("ire_metric5: %lx\n", RouteEntries[i].ire_metric5); + indent_printf("ire_context: %lx\n", RouteEntries[i].ire_context); + + IndentationLevel--; + } + } + + IndentationLevel--; +} + +typedef struct ARPInfo +{ + unsigned long ai_numroutes; + unsigned long ai_unknown; +} ARPInfo; + +typedef struct ARPEntry +{ + unsigned long ae_index; + unsigned long ae_physaddrlen; + unsigned char ae_physaddr[MAX_PHYSADDR_SIZE]; + unsigned long ae_address; + unsigned long ae_unknown; +} ARPEntry; + +static +void +test_AT_ARP_STATS( + TDIEntityID Id, + ULONG EntityType) +{ + ARPInfo ArpInfo; + TCP_REQUEST_QUERY_INFORMATION_EX Request; + ULONG BufferSize = 0; + BOOL Result; + + /* Not valid for other entity types */ + if (EntityType != AT_ARP) + return; + + ZeroMemory(&Request, sizeof(Request)); + Request.ID.toi_entity = Id; + Request.ID.toi_class = INFO_CLASS_PROTOCOL; + Request.ID.toi_type = INFO_TYPE_PROVIDER; + Request.ID.toi_id = AT_MIB_ADDRXLAT_INFO_ID; + + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + &ArpInfo, + sizeof(ArpInfo), + &BufferSize, + NULL); + ok(Result, "DeviceIoControl failed.\n"); + ok_long(BufferSize, sizeof(ArpInfo)); + + indent_printf("ARP Info:\n"); + IndentationLevel++; + + indent_printf("ai_numroutes: %lu\n", ArpInfo.ai_numroutes); + indent_printf("ai_unknown: %lx\n", ArpInfo.ai_unknown); + + if (ArpInfo.ai_numroutes) + { + ARPEntry* ArpEntries; + ULONG i; + + Request.ID.toi_id = AT_MIB_ADDRXLAT_ENTRY_ID; + + ArpEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ArpInfo.ai_numroutes * sizeof(ArpEntries[0])); + ok(ArpEntries != NULL, "\n"); + + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + ArpEntries, + ArpInfo.ai_numroutes * sizeof(ArpEntries[0]), + &BufferSize, + NULL); + ok(Result, "DeviceIoControl failed.\n"); + ok_long(BufferSize, ArpInfo.ai_numroutes * sizeof(ArpEntries[0])); + + for (i = 0; i < ArpInfo.ai_numroutes; i++) + { + CHAR AddressString[16]; + struct in_addr Addr; + + Addr.S_un.S_addr = ArpEntries[i].ae_address; + RtlIpv4AddressToStringA(&Addr, AddressString); + + indent_printf("ARP Entry %lu:\n", i); + + IndentationLevel++; + + indent_printf("ae_index: %lu\n", ArpEntries[i].ae_index); + indent_printf("ae_physaddr: %lu\n", dbg_print_physaddr(ArpEntries[i].ae_physaddr, ArpEntries[i].ae_physaddrlen)); + indent_printf("ae_address: %lx (%s)\n", ArpEntries[i].ae_address, AddressString); + indent_printf("ae_unknown: %lu.\n", ArpEntries[i].ae_unknown); + + IndentationLevel--; + } + + HeapFree(GetProcessHeap(), 0, ArpEntries); + } + + IndentationLevel--; +} + +START_TEST(tcp_info) +{ + TDIEntityID* Entities; + DWORD BufferSize; + BOOL Result; + ULONG i, EntityCount; + TCP_REQUEST_QUERY_INFORMATION_EX Request; + + /* Open a control channel file for TCP */ + TcpFileHandle = CreateFileW( + L"\\\\.\\Tcp", + FILE_READ_DATA | FILE_WRITE_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + ok(TcpFileHandle != INVALID_HANDLE_VALUE, "CreateFile failed, GLE %lu\n", GetLastError()); + + /* Try the IOCTL */ + BufferSize = 0; + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + NULL, + 0, + NULL, + 0, + &BufferSize, + NULL); + ok(!Result, "DeviceIoControl succeeded.\n"); + ok_long(GetLastError(), ERROR_INVALID_PARAMETER); + ok_long(BufferSize, 0); + + ZeroMemory(&Request, sizeof(Request)); + Request.ID.toi_entity.tei_entity = GENERIC_ENTITY; + Request.ID.toi_entity.tei_instance = 0; + Request.ID.toi_class = INFO_CLASS_GENERIC; + Request.ID.toi_type = INFO_TYPE_PROVIDER; + Request.ID.toi_id = ENTITY_LIST_ID; + + BufferSize = 0; + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + NULL, + 0, + &BufferSize, + NULL); + ok(!Result, "DeviceIoControl succeeded.\n"); + ok_long(GetLastError(), ERROR_INVALID_PARAMETER); + ok_long(BufferSize, 0); + + BufferSize = 4 * sizeof(Entities[0]); + Entities = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize); + ok(Entities != NULL, "\n"); + + while (TRUE) + { + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + Entities, + BufferSize, + &BufferSize, + NULL); + + if (Result) + break; + + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; + + BufferSize *= 2; + Entities = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Entities, BufferSize); + ok(Entities != NULL, "\n"); + } + + ok(Result, "DeviceIoControl failed!\n"); + EntityCount = BufferSize / sizeof(Entities[0]); + trace("Got %lu entities.\n", EntityCount); + + for (i = 0; i < EntityCount; i++) + { + ULONG EntityType; + + /* Get the type */ + Request.ID.toi_entity = Entities[i]; + Request.ID.toi_class = INFO_CLASS_GENERIC; + Request.ID.toi_type = INFO_TYPE_PROVIDER; + Request.ID.toi_id = ENTITY_TYPE_ID; + + Result = DeviceIoControl( + TcpFileHandle, + IOCTL_TCP_QUERY_INFORMATION_EX, + &Request, + sizeof(Request), + &EntityType, + sizeof(EntityType), + &BufferSize, + NULL); + ok(Result, "DeviceIoControl failed.\n"); + + printf("Entity %lu: %#lx, %#lx, type %#lx\n", i, Entities[i].tei_entity, Entities[i].tei_instance, EntityType); + test_IF_MIB_STATS(Entities[i], EntityType); + test_IP_MIB_STATS(Entities[i], EntityType); + test_AT_ARP_STATS(Entities[i], EntityType); + } + + HeapFree(GetProcessHeap(), 0, Entities); + CloseHandle(TcpFileHandle); +} diff --git a/rostests/drivers/tcpip/testlist.c b/rostests/drivers/tcpip/testlist.c index 93538638238..3d8ab30d537 100644 --- a/rostests/drivers/tcpip/testlist.c +++ b/rostests/drivers/tcpip/testlist.c @@ -4,10 +4,12 @@ #include extern void func_InterfaceInfo(void); +extern void func_tcp_info(void); const struct test winetest_testlist[] = { { "InterfaceInfo", func_InterfaceInfo }, + { "tcp_info", func_tcp_info }, { 0, 0 } }; -- 2.17.1