/* Nessuslib -- the Nessus Library
 * Copyright (C) 1998 Renaud Deraison
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Hostname resolver.
 */

#define EXPORTING
#include <includes.h>
#include "resolve.h"

#ifndef __u32
#define __u32 unsigned long
#endif

#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif

#ifdef USE_FORK_THREADS
struct _nn_resolve_cache_t
{
  __u32 address;
  const char * hostname;
  struct _nn_resolve_cache_t * next;
};
#endif
struct _nn_resolve_cache_t * _nn_cache = NULL;


ExtFunc
struct in_addr nn_resolve (hostname)
  const char * hostname;
{
  struct in_addr in;
  struct hostent *ent;
  unsigned long ip;
#ifdef USE_FORK_THREADS
  struct _nn_resolve_cache_t * l_cache;
#endif  
  char *hostname_lc;
  int j;
  
 in.s_addr = 0;
 hostname_lc = emalloc(strlen(hostname)+1);
 strncpy(hostname_lc, hostname, strlen(hostname));
  for(j=0;j<strlen(hostname_lc);j++)
    hostname_lc[j]=tolower(hostname_lc[j]);
#ifdef USE_FORK_THREADS
 if(_nn_cache)
    {
      l_cache = _nn_cache;
      while(l_cache)
	{
       	  if(l_cache->hostname &&
	     (!strcmp(l_cache->hostname,hostname_lc)))
	    {
	      in.s_addr = l_cache->address;
	      return(in);
	    }
	  else l_cache = l_cache->next;
	}
    }
#endif
  
  if(!in.s_addr)
    { 
#ifndef USE_PTHREADS
	  ent = gethostbyname(hostname_lc);
#else
  	 int Errno=0;
         char * buf = emalloc(4096);
         struct hostent * res = NULL;
         struct hostent * t = NULL;
	 ent = emalloc(sizeof(struct hostent));
#ifdef HAVE_SOLARIS_GETHOSTBYNAME_R
	 gethostbyname_r(hostname_lc, ent, buf, 4096, &Errno);
	 if(h_errno){
	 	free(ent);
		ent = NULL;
		}
#else
         gethostbyname_r(hostname_lc, ent, buf, 4096, &res, &Errno);
         t = ent;
         ent = res;
#endif
#endif
	  if (ent)
	    { 
	      in = *(struct in_addr *)ent->h_addr;
	      if(in.s_addr != 0)_nn_resolve_add_cache(hostname_lc, in);
	    }
	  else in.s_addr = 0;
#if defined(USE_PTHREADS) && defined(HAVE_GETHOSTBYNAME_R)
	   if(ent)free(ent);
	   free(buf);
#endif
     if(!in.s_addr)
      {
        if ((ip = inet_addr(hostname_lc)) != INADDR_NONE)
	{
	  in.s_addr = ip;
	  _nn_resolve_add_cache(hostname_lc, in);
	}
      }
    }
  free(hostname_lc);
  return in;
}

ExtFunc
int _nn_resolve_add_cache (human, in)
    const char * human;
    struct in_addr in;
{
#ifdef USE_FORK_THREADS
struct _nn_resolve_cache_t * l_cache = _nn_cache;
 if(!_nn_cache)
   {
     _nn_cache = malloc(sizeof(struct _nn_resolve_cache_t));
     if(!_nn_cache)return(-1);
     bzero(_nn_cache, sizeof(struct _nn_resolve_cache_t));
     
     _nn_cache->hostname = strdup(human);
     if(!_nn_cache->hostname)return(-1);
     _nn_cache->address = in.s_addr;
     _nn_cache->next = NULL;
   }
 else
   {
     while(l_cache->next)l_cache = l_cache->next;
     l_cache->next = malloc(sizeof(struct _nn_resolve_cache_t));
     if(!l_cache->next)return(-1);
     bzero(l_cache->next, sizeof(struct _nn_resolve_cache_t));
     
     l_cache = l_cache->next;
     l_cache->hostname = strdup(human);
     if(!l_cache->hostname)return(-1);
     l_cache->address = in.s_addr;
     l_cache->next = NULL;
   }
#endif
 return 0;
}
