From 0d47952611198ef6b1163f366dc03922d20b1475 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:42:04 +0200 Subject: Adding upstream version 7.94+git20230807.3be01efb1+dfsg. Signed-off-by: Daniel Baumann --- nmap_tty.cc | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 nmap_tty.cc (limited to 'nmap_tty.cc') diff --git a/nmap_tty.cc b/nmap_tty.cc new file mode 100644 index 0000000..0f2b5ff --- /dev/null +++ b/nmap_tty.cc @@ -0,0 +1,325 @@ +/*************************************************************************** + * nmap_tty.cc -- Handles runtime interaction with Nmap, so you can * + * increase verbosity/debugging or obtain a status line upon request. * + * * + ***********************IMPORTANT NMAP LICENSE TERMS************************ + * + * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap + * Project"). Nmap is also a registered trademark of the Nmap Project. + * + * This program is distributed under the terms of the Nmap Public Source + * License (NPSL). The exact license text applying to a particular Nmap + * release or source code control revision is contained in the LICENSE + * file distributed with that version of Nmap or source code control + * revision. More Nmap copyright/legal information is available from + * https://nmap.org/book/man-legal.html, and further information on the + * NPSL license itself can be found at https://nmap.org/npsl/ . This + * header summarizes some key points from the Nmap license, but is no + * substitute for the actual license text. + * + * Nmap is generally free for end users to download and use themselves, + * including commercial use. It is available from https://nmap.org. + * + * The Nmap license generally prohibits companies from using and + * redistributing Nmap in commercial products, but we sell a special Nmap + * OEM Edition with a more permissive license and special features for + * this purpose. See https://nmap.org/oem/ + * + * If you have received a written Nmap license agreement or contract + * stating terms other than these (such as an Nmap OEM license), you may + * choose to use and redistribute Nmap under those terms instead. + * + * The official Nmap Windows builds include the Npcap software + * (https://npcap.com) for packet capture and transmission. It is under + * separate license terms which forbid redistribution without special + * permission. So the official Nmap Windows builds may not be redistributed + * without special permission (such as an Nmap OEM license). + * + * Source is provided to this software because we believe users have a + * right to know exactly what a program is going to do before they run it. + * This also allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to submit your changes as a Github PR + * or by email to the dev@nmap.org mailing list for possible incorporation into + * the main distribution. Unless you specify otherwise, it is understood that + * you are offering us very broad rights to use your submissions as described in + * the Nmap Public Source License Contributor Agreement. This is important + * because we fund the project by selling licenses with various terms, and also + * because the inability to relicense code has caused devastating problems for + * other Free Software projects (such as KDE and NASM). + * + * The free version of Nmap 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. Warranties, + * indemnification and commercial support are all available through the + * Npcap OEM program--see https://nmap.org/oem/ + * + ***************************************************************************/ + +#ifndef WIN32 +#include "nmap_config.h" +#endif + +#include "nmap.h" + +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#if HAVE_TERMIOS_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "nmap_tty.h" +#include "NmapOps.h" + +extern NmapOps o; + +#ifdef WIN32 +#include + +// Microsoft's runtime makes this fairly simple. :) +void tty_init() { return; } +static int tty_getchar() { return _kbhit() ? _getch() : -1; } +static void tty_done() { return; } + +static void tty_flush(void) +{ + static HANDLE stdinput = GetStdHandle(STD_INPUT_HANDLE); + + FlushConsoleInputBuffer(stdinput); +} + +#else //!win32 +#include +#if !defined(O_NONBLOCK) && defined(O_NDELAY) +#define O_NONBLOCK O_NDELAY +#endif + +#ifdef __CYGWIN32__ +#include +#include +#ifndef __CYGWIN__ +extern int tcgetattr(int fd, struct termios *termios_p); +extern int tcsetattr(int fd, int actions, struct termios *termios_p); +#endif +#endif + +static int tty_fd = 0; +static struct termios saved_ti; + +static int tty_getchar() +{ + int c, numChars; +#ifdef __CYGWIN32__ + fd_set set; + struct timeval tv; +#endif + + if (tty_fd && tcgetpgrp(tty_fd) == getpgrp()) { + + // This is so that when the terminal has been disconnected, it will be + // reconnected when possible. If it slows things down, just remove it + // tty_init(); + +#ifdef __CYGWIN32__ + FD_ZERO(&set); FD_SET(tty_fd, &set); + tv.tv_sec = 0; tv.tv_usec = 0; + if (select(tty_fd + 1, &set, NULL, NULL, &tv) <= 0) + return -1; +#endif + c = 0; + numChars = read(tty_fd, &c, 1); + if (numChars > 0) return c; + } + + return -1; +} + +static void tty_done() +{ + if (!tty_fd) return; + + tcsetattr(tty_fd, TCSANOW, &saved_ti); + + close(tty_fd); + tty_fd = 0; +} + +static void tty_flush(void) +{ + /* we don't need to test for tty_fd==0 here because + * this isn't called unless we succeeded + */ + + tcflush(tty_fd, TCIFLUSH); +} + +static void install_handler(int signo, void (*handler) (int signo)) +{ + struct sigaction sa; + sa.sa_handler = handler; + sigfillset(&sa.sa_mask); /* block all signals during handler execution */ + sa.sa_flags = 0; + sigaction(signo, &sa, NULL); +} + +static void shutdown_clean(int signo) +{ + sigset_t set; + +/* We reinstall the default handler and call tty_done */ + install_handler(signo, SIG_DFL); + tty_done(); + +/* Unblock signo and raise it (thus allowing the default handler to occur) */ + sigemptyset(&set); + sigaddset(&set, signo); + sigprocmask(SIG_UNBLOCK, &set, NULL); + raise(signo); /* This _should_ kill us */ + _exit(EXIT_FAILURE); /* If it does not */ +} + +static void install_all_handlers() { + install_handler(SIGINT, shutdown_clean); + install_handler(SIGTERM, shutdown_clean); + install_handler(SIGQUIT, shutdown_clean); +} + +/* + * Initializes the terminal for unbuffered non-blocking input. Also + * registers tty_done() via atexit(). You need to call this before + * you ever call keyWasPressed(). + */ +void tty_init() +{ + struct termios ti; + + if(o.noninteractive) + return; + + install_all_handlers(); + + if (tty_fd) + return; + + if ((tty_fd = open("/dev/tty", O_RDONLY | O_NONBLOCK)) < 0) { + o.noninteractive = true; + return; + } + +#ifndef __CYGWIN32__ + if (tcgetpgrp(tty_fd) != getpgrp()) { + close(tty_fd); return; + } +#endif + + tcgetattr(tty_fd, &ti); + saved_ti = ti; + ti.c_lflag &= ~(ICANON | ECHO); + ti.c_cc[VMIN] = 1; + ti.c_cc[VTIME] = 0; + tcsetattr(tty_fd, TCSANOW, &ti); + + atexit(tty_done); +} + +#endif //!win32 + +/* Catches all of the predefined + keypresses and interpret them, and it will also tell you if you + should print anything. A value of true being returned means a + nonstandard key has been pressed and the calling method should + print a status message */ +bool keyWasPressed() +{ + /* Where we keep the automatic stats printing schedule. */ + static struct timeval stats_time = { 0 }; + int c; + + if (o.noninteractive) + return false; + + if ((c = tty_getchar()) >= 0) { + tty_flush(); /* flush input queue */ + + // printf("You pressed key '%c'!\n", c); + if (c == 'v') { + if (o.verbose < 10) o.verbose++; + log_write(LOG_STDOUT, "Verbosity Increased to %d.\n", o.verbose); + } else if (c == 'V') { + if (o.verbose > 0) o.verbose--; + log_write(LOG_STDOUT, "Verbosity Decreased to %d.\n", o.verbose); + } else if (c == 'd') { + if (o.debugging < 10) o.debugging++; + log_write(LOG_STDOUT, "Debugging Increased to %d.\n", o.debugging); + } else if (c == 'D') { + if (o.debugging > 0) o.debugging--; + log_write(LOG_STDOUT, "Debugging Decreased to %d.\n", o.debugging); + } else if (c == 'p') { + o.setPacketTrace(true); + log_write(LOG_STDOUT, "Packet Tracing enabled.\n"); + } else if (c == 'P') { + o.setPacketTrace(false); + log_write(LOG_STDOUT, "Packet Tracing disabled.\n"); + } else if (c == '?') { + log_write(LOG_STDOUT, + "Interactive keyboard commands:\n" + "? Display this information\n" + "v/V Increase/decrease verbosity\n" + "d/D Increase/decrease debugging\n" + "p/P Enable/disable packet tracing\n" + "anything else Print status\n" + "More help: https://nmap.org/book/man-runtime-interaction.html\n"); + } else { + printStatusMessage(); + return true; + } + } + + /* Check if we need to print a status update according to the --stats-every + option. */ + if (o.stats_interval != 0.0) { + struct timeval now; + + gettimeofday(&now, NULL); + if (stats_time.tv_sec == 0) { + /* Initialize the scheduled stats time. */ + stats_time = *o.getStartTime(); + TIMEVAL_ADD(stats_time, stats_time, (time_t) (o.stats_interval * 1000000)); + } + + if (TIMEVAL_AFTER(now, stats_time)) { + /* Advance to the next print time. */ + TIMEVAL_ADD(stats_time, stats_time, (time_t) (o.stats_interval * 1000000)); + /* If it's still in the past, catch it up to the present, + * plus half a second to avoid double-printing without any progress. */ + if (TIMEVAL_AFTER(now, stats_time)) + TIMEVAL_MSEC_ADD(stats_time, now, 500); + printStatusMessage(); + /* Instruct the caller to print status too. */ + return true; + } + } + + return false; +} -- cgit v1.2.3