Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Programmaticaly retrieve subnet address on Windows NT 4.0 Workstation

Posted on 2005-05-06
14
Medium Priority
?
568 Views
Last Modified: 2013-11-13
I am doing my nut on this one. I have a solution on Win2k/XP with GetAdaptersInfo in the IPHLPAPI library. However, although IPHLPAPI is available on NT the GetAdpatersInfo call does nothing but return an error code. There are a number of posts out there claiming it works on NT SP4 and above - but it appears that the function is provided but only for backward compatibility and does nothing but return a ERROR_NOT_SUPPORTED (50)

The best solution I have for NT 4 is to shell a ROUTE PRINT command and redirect the output to a file and then parse the file. This works but the problem is that some workstations out there have there are giving problems because ROUTE.EXE cannot be found for one or other reason.

Question: Is there a programatic way of retrieving the subnet address of an adapter on Windows NT 4.0?

0
Comment
Question by:Julian Hansen
  • 6
  • 4
  • 2
  • +1
14 Comments
 
LVL 2

Expert Comment

by:jhilving
ID: 13947164
This may not the best for you but is SNMP an option?
-James
0
 
LVL 6

Expert Comment

by:billtouch
ID: 13947989
When you say subnet address, do you mean the part of your address that is under the subnet mask?

As in:

IP address:  192.168.50.3
Subnet Mask: 255.255.255.0

Are you looking for 192.168.50.0 or 0.0.0.3?


 
0
 
LVL 2

Expert Comment

by:jhilving
ID: 13948518
Good question Bill, I just assumed the mask was what he wanted but you raise a good point.

-James
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 22

Accepted Solution

by:
cookre earned 1000 total points
ID: 13948725
Here's something I wrote a couple years ago for getting such info.  2K is similar, just a few differences, as is XP.

I was just interested in tracking down nameservers, but the same subkey has all the other stuff, too.

BOOL DoNT4()
{
// What we do:
// Fetch ..NetBT\Linkage\Route
// This value contains (strings seperated by spaces) the names of the
// ..NetBT\Adapters Subkeys that we want to update.  Note that the
// ...\Route value may specify ..\Adapters Subkeys that no longer exist.
HKEY   LinkageSubkey;
HKEY   AdapterSubkey;
char   AdapterSubkeyName[1024];
char   Candidate[1024];
char   ValueData[4096];
DWORD  ValueType;
DWORD  ValueLen=4096;
char  *QuotePos1;
char  *QuotePos2;
char  *CurrPos;
int    idx;

PostMsg("OS=NT");
// Ok, first point at Subkey ..\NetBT\Linkage
RC=RegOpenKeyEx(HKEY_LOCAL_MACHINE
               ,"System\\CurrentControlSet\\Services\\NetBT\\Linkage"
               ,NULL
               ,KEY_ALL_ACCESS
               ,&LinkageSubkey);
if (RC!=ERROR_SUCCESS) return FALSE;

// Now get the list of strings from value ..\NetBT\Linkage\Bind
RC=RegQueryValueEx(LinkageSubkey
                  ,"Route"
                  ,NULL
                  ,&ValueType
                  ,(unsigned char *)ValueData
                  ,&ValueLen);
if (RC!=ERROR_SUCCESS) return FALSE;
if (  (ValueType!=REG_BINARY)
    &&(ValueType!=REG_MULTI_SZ)
    &&(ValueType!=REG_NONE)
    &&(ValueType!=REG_SZ))
    return FALSE;
// This guy has quoted strings seperated by spaces, look at each one
idx=0;
CurrPos=ValueData;
while (CurrPos<(ValueData+ValueLen))
      {
      // Fetch the endpoints of the next quoted string
      QuotePos1=strchr(CurrPos    ,'\"');
      if (QuotePos1==NULL)
         {
         // Once we've scanned one string, no more quotes is OK
         if (CurrPos==ValueData) exit(10);
         break;
         }
      QuotePos2=strchr(QuotePos1+1,'\"');
      if (QuotePos2==NULL) return FALSE;
      // Extract out the string without the quotes
      strncpy(Candidate,QuotePos1+1,(QuotePos2-QuotePos1)-1);
      Candidate[(QuotePos2-QuotePos1)-1]='\0';
      // See if NIC Candidate is the one we want
      // (Note, Route may include NICs long since gone)

      // Ok, step over to subkey ..\NetBT\Adapters\<ThisNIC>
      strcpy(AdapterSubkeyName,"System\\CurrentControlSet\\Services\\NetBT\\Adapters\\");
      strcat(AdapterSubkeyName,Candidate);
      RC=RegOpenKeyEx(HKEY_LOCAL_MACHINE
                     ,AdapterSubkeyName
                     ,NULL
                     ,KEY_ALL_ACCESS
                     ,&AdapterSubkey);
      if (RC==ERROR_SUCCESS)
         {
         // Since all of these boxes are SUPPOSED to have just one NIC,
         // a hit here is, perforce, the right one
         ValueLen=4096;
         RC=RegQueryValueEx(AdapterSubkey
                           ,"NameServer"
                           ,NULL
                           ,&ValueType
                           ,(unsigned char *)ValueData
                           ,&ValueLen);
         // Save it if it was there
         if (RC==ERROR_SUCCESS) strcpy(DNSes[idx++],ValueData);
         ValueLen=4096;
         RC=RegQueryValueEx(AdapterSubkey
                           ,"NameServerBackup"
                           ,NULL
                           ,&ValueType
                           ,(unsigned char *)ValueData
                           ,&ValueLen);
         // Likewise
         if (RC==ERROR_SUCCESS) strcpy(DNSes[idx++],ValueData);
         if (DNSes[0][0]!='0')
            {
            RegCloseKey(AdapterSubkey);
            RegCloseKey(LinkageSubkey);
            return TRUE;
            }
         // We didn't find snything, so look at DHCP
         ValueLen=4096;
         RC=RegQueryValueEx(AdapterSubkey
                           ,"DHCPNameServer"
                           ,NULL
                           ,&ValueType
                           ,(unsigned char *)ValueData
                           ,&ValueLen);
         // Save it if it was there
         if (RC==ERROR_SUCCESS) strcpy(DNSes[idx++],ValueData);
         ValueLen=4096;
         RC=RegQueryValueEx(AdapterSubkey
                           ,"DHCPNameServerBackup"
                           ,NULL
                           ,&ValueType
                           ,(unsigned char *)ValueData
                           ,&ValueLen);
         // Likewise
         if (RC==ERROR_SUCCESS) strcpy(DNSes[idx++],ValueData);
         RegCloseKey(AdapterSubkey);
         RegCloseKey(LinkageSubkey);
         return TRUE;
         }
      // Guess we need to look at the next one
      CurrPos=QuotePos2+1;
      }
// If we got here, we didn't find a suitable candidate - oops.
return FALSE;
}
0
 
LVL 61

Author Comment

by:Julian Hansen
ID: 13949899
jhilving  SNMP - not really an option - as far as I know SNMP is an option on NT4 workstation and there is no guarantee it will be installed

Subnet address - I am referring to the default gateway address not the mask. You can assume a single adapter so the first gateway will do

Example

If you run the following command in the CMD shell

ROUTE PRINT 0.0.0.0

You should get the following results (or similar)

===========================================================================
Interface List
0x1 ........................... MS TCP Loopback interface
0x1000003 ...00 07 e9 83 90 c6 ...... Intel(R) PRO/100 VE Network Connection
===========================================================================
===========================================================================
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0                    0.0.0.0      192.168.1.1   192.168.1.110       1
Default Gateway:       192.168.1.1 <------ I WANT THIS.
===========================================================================
Persistent Routes:
  None

I have a solution (as I mentioned in my first post) where I shell a ROUTE PRINT command and redirect to a file - but this is messy and fails in some instances.


Cookre - I will give your solution a try and get back to you.


Thanks to all who responded so far.
0
 
LVL 61

Author Comment

by:Julian Hansen
ID: 13950006
Cookre,

I tried the code and found the following

1. The key ...\NetBT\Adapters does not exist on 2000. This was not part of my original spec but I was hoping for a solution that would work on both NT and 2000 - just in case someone does know of a way (posted for information not as a criticism of the posted solution ;) ).

2. I noticed something weird on the NT 4 installation I am using as a test. Before running the code I manually followed the steps in the code by browsing the registry. The adapter name found in the NetBT\Linkage\Route was DC21X41. Browsing to

    ...\NetBT\Adapters\DC21X41

I found the following two values

    DhcpNameServer = "DC21X41" "DC21X41"
    DhcpNameServerBackup =  "DC21X41" "DC21X41"

When I looked again (after doing nothing more than look at another key in the registry) these had changed to

    DhcpNameServer = "PCI .. something or other - can't remember the full string but it started with PCI and was quite short"
    DhcpNameServerBackup  = ditto

I did the same thing again - looked at another key and came back and this time

    DhcpNameServer = ""
    DhcpNameServerBackup =  ""

And they stayed that way.

Obviously when I ran your code it dumped empty strings.

I don't have a genuine NT 4 workstation on our network so I am testing in Microsoft Virtual PC session - I am not sure if this is affecting it. Having said that though,, when I do a

ROUTE PRINT 0.0.0.0

On the virtual PC I get the correct gateway information.

Question: How do the IPCONFIG and ROUTE apps retrieve this value on NT ? I have been trying to answer this question for a number of years and found nothing.



0
 
LVL 61

Author Comment

by:Julian Hansen
ID: 13950011
More info

I replicated the changing DHCPNameServer issue - the second time around it is set to "PNP_TDI"

The weird thing is - when the PC comes up the items are blank
When I browse to ...\Services\Tcpip the value changes to "PNP_TDI"
When I browse to ...\Services\NetBT\Linkage it changes back to "DC21X41" "DC21X41"

Not sure why ...
0
 
LVL 6

Expert Comment

by:billtouch
ID: 13950556
What I woudl do is run RegMon. There is a version for NT. You can get it at: http://www.sysinternals.com/ntw2k/source/regmon.shtml

It tracks ALL registry access by everyone. So... don't load RegMon until you have the Dos window already open. Then run Route print.

Stop RegMon (by unclicking File/Capture Events) and look down the capture list for route.exe. It might help you to use the filter (Option/FilteHighLight) and set include to Route.exe. Now all you will see is route.exe accesses. Look towards the end of the entries. If you double click on a line, it will open up RegEdit to show you the key and its value.

This will tell you exactly how route gets its info. I have an XP system or else I would give you more.

Happy Hunting!

Bill
0
 
LVL 22

Expert Comment

by:cookre
ID: 13950561
Here's the 2K one.  I also have it for 95, but, when I wrote it, my customer had not yet moved to XP, so I don't have one for XP.


BOOL Do2000()
{
// What we do:
// Fetch ..NetBT\Linkage\Route
// The first quoted string pair provides the name of the
// ..\NetBT\Parameters\Interfaces subkey to plop our values into.
// If the Route value looks like:
// "st1" "st2" "st3" "st4"
// We go to subkey ..\Interfaces\st1_st2
//
// Example:
// Subkey:   ..\NetBT\Linkage
// Value:    Route
// Contents: "TcpIp"

HKEY   LinkageSubkey;
char   ServiceStr[256];
char   ClassIDStr[256];
char   InterfacesSubkeyName[1024];
HKEY   InterfacesSubkey;
char   ValueData[4096];
DWORD  ValueType;
DWORD  ValueLen=4096;
char  *QuotePos1;
char  *QuotePos2;
char  *CurrPos;
int    idx;

PostMsg("OS=Win2K");
// Ok, first point at Subkey ..\NetBT\Linkage
RC=RegOpenKeyEx(HKEY_LOCAL_MACHINE
               ,"System\\CurrentControlSet\\Services\\NetBT\\Linkage"
               ,NULL
               ,KEY_ALL_ACCESS
               ,&LinkageSubkey);
if (RC!=ERROR_SUCCESS)
   {
   PostMsg("Failed: System\\CurrentControlSet\\Services\\NetBT\\Linkage");
   return FALSE;
   }

// Now get the list of strings from value ..\NetBT\Linkage\Bind
RC=RegQueryValueEx(LinkageSubkey
                  ,"Route"
                  ,NULL
                  ,&ValueType
                  ,(unsigned char *)ValueData
                  ,&ValueLen);
if (RC!=ERROR_SUCCESS)
   {
   return FALSE;
   }
if (  (ValueType!=REG_BINARY  )
    &&(ValueType!=REG_MULTI_SZ)
    &&(ValueType!=REG_NONE    )
    &&(ValueType!=REG_SZ      )
   )
   {
   return FALSE;
   }
// The ..\Interfaces value we want is named Service_ClassID where
// Service is the first quoted string from Route and ClassId is the second
CurrPos=ValueData;

// Extract service name from first quoted string
QuotePos1=strchr(CurrPos    ,'\"');
if (QuotePos1==NULL) return FALSE;
QuotePos2=strchr(QuotePos1+1,'\"');
if (QuotePos2==NULL) return FALSE;
strncpy(ServiceStr,QuotePos1+1,(QuotePos2-QuotePos1)-1);
ServiceStr[(QuotePos2-QuotePos1)-1]='\0';

// Now do the same thing for ClassID from second quoted string
CurrPos=QuotePos2+1;
QuotePos1=strchr(CurrPos    ,'\"');
if (QuotePos1==NULL) return FALSE;
QuotePos2=strchr(QuotePos1+1,'\"');
if (QuotePos2==NULL) return FALSE;
strncpy(ClassIDStr,QuotePos1+1,(QuotePos2-QuotePos1)-1);
ClassIDStr[(QuotePos2-QuotePos1)-1]='\0';

// Now build the target subkey
strcpy(InterfacesSubkeyName,"System\\CurrentControlSet\\Services\\NetBT\\Parameters\\Interfaces\\");
strcat(InterfacesSubkeyName,ServiceStr);
strcat(InterfacesSubkeyName,"_");
strcat(InterfacesSubkeyName,ClassIDStr);

// Fetch it
sprintf(TempStr,"(%s)",InterfacesSubkeyName);
PostMsg(TempStr);
RC=RegOpenKeyEx(HKEY_LOCAL_MACHINE
               ,InterfacesSubkeyName
               ,NULL
               ,KEY_ALL_ACCESS
               ,&InterfacesSubkey);
if (RC!=ERROR_SUCCESS)
   {
   return FALSE;
   }

// First look for NameServer
idx=0;
ValueLen=4096;
PostMsg("Checking NameServer");
RC=RegQueryValueEx(InterfacesSubkey
                  ,"NameServer"
                  ,NULL
                  ,&ValueType
                  ,(unsigned char *)ValueData
                  ,&ValueLen);
if (RC==ERROR_SUCCESS)
   {
   PostMsg("Checking Size");
   if (ValueLen<17) strcpy(DNSes[idx++],ValueData);
   }
// Now look for NameServerList
ValueLen=4096;
PostMsg("Checking NameServerList");
RC=RegQueryValueEx(InterfacesSubkey
                  ,"NameServerList"
                  ,NULL
                  ,&ValueType
                  ,(unsigned char *)ValueData
                  ,&ValueLen);
if (RC==ERROR_SUCCESS && ValueLen>6)
   {
   PostMsg("Got something");
   // Check for two IPs
   CurrPos=strchr(ValueData,' ');

   // If two, cram a nul betwixtem
   if (CurrPos!=NULL) *CurrPos='\0';

   // Save the first one
   strcpy(DNSes[idx++],ValueData);

   // Save second, if there
   if (CurrPos!=NULL) strcpy(DNSes[idx++],CurrPos+1);
   }

if (DNSes[0][0]!='\0')
   {
   PostMsg("Found a good one");
   RegCloseKey(InterfacesSubkey);
   return TRUE;
   }

// If we didn't find anything there, look over in DHCP
PostMsg("Checking DhcpNameServerList");
ValueLen=4096;
RC=RegQueryValueEx(InterfacesSubkey
                  ,"DhcpNameServerList"
                  ,NULL
                  ,&ValueType
                  ,(unsigned char *)ValueData
                  ,&ValueLen);
if (RC==ERROR_SUCCESS)
   {
   PostMsg("Goodie!");
   CurrPos=strchr(ValueData,' ');
   if (CurrPos!=NULL) *CurrPos='\0';
   strcpy(DNSes[idx++],ValueData);
   if (CurrPos!=NULL) strcpy(DNSes[idx++],CurrPos+1);
   }

// If we found something, we can leave now
if (DNSes[0][0]!='\0')
   {
   PostMsg("GBB27");
   RegCloseKey(InterfacesSubkey);
   return TRUE;
   }

// Otherwise, we look for DHCP in one other spot
strcpy(InterfacesSubkeyName,"System\\CurrentControlSet\\Services\\TcpIp\\Parameters\\Interfaces\\");
// No service prefix here!
// strcat(InterfacesSubkeyName,ServiceStr);
// strcat(InterfacesSubkeyName,"_");
strcat(InterfacesSubkeyName,ClassIDStr);

// Fetch it
sprintf(TempStr,"((%s))",InterfacesSubkeyName);
PostMsg(TempStr);
RC=RegOpenKeyEx(HKEY_LOCAL_MACHINE
               ,InterfacesSubkeyName
               ,NULL
               ,KEY_ALL_ACCESS
               ,&InterfacesSubkey);
if (RC!=ERROR_SUCCESS)
   {
   PostMsg("Nuep");
   return FALSE;
   }
ValueLen=4096;
PostMsg("Look at DhcpNameServer");
RC=RegQueryValueEx(InterfacesSubkey
                  ,"DhcpNameServer"
                  ,NULL
                  ,&ValueType
                  ,(unsigned char *)ValueData
                  ,&ValueLen);
if (RC==ERROR_SUCCESS)
   {
   PostMsg("++good");
   strcpy(DNSes[idx++],ValueData);
   RegCloseKey(InterfacesSubkey);
   return TRUE;
   }
PostMsg("Alas");
RegCloseKey(InterfacesSubkey);
return FALSE;
}
0
 
LVL 22

Expert Comment

by:cookre
ID: 13950566
I've never used VirtualPC, but the little bit I just read about it makes me suspect that it's not entirely compatible at this level.
0
 
LVL 61

Author Comment

by:Julian Hansen
ID: 13962293
cookre,

Ok, on the target machines DHCPNameServer has a value - however - I think there has been a misunderstanding. The value I am looking for is the gateway and the value stored there is not it.

We did find a key

HKLM\Services\CurrentControlSet\Services\<adaptername>\Parameters\Tcpip

That had the following values

DefaultGateway
DHCPDefaultGateway

That seem to hold the values we are looking for

The solution we are pursuing is to write the function as follows

1. Try the IPHLPAPI GetAdaptersInfo call to get the gateway. If this fails or returns error not supported then proceed to 2
2. Try to get the values from the registry at HKLM\Services\CurrentControlSet\Services\<adaptername>\Parameters\Tcpip
3. If that fails shell to ROUTE PRINT 0.0.0.0 command

Will post back with results
0
 
LVL 22

Expert Comment

by:cookre
ID: 13962600
Yes, the sample code drilled down to DHCPNameServer, but, as you saw the gateway info was in the same subkey.

You should, however, start your enumeration with the ...\NetBT\Linkage\Route value to get the ...\Services\<thingy>\Parameters\TcpIp to look at - there may very well be gateway values in <thingy> subkeys not found in Route.

Also note the difference between how NT and 2K format entries in Route and the Thingy subkey.
0
 
LVL 61

Author Comment

by:Julian Hansen
ID: 13966132
Thanks Cookre,

>>  Yes, the sample code drilled down to DHCPNameServer, but, as you saw the gateway info was in the same subkey.

Couldn't find any gateway info on NT 4.0 in the \NetBT\Adapters\<adapter_from_route> key - Just the DHCPNameServer and DHCPNameServerBackup - nothing else.

Regarding 2k - won't go the registry route for this - if the process was the same for NT and 2K and XP and involved the registry then it would be an option but if I have to use a different approach for 2k anyway I prefer the GetAdaptersInfo method - gives me the IP and a bunch of other stuff I need in one call.

0
 
LVL 61

Author Comment

by:Julian Hansen
ID: 13996281
Thanks to all who responded. I have a solution - not as neat as I would like but does seem to be working on the problem machines.

Solution:

I created a function that tries 3 different approaches to getting the subnet (default gateway). If a method fails the next would be tried and so on.

The first method uses GetAdaptersInfo to get the information. If this fails or reports ERROR_NOT_SUPPORTED the next method is tried.

The second method is to read the values from the following key in the registry

HKLM\Services\CurrentControlSet\Services\<adaptername>\Parameters\Tcpip

The gateway info is read from either the following values - whichever holds a valid address.

DefaultGateway
DHCPDefaultGateway

If this fails (key does not exist or values not found) the third method is tried.

This method runs the ROUTE PRINT 0.0.0.0 command after redirecting STDOUT to a pipe - from which the output is read.

I was hoping for a single method for both Win2k and NT but that does not seem to be an option.

cookre - I am assigning points with grade C (based on content not effort). Reason: it was a toss up between assinging points and requesting the question be deleted. Unfortunately the code (and reg key) you posted was not what we were looking for. However, I did use some of your code to get the adapter information from the NetBT key so some points are in order.
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this post we will learn different types of Android Layout and some basics of an Android App.
We live in a world of interfaces like the one in the title picture. VBA also allows to use interfaces which offers a lot of possibilities. This article describes how to use interfaces in VBA and how to work around their bugs.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…
Six Sigma Control Plans

578 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question