mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-11-03 21:46:32 +00:00
- GetIfEntry, GetIfTable and GetNumberOfInterfaces answer from the host's interfaces. GetIfEntry names one by the index the record handed in carries, GetIfTable puts the rows behind a count, and a table that does not fit is refused with ERROR_INSUFFICIENT_BUFFER and the size it needs. - The interface walk moved out of host_api.cpp into interfaces.cpp, so the records GetAdaptersAddresses reports and the rows these calls report come from one enumeration of the host rather than two. - interfaces_test checks the record against the MIB_IFROW offsets Windows declares and the cutting of a long name. The new guest fixture interface_client.c reads the tables through the runtime, in 64-bit and 32-bit builds: it checks that the count, the rows and GetIfEntry agree, that a sorted table lists the rows by index, and that an unknown index and a short table fail as Windows fails them. Assisted-by: Claude Code:deepseek-v4.1-flash-1017 AI-Scope: Read the MIB_IFROW and MIB_IFTABLE layouts, moved the interface enumeration into interfaces.cpp, wrote the three handlers and both tests, and checked them with ctest (native_interface_table_contract, native_interface_table_client, native_interface_table_client_x32).
88 lines
2.9 KiB
C
88 lines
2.9 KiB
C
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <iphlpapi.h>
|
|
|
|
/* A program reads how the machine is networked before it opens its first socket: how many interfaces there are, a row for each, and one
|
|
row by index. Every answer has to agree with the others, and a bad request has to fail the way Windows fails it. */
|
|
typedef char mib_if_row_is_860_bytes[sizeof(MIB_IFROW) == 860 ? 1 : -1];
|
|
|
|
static int failure;
|
|
|
|
static void expect(int condition, int code)
|
|
{
|
|
if (!condition && !failure)
|
|
failure = code;
|
|
}
|
|
|
|
static void zero(void *buffer, unsigned size)
|
|
{
|
|
BYTE *bytes = buffer;
|
|
for (unsigned at = 0; at < size; ++at)
|
|
bytes[at] = 0;
|
|
}
|
|
|
|
static int same_name(const WCHAR *left, const WCHAR *right)
|
|
{
|
|
for (unsigned at = 0; at < 256; ++at)
|
|
if (left[at] != right[at])
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int raven_entry(void)
|
|
{
|
|
ULONG count = 0;
|
|
expect(GetNumberOfInterfaces(&count) == NO_ERROR && count > 0, 1);
|
|
|
|
ULONG size = 0;
|
|
expect(GetIfTable(NULL, &size, 0) == ERROR_INSUFFICIENT_BUFFER && size >= sizeof(MIB_IFTABLE), 2);
|
|
MIB_IFTABLE *table = LocalAlloc(LMEM_FIXED, size);
|
|
expect(table != NULL, 3);
|
|
if (!table)
|
|
return failure;
|
|
expect(GetIfTable(table, &size, 0) == NO_ERROR, 4);
|
|
expect(table->dwNumEntries == count, 5);
|
|
expect(size == 4 + count * sizeof(MIB_IFROW), 6);
|
|
|
|
for (DWORD at = 0; at < table->dwNumEntries; ++at) {
|
|
const MIB_IFROW *row = &table->table[at];
|
|
expect(row->dwIndex != 0, 7);
|
|
expect(row->dwDescrLen <= MAXLEN_IFDESCR, 8);
|
|
expect(row->dwPhysAddrLen <= MAXLEN_PHYSADDR, 9);
|
|
// The name is a wide string in a fixed field, so a terminator has to be somewhere in it.
|
|
int terminated = 0;
|
|
for (unsigned character = 0; character < 256; ++character)
|
|
terminated |= row->wszName[character] == 0;
|
|
expect(terminated, 10);
|
|
// The same interface, asked for by the index the row carries, is described the same way.
|
|
MIB_IFROW one;
|
|
zero(&one, sizeof one);
|
|
one.dwIndex = row->dwIndex;
|
|
expect(GetIfEntry(&one) == NO_ERROR, 11);
|
|
expect(same_name(one.wszName, row->wszName), 12);
|
|
expect(one.dwType == row->dwType && one.dwMtu == row->dwMtu, 13);
|
|
expect(one.dwDescrLen == row->dwDescrLen, 14);
|
|
for (DWORD character = 0; character < one.dwDescrLen; ++character)
|
|
expect(one.bDescr[character] == row->bDescr[character], 15);
|
|
}
|
|
|
|
// An index no interface has is refused, as Windows refuses it.
|
|
MIB_IFROW missing;
|
|
zero(&missing, sizeof missing);
|
|
missing.dwIndex = 0x7fffffffu;
|
|
expect(GetIfEntry(&missing) == ERROR_INVALID_PARAMETER, 16);
|
|
|
|
// A table one byte short of the rows is refused, and the size it needs comes back.
|
|
ULONG short_size = size - 1;
|
|
expect(GetIfTable(table, &short_size, 0) == ERROR_INSUFFICIENT_BUFFER, 17);
|
|
expect(short_size == size, 18);
|
|
|
|
// The sorted order lists the rows by index.
|
|
expect(GetIfTable(table, &size, 1) == NO_ERROR, 19);
|
|
for (DWORD at = 1; at < table->dwNumEntries; ++at)
|
|
expect(table->table[at - 1].dwIndex < table->table[at].dwIndex, 20);
|
|
|
|
LocalFree(table);
|
|
return failure;
|
|
}
|