Skip to content
/ koffi Public

[Windows] How to correctly decode rows from a pointer to a table of structures as input argument? #245

@josej14

Description

@josej14

Hey there! I'm dealing with a problem trying to decode the data from a pointer argument passed to the GetIpInterfaceTable function. For context, this is the definition of the structures and function I have (which may be incorrect):

export const MIB_IPINTERFACE_ROW = koffi.struct('MIB_IPINTERFACE_ROW', {
  Family: 'uint32',
  InterfaceLuid: 'uint64',
  InterfaceIndex: 'uint32',
  MaxReassemblySize: 'uint32',
  InterfaceIdentifier: 'uint64',
  MinRouterAdvertisementInterval: 'uint32',
  MaxRouterAdvertisementInterval: 'uint32',
  AdvertisingEnabled: 'bool',
  ForwardingEnabled: 'bool',
  WeakHostSend: 'bool',
  WeakHostReceive: 'bool',
  UseAutomaticMetric: 'bool',
  UseNeighborUnreachabilityDetection: 'bool',
  ManagedAddressConfigurationSupported: 'bool',
  OtherStatefulConfigurationSupported: 'bool',
  AdvertisedReachableTime: 'uint32',
  RouterDiscoveryBehavior: 'uint32',
  DadTransmits: 'uint32',
  BaseReachableTime: 'uint32',
  RetransmitTimer: 'uint32',
  PathMtuDiscoveryTimeout: 'uint32',
  LinkLocalAddressBehavior: 'uint32',
  LinkLocalAddressTimeout: 'uint32',
  ZoneIndices: koffi.array('uint32', 16),
  SitePrefixLength: 'uint8',
  Metric: 'uint32',
  NlMtu: 'uint32',
  Connected: 'bool',
  SupportWakeUpPatterns: 'bool',
  SupportNeighborDiscovery: 'bool',
  SupportRouterDiscovery: 'bool',
  ReachableTime: 'uint32',
  TransmitOffload: 'uint32',
  ReceiveOffload: 'uint32',
  DisableDefaultRoutes: 'bool',
});
...
iphlpapi.func(
    'uint32 __stdcall GetIpInterfaceTable(uint16 Family, void **Table)',
)

And here is how I'm calling that function to get the pointer to the interfaces table:

      const outPtrPtr = koffi.alloc('void *', 1);
      const result = getIpInterfaceTableFunc(0, outPtrPtr);

      if (result === WinError.NO_ERROR) {
        const tablePtr = koffi.decode(outPtrPtr, 'void *');
        const numEntries = koffi.decode(tablePtr, 'uint32');

        const rowSize = koffi.sizeof(MIB_IPINTERFACE_ROW);
        const numEntriesSize = koffi.sizeof('uint32');
        ...

I've tried different ways to decode the Table content, without success. Specifically, I've tried to:

  1. Create a dynamic structure for MIB_IPINTERFACE_TABLE based on the numEntries value decoded as a uint32 structure with the first bytes from the pointer.
const MIB_IPINTERFACE_TABLE = koffi.struct('MIB_IPINTERFACE_TABLE', {
  NumEntries:'uint32,
  Table: koffi.array(MIB_IPINTERFACE_ROW, numEntries),
});
const tableView = koffi.view(tablePtr, koffi.sizeof(MIB_IPINTERFACE_TABLE));
const table = koffi.decode(tableView, MIB_IPINTERFACE_TABLE);
  1. Creating chunks of byte arrays and decoding them calculating the offset for each row:
        const totalSize = numEntriesSize + numEntries * rowSize;
        const tableView = koffi.view(tablePtr, totalSize);

        const rows = [];
        for (let i = 0; i < numEntries; i++) {
          const rowStart = numEntriesSize + i * rowSize;
          const rowBuf = Buffer.from(tableView, rowStart, rowSize);
          const row = koffi.decode(rowBuf, MIB_IPINTERFACE_ROW);
          rows.push(row);
        }

However, I get different errors on both implementations. Should I consider alignment/padding between rows? Could someone please tell me which is the right approach to access the table data on this or a similar scenario? Thanks!

Some extra context

If I create a placeholder structure for MIB_IPINTERFACE_TABLE as:

const MIB_IPINTERFACE_TABLE = koffi.struct('MIB_IPINTERFACE_TABLE', {
  NumEntries:'uint32,
  Table: koffi.array(MIB_IPINTERFACE_ROW, 1),
});

And I use it to decode the array buffer returned by the table pointer:

        const tableView = koffi.view(tablePtr, totalSize);
        const table = koffi.decode(tableView, MIB_IPINTERFACE_TABLE);

I can see that table contains an object with NumEntries and Table fields, but Table just contains the first MIB_IPINTERFACE_ROW entry, but I can't find a way to get the rest of rows without receiving errors from koffi.decode

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions