How to Get Domain Whois Data in C with Sockets on Linux – Code Example

By | August 7, 2020

Whois

A whois client is a program that will simply fetch the whois information for a domain/ip address from the whois servers. The code over here works according to the algorithm discussed here.

A whois server runs a whois service on port 43 (whois port). We need to connect to this port with sockets and send the domain name for which we want the details.

The first step is to find the whois server and then connect to it and make the query.

Whois Servers

To get the full whois data of a domain, there are several whois servers that need to be queried. For example if the domain name is wikipedia.org then the following whois servers are involved:

1. whois.iana.org will tell the authoritative whois server for the domain extension. In this case the extension is .org so the authoritative whois server is whois.pir.org.

2. Next contact the authoritative whois server to find the registrant whois server of the particular domain. In this case the registrant of wikipedia.org is MarkMonitor so the whois server is whois.markmonitor.com

3. Finally contact the registrant whois server for actual whois data of the domain. Here the registrant whois server is whois.markmonitor.com

Code

/*
    This program shall perform whois for a domain and get you the whois data of that domain
*/

#include <stdio.h>	//scanf , printf
#include <string.h>	//strtok
#include <stdlib.h>	//realloc
#include <sys/socket.h>	//socket
#include <netinet/in.h> //sockaddr_in
#include <arpa/inet.h>	//getsockname
#include <netdb.h>	//hostent
#include <unistd.h>	//close

int get_whois_data(char * , char **);
int hostname_to_ip(char * , char *);
int whois_query(char * , char * , char **);
char *str_replace(char *search , char *replace , char *subject );
char* str_copy(char*);

int main(int argc , char *argv[])
{
	char *domain , *data = NULL;
	
	printf("Enter domain name to whois: ");
	scanf("%s" , domain);
	
	get_whois_data(domain , &data);
	
	//puts(data);
	return EXIT_SUCCESS;
}

/*
    Get the whois data of a domain
*/
int get_whois_data(char *domain , char **data)
{
	char ext[1024] , *pch , *response = NULL , *response_2 = NULL , *wch , *dt;

	//remove "http://" and "www."
	domain = str_replace("http://" , "" , domain);
	domain = str_replace("www." , "" , domain);

	//get the extension , com , org , edu
	dt = strdup(domain);
	if(dt == NULL)
	{
		printf("strdup failed");
	}
	pch = (char*)strtok(dt , ".");
	while(pch != NULL)
	{
		strcpy(ext , pch);
		pch = strtok(NULL , ".");
	}
	
	// This will tell the whois server for the particular TLD like com , org
	if( whois_query("whois.iana.org" , ext , &response) == EXIT_FAILURE)
	{
		printf("Whois query failed");
        return 1;
	}
	printf("\n\nResponse is:\n\n");
	printf("%s", response);
	
	
	
	// Now analysze the response
	pch = strtok(response , "\n");
	while(pch != NULL)
	{
		// Check if whois line
		wch = strstr(pch , "whois.");
		if(wch != NULL)
		{
			break;
		}

		// Next line please
		pch = strtok(NULL , "\n");
	}

	
	
	// Now we have the TLD whois server in wch , query again
	
	//This will provide minimal whois information along with the parent whois server of the specific domain :)
	free(response);
	
    //This should not be necessary , but segmentation fault without this , why ?
	response = NULL;
	if(wch != NULL)
	{
		printf("\nTLD Whois server is : %s" , wch);
		
        //wch[strcspn(wch, "\r\n")] = '\0';
        
        if( whois_query(wch , domain , &response) == EXIT_FAILURE)
		{
			printf("Whois query failed\n");
            return EXIT_FAILURE;
		}
	}
	else
	{
		printf("\nTLD whois server for %s not found\n" , ext);
		return EXIT_SUCCESS;
	}
	
	response_2 = strdup(response);

	// Again search for a whois server in this response. :)
	pch = strtok(response , "\n");
	while(pch != NULL)
	{
		// Check if whois line
		wch = strstr(pch , "whois.");
		if(wch != NULL)
		{
			break;
		}

		//Next line please
		pch = strtok(NULL , "\n");
	}


	/*
        If a registrar whois server is found then query it
    */
	if(wch)
	{
		// Now we have the registrar whois server , this has the direct full information of the particular domain
		// so lets query again
		
		printf("\nRegistrar Whois server is : %s" , wch);
		
		if( whois_query(wch , domain , &response) == EXIT_FAILURE )
		{
			printf("Whois query failed");
		}
		else
        {
            printf("\n%s" , response);
        }
	}
	
	/*
        otherwise echo the output from the previous whois result
    */
	else
	{
		printf("%s" , response_2);
	}
	
	return 0;
}

/*
    Perform a whois query to a server and record the response
*/
int whois_query(char *server , char *query , char **response)
{
	char ip[32] , message[100] , buffer[1500];
	int sock , read_size , total_size = 0;
	int WHOIS_PORT = 43;
    struct sockaddr_in dest;
    
	sock = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
     
    //Prepare connection structures :)
    memset( &dest , 0 , sizeof(dest) );
    dest.sin_family = AF_INET;
    
    server = str_copy(server);
    server[strcspn(server, "\r\n")] = '\0';
    
	printf("\nResolving: %s ...\n" , server);
	if( hostname_to_ip(server , ip) == EXIT_FAILURE )
	{
        printf("Failed\n");
        return EXIT_FAILURE;
	}
	
	printf("Found ip: %s \n" , ip);    
	
    dest.sin_addr.s_addr = inet_addr( ip );
	dest.sin_port = htons( WHOIS_PORT );

	//Now connect to remote server
	if(connect( sock , (const struct sockaddr*) &dest , sizeof(dest) ) < 0)
	{
		perror("connect failed");
        return EXIT_FAILURE;
	}
	
	//Now send some data or message
	printf("\nQuerying for: %s ...\n" , query);
	sprintf(message , "%s\r\n" , query);
	if( send(sock , message , strlen(message) , 0) < 0)
	{
		perror("send failed");
        return EXIT_FAILURE;
	}
	
	//Now receive the response
	while( (read_size = recv(sock , buffer , sizeof(buffer) , 0) ) )
	{
		*response = realloc(*response , read_size + total_size);
		if(*response == NULL)
		{
			printf("realloc failed");
            return EXIT_FAILURE;
            
		}
		
		memcpy(*response + total_size , buffer , read_size);
		total_size += read_size;
	}
	
	printf("Done\n");
	fflush(stdout);
	
	*response = realloc(*response , total_size + 1);
	*(*response + total_size) = '\0';
	
	close(sock);
	
    return EXIT_SUCCESS;
}

/*
    Get the ip address of a given hostname
*/
int hostname_to_ip(char *hostname , char *ip)
{
	struct hostent *he;
	struct in_addr **addr_list;
	int i;
	
    // create editable copy
    hostname = str_copy(hostname);
    
    // remove trailing LF CR
    hostname[strcspn(hostname, "\r\n")] = '\0';
    
    if ( (he = gethostbyname( hostname ) ) == NULL) 
	{
        // print the error
		herror("Error in gethostbyname: ");
        
		return EXIT_FAILURE;
	}
    
    if(he)
    {
        addr_list = (struct in_addr **) he->h_addr_list;
        
        for(i = 0; addr_list[i] != NULL; i++) 
        {
            // Return the first one;
            strcpy(ip , inet_ntoa(*addr_list[i]) );
            return EXIT_SUCCESS;
        }
    }
	return 0;
}

/*
    Search and replace a string with another string , in a string
*/
char *str_replace(char *search , char *replace , char *subject)
{
	char  *p = NULL , *old = NULL , *new_subject = NULL ;
	int c = 0 , search_size;
	
	search_size = strlen(search);
	
	//Count how many occurences
	for(p = strstr(subject , search) ; p != NULL ; p = strstr(p + search_size , search))
	{
		c++;
	}
	
	//Final size
	c = ( strlen(replace) - search_size )*c + strlen(subject);
	
	//New subject with new size
	new_subject = malloc( c );
	
	//Set it to blank
	strcpy(new_subject , "");
	
	//The start position
	old = subject;
	
	for(p = strstr(subject , search) ; p != NULL ; p = strstr(p + search_size , search))
	{
		//move ahead and copy some text from original subject , from a certain position
		strncpy(new_subject + strlen(new_subject) , old , p - old);
		
		//move ahead and copy the replacement text
		strcpy(new_subject + strlen(new_subject) , replace);
		
		//The new start position after this search match
		old = p + search_size;
	}
	
	//Copy the part after the last search match
	strcpy(new_subject + strlen(new_subject) , old);
	
	return new_subject;
}

char* str_copy(char *source)
{
    char *copy = malloc(strlen(source) + 1); 
    
    if(copy)
    {
        strcpy(copy, source);
    }
    
    return copy;
}

hostname_to_ip - This is a simple function to get an IP of a domain.
str_replace - This is a generic string processing function that is used to search for a string in another big string and replace it with another string.

Compile and Run

Compiling is simple, just use the gcc command. Then run the output file and it will ask for the domain name.

$ gcc whois.c
$ ./a.out
Enter domain name to whois:

Output

The output would look something like this:

$ ./a.out
Enter domain name to whois: wikipedia.org
Resolving: whois.iana.org ...
Found ip: 192.0.32.59
Querying for: org ...
Done
Response is:
% IANA WHOIS server
% for more information on IANA, visit http://www.iana.org
% This query returned 1 object
domain:       ORG
organisation: Public Interest Registry (PIR)
address:      1775 Wiehle Avenue
address:      Suite 100
address:      Reston Virginia 20190
address:      United States
contact:      administrative
name:         Director of Operations, Compliance and Customer Support
organisation: Public Interest Registry (PIR)
address:      1775 Wiehle Avenue
address:      Reston Virginia 20190
address:      United States
phone:        +1 703 889 5778
fax-no:       +1 703 889 5779
e-mail:       [email protected]
contact:      technical
name:         Senior Director, DNS Infrastructure Group
organisation: Afilias
address:      Building 3, Suite 105
address:      300 Welsh Road
address:      Horsham, Pennsylvania 19044
address:      United States
phone:        +1 215.706.5700
fax-no:       +1 215.706.5701
e-mail:       [email protected]
nserver:      A0.ORG.AFILIAS-NST.INFO 199.19.56.1 2001:500:e:0:0:0:0:1
nserver:      A2.ORG.AFILIAS-NST.INFO 199.249.112.1 2001:500:40:0:0:0:0:1
nserver:      B0.ORG.AFILIAS-NST.ORG 199.19.54.1 2001:500:c:0:0:0:0:1
nserver:      B2.ORG.AFILIAS-NST.ORG 199.249.120.1 2001:500:48:0:0:0:0:1
nserver:      C0.ORG.AFILIAS-NST.INFO 199.19.53.1 2001:500:b:0:0:0:0:1
nserver:      D0.ORG.AFILIAS-NST.ORG 199.19.57.1 2001:500:f:0:0:0:0:1
ds-rdata:     17883 7 2 d889cad790f01979e860d6627b58f85ab554e0e491fe06515f35548d1eb4e6ee
ds-rdata:     17883 7 1 38c5cf93b369c7557e0515faaa57060f1bfb12c1
whois:        whois.pir.org
status:       ACTIVE
remarks:      Registration information: http://www.pir.org
created:      1985-01-01
changed:      2020-04-29
source:       IANA
TLD Whois server is : whois.pir.org
Resolving: whois.pir.org ...
Found ip: 199.15.84.131
Querying for: wikipedia.org ...
Done
Registrar Whois server is : whois.markmonitor.com
Resolving: whois.markmonitor.com ...
Found ip: 64.124.14.21
Querying for: wikipedia.org ...
Done
Domain Name: wikipedia.org
Registry Domain ID: D51687756-LROR
Registrar WHOIS Server: whois.markmonitor.com
Registrar URL: http://www.markmonitor.com
Updated Date: 2015-12-12T02:16:20-0800
Creation Date: 2001-01-12T16:12:14-0800
Registrar Registration Expiration Date: 2023-01-12T00:00:00-0800
Registrar: MarkMonitor, Inc.
Registrar IANA ID: 292
Registrar Abuse Contact Email: [email protected]
Registrar Abuse Contact Phone: +1.2083895770
Domain Status: clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited)
Domain Status: clientTransferProhibited (https://www.icann.org/epp#clientTransferProhibited)
Domain Status: clientDeleteProhibited (https://www.icann.org/epp#clientDeleteProhibited)
Registrant Organization: Wikimedia Foundation, Inc.
Registrant State/Province: CA
Registrant Country: US
Registrant Email: Select Request Email Form at https://domains.markmonitor.com/whois/wikipedia.org
Admin Organization: Wikimedia Foundation, Inc.
Admin State/Province: CA
Admin Country: US
Admin Email: Select Request Email Form at https://domains.markmonitor.com/whois/wikipedia.org
Tech Organization: Wikimedia Foundation, Inc.
Tech State/Province: CA
Tech Country: US
Tech Email: Select Request Email Form at https://domains.markmonitor.com/whois/wikipedia.org
Name Server: ns2.wikimedia.org
Name Server: ns1.wikimedia.org
Name Server: ns0.wikimedia.org
DNSSEC: unsigned
URL of the ICANN WHOIS Data Problem Reporting System: http://wdprs.internic.net/
>>> Last update of WHOIS database: 2020-08-06T21:35:14-0700 <<<
For more information on WHOIS status codes, please visit:
  https://www.icann.org/resources/pages/epp-status-codes
About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

4 thoughts on “How to Get Domain Whois Data in C with Sockets on Linux – Code Example

  1. Tushar Marne

    In the whois information, I’ve got creation date of the domain.
    But different whois server responses has different date format of creation date.
    Is there any way to get that date in a specific date format?

  2. nimish

    Very great work sir,got lots of information from your work…..thank you very much…..i Need your help sir……can you please give me code or the way/idea to find / detect the operating system of remote system most preferably in winsock…..inux also no problem.
    I am building a port scanner for my academic project…..waiting for your reply

    1. Silver Moon Post author

      to find out the os of the remote system is called “os fingerprinting” and can be done by reading various fields of the tcp header from the packets of the remote system. Fields like ttl, window size etc.

      this will require some raw socket programming/packet sniffing.
      google for more information.

Leave a Reply to Nimish Cancel reply

Your email address will not be published. Required fields are marked *