Floating IP (or Virtual IP) on Windows XP and newer

J

Jeff55

We are trying to create a redundant environment where we have two
machines configured to handle our application and our application on
the two machines negotiates which one is active and which copy is
standby. We would like to create an IP address which the client
software uses to connect to the application but we cannot figure out
how to activate it either via a script or a C program on the machine
which is hosting the live instance. The machines are configured with
DHCP and this virtual address has been reserved on the DHCP server so
it never gets assigned.

TIA
 
A

Anteaus

The netsh command will allow you to assign an IP address to an interfsce,
plus a lot more besides. The syntax is a little cryptic but there are plenty
sites with details of how to use it.

Bear in mind that assigning the same IP to a different computer may confuse
a 'smart' switch, requring a hub reboot (or long wait) for the connection to
reestablish.
 
J

Jeff55

Thank you.

We've been playing with netsh but I was hoping to find some some way
to
do it from C. I've been playing with AddIPAddress but this fails when
DHCP
is enabled. netsh fails too with DHCP but if we disable that first,
then it works.
 
J

Jeff55

Oh, I spoke too soon. DHCP is a problem regardless of whether we try
to call AddIPAddress or use netsh. If DHCP is enabled on the interface
we can't add a 2nd address. This is on XP so maybe the behavior
is different now. If we disable DHCP we can add the 2nd address
however
the address is disabled if DHCP is re-enabled. We can leave DHCP
disabled
until the application shuts down but if the box reboots, we don't get
a chance
to re-enable DHCP so it is disabled after the reboot.
 
J

Jeff55

Seems we were confused and DHCP doesn't actually interfere with adding
an address
via AddIPAddress however it does block netsh from adding a 2nd
address.

For anyone interested here is a C program built mostly from examples
in the MSDN
which uses AddIPAddress and DeleteIPAddress and will list the
interfaces and/or
the current set of ip addresses.

---------------------------------------------------------------------------------------------------------------------------------
/* Program: iphelper..c
* This is a collection of code pulled together from various
* examples in the MSDN to create a program that can add and
* delete IP alias addresses using AddIPAddress and DeleteIPAddress
*
* cc [-Zi] -c iphelper.c
* link [/debug] iphelper.obj
*/
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

/* Note: could also use malloc() and free() */
int listInterfaces();
int listAddresses();
int addAddress(UINT,UINT,UINT);
int delAddress(UINT);
int findAdapter(UINT);
int findIndex(UINT);

dohelp(char *prog) {
printf("usage: %s -a IPAddress NewIPAddress SubnetMask\n", prog);
printf("usage: %s -d IPAddress\n", prog);
printf("usage: %s -li list interfaces\n", prog);
printf("usage: %s -la list addresses\n", prog);
}

int __cdecl main(int argc, char **argv)
{
UINT iaNewIPAddress;
UINT iaIPAddress;
UINT iaIPMask;
char opt;
int rc;
ULONG context;

if (argc < 2 || *argv[1] != '-') {
dohelp(argv[0]);
exit(1);
}
opt = argv[1][1];
opt = tolower(opt);
if (opt != 'l' && opt != 'a' && opt != 'd') {
printf("invalid option -%c\n",opt);
dohelp(argv[0]);
exit(1);
}
if (opt == 'l') {
opt = argv[1][2];
opt = tolower(opt);
if (opt == 'i')
listInterfaces();
else if (opt == 'a')
listAddresses();
else {
printf("invalid list type -l%c\n",opt);
dohelp(argv[0]);
}
exit(0);
}

if ((opt == 'd' && argc != 3) ||
(opt == 'a' && argc != 5)) {
printf("Insufficient arguments for -%c\n",opt);
dohelp(argv[0]);
exit(1);
}


if (opt == 'a') {
iaIPAddress = inet_addr(argv[2]);
if (iaIPAddress == INADDR_NONE) {
printf("1st argument is not a valid ip address\n");
dohelp(argv[0]);
exit(1);
}

iaNewIPAddress = inet_addr(argv[3]);
if (iaNewIPAddress == INADDR_NONE) {
printf("New IP address is invalid\n");
dohelp(argv[0]);
exit(1);
}
iaIPMask = inet_addr(argv[4]);
if (iaIPMask == INADDR_NONE) {
printf("Invalid subnet mask\n");
dohelp(argv[0]);
exit(1);
}
rc = addAddress(iaIPAddress, iaNewIPAddress, iaIPMask);
}

if (opt == 'd') {
iaIPAddress = inet_addr(argv[2]);
if (iaIPAddress == INADDR_NONE) {
printf("1st argument is not a valid ip address\n");
dohelp(argv[0]);
exit(1);
}

rc = delAddress(iaIPAddress);
}
exit(rc);
}

/* Note: could also use malloc() and free() */

addAddress(UINT iaTargIPAddress, UINT iaIPAddress, UINT iaIPMask)
{
/* Variables used by GetIpAddrTable */
DWORD ifIndex;

/* Variables where handles to the added IP are returned */
ULONG NTEContext = 0;
ULONG NTEInstance = 0;
DWORD dwRetVal = 0;

/* Variables used to return error message */
LPVOID lpMsgBuf;


ifIndex = findAdapter(iaTargIPAddress);
if (ifIndex == -1) {
printf("Failed to find existing adaptor for target address\n");
return 1; /* failure */
}

if ((dwRetVal = AddIPAddress(iaIPAddress,
iaIPMask,
ifIndex,
&NTEContext, &NTEInstance)) == NO_ERROR) {
printf("\tIPv4 address was successfully added.\n");
} else {
printf("AddIPAddress failed with error: %d\n", dwRetVal);

if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default
language
(LPTSTR) & lpMsgBuf, 0, NULL)) {
printf("\tError: %s", lpMsgBuf);
LocalFree(lpMsgBuf);
return 1;
}
}
return 0;
}

delAddress(UINT iAddr)
{
DWORD dwRetVal = 0;
int context;

context = findIndex(iAddr);
if (context == -1) {
printf("Failed to find address to delete\n");
return 1;
}

if ((dwRetVal = DeleteIPAddress(context)) != NO_ERROR) {
printf("DeleteIPAddress call failed with %d\n", dwRetVal);
}
return 0;
}


listInterfaces() {
/* Declare and initialize variables */

// It is possible for an adapter to have multiple
// IPv4 addresses, gateways, and secondary WINS servers
// assigned to the adapter.
//
// Note that this sample code only prints out the
// first entry for the IP address/mask, and gateway, and
// the primary and secondary WINS server for each adapter.

PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
UINT i;

/* variables used to print DHCP time info */
struct tm newtime;
char buffer[32];
errno_t error;

ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(sizeof
(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo
\n");
return 1;
}
// Make an initial call to GetAdaptersInfo to get
// the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) ==
ERROR_BUFFER_OVERFLOW) {
FREE(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(ulOutBufLen);
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return 1;
}
}

if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) ==
NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
printf("\tComboIndex: \t%d\n", pAdapter->ComboIndex);
printf("\tAdapter Name: \t%s\n", pAdapter->AdapterName);
printf("\tAdapter Desc: \t%s\n", pAdapter->Description);
printf("\tAdapter Addr: \t");
for (i = 0; i < pAdapter->AddressLength; i++) {
if (i == (pAdapter->AddressLength - 1))
printf("%.2X\n", (int) pAdapter->Address);
else
printf("%.2X-", (int) pAdapter->Address);
}
printf("\tIndex: \t%d\n", pAdapter->Index);
printf("\tType: \t");
switch (pAdapter->Type) {
case MIB_IF_TYPE_OTHER:
printf("Other\n");
break;
case MIB_IF_TYPE_ETHERNET:
printf("Ethernet\n");
break;
case MIB_IF_TYPE_TOKENRING:
printf("Token Ring\n");
break;
case MIB_IF_TYPE_FDDI:
printf("FDDI\n");
break;
case MIB_IF_TYPE_PPP:
printf("PPP\n");
break;
case MIB_IF_TYPE_LOOPBACK:
printf("Lookback\n");
break;
case MIB_IF_TYPE_SLIP:
printf("Slip\n");
break;
default:
printf("Unknown type %ld\n", pAdapter->Type);
break;
}

printf("\tIP Address: \t%s\n",
pAdapter->IpAddressList.IpAddress.String);
printf("\tIP Mask: \t%s\n", pAdapter->IpAddressList.IpMask.String);

printf("\tGateway: \t%s\n", pAdapter->GatewayList.IpAddress.String);
printf("\t***\n");

if (pAdapter->DhcpEnabled) {
printf("\tDHCP Enabled: Yes\n");
printf("\t DHCP Server: \t%s\n",
pAdapter->DhcpServer.IpAddress.String);

printf("\t Lease Obtained: ");
/* Display local time */
error = _localtime32_s(&newtime, (__time32_t*) &pAdapter-
LeaseObtained);
if (error)
printf("Invalid Argument to _localtime32_s\n");
else {
// Convert to an ASCII representation
error = asctime_s(buffer, 32, &newtime);
if (error)
printf("Invalid Argument to asctime_s\n");
else
/* asctime_s returns the string terminated by \n\0 */
printf("%s", buffer);
}

printf("\t Lease Expires: ");
error = _localtime32_s(&newtime, (__time32_t*) &pAdapter-
LeaseExpires);
if (error)
printf("Invalid Argument to _localtime32_s\n");
else {
// Convert to an ASCII representation
error = asctime_s(buffer, 32, &newtime);
if (error)
printf("Invalid Argument to asctime_s\n");
else
/* asctime_s returns the string terminated by \n\0 */
printf("%s", buffer);
}
} else
printf("\tDHCP Enabled: No\n");

if (pAdapter->HaveWins) {
printf("\tHave Wins: Yes\n");
printf("\t Primary Wins Server: %s\n",
pAdapter->PrimaryWinsServer.IpAddress.String);
printf("\t Secondary Wins Server: %s\n",
pAdapter->SecondaryWinsServer.IpAddress.String);
} else
printf("\tHave Wins: No\n");
pAdapter = pAdapter->Next;
printf("\n");
}
} else {
printf("GetAdaptersInfo failed with error: %d\n", dwRetVal);

}
if (pAdapterInfo)
FREE(pAdapterInfo);

return 0;
}
int findAdapter(UINT iaAddress) {
int i;
int ifIndex;

/* Variables used by GetIpAddrTable */
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
IN_ADDR IPAddr;

/* Variables used to return error message */
LPVOID lpMsgBuf;

// Before calling AddIPAddress we use GetIpAddrTable to get
// an adapter to which we can add the IP.
pIPAddrTable = (MIB_IPADDRTABLE *) MALLOC(sizeof
(MIB_IPADDRTABLE));

if (pIPAddrTable) {
// Make an initial call to GetIpAddrTable to get the
// necessary size into the dwSize variable
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) ==
ERROR_INSUFFICIENT_BUFFER) {
FREE(pIPAddrTable);
pIPAddrTable = (MIB_IPADDRTABLE *) MALLOC(dwSize);

}
if (pIPAddrTable == NULL) {
printf("Memory allocation failed for GetIpAddrTable\n");
return -1;
}
}
// Make a second call to GetIpAddrTable to get the
// actual data we want
if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) !=
NO_ERROR ) {
printf("GetIpAddrTable failed with error %d\n", dwRetVal);
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default
language
(LPTSTR) & lpMsgBuf, 0, NULL)) {
printf("\tError: %s", lpMsgBuf);
LocalFree(lpMsgBuf);
}
return -1;
}

ifIndex = -1; /* not found */
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
if ((u_long) pIPAddrTable->table.dwAddr == iaAddress) {
ifIndex = pIPAddrTable->table.dwIndex;
goto done;
}
}
done:
if (pIPAddrTable) {
FREE(pIPAddrTable);
pIPAddrTable = NULL;
}

return ifIndex;
}

int listAddresses() {
int i;
/* Variables used by GetIpAddrTable */
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
IN_ADDR IPAddr;

/* Variables used to return error message */
LPVOID lpMsgBuf;

// Before calling AddIPAddress we use GetIpAddrTable to get
// an adapter to which we can add the IP.
pIPAddrTable = (MIB_IPADDRTABLE *) MALLOC(sizeof
(MIB_IPADDRTABLE));

if (pIPAddrTable) {
// Make an initial call to GetIpAddrTable to get the
// necessary size into the dwSize variable
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) ==
ERROR_INSUFFICIENT_BUFFER) {
FREE(pIPAddrTable);
pIPAddrTable = (MIB_IPADDRTABLE *) MALLOC(dwSize);

}
if (pIPAddrTable == NULL) {
printf("Memory allocation failed for GetIpAddrTable\n");
return 0;
}
}
// Make a second call to GetIpAddrTable to get the
// actual data we want
if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) !=
NO_ERROR ) {
printf("GetIpAddrTable failed with error %d\n", dwRetVal);
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default
language
(LPTSTR) & lpMsgBuf, 0, NULL)) {
printf("\tError: %s", lpMsgBuf);
LocalFree(lpMsgBuf);
}
return 0;
}

printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table
.dwIndex);
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table.dwAddr;
printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table.dwMask;
printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table
.dwBCastAddr;
printf("\tBroadCast[%d]: \t%s (%ld%)\n", i, inet_ntoa
(IPAddr), pIPAddrTable->table.dwBCastAddr);
printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table
.dwReasmSize);
printf("\tType and State[%d]:", i);
if (pIPAddrTable->table.wType & MIB_IPADDR_PRIMARY)
printf("\tPrimary IP Address");
if (pIPAddrTable->table.wType & MIB_IPADDR_DYNAMIC)
printf("\tDynamic IP Address");
if (pIPAddrTable->table.wType & MIB_IPADDR_DISCONNECTED)
printf("\tAddress is on disconnected interface");
if (pIPAddrTable->table.wType & MIB_IPADDR_DELETED)
printf("\tAddress is being deleted");
if (pIPAddrTable->table.wType & MIB_IPADDR_TRANSIENT)
printf("\tTransient address");
printf("\n");
}

if (pIPAddrTable) {
FREE(pIPAddrTable);
pIPAddrTable = NULL;
}

return 0;
}

int findIndex(UINT iFindAddr) {
/* Declare and initialize variables */

// It is possible for an adapter to have multiple
// IPv4 addresses, gateways, and secondary WINS servers
// assigned to the adapter.
//
// Note that this sample code only prints out the
// first entry for the IP address/mask, and gateway, and
// the primary and secondary WINS server for each adapter.

IP_ADDR_STRING * pIPAddr;
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
UINT i;
UINT iAddr;
int retContext;

/* variables used to print DHCP time info */
struct tm newtime;
char buffer[32];
errno_t error;

ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(sizeof
(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return -1;
}
// Make an initial call to GetAdaptersInfo to get
// the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) ==
ERROR_BUFFER_OVERFLOW) {
FREE(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(ulOutBufLen);
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo
\n");
return -1;
}
}
retContext = -1;
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) ==
NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
pIPAddr = &pAdapter->IpAddressList;
while (pIPAddr) {
iAddr = inet_addr(pIPAddr->IpAddress.String);
if (iAddr == iFindAddr) {
retContext = pIPAddr->Context;
goto done;
}
pIPAddr = pIPAddr->Next;
}
pAdapter = pAdapter->Next;
}
} else {
printf("GetAdaptersInfo failed with error: %d\n", dwRetVal);
}
done:
if (pAdapterInfo)
FREE(pAdapterInfo);

return retContext;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top