/*
 
 This file is part of LFT.
 
 The LFT software provided in this Distribution is
 Copyright 2007 VOSTROM Holdings, Inc.
 
 The full text of our legal notices is contained in the file called
 COPYING, included with this Distribution.
 
 Authors:
 
 -  Victor Oppleman <lft@oppleman.com>
 -  Eugene Antsilevitch <ugen@xonix.com>
 
 Other copyrights and former authors:
 
 -  Portions copyright (c) Genuity, Inc. 
 -  Portions copyright (c) Markus Gothe <nietzsche@lysator.liu.se>
 -  Portions copyright (c) Nils McCarthy
 
 */
#include "lft_lib.h"
#ifdef HAVE_NCURSES
#include <ncurses.h>
#include "lft_watch.h"
#endif

/* DNS resolver tuning: short timeout/retry so failed lookups don't stall traces.
 * _res is the global resolver state; on Linux/glibc it is consulted by
 * getnameinfo() (which LFT now uses in place of gethostbyname/gethostbyaddr).
 * On macOS, getnameinfo() may route through mDNSResponder which ignores _res,
 * so lft_lib.c wraps getnameinfo() calls in alarm(1) as a hard ceiling.
 * res_ninit() with a local state would not affect getnameinfo(), so direct
 * _res modification remains correct for the Linux/glibc path.
 * _res is declared in <resolv.h>. */
#include <resolv.h>
#include <getopt.h>

#if 0
static char def_payload[] = "\0\0\0\0\0\0\0\0\0\0"; /* default payload for UDP packets */
#endif

const char *version = "3.98";  		/* set version string */
static const char *version_date = "(04/2026)";	/* date of this version */

/* Sentinel value for the long-only --help option.  Must not collide with any
 * printable ASCII character used as a short option. */
#define OPT_HELP          1
#define OPT_NO_ASCII_CHART 2
#define OPT_NO_LEARN      3   /* LFT-AUTOTUNE — disable topology inheritance */
#define OPT_LEARN_MARGIN  4   /* LFT-AUTOTUNE — TTL margin above learned path */

static struct option long_options[] = {
    {"sport",               required_argument, 0, 's'},
    {"dport",               required_argument, 0, 'd'},
    {"random-sport",        no_argument,       0, 'z'},
    {"min-probes",          required_argument, 0, 'm'},
    {"max-probes",          required_argument, 0, 'M'},
    {"device",              required_argument, 0, 'D'},
    {"receive-device",      required_argument, 0, 'D'},
    {"length",              required_argument, 0, 'L'},
    {"bytes",               required_argument, 0, 'L'},
    {"fin",                 no_argument,       0, 'F'},
    {"from-device",         required_argument, 0, 'f'},
    {"source-device",       required_argument, 0, 'f'},
    {"adaptive",            no_argument,       0, 'E'},
    {"udp",                 no_argument,       0, 'u'},
    {"basic-tcp",           no_argument,       0, 'b'},
    {"icmp",                no_argument,       0, 'p'},
    {"ahead",               required_argument, 0, 'a'},
    {"scatter",             required_argument, 0, 'c'},
    {"timeout",             required_argument, 0, 't'},
    {"min-ttl",             required_argument, 0, 'l'},
    {"first-hop",           required_argument, 0, 'l'},
    {"max-hops",            required_argument, 0, 'H'},
    {"ttl-max",             required_argument, 0, 'H'},
    {"isn",                 required_argument, 0, 'q'},
    {"minimize-delay",      no_argument,       0, 'I'},
    {"ignore-unreachables", no_argument,       0, 'i'},
    {"tcp-window",          required_argument, 0, 'w'},
    {"numeric",             no_argument,       0, 'n'},
    {"hostnames-only",      no_argument,       0, 'h'},
    {"netname",             no_argument,       0, 'N'},
    {"asn",                 no_argument,       0, 'A'},
    {"no-async-dns",        no_argument,       0, 'Q'},
    {"ripe-riswhois",       no_argument,       0, 'r'},
    {"radb",                no_argument,       0, 'R'},
    {"cymru",               no_argument,       0, 'C'},
    {"time-keeping",        no_argument,       0, 'T'},
    {"time-keeping-utc",    no_argument,       0, 'U'},
    {"quiet",               no_argument,       0, 'S'},
    {"silent",              no_argument,       0, 'S'},
    {"verbose",             no_argument,       0, 'V'},
    {"xml",                 no_argument,       0, 'x'},
    {"graphviz",            no_argument,       0, 'g'},
    {"graphviz-icons",      required_argument, 0, 'G'},
    {"ascii",               no_argument,       0, 'o'},
    {"verify-seam",         no_argument,       0, 'y'},
    {"version",             no_argument,       0, 'v'},
    {"mtu",                 no_argument,       0, 'K'},
    {"path-mtu",            no_argument,       0, 'K'},
    {"stats",               required_argument, 0, 'j'},
    {"no-async-chart",      no_argument,       0, OPT_NO_ASCII_CHART},
    {"no-ascii-chart",      no_argument,       0, OPT_NO_ASCII_CHART},
    {"watch",               optional_argument, 0, 'W'},
    {"continuous",          optional_argument, 0, 'W'},
    /* LFT-AUTOTUNE — see lft_lib.c lft_auto_tune_from_learned() */
    {"no-learn",            no_argument,       0, OPT_NO_LEARN},
    {"learn-margin",        required_argument, 0, OPT_LEARN_MARGIN},
    {"help",                no_argument,       0, OPT_HELP},
    {0, 0, 0, 0}
};

static void
usage(lft_session_params * sess, char *prog)
{
    fprintf (stderr,
             "\nLayer Four Traceroute (LFT)\n\n"
             "    - the alternative traceroute tool for network [reverse] engineers\n"
             "                                          visit http://www.pwhois.org\n\n"
             "Usage: %s [<options>] [<gateway> <...>] <target:port>\n"
             "\nMainstream Options:\n"
             "  -s <sport>       Set source port (default: random dynamic port in 49152-65535)\n"
             "  -d <dport>       Destination port number, same as target:port (default: 443)\n"
             "  -z               Pseudo-randomize the source port number\n"
             "  -m <min>         Minimum number of probes to send per hop\n"
             "  -M <max>         Maximum number of probes to send per hop\n"
             "  -D <device|ip>   Listen-on/use a device by name or address (\"en1\" or \"1.2.3.4\")\n"
             "  -L <length>      Set the length of the probe packet in bytes (ignored when -K is active)\n"
             "  -K               Active path MTU discovery: probe at interface MTU, reduce on PTB\n"
             "  -j <N>           Collect N probes/hop for RTT stats (min/avg/max/jitter); use with -o for chart\n"
             "  --no-ascii-chart  Suppress the candlestick chart from -j output (keep numerical stats)\n"
             "  -W N             Continuous monitoring mode (ncurses); N=interval seconds\n"
             "                   Also: --watch=N / --continuous=N  (e.g. --watch 5)\n"
#ifndef HAVE_NCURSES
             "                   (unavailable — rebuild with --with-ncurses)\n"
#endif
             "  --no-learn       Disable topology inheritance — every --watch cycle\n"
             "                   probes the full TTL ladder.  Default: enabled (cycle 2+\n"
             "                   reuses prior path length, RTT envelope, and tighter\n"
             "                   timeouts after 3 stable cycles)\n"
             "  --learn-margin N TTL probe margin above the learned path length\n"
             "                   (default 2; clamped 0..10)\n"
             "\nAdvanced Tracing Options:\n"
             "  -F               Use TCP FIN packets exclusively (defaults are SYN)\n"
             "  -f <device|ip>   Send using a device by name or address (spoofing allowed)\n"
             "  -e | -E          Use LFT's stateful engine to detect firewalls and path anomalies\n"
             "  -u               Use traditional UDP (probes) for tracing instead of TCP\n"
             "  -b               Basic TCP trace\n"
             "  -p               Use traditional ICMP (probes) for tracing instead of TCP\n"
             /*"  -P               Use RFC1393 IP option for tracing instead of TCP\n" */
             "  -a <ahead>       Number of hops forward to query before pausing to wait for replies\n"
             "  -c <scatter ms>  Minimum number of milliseconds between subsequent probes\n"
             "  -t <timeout ms>  Maximum RTT to wait before assuming packet was dropped\n"
             "  -l <min ttl>     Minimum TTL to use on outgoing packets (skips close-proximity hops)\n"
             "  -H <ttl>         Maximum number of hops to traverse (max TTL of packets)\n"
             "  -q <sequence>    Set the initial sequence number (ISN) manually\n"
             "  -w <window>      Set the TCP window size in bytes (TCP traces only; default: 32768)\n"
             "  -I               Set the ToS field in the IP packet to minimize-delay\n"
             "  -i               Ignore ICMP unreachable messages; trace continues through firewalls\n"
             "  -y               Test destination upstream transition hop\n"
             "\nResolution Options:\n"
             "  -n               Display hosts numerically; disable use of the DNS resolver\n"
             "  -h               Display hosts symbolically; suppress IP address display\n"
             "  -N               Display network or AS names where appropriate\n"
             "  -A               Display AS numbers resolved by Prefix WhoIs\n"
             "\nAdvanced Resolution Options:\n"
             "  -Q               Disable asynchronous DNS"
#ifdef HAVE_CARES
             "; fall back to synchronous resolver\n"
#else
             " (not compiled in; flag accepted but has no effect)\n"
#endif
             "  -r               Use RIPE NCC's RIS to resolve ASNs instead of Prefix WhoIs\n"
             "  -R               Use the RADB to resolve ASNs instead of Prefix WhoIs\n"
             "  -C               Use Cymru to resolve ASNs instead of Prefix WhoIs\n"
             "\nVerbosity Options and Status:\n"
             "  -T               Use execution timers and summarize where LFT spent its time\n"
             "  -U               Display all times in UTC (GMT0).  Activates -T option automatically\n"
             "  -S               Disable the status bar (only show the completed trace)\n"
             "  -v               Display LFT's version information and exit\n"
             "\nOutput Options:\n"
             "  -V               Display verbose/debug output.  Use more \'V\'s for additional detail\n"
             "  -W               Watch mode: ncurses textual user interface. Several dashboards.\n"
             "  -x               XML output\n"
             "  -g               GraphViz output\n"
             "  -G <icons path>  Enable GraphViz output and override path to icons\n"
             "  -o               ASCII art hop diagram (color and Unicode auto-detected)\n"
             "  --help           Show this summary; long-form options available, see lft(8)\n"
             "\n"
             "Default is: %s -s %d -d %d -m %d -M %d -a %d -c %.0f -t %d -H %d \n\n",
             prog, prog, sess->sport, sess->dport, sess->retry_min, sess->retry_max, sess->ahead_limit,
             sess->scatter_ms, sess->timeout_ms, sess->ttl_limit);
   exit(EXIT_FAILURE);
}

static void
show_version (void)
{
    /* Compile-time options block — one big fprintf so #ifdefs can gate strings */
    fprintf (stderr, "\n"
             "Layer Four Traceroute (LFT) - version %s %s\n\n"
             "    - the alternative traceroute tool for network [reverse] engineers\n\n"
             "    Compile-time options:\n\n"
#if defined(DARWIN) || defined(__APPLE__)
             "      + MacOS (or Darwin)\n"
#endif
#if defined(UNIVERSAL)
             "      + Universal binary\n"
#endif
#if defined(NETBSD)
             "      + NetBSD\n"
#endif
#if defined(OPENBSD)
             "      + OpenBSD\n"
#endif
#if defined(BSD_IP_STACK)
             "      + BSD IP stack\n"
#endif
#if defined(BSD)
             "      + BSD platform\n"
#endif
#if defined(linux)
             "      + Linux platform\n"
#endif
#if defined(sun)
             "      + SUN platform\n"
#endif
#if !defined(sun) && !defined(linux) && !defined(BSD_IP_STACK) && !defined(OPENBSD)
             "      (unknown architecture)\n"
#endif
#if defined(SCREWED_IP_LEN)
             "      + IP length big-endian\n"
#else
             "      + IP length little-endian\n"
#endif
#if defined(IP_HDRINCL)
             "      + Full IP headers for raw sockets\n"
#else
             "      + Without IP header inclusion\n"
#endif
#if defined( __CYGWIN__ ) || defined( WIN32 ) || defined(_WIN32) || defined( USE_GTOD )
             "      + Calling gettimeofday() on each packet\n"
#endif
             "      + " HOST_SYSTEM_TYPE "\n"
#ifdef LFT_DONT_USE_SAFE_UID
             "      + Privilege drop disabled (LFT_DONT_USE_SAFE_UID)\n"
#endif
             "\n    Capabilities:\n\n",
             version, version_date);

    /* Capabilities — runtime version strings require separate fprintf calls */
    fprintf(stderr, "      + Packet capture:    %s\n", pcap_lib_version());

#ifdef HAVE_CARES
    fprintf(stderr, "      + c-ares async DNS:  c-ares %s\n", ares_version(NULL));
#else
    fprintf(stderr, "      - c-ares async DNS:  unavailable\n");
#endif

#ifdef HAVE_NCURSES
    fprintf(stderr, "      + ncurses TUI:       %s\n", curses_version());
#else
    fprintf(stderr, "      - ncurses TUI:       unavailable\n");
#endif

    fprintf(stderr, "\n");
    exit(EXIT_SUCCESS);
}

static void
lft_check_permissions(const char *binpath)
{
    /* Fast path: effective root covers both direct root and setuid-root. */
    if (geteuid() == 0)
        return;

#if defined(__CYGWIN__) || defined(WIN32) || defined(_WIN32)
    /* On Windows/Cygwin, raw socket access requires Administrator privileges
     * and the Npcap packet capture service must be installed and running. */
    (void)binpath;
    fprintf(stderr,
        "\nLFT: insufficient privileges.\n\n"
        "    On Windows, LFT must be run as Administrator, and the Npcap\n"
        "    packet capture service must be installed and running.\n"
        "    Right-click the terminal and choose \"Run as administrator\",\n"
        "    or launch from an elevated command prompt.\n\n");
    exit(EXIT_FAILURE);
#else
    /* Try to open a raw socket — the same privilege that pcap will demand. */
    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if (sock >= 0) {
        close(sock);
        return; /* capabilities or other mechanism is granting access */
    }
    if (errno != EPERM && errno != EACCES)
        return; /* unexpected error; let the real code surface it */

    /* No permission.  Emit platform-appropriate guidance. */
#if defined(DARWIN) || defined(__APPLE__)
    (void)binpath; /* suppress unused-variable warning on this path if needed */
    fprintf(stderr,
        "\nLFT: insufficient privileges — raw socket and BPF access are required.\n\n"
        "    LFT is not running as root.  macOS does not support Linux-style\n"
        "    capability grants (setcap); the setuid-root method is required:\n\n"
        "        sudo chown root %s && sudo chmod u+s %s\n\n",
        binpath, binpath);

#elif defined(linux) || defined(__linux__)
    fprintf(stderr,
        "\nLFT: insufficient privileges — raw socket access is required.\n\n"
        "    LFT does not appear to have the necessary Linux capabilities\n"
        "    (cap_net_raw, cap_net_admin).\n\n"
        "    Recommended fix using Linux capabilities (no setuid-root needed):\n\n"
        "        sudo setcap 'cap_net_raw,cap_net_admin=eip' %s\n\n"
        "    To verify:  getcap %s\n"
        "    To remove:  sudo setcap -r %s\n\n"
        "    As a last resort, the traditional setuid-root method also works:\n\n"
        "        sudo chown root %s && sudo chmod u+s %s\n\n",
        binpath, binpath, binpath, binpath, binpath);

#elif defined(BSD_IP_STACK)
    fprintf(stderr,
        "\nLFT: insufficient privileges — raw socket access is required.\n\n"
        "    LFT is not running as root.  Use the setuid-root method:\n\n"
        "        sudo chown root %s && sudo chmod u+s %s\n\n",
        binpath, binpath);

#else
    fprintf(stderr,
        "\nLFT: insufficient privileges — raw socket access is required.\n\n"
        "    LFT is not running as root.  You may need to run it as root\n"
        "    or set the setuid-root bit on the binary:\n\n"
        "        sudo chown root %s && sudo chmod u+s %s\n\n",
        binpath, binpath);
#endif

    exit(EXIT_FAILURE);
#endif /* !Windows */
}

extern int
main (int argc, char **argv)
{
    lft_session_params * sess;
    int ch;
    int long_index = 0;
    char *cp = NULL;
    struct timeval tb;
#if defined( __CYGWIN__ ) || defined( WIN32 ) || defined(_WIN32)
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD( 2, 2 );
    WSAStartup( wVersionRequested, &wsaData );
#endif

    res_init();
    _res.retrans = 1;   /* 1s timeout per query attempt */
    _res.retry = 1;     /* 1 retry; default is 4 which causes 20s+ stalls */

    sess = LFTSessionOpen();
    setbuf(stdout, NULL);

    gettimeofday (&tb, NULL);
    /* eventually this might want to use /dev/urandom or
        * something on machines that have it.  otherwise,
        * this does a fairly decent job of using the system
        * clock.
        *
        * multiply tv_usec (range 0-1000000) to be in range 0-2^31,
        * and xor to randomize the high bits of tv_sec that don't
        * change very much.
        */
    srand(tb.tv_sec ^ (tb.tv_usec * 2147));
    
    int user_set_retry_min = 0, user_set_retry_max = 0;
    while ((ch = getopt_long(argc, argv, "Aa:bCc:D:d:EeFf:H:hIij:KL:l:M:m:NnoPpq:QRrSs:Tt:UuVvW::xw:zgG:y", long_options, &long_index)) != EOF)
        switch (ch) {
            case 'f':
                LFTSetupSendDevice(sess, optarg);
                break;
            case 'F':
                LFTSetupFIN(sess);
                break;
            case 'h':
                LFTSetupDispSymbHost(sess);
                break;
            case 'u':
                LFTSetupUDPMode(sess);
                break;
            case 'r':
                LFTSetupRISLookup(sess);
                break;
            case 'R':
                LFTSetupRADBLookup(sess);
                break;
            case 'C':
                LFTSetupCYMRULookup(sess);
                break;
            case 'd':
                LFTSetupDestinationPort(sess, optarg);
                break;
            case 'L':
                LFTSetupLengthOfPacket(sess, (int)strtol(optarg, (char **)NULL, 10));
                break;
            case 'K':
                LFTSetupPMTUD(sess);
                break;
            case 'q':
                sess->seq_start = strtol(optarg, (char **)NULL, 10);
                break;
            case 'w':
                sess->win_len = (int)strtol(optarg, (char **)NULL, 10);
                break;
            case 'm':
                sess->retry_min = (int)strtol(optarg, (char **)NULL, 10);
                user_set_retry_min = 1;
                break;
            case 'M':
                sess->retry_max = (int)strtol(optarg, (char **)NULL, 10);
                user_set_retry_max = 1;
                break;
            case 'j': {
                int n = (int)strtol(optarg, (char **)NULL, 10);
                LFTSetupRTTStats(sess, n);
                break;
            }
            case OPT_NO_ASCII_CHART:
                sess->no_ascii_chart = 1;
                break;
            /* LFT-AUTOTUNE — runtime toggles for topology inheritance */
            case OPT_NO_LEARN:
                sess->no_autotune = 1;
                break;
            case OPT_LEARN_MARGIN: {
                int m = (int)strtol(optarg, (char **)NULL, 10);
                if (m < 0)  m = 0;
                if (m > 10) m = 10;
                sess->learn_margin = m;
                break;
            }
            case 'N':
                sess->do_netlookup = 1;
                break;
            case 'A':
                sess->do_aslookup = 1;
                break;
            case 'n':
                LFTSetupDisableResolver(sess);
                break;
            case 'T':
                sess->timetrace = 1;
                break;
            case 's':
                LFTSetupSourcePort(sess, lft_resolve_port(sess,optarg));
                break;
            case 'E':
            case 'e':
                LFTSetupAdaptiveMode(sess);
                break;
            case 'S':
                sess->nostatus = 1;
                break;
            case 'D':
                LFTSetupDevice(sess,optarg);
                break;
            case 'a':
                sess->ahead_limit = (int)strtol(optarg, (char **)NULL, 10);
                break;
            case 'c':
                sess->scatter_ms = (int)strtol(optarg, (char **)NULL, 10);
                if (sess->scatter_ms < 1)
                    sess->scatter_ms = 1;
                    if (sess->scatter_ms > 100)
                        sess->scatter_ms = 100;
                        break;
            case 't':
                sess->timeout_ms = (int)strtol(optarg, (char **)NULL, 10);
                break;
            case 'p':
		sess->protocol = 2;
                break;
            /*case 'P':					//We comment this option. Hardly any routers support this.
		sess->protocol = 3;
                break;*/
            case 'b':
		sess->protocol = 4;
                break;
            case 'H':
                if (strtol(optarg, (char **)NULL, 10) > 255) 
                    sess->ttl_limit = 255; else
                        sess->ttl_limit = (int)strtol(optarg, (char **)NULL, 10);
                break;
            case 'l':
                sess->ttl_min = (int)strtol(optarg, (char **)NULL, 10);
                sess->hop_info_length = sess->ttl_min;
                if (sess->ttl_min > 0)
                    sess->ttl_min--;
                    break;
            case 'i':
                sess->break_on_icmp = 0;
                break;
            case 'I':
                sess->set_tos = 1;
                break;
            case 'v':
                show_version();
                break;
            case 'U':   /* show all times in UTC */
                LFTSetupUTCTimes(sess);
                break;                
            case 'V':
                sess->noisy++;
                sess->nostatus = 1; 
                break;
            case 'z':
                sess->random_source = 1;
                /* Yes, this is a ridiculous randomizer, but it's adequate */
                sess->sport = rand()%16384+49152;
                break;
            case 'x':
                setOutputStyle(1);
                break;
            case 'g':
                setOutputStyle(2);
                break;
            case 'G':
                setOutputStyle(2);
				sess->graphviz_icon_path=optarg;
                break;
            case 'o':
                setOutputStyle(3);
                break;
            case 'y':
                sess->check_seam=1;
                break;
            case 'Q':
#ifdef HAVE_CARES
                sess->async_dns_disabled = 1;
#else
                fprintf(stderr, "LFT: -Q has no effect: c-ares was not compiled in\n");
#endif
                break;
            case 'W': {
                int n = optarg ? (int)strtol(optarg, (char **)NULL, 10) : 0;
                if (n <= 0) n = 5; /* default interval: 5 seconds */
#ifdef HAVE_NCURSES
                sess->watch_mode     = 1;
                sess->watch_interval = n;
                setOutputStyle(4);
#else
                fprintf(stderr,
                    "\nLFT: Support for nCurses was not enabled at compile-time.\n"
                    "     Please re-run ./configure and rebuild with --with-ncurses\n"
                    "     if ncurses is not found automatically by autoconf.\n\n");
                exit(EXIT_FAILURE);
#endif
                break;
            }
            case OPT_HELP:
                usage(sess, argv[0]);
                break;
            default:
                usage(sess, argv[0]);
        }
            
    /* rtt_stats: apply probe count to retry_min/retry_max (unless user explicitly set them) */
    if (sess->rtt_stats) {
        if (!user_set_retry_min) sess->retry_min = sess->rtt_stats;
        if (!user_set_retry_max) sess->retry_max = sess->rtt_stats;
        if (sess->retry_max < sess->retry_min) sess->retry_max = sess->retry_min;
        /* auto ahead_limit = 2 × retry_min so the pipeline keeps flowing without
         * excessive target overrun while collecting multi-probe RTT samples */
        sess->ahead_limit = sess->retry_min * 2;
    }

    if((argc - optind) < 1)
	usage(sess, argv[0]);
        
    if (sess->noisy && !outputStyleIsXML() && !outputStyleIsGraphViz() && !outputStyleIsASCII())
        printf ("Layer Four Traceroute (LFT) version %s", version);
    if (sess->noisy > 1 && !outputStyleIsXML() && !outputStyleIsGraphViz() && !outputStyleIsASCII())
        printf (" ... (verbosity level %d)",sess->noisy);
    if (sess->noisy && !outputStyleIsXML() && !outputStyleIsGraphViz() && !outputStyleIsASCII())
        printf ("\n");
	if(outputStyleIsXML())
	{
		printf("<lft verbositylevel=\"%d\">\n",sess->noisy);
	}
    
    sess->hostname = argv[optind++];
    sess->hostname_lsrr_size = 0;
    while (optind < argc) {
        sess->hostname_lsrr[sess->hostname_lsrr_size++] = argv[optind++];
        if (sess->hostname_lsrr_size > IP_LSRR_DEST) {
			if(outputStyleIsXML())
			{
				printf("<error>Unknown host: Too many LSRR hosts - maximum is 8</error>");
				printf("</lft>\n");
			}
			else
			{
				fprintf(stderr, "LFT: Too many LSRR hosts - maximum is 8\n");
			}
            exit(EXIT_FAILURE);
        }
    }
    if (sess->hostname_lsrr_size > 0) {
        sess->hostname_lsrr[sess->hostname_lsrr_size++] = sess->hostname;
        sess->hostname = sess->hostname_lsrr[0];
    }
    
    /* allow hostname:port syntax when -d not specified */
    if ((cp = strchr(sess->hostname, ':'))) {
        if (!sess->dflag) {
            *cp++ = '\0';
            sess->dport = lft_resolve_port(sess, cp);
            if (sess->dport > 65534) {
                if(outputStyleIsXML())
                    printf("<warning>Starting port %d is too high.  Will use %d instead.</warning>",
                           sess->dport, 65534);
                else
                    fprintf(stderr,
                            "LFT warning: Starting port %d is too high.  Will use %d instead.\n",
                            sess->dport, 65534);
                sess->dport = 65534;
            }
            sess->auto_ports = 0;
        }
    }
    {
        char *binpath = realpath(argv[0], NULL);
        lft_check_permissions(binpath ? binpath : argv[0]);
        if (binpath) free(binpath);
    }

#ifdef HAVE_NCURSES
    if (sess->watch_mode) {
        WatchModeRun(sess);
    } else {
#endif
        if (getOutputStyle() == 3)
            lft_o_spinner_start(sess);   /* start live probe counter for -o */
        LFTExecute(sess);
#ifdef HAVE_NCURSES
    }
#endif

    LFTSessionClose(sess);
#if defined( __CYGWIN__ ) || defined( WIN32 ) || defined(_WIN32)
    WSACleanup();
#endif
	if(outputStyleIsXML())
		printf("</lft>\n");
	//getch();
    return 0;
}
