/*
 *  $Id: main.c,v 1.1.1.1 1999/04/26 22:44:53 route Exp $
 *
 *  Firewalk
 *  firewalk client
 *  main.c - main control logic
 *
 *  Copyright (c) 1999 Mike D. Schiffman <mike@infonexus.com>
 *  Copyright (c) 1998 Mike D. Schiffman <mds@es2.net>
 *  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#if (HAVE_CONFIG_H)
#include "./config.h"
#endif
#include "./main.h"
#include "./firewalk.h"
#include "./firepack.h"
#include "./watcher.h"
#include "./packet.h"
#include "./version.h"
#if (HAVE_GTK)
#include "./gtk_main.h"
#include "./gtk_pack.h"
#endif

int
main(int argc, char *argv[])
{
    int c, i, fd = -2, n;
    u_char *w_prots[] = {"UDP", "TCP", "ICMP", 0};
    u_char ebuf[BUFSIZ];

    if (geteuid() && getuid())
    {
        fprintf(stderr, "root access required\n");
        exit(EXIT_FAILURE);
    }

    /*
     *  Initialize the firepack structure with the program defaults.
     */
    if (firewalk_init_firepack(&fp) == -1)
    {
        fprintf(stderr, "Can't initlialize the firepack structure.\n");
        exit(EXIT_FAILURE);
    }

#if (HAVE_GTK)
    if (gtk_init_gtkpack(&gp) == -1)
    {
        fprintf(stderr, "Can't initlialize the gtkpack structure.\n");
        exit(EXIT_FAILURE);
    }
#endif

    /*
     *  Process commandline arguments.
     */
    while ((c = getopt(argc, argv, "hI:i:no:P:p:qr:S:s:T:t:vx:")) != EOF)
    {
        switch (c)
        {
            case 'h':   /* Help */
                usage(argv[0]);
                exit(EXIT_FAILURE);
                break;
            case 'I':   /* The initial port to use for TTL ramping */
                n = atoi(optarg);
                if (n > PORT_MAX || n < PORT_MIN)
                {
                    fprintf(stderr, "Invalid probe port: %d\n", n);
                    usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                fp->init_probe_port = n; 
                break;
            case 'i':   /* Select interface */
                fp->device = optarg;
                break;
            case 'n':   /* Do not use names */
                fp->use_name = 0;
                break;
            case 'o':   /* Output to a file */
                fd = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
                if (fd == -1)
                {
                    perror("main: cannot create file");
                    exit(EXIT_FAILURE);
                }
                fp->output_fd   = fd;
                fp->output_file = optarg;
                break;
            case 'P':   /* Time to pause in between sends */
                n = atoi(optarg);
                if (n > WRITE_PAUSE_MAX || n < WRITE_PAUSE_MIN)
                {
                    fprintf(stderr, "Invalid pause: %d\n", n);
                    usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                fp->write_pause = n;
                break;
            case 'p':   /* Select walking protocol */
                for (i = 0; w_prots[i]; i++)
                {
                    if ((!strcasecmp(w_prots[i], optarg)))
                    {
                        switch (i)
                        {
                            case 0:
                                fp->protocol = IPPROTO_UDP;
                                break;
                            case 1:
                                fp->protocol = IPPROTO_TCP;
                                break;
                        }
                        break;
                    }
                }
                /*
                 *  Did we hit the end of the protocol array?
                 */
                if (!w_prots[i])
                {
                    fprintf(stderr, "\"%s\" unknown.  Supported : ", optarg);
                    for (i = 0; w_prots[i]; i++)
                    {
                        fprintf(stderr, "%s ", w_prots[i]);
                    }
                    puts(".");
                    exit(EXIT_FAILURE);
                }
                break;
            case 'q':   /* Quiet mode */
                fp->quiet = 1;
                break;
            case 'r':   /* Redundancy count */
                n = atoi(optarg);
                if (n > RED_CNT_MAX || n < RED_CNT_MIN)
                {
                    fprintf(stderr, "Invalid redundancy count: %d\n", n);
                    usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                fp->red_cnt = n;
                break;
            case 'S':   /* Scan these ports */
                if (parse_port_list(optarg) == -1)
                {
                    fprintf(stderr, "Could not build port list\n");
                    exit(EXIT_FAILURE);
                }
                break;
            case 's':   /* Source port */
                n = atoi(optarg);
                if (n > PORT_MAX || n < PORT_MIN)
                {
                    fprintf(stderr, "Invalid source port: %d\n", n);
                    usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                fp->sport = n;
                break;
            case 'T':   /* Time to wait for packets from other end */
                n = atoi(optarg);
                if (n > PCAP_TIMEOUT_MAX || n < PCAP_TIMEOUT_MIN)
                {
                    fprintf(stderr, "Invalid read timeout: %d\n", n);
                    usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                fp->pcap_timeout = n;
                break;
            case 't':   /* Set initial IP TTL */
                n = atoi(optarg);
                if (n > IP_HOP_MAX || n < IP_HOP_MIN)
                {
                    fprintf(stderr, "Invalid initial TTL : %d\n", n);
                    usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                fp->ttl = n;
                break;
            case 'v':   /* Version */
                fprintf(stderr, BANNER "Firewalk version : %s\n", version);
                exit(EXIT_SUCCESS);
            case 'x':   /* Change expire vector */
                n = atoi(optarg);
                if (n > XV_MIN || n < XV_MIN)
                {
                    fprintf(stderr, "Invalid initial expire vector: %d\n", n);
                    usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                fp->xv = n;
                break;
            default:
                usage(argv[0]);
                exit(EXIT_FAILURE);
        }
    }

    /*
     *  Set up the network interface and determine our outgoing IP address.
     */
    if (libnet_select_device(&fp->sin, &fp->device, ebuf) == -1)
    {
        fprintf(stderr, "libnet_select_device choked\n");
        exit(EXIT_FAILURE);
    }

    /*
     *  Do we have a destination host and a gateway host?
     */
    if (argc > optind)
    {
        if ((fp->gateway = libnet_name_resolve(argv[optind], 1)) == -1)
        {
            fprintf(stderr, "Cannot resolve gateway IP address\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        fp->gateway = 0;
#if (!HAVE_GTK)
        fprintf(stderr, "Need a gateway IP address\n");
        exit(EXIT_FAILURE);
#endif
    }
    if (argc > optind + 1)
    {
        if ((fp->destination = libnet_name_resolve(argv[optind + 1], 1)) == -1)
        {
            fprintf(stderr, "Cannot resolve destination IP address\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        fp->destination = 0;
    }
    if (fp->gateway && fp->gateway == fp->destination)
    {
        fprintf(stderr, "Gateway and destination can't be the same.\n");
        exit(EXIT_FAILURE);
    }

    /*
     *  Open the raw IP socket and set IPHDR_INCL.
     */
    fp->sock = libnet_open_raw_sock(IPPROTO_RAW);
    if (fp->sock == -1)
    {
        perror("No socket");
        exit(EXIT_FAILURE);
    }

    /*
     *  Make sure we have a port list to scan.
     */
    if (!fp->plist)
    {
        parse_port_list(strdup(DEFAULT_PORT_LIST));
    }

#if (HAVE_GTK)
    /*
     *  Power up the GTK interface and pass control and wait for X events.
     */
    gtk_init_interface(&argc, &argv);
    gtk_main();
#else
    if (!fp->gateway || !fp->destination)
    {
        fprintf(stderr, "Fire, walk with me where?\n");
        exit(EXIT_FAILURE);
    }
    firewalk();
#endif

    /* UNREACHED */
    return (EXIT_SUCCESS);
}


/* EOF */
