[XenoCafe Logo] Click for Homepage
Home Tutorials Forum Blog Advertising Links Contact About



Whois Client in Visual Basic .NET

Written by Tony Bhimani
September 5, 2004

Requirements
Microsoft Windows 98/ME/NT4/2000/XP
Microsoft .NET Framework Version 1.1

Download the source code: Whois_VB.NET.zip

I frequently use the Whois Client on my RedHat server and wanted to add the same tool to my Windows system. I figured it would be a good opportunity to start learning VB.NET and a tool of this type incorporates a few important features. By features I mean the use of regular expressions, file I/O, hash tables, and tcp/ip sockets. So there is a little bit of everything for those reading this tutorial. As I wrote the client, there was one thing about multiline text boxes that Microsoft changed I was unaware of. In VB when you put a multiline string in a multiline text box you use newline characters (vbCrLf or vbNewLine) to mark lines in text. In VB.NET the multiline text box has a property called Lines that expects an array of strings. This makes more sense and I thought was kind of cool.

The Whois Client is GUI based. Later I will write a console based version and post the source code.You can do queries for domain names as well as IP addresses. As the program is loaded it reads in a text file containing whois servers and the TLD's (Top Level Domains) they service. The text file was borrowed from a PHP whois script called mwhois which is available from Matt's Script Archive (why reinvent the wheel when you don't have to.) A hash table is created as the servers and TLD's are read in. A hash table is similar to a PHP associative array. When you do a query the TLD (i.e. com, net, co.uk, etc) is parsed from the domain name and passed to the hash table. The hash table returns the whois server to contact for the query. The domain name and the server are passed to a function which contacts the whois server to retrieve the domain's information. That information is then parsed using regular expressions to check for the whois server of the registrar for the domain. If it is found an additional query is performed to retrieve more detailed information about the domain. Finally all the information is placed in the multiline text box and shown to the user.

Now we will look at some code segments. We start with the servers.lst file which contains all the TLD and whois servers.

com|whois.crsnic.net|No match for|whois.networksolutions.com|whois.internic.net|Whois Server:
net|whois.crsnic.net|No match for|whois.networksolutions.com|whois.internic.net|Whois Server:
...

Each line has several fields but we are interested in only the first and second ones. The first field is the TLD and the second one is the whois server that handles its requests. We read these lines in and create a hash table containing the TLD and whois server with the LoadWhoisServers function.

Private Shared Function LoadWhoisServers(ByVal filename As String) As Hashtable
    Dim tmpArray() As String
    Dim whoisTable As New Hashtable()
    Try
        Dim MyStreamReader As StreamReader = IO.File.OpenText(filename)
        Do While MyStreamReader.Peek() >= 0
            tmpArray = MyStreamReader.ReadLine().Split("|")
            If (tmpArray.GetLength(0) = 6 And tmpArray(0).StartsWith("#") = False) Then
                whoisTable.Add(tmpArray(0), tmpArray(1))
            End If
        Loop
        MyStreamReader.Close()
    Catch e As Exception
        MsgBox(e.Message + vbLf + "The application will now exit.", MsgBoxStyle.Critical)
        End
    End Try
    Return whoisTable
End Function

...

Private Sub Whois_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    whoisTable = LoadWhoisServers("servers.lst")
End Sub

LoadWhoisServers takes the whois servers list file name as a parameter and returns a hash table. Each line of the file is read in until end of file is reached. The file allows for comments on lines beginning with a #. With the line read in it is split by the | (pipe) character and the pieces are stored in a string array called tmpArray. Next the size of the array is tested to see if it has six elements and if it does not begin with a # character. If this is the case then the TLD and whois server is added to the hash table. If the array does not have six elements and starts with a # character, then it is a comment line and the line is skipped. Once the lines have all been read in and processed, the file is closed and the hash table is returned. If at any point there is an error the Catch section is executed. A message box is displayed with the error message and the application ends. LoadWhoisServers is called from the form's Load event and the resulting hash table is stored in a global variable called whoisTable.

The action of the client rests upon the Lookup button's Click event.

Private Sub btnLookup_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLookup.Click
    Dim i As Int32
    Dim lines As String
    Dim server As String
    Dim domain As String = txtDomain.Text
    Dim tld As String

    If (isIP(domain.Trim)) Then
        server = "whois.arin.net"
    ElseIf (isDomain(domain.Trim)) Then
        tld = domain.Substring(domain.IndexOf(".") + 1)
        server = whoisTable.Item(tld)
    Else
        MsgBox("It appears you entered something other than a Domain Name or IP Address.")
        txtDomain.Focus()
        txtDomain.SelectAll()
        Exit Sub
    End If
    ' display our working status
    txtResults.Lines = New String() {"Querying whois server(s)...Please wait"}
    txtResults.Refresh()
    ' do the whois query
    Dim whoisResult As String = doWhoisQuery(domain, server)
    ' send the output to the results textbox
    lines += "[" + server + "]" + vbLf
    lines += whoisResult + vbLf
    ' check for a redirect whois server
    Dim infoServer As String = GetInfoServer(whoisResult)
    If (infoServer <> "") Then
        whoisResult = doWhoisQuery(domain, infoServer)
        lines += "[" + infoServer + "]" + vbLf
        lines += whoisResult
    End If
    txtResults.Lines = lines.Split(vbLf)
End Sub

The domain or IP address is read from the text box and stored in the domain variable. First it is tested whether it is an IP address, a domain name, or something that we don't understand (empty strings, malformed domain names, etc.) If it is an IP then we set the server to whois.arin.net which is used to query the IP and see who it belongs to. If it is a domain name then we extract the TLD (everything after the first period encountered) and pass it to the hash table to get the whois server. If it is not an IP or domain name then we display an error and set focus to the domain/IP text box, highlight the contents, and exit the function.

Now with our server set we call the doWhoisQuery function (which we will go over soon) and pass it the domain name and whois server. The results are passed back and stored in a string called whoisResult. We append our results to a string called lines which we will later use for our multiline text box to show our results. With the whois results we currently have we then call another function called GetInfoServer. GetInfoServer parses the results looking for the domain name registrar's whois server so we can query it for additional details about the domain. If it is found it is stored in the infoServer variable and we perform another query. More lines are appended to our result and it is finally stored in our multiline text box. Now earlier I mentioned multiline text boxes in VB.NET have a property called Lines that expects a string array. So all we have to do is convert our lines variable into an array using the Split method and assign it to the Lines property. We do the split on new line characters or vbLf.

Private Function isDomain(ByVal domain As String) As Boolean
    Dim regex As New RegularExpressions.Regex("^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$")
    Return regex.IsMatch(domain)
End Function

Private Function isIP(ByVal ip As String) As Boolean
    Dim regex As New RegularExpressions.Regex("^(?:(?:25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)(?(\.?\d)\.)){4}$")
    Return regex.IsMatch(ip)
End Function

For testing whether the user input is either a domain name or IP address we create two functions that use regular expressions. They test whether the data matches the expression. They both return boolean values of either True or False.

Private Shared Function GetInfoServer(ByVal queryTxt As String) As String
    Dim regex As New RegularExpressions.Regex("Whois Server:\s+(.+)", RegularExpressions.RegexOptions.IgnoreCase)
    Dim match As RegularExpressions.Match = regex.Match(queryTxt)
    If (match.Value <> "") Then
        Return match.Value.Substring(14)
    Else
        Return ""
    End If
End Function

GetInfoServer also uses regular expressions to see if the domain's registrar whois server is listed. If it is listed we get the expression text and take the substring after "Whois Server: " which will be the server name and return it. If it is not found we return a null string.

Finally we will look at the tcp/ip sockets code portion.

Private Function doWhoisQuery(ByVal domain As String, ByVal server As String) As String
    Dim returnData As String = ""
    Dim tcpClient As New TcpClient()
    tcpClient.Connect(server, 43)
    Dim networkStream As NetworkStream = tcpClient.GetStream()
    If networkStream.CanWrite And networkStream.CanRead Then
        Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(domain + vbCrLf)
        networkStream.Write(sendBytes, 0, sendBytes.Length)
        Dim bytes(tcpClient.ReceiveBufferSize) As Byte
        Dim recvSize As Int32
        recvSize = networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
        While (recvSize <> 0)
            returnData += Encoding.ASCII.GetString(bytes, 0, recvSize)
            recvSize = networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
        End While
    Else
        If Not networkStream.CanWrite Then
            returnData = "Cannot write data to this stream."
        Else
            If Not networkStream.CanRead Then
                returnData = "Cannot read data from this stream."
            End If
        End If
    End If
    tcpClient.Close()
    Return returnData
End Function

doWhoisQuery accepts the domain name and the whois server to query as parameters. The results of the query are returned as a string. The first thing we do is create a new TcpClient object and connect to the whois server on port 43. If the connection is successful the TcpClient object creates a new NetworkStream which we get access to using with the GetStream method. With this stream we can send as well as receive data on our connection. The data must be sent/received in the form of a byte array. We convert the domain name followed by a newline into an array of bytes using Encoding.ASCII.GetBytes. We then send these bytes using the NetworkStream's Write method. Now we wait for the whois server sends us a response (if any). We enter a loop and continue to read the bytes received from the server, convert them back into an ASCII string, and append them to the returnData string variable. Once we have finished reading all the data we close the connection and return the data string.

I have found VB.NET much more friendly in the socket area (as well as others) than prior versions of VB that used the Winsock control. With the old VB if you wanted anything extra you most likely had to use COM objects. But now with the .NET Framework you have everything at your disposal. Next on my list is to write a console version of this program and a C# port. Stay tuned for this page to update with that source code.



How would you rate the usefulness of this content?

Poor 1
2
3
4
5
6
7
8
9
Outstanding

Optional: Tell us why you rated the content this way.
Characters remaining: 1024
Average rating: 5.50 out of 9.

1 2 3 4 5 6 7 8 9
8 people have rated this content.
This page has been viewed 9,111 times
Copyright © 2004-2008 XenoCafe. All Rights Reserved. XenoCafe is Powered by Linux. Free your mind and your wallet. Switch to Linux.