setting an IP address - kernel or userspace?

Under Xen it is possible to add an IP address to the VM configuration
file, and Linux picks this up and configures the virtual network
interface with that IP address.

If I wanted to do this under Windows, I can get the configuration data
easily enough but can I (should I?) actually set the IP address from my
driver or is it something I should do from userspace? Kernel would be
nicer but only if it’s a supported thing to do.

I’m comfortable with the fact that it will be set at boot time and that
the user can change it later if they want but it will be reset again
next boot. Preventing the user from changing the configuration might be
a nice feature but is not necessary - appropriate firewall rules will
prevent the user breaking the network outside their own VM.

James

VMware creates number of virtual network cards (or hubs)
and even provides its own dhcp server and NAT. Each virtual hub gets
two addresses, on host side and VM side.

Forcing the host to use IP specified by a network interface is
kind of antipodic… if you want this anyway, look for a thread
that mentions calling WMI from a driver.
– pa

“James Harper” wrote in message
news:xxxxx@ntdev…
> Under Xen it is possible to add an IP address to the VM configuration
> file, and Linux picks this up and configures the virtual network
> interface with that IP address.
>
> If I wanted to do this under Windows, I can get the configuration data
> easily enough but can I (should I?) actually set the IP address from my
> driver or is it something I should do from userspace? Kernel would be
> nicer but only if it’s a supported thing to do.
>
> I’m comfortable with the fact that it will be set at boot time and that
> the user can change it later if they want but it will be reset again
> next boot. Preventing the user from changing the configuration might be
> a nice feature but is not necessary - appropriate firewall rules will
> prevent the user breaking the network outside their own VM.
>
> James

> VMware creates number of virtual network cards (or hubs) and even provides its own dhcp server and NAT. Each virtual hub gets two addresses, on host side and VM side.

Having to fake up a DHCP server isn’t necessarily a feature – it’s kind of a nuisance to implement it correctly (see what a mess that got mobile broadband NICs into). Thus Windows 7 permits a NIC to declare “I am special. Do not attempt to use DHCP on me.” by setting EnableDhcp=0 in the miniport driver’s INF file. However, this is probably not flexible enough for you since, if you ever want to change this setting, you’d have to go reinstall your miniport.

if you want this anyway, look for a thread that mentions calling WMI from a driver.

It’s unclear to me which WMI class would be used here. Win32_NetworkAdapterConfiguration (which is the canonical WMI class for meddling with DHCP through its EnableDHCP / EnableStatic methods) can’t be called from kernel mode since its provider isn’t implemented as a driver. (MSNdis_* classes are nicer that way…).

is it something I should do from userspace?

Ultimately the easiest way to do this in a manner that works on all popular OSes (i.e., at least WinXP, possibly even Win2k) and carries the least risk of user astonishment is to have some usermode agent do the work. (Start with the previously-mentioned WMI class).

But it’s no fun if there aren’t *some* kernel APIs to play with :). On Vista / Server 2008 or later, you can actually make a solid dent in your requirements by using the kernelmode Netio API. As a caveat, however, you aren’t actually *disabling* DHCP or *permanently* configuring the interface with a static IP address. So the management UIs will be sort of misleading, in that they might state that DHCP is still enabled. (Since the permanent setting *is* still DHCP enabled.) But if the caveats are ok, then you can go party on CreateUnicastIpAddressEntry / DeleteUnicastIpAddressEntry. These routines will let you associate a temporary IP address with a network interface, and delete any the other ones.

A full discussion of how to use these APIs is located here: http://msdn.microsoft.com/en-us/library/ff552604(VS.85).aspx (ignore the fact that it’s written for Mobile Broadband miniports; much of it applies to you, except, probably, the EnableDhcp=0 INF directive). The key concept is that the OS keeps associations of tuples, and you there’s an API to enum/create/delete/query/modify these associations.

> Preventing the user from changing the configuration might be a nice feature

If you really want to get into the business of enforcing policy from kernelmode, you can register for notifications (NotifyUnicastIpAddressChange) and reassert your own addresses. But this is, IMHO, a bad idea, since it doesn’t buy you much (obviously you can’t actually protect the VM host from within the guest), and I can see code like this needlessly annoying the admin. It would not really work well with the management UIs. (“I applied the new settings successfully - now why aren’t they showing up in ipconfig?”). I think users generally understand that if they set their IP address to “some random value”, then their network might break; they don’t need any more hand-holding on that.

Anyway, more concretely, here’s some sample code to do this. I just cobbled this together from bits and pieces of my test code, so I don’t guarantee that it works – do your own QA :slight_smile:

#include <wdm.h>
#include <netioapi.h>

NTSTATUS
DeleteAllAddressesOnInterfaceEx(
in NET_IFINDEX TargetInterface,
in ADDRESS_FAMILY AddressFamily
);

NTSTATUS
DeleteAllAddressesOnInterface(
__in NET_IFINDEX TargetInterface
)
{
NTSTATUS NtStatus;

NtStatus = DeleteAllAddressesOnInterfaceEx(TargetInterface, AF_INET); // IPV4
if (STATUS_SUCCESS != NtStatus)
{
return NtStatus;
}

NtStatus = DeleteAllAddressesOnInterfaceEx(TargetInterface, AF_INET6); // IPV6
if (STATUS_SUCCESS != NtStatus)
{
return NtStatus;
}

return STATUS_SUCCESS;
}

NTSTATUS
DeleteAllAddressesOnInterfaceEx(
__in NET_IFINDEX TargetInterface,
__in ADDRESS_FAMILY AddressFamily
)
{
NTSTATUS NtStatus;
PMIB_UNICASTIPADDRESS_TABLE Table = NULL;
ULONG i;

// Enumerate all interfaces for the given address family
NtStatus = GetUnicastIpAddressTable(AddressFamily, &Table);
if (STATUS_SUCCESS != NtStatus)
{
return NtStatus;
}

for (i = 0; i < Table->NumEntries; i++)
{
PMIB_UNICASTIPADDRESS_ROW Row = &Table->Table[i];

// Ignore network interface if it’s not my network interface
if (Row->InterfaceIndex != TargetInterface)
{
continue;
}

// Don’t delete IPv6 link-local addresses
if ((AddressFamily == AF_INET6)
&& (Row->PrefixOrigin == IpPrefixOriginWellKnown))
{
continue;
}

NtStatus = DeleteUnicastIpAddressEntry(Row);
if (STATUS_SUCCESS != NtStatus)
{
// Note that it may be undesirable to break while we’re
// only part-way through this operation.
break;
}
}

if (Table)
{
FreeMibTable(Table);
}

return NtStatus;
}

NTSTATUS
AddAddressToInterface(
__in SOCKADDR_INET *TargetAddress,
__in NET_IFINDEX TargetInterface
)
{
NTSTATUS NtStatus;
MIB_UNICASTIPADDRESS_ROW Row;

InitializeUnicastIpAddressEntry(&Row);

Row.Address = *TargetAddress;
Row.InterfaceIndex = TargetInterface;

NtStatus = CreateUnicastIpAddressEntry(&Row);
if (STATUS_SUCCESS != NtStatus)
{
return NtStatus;
}

return NtStatus;
}

This is a stupid example of how one might use the functions above.

NTSTATUS
Set192_168_1_99(
__in NET_IFINDEX TargetIndex
)
{
NTSTATUS NtStatus;
SOCKADDR_INET Address;

NtStatus = DeleteAllAddressesOnInterface(TargetIndex);
if (STATUS_SUCCESS != NtStatus)
{
return NtStatus;
}

// Build up the IPv4 address 192.168.1.99
RtlZeroMemory(&Address, sizeof(Address));
Address.si_family = AF_INET;
Address.Ipv4.sin_addr.S_un.S_un_b.s_b1 = 192;
Address.Ipv4.sin_addr.S_un.S_un_b.s_b2 = 168;
Address.Ipv4.sin_addr.S_un.S_un_b.s_b3 = 1;
Address.Ipv4.sin_addr.S_un.S_un_b.s_b4 = 99;

NtStatus = AddAddressToInterface(&Address, TargetIndex);
if (STATUS_SUCCESS != NtStatus)
{
return NtStatus;
}

return STATUS_SUCCESS;
}

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Pavel A.
Sent: Monday, November 22, 2010 2:09 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] setting an IP address - kernel or userspace?

VMware creates number of virtual network cards (or hubs) and even provides its own dhcp server and NAT. Each virtual hub gets two addresses, on host side and VM side.

Forcing the host to use IP specified by a network interface is kind of antipodic… if you want this anyway, look for a thread that mentions calling WMI from a driver.
– pa

“James Harper” wrote in message news:xxxxx@ntdev…
> Under Xen it is possible to add an IP address to the VM configuration
> file, and Linux picks this up and configures the virtual network
> interface with that IP address.
>
> If I wanted to do this under Windows, I can get the configuration data
> easily enough but can I (should I?) actually set the IP address from
> my driver or is it something I should do from userspace? Kernel would
> be nicer but only if it’s a supported thing to do.
>
> I’m comfortable with the fact that it will be set at boot time and
> that the user can change it later if they want but it will be reset
> again next boot. Preventing the user from changing the configuration
> might be a nice feature but is not necessary - appropriate firewall
> rules will prevent the user breaking the network outside their own VM.
>
> James


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</netioapi.h></wdm.h>

Of course the UM agent Mr. Tippet is suggesting is the most sanctioned and
robust way.

However, you can go whack the registry settings in

HKLM\System\CurrentControlSet\Service\TCPIP\Interfaces{your-adapter-netcfgi
d}.…

which still works in NT6 because of the great attention to not breaking
backward compatibility that MSFT put into that area.

You of course need to figure out what the adapter netcfgid is but that
nicely is stored (post device install) in the registry properties (sw key).

So with just a little bit of machinery in your bus or function driver, you
can go pound on those settings before TCPIP.SYS binds to the adapter and
decides how to operate.

I built such a thing in the virtual bus driver so I cannot speak to whether
or not it would work as well from the function driver.

Good Luck,
Dave Cattley