/*
 *  $Id: udptcpwalk.c,v 1.1.1.1 1999/04/26 22:44:53 route Exp $
 *
 *  Firewalk
 *  udptcpwalk implementation
 *  udptcpwalk.c - UDP and TCP firewalking module
 *
 *  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 "./firewalk.h"
#include "./firepack.h"
#include "./watcher.h"
#include "./signal.h"
#include "./packet.h"
#if (HAVE_GTK)
#include "./gtk_main.h"
#include "./gtk_pack.h"
#endif

void
udptcpwalk()
{
    u_char *buf;            /* packet memory buffer */
    u_short bport,          /* begining port in the range we are scanning */
            eport,          /* ending port in the range we are scanning */
            cport,          /* current port we are scanning */
            p;              /* monotonic port counter */
    int c, i, j, t_size;    /* counters, transport header size */
    int done;               /* true when we are done scanning */

    t_size = (fp->protocol == IPPROTO_TCP ? TCP_H : UDP_H);
    p = 0;
    /*
     *  Packet header memory.
     */
    if (libnet_init_packet(IP_H + t_size, &buf) == -1)
    {
        perror("No memory for packet header");
        exit(EXIT_FAILURE);
    }

    /*
     *  As long as we have a port pair, we should be scanning.  If we get
     *  here, this will always happen at least once.
     */
    while (get_next_port_pair(fp->plist, &bport, &eport))
    {
        /*
         *  Keep going until we have exhausted this port range.  Make sure we
         *  don't wrap around at PORT_MAX (2^16 -1).
         */
        while (!(bport > eport) && bport != 0)
        {
            /*
             *  Check to see if we are bound.  If so, we don't need to ramp up
             *  TTLs again to get there again.  TTL ramping should only occur
             *  once.
             */
            if (fp->bound)
            {
                /*
                 *  Once we are bound, grab the current port and restrict the
                 *  hop count to fp->xv hops beyond the target gateway.
                 */
                cport = bport++;
                fp->ttl = fp->gway_hop_cnt + fp->xv;
#if (HAVE_GTK)
                /*
                 *  Update the progess bar.
                 */
                gtk_do_progress_bar_update(p++);
#endif
            }
            else    /* not bound, need to ramp TTLs */
            {
                /*
                 *  We need to ramp up TTLs until we get one beyond the
                 *  gateway.  Then we are bound and can simply send packets
                 *  with that binding TTL and look for the ICMP expired in
                 *  transit messages.
                 */
                if (!fp->quiet)
                {
                    fire_write("Ramping up hopcounts to binding host...\n");
                }
                cport = fp->init_probe_port;
            }
            done = 0;

            /*
             *  The first run through the loop, TTL ramping happens here.
             */
            for (i = 0; fp->ttl < IP_HOP_MAX && !done; i++, fp->ttl++)
            {
                /*
                 *  Build the IP packet.  We increment the packet ID so we can
                 *  differentiate between probes.  The TTL is bumped up so we
                 *  can determine how many hops away the gateway is.
                 */
                libnet_build_ip(t_size,
                        0,                      /* regular service */
                        ++fp->id,
                        0,                      /* No fragmentation bits set */
                        fp->ttl,
                        fp->protocol,
                        fp->sin.sin_addr.s_addr,
                        fp->destination,
                        NULL,
                        0,
                        buf);

                if (fp->protocol == IPPROTO_UDP)
                {
                    libnet_build_udp(fp->sport, cport, NULL, 0, IP_H + buf);
                }
                else
                {
                    libnet_build_tcp(fp->sport,
                            cport,
                            libnet_get_prand(PRu32),
                            0L,                 /* No ACK number */
                            TH_SYN,
                            1024,
                            0,                  /* No urgent data */
                            NULL,
                            0,
                            buf + IP_H);
                }
                if (libnet_do_checksum(buf, fp->protocol, t_size) == -1)
                {
                    fire_write("can't compute transport checksum!\n");
                    goto clean_up;
                }

                /*
                 *  Write red_cnt number of packets.
                 */
                for (j = 0, fp->red_flag = 0; j < fp->red_cnt; j++)
                {
                    usleep(fp->write_pause);
                    c = libnet_write_ip(fp->sock, buf, IP_H + t_size);
                    if (c < IP_H + t_size)
                    {
                        fire_write("error writing probe %d (only %d bytes)\n",
                            i + 1, c);
                        continue;
                    }
                    fp->packets_sent++;

                    /*
                     *  Only print the ramping template while we are ramping,
                     *  and not for redundant packets.
                     */
                    if (!fp->bound && !fp->red_flag && !fp->quiet)
                    {
                        fire_write("probe: %2d  TTL: %2d  port %3d:  ",
                            i + 1, fp->ttl, cport);
                    }
                    else if (!fp->red_flag && !fp->quiet)
                    {
                        fire_write("\nport %3d: ", cport);
                    }
                    /*
                     *  Call the watcher to recieve the response (if any).
                     *  Then process what it gives us.
                     */
                    if (process_response(&cport, firewalk_do_watcher()) == -1)
                    {
                        /*
                         *  Either we received a TTL expired from the gateway
                         *  or the gateway host was not found.
                         */
                        goto clean_up;
                    }
                    if (fp->bound)
                    {
                        done = 1;
                    }
                    if (j + 1 == fp->red_cnt && !fp->quiet)
                    {
                        fire_write("\n");
                    }
                }   /* Innermost packet writing loop */
            }   /* Third TTL ramping loop */
            if (fp->ttl == IP_HOP_MAX)
            {
                fire_write("Hop count exceeded\n");
                goto clean_up;
            }
        }   /* Second port incrementing loop */
    }   /* Outer port pair grabbing loop */
    clean_up:
    libnet_destroy_packet(&buf);
    p_stats();
}

/* EOF */
