/* Resolve an IP address to a host name or the other way around.
   Both forward and reverse lookup will be attempted. The input
   item must match the reverse lookup item.
   Rick Smereka, Copyright (C) 1999-2004.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, get a copy via the Internet at
   http://gnu.org/copyleft/gpl.html or write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   MA 02111-1307 USA

   You can contact the author via email at rsmereka@future-lab.com

   Original CodeWarrior V4 Windows 32-bit version Jul/99, Rick Smereka

   Port to Unix Aug/99 and made messages more verbose.
   Aug/99, Rick Smereka

   Moved function 'isip' to the 'clib' parse module.
   Oct/99, Rick Smereka
   
   Added the new 'clib' module 'ip.c'.
   Jul/2000, Rick Smereka

   Ported to Debian Linux. Jan/2003, Rick Smereka

   Code cleanup. Dec/2004, Rick Smereka */

#include "stdhead.h"
#include "flsocket.h"
#include "ip.h"

// global (to module) socket data

#ifdef OS_WIN32
WSADATA wsaData;                  // struct used by 'WSAStartup()'
SOCKET clientSocket;              // client socket
SOCKADDR_IN sockClientAddr;       // client address structure
LPHOSTENT lpHostEnt;              // host info structure
#else
int clientSocket;
struct sockaddr_in sockClientAddr;
struct hostent *lpHostEnt;
#endif

#define VERSION "1.04.02-2004.12.23"
#define APNAME "iresolve"

void ip2host(char *);
void host2ip(char *);
void usage(void);

int main(int argc, char **argv)
{
   char str[1024];

   // print logo

#ifndef OS_UNIX
   // non-Unix

   printf("%s for %s Version %s\n", APNAME, PLATFORM_STRING, VERSION);
#else
   // Unix

   printf("%s for %s Version %s\n", APNAME, SUB_PLATFORM_STRING, VERSION);
#endif

   printf("By Rick Smereka, Copyright (c) 1999-2004\n");
   printf("%s comes with ABSOLUTELY NO WARRANTY\n", APNAME);
   printf("This is free software, and you are welcome to redistribute it\n");
   printf("under certain conditions; see 'gpl.txt' for information.\n");

   if (argc == 1)
      {
      usage();
      return(0);
      }

   /* get first and only required parameter */

   strcpy(str, (char *)argv[1]);

#ifdef OS_WIN32
   if (WSAStartup(WINSOCK_VERSION, &wsaData))
      {
      printf("%s:unable to start WinSock library. Program abort\n", APNAME);
      WSACleanup();
      return(0);
      }
#endif

   // is it an IP address?

   if (isip(str))
      ip2host(str);
   else
      host2ip(str);

#ifdef OS_WIN32
   WSACleanup();
#endif
   return(0);
}

void host2ip(char *hostname)
{
   /* Take a host name and get its IP address and use this to get
      the host name again. */

#ifdef OS_WIN32
   LPSTR ipstr;
   DWORD ipbin;
#else
   struct in_addr ipbin;
   char *ipstr;
#endif
   char mname[] = "host2ip";
   char fhost[1024];

   // get host details based on name

   printf("%s:%s:host name to resolve is '%s'\n", APNAME, mname, hostname);
   strcpy(fhost, hostname);
   lpHostEnt = gethostbyname(hostname);

   if (!lpHostEnt)
      {
#ifdef OS_WIN32
      WSACleanup();
#endif
      printf("%s:%s:unable to resolve host name to IP address\n", APNAME,
             mname);
      return;
      }

   strcpy(fhost, lpHostEnt->h_name);
   printf("%s:%s:returned host name is '%s'\n", APNAME, mname, fhost);

   // take the binary IP address and convert it to a dotted string

#ifdef OS_WIN32
   ipstr = inet_ntoa(*(LPIN_ADDR)*(lpHostEnt->h_addr_list));
#else
   ipbin.s_addr = ((struct in_addr *)(lpHostEnt->h_addr))->s_addr;
   ipstr = inet_ntoa(ipbin);
#endif
   printf("%s:%s:resolved host name '%s' to IP address '%s'\n", APNAME,
          mname, fhost, ipstr);

   // convert IP address back to a binary number

#ifdef OS_WIN32
   ipbin = inet_addr(ipstr);

   if (ipbin == INADDR_NONE)
#else
   ipbin.s_addr = inet_addr(ipstr);

   if (ipbin.s_addr == INADDR_NONE)
#endif

      {
      printf("%s:%s:error converting IP string to 32-bit number\n", APNAME,
             mname);
      return;
      }

   // lookup host details by binary IP address

#ifdef OS_WIN32
   lpHostEnt = gethostbyaddr((LPSTR)&ipbin, 4, AF_INET);
#else
   lpHostEnt = gethostbyaddr((char *)&ipbin, 4, AF_INET);
#endif

   if (!lpHostEnt)
      {
      printf("%s:%s:reverse lookup:unable to resolve IP to host name\n",
             APNAME, mname);
      return;
      }

   printf("%s:%s:IP address resolve to host '%s'\n", APNAME, mname,
          lpHostEnt->h_name);

   if (!strcmp(lpHostEnt->h_name, fhost))
      printf("%s:%s:reverse lookup:resolved to same host name\n", APNAME,
             mname);
   else
      printf("%s:%s:reverse lookup:resolved host name different,"
             "orig='%s',new='%s'\n", APNAME, mname, fhost, lpHostEnt->h_name);
}

void ip2host(char *ipstr)
{
   /* Take an IP address and get its host name and use this to get
      the IP address again. */

#ifdef OS_WIN32
   LPSTR ipstrt;
   DWORD ipbin;
#else
   struct in_addr ipbin;
   char *ipstrt;
#endif

   char mname[] = "ip2host";
   char fhost[1024];

   printf("%s:%s:IP to resolve is '%s'\n", APNAME, mname, ipstr);

#ifdef OS_WIN32
   ipbin = inet_addr((LPSTR)ipstr);

   if (ipbin == INADDR_NONE)
#else
   ipbin.s_addr = inet_addr(ipstr);

   if (ipbin.s_addr == INADDR_NONE)
#endif

      {
      printf("%s:%s:error converting IP string to 32-bit number\n", APNAME,
             mname);
      return;
      }

#ifdef OS_WIN32
   lpHostEnt = gethostbyaddr((LPSTR)&ipbin, 4, AF_INET);
#else
   lpHostEnt = gethostbyaddr((char *)&ipbin, 4, AF_INET);
#endif

   if (!lpHostEnt)
      {
      printf("%s:%s:unable to resolve IP to host name\n", APNAME, mname);
      return;
      }

   printf("%s:%s:IP address resolve to host '%s'\n", APNAME, mname,
          lpHostEnt->h_name);
   strcpy(fhost, lpHostEnt->h_name);
   lpHostEnt = gethostbyname(fhost);

   if (!lpHostEnt)
      {
      printf("%s:%s:error geting IP from resolved host name\n", APNAME,
             mname);
      return;
      }

#ifdef OS_WIN32
   ipstrt = inet_ntoa(*(LPIN_ADDR)*(lpHostEnt->h_addr_list));
#else
   ipbin.s_addr = ((struct in_addr *)(lpHostEnt->h_addr))->s_addr;
   ipstrt = inet_ntoa(ipbin);
#endif

   if (!strcmp(ipstr, (char *)ipstrt))
      printf("%s:%s:reverse lookup:resolved to same IP address\n", APNAME,
             mname);
   else
      printf("%s:%s:reverse lookup:resolved IP address different,"
             "orig='%s',new='%s'\n", APNAME, mname, ipstr, (char *)ipstrt);
}

void usage(void)
{
   /* Display program usage. */

   printf("usage: iresolve ip_addr|host_name\n");
}
