// Emacs style mode select -*- C++ -*-
//------------------------------------------------------------------------
//
// Copyright(c) 2001, 2002 Simon Howard
//
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//--------------------------------------------------------------------------
//
// Generic finger: determine whether a machine is up by connecting
// to it
//
//--------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>

#include "parse.h"
#include "scan.h"
#include "generic.h"

//
// finger a machine
//

void generic_finger_machine(int machine)
{
        struct sockaddr_in sa;
        struct hostent *hp;
        struct servent *service;
        int sock;
        char *hostname = machines[machine]->hostname;

	// find host ip
     
        hp = gethostbyname(hostname);
        
        if(!hp) {
                fprintf(stderr,
                        "generic_finger_machine: unable to resolve '%s'\n", 
                        hostname);
                scan_set_status(machine, STATUS_FAULT);
                return;
        }
     
        // create sockaddr
        
        memset(&sa,0,sizeof(sa));
        
        memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length);
        sa.sin_family = hp->h_addrtype;

        // use port 23 (telnet)
        // the port used isnt really important
        
        sa.sin_port = htons(23);
        
        // create socket
        
        sock = socket(hp->h_addrtype, SOCK_STREAM, 0);
     
        if (sock < 0) {
                fprintf(stderr, "cant create socket");
                perror("generic_finger_machine");

                scan_set_status(machine, STATUS_FAULT);

                return;
        }
        
        // connect
        
        if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
                fprintf(stderr,
                        "generic_finger_machine: cant connect to %s (%s)\n",
                        hostname,
                        strerror(errno)); 

                // catch certain types of error:
                // if we get ECONNREFUSED, then there is obviously 
                // a machine up refusing the connections
                // possibly the fingerd has just died or something

                if(errno == ECONNREFUSED) {

                        // up but unknown
                        // go for plain up, since this is the default
                        // operation with generic anyway
                        
                        scan_set_status(machine, STATUS_UP);
                } else {
                
                        // mark machine as down
                
                        scan_set_status(machine, STATUS_DOWN);
                }
        } else {

                // we actually connected to the machine,
                // but we dont care

		scan_set_status(machine, STATUS_UP);                
        }
        
        close(sock);
}
