/* Hostloop -- the Hostloop 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.
 */



#include <includes.h>

#ifndef NESSUSNT
#ifndef __USE_BSD
#define __USE_BSD
#endif 
#ifdef HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#ifdef HAVE_NETINET_IP_ICMP_H
#include <netinet/ip_icmp.h>
#endif
#endif

#include "icmp.h"
#include "hosts_loop.h"

/*
 * Checksum routine for Internet Protocol family headers (C Version)
 * From ping examples in W.Richard Stevens "UNIX NETWORK PROGRAMMING" book.
 */
int in_cksum(p,n)
u_short *p; int n;
{
  register u_short answer;
  register long sum = 0;
  u_short odd_byte = 0;

  while( n > 1 )  { sum += *p++; n -= 2; }

  /* mop up an odd byte, if necessary */
  if( n == 1 ) {
      *(u_char *)(&odd_byte) = *(u_char *)p;
      sum += odd_byte;
  }

  sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
  sum += (sum >> 16);			/* add carry */
  answer = (int)~sum;			/* ones-complement, truncate*/
  return (answer);
}


int is_host_alive(struct in_addr addr)
{
 int soc;
 char * buf;
 struct ip *ip;
 struct icmp *icmp;
 struct protoent * ip_proto;
 struct timeval tv;
#ifndef NESSUSNT
 struct timezone tz;
#endif
 int len;
 struct sockaddr_in saddr;
 int count = 1;
 int max_to = 3;
 int ok = 0;
 ip_proto = getprotobyname("icmp");
 if(!ip_proto)return(1);
  
 soc = socket(AF_INET, SOCK_RAW, ip_proto->p_proto);
 bzero(&saddr, sizeof(saddr));
 if(soc < 0 )return(1);
 while(max_to && !ok)
 {
  fd_set r,w;
  int n;
  buf = (char*)malloc(32);
  bzero(buf, 32);
  icmp = (struct icmp *)buf;
#ifndef NESSUSNT
  gettimeofday(&tv, &tz);
#endif
  icmp->icmp_type = ICMP_ECHO;
  icmp->icmp_code = 0;
  icmp->icmp_cksum = 0;
  icmp->icmp_seq = 1;
/*  SET_ICMP_LIFETIME(*icmp, 1024); */
  icmp->icmp_id = getpid() & 0xFFFF;

#ifndef NESSUSNT
  bcopy(&tv, &buf[8], sizeof(struct timeval));
  len = 8 + sizeof(struct timeval)+sizeof(int);
#else
  len = 8 + sizeof(int);
#endif
  saddr.sin_family = AF_INET;
  saddr.sin_addr = addr;
  saddr.sin_port = 0;
  bcopy(&count, &buf[8+sizeof(struct timeval)], sizeof(int));
  icmp->icmp_cksum = in_cksum((u_short *)icmp,len);
  sendto(soc, buf, len, 0, (struct sockaddr *)(&saddr), sizeof(struct sockaddr_in));
  sendto(soc, buf, len, 0, (struct sockaddr *)(&saddr), sizeof(struct sockaddr_in));
  sendto(soc, buf, len, 0, (struct sockaddr *)(&saddr), sizeof(struct sockaddr_in));
  free(buf);
  
  FD_ZERO(&r);
  FD_ZERO(&w);
#ifndef NESSUSNT  
  tv.tv_sec = 3;
  tv.tv_usec = 0;
#endif
  FD_SET(soc, &r);
  n = select(soc+1, &r, &w, NULL, &tv);
  if(n>0)
  {
   int slen = sizeof(struct sockaddr);
   buf = malloc(4096);
   bzero(buf, 4096);
   ip  = (struct ip *)buf;
   bzero(&saddr, sizeof(struct sockaddr_in));
   recvfrom(soc, buf, 4096, 0, (struct sockaddr *)&saddr, &slen);
   icmp = (struct icmp *)(buf + (ip->ip_hl << 2));
   if((icmp->icmp_type == ICMP_ECHOREPLY)&&
      (icmp->icmp_id == (getpid() & 0xFFFF)))
	  ok = 1;
   free(buf);
   }
   else max_to--;
  }
  shutdown(soc, 2);
  close(soc);
  return(ok);
}
  
