1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-16 04:39:03 +00:00

make a ton of global symbols static

This commit is contained in:
fyodor
2006-03-05 23:59:46 +00:00
parent 7224f4a52d
commit 76ab1500b3
25 changed files with 2982 additions and 3194 deletions

View File

@@ -1,4 +1,14 @@
# Nmap Changelog ($Id$); -*-text-*-
o Made some changes to various Nmap initialization functions which
help ALT Linux (altlinux.org) developers run Nmap in a chroot
environment. Thanks to Dmitry V. Levin (ldv(a)altlinux.org) for the
patch.
o Cleaned up the code a bit by making a bunch (nearly 100) global
symols (mostly function calls) static. I was also able to removed
some unused functions. Thanks to Dmitry V. Levin (ldv(a)altlinux.org)
for sending a list of candidate symbols.
Nmap 4.02ALPHA1
o Added the --log-errors option, which causes most warnings and error

View File

@@ -117,8 +117,6 @@ struct MAC_hash_table {
struct MAC_entry **table;
} MacTable;
static int initialized = 0;
static inline int MacCharPrefix2Key(const u8 *prefix) {
return (prefix[0] << 16) + (prefix[1] << 8) + prefix[2];
}
@@ -130,7 +128,8 @@ static inline int MACTableHash(int prefix, int table_capacity) {
return prefix % table_capacity;
}
void InitializeTable() {
void mac_prefix_init() {
static int initialized = 0;
if (initialized) return;
initialized = 1;
char filename[256];
@@ -196,7 +195,7 @@ void InitializeTable() {
}
struct MAC_entry *findMACEntry(int prefix) {
static struct MAC_entry *findMACEntry(int prefix) {
int pos = MACTableHash(prefix, MacTable.table_capacity);
while (MacTable.table[pos]) {
@@ -216,7 +215,7 @@ const char *MACPrefix2Corp(const u8 *prefix) {
struct MAC_entry *ent;
if (!prefix) fatal("MACPrefix2Corp called with a NULL prefix");
if (!initialized) InitializeTable();
mac_prefix_init();
ent = findMACEntry(MacCharPrefix2Key(prefix));
return (ent)? ent->vendor : NULL;
@@ -231,7 +230,7 @@ const char *MACPrefix2Corp(const u8 *prefix) {
bool MACCorp2Prefix(const char *vendorstr, u8 *mac_data) {
if (!vendorstr) fatal("%s: vendorstr is NULL", __FUNCTION__);
if (!mac_data) fatal("%s: mac_data is NULL", __FUNCTION__);
if (!initialized) InitializeTable();
mac_prefix_init();
for(int i = 0; i < MacTable.table_capacity; i++ ) {
if (MacTable.table[i])

View File

@@ -107,11 +107,13 @@ static char *charpool[16];
static int currentcharpool;
static int currentcharpoolsz;
static char *nextchar;
static int charpool_initialized = 0;
#define ALIGN_ON sizeof(char *)
static int cp_init(void) {
static int charpool_initialized = 0;
if (charpool_initialized) return 0;
/* Create our char pool */
currentcharpool = 0;
currentcharpoolsz = 16384;
@@ -135,7 +137,7 @@ void *cp_alloc(int sz) {
char *p;
int modulus;
if (!charpool_initialized) cp_init();
cp_init();
if ((modulus = sz % ALIGN_ON))
sz += ALIGN_ON - modulus;
@@ -159,7 +161,6 @@ char *q;
char *end;
int modulus;
if (!charpool_initialized)
cp_init();
end = charpool[currentcharpool] + currentcharpoolsz;

View File

@@ -154,7 +154,7 @@ struct idle_proxy_info {
Proxy timing is adjusted, but proxy->latestid is NOT ADJUSTED --
you'll have to do that yourself. Probes_sent is set to the number
of probe packets sent during execution */
int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent,
static int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent,
int *probes_rcvd) {
struct timeval tv_end;
int tries = 0;
@@ -248,7 +248,7 @@ int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent,
one, assuming the given IPID Sequencing class. Returns -1 if the
distance cannot be determined */
int ipid_distance(int seqclass , u16 startid, u16 endid) {
static int ipid_distance(int seqclass , u16 startid, u16 endid) {
if (seqclass == IPID_SEQ_INCR)
return endid - startid;
@@ -279,7 +279,7 @@ static void initialize_proxy_struct(struct idle_proxy_info *proxy) {
proxy is determined to be unsuitable, the function whines and exits
the program */
#define NUM_IPID_PROBES 6
void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
const struct in_addr *first_target) {
int probes_sent = 0, probes_returned = 0;
int hardtimeout = 9000000; /* Generally don't wait more than 9 secs total */
@@ -378,7 +378,7 @@ void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
proxy->ethptr = &proxy->eth;
} else {
if ((proxy->rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0 )
pfatal("socket trobles in get_fingerprint");
pfatal("socket trobles in %s", __FUNCTION__);
unblock_socket(proxy->rawsd);
broadcast_socket(proxy->rawsd);
#ifndef WIN32
@@ -560,7 +560,7 @@ void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
count of 'testcount' while the 'realcount' is as given. If the
testcount was correct, timing is made more aggressive, while it is
slowed down in the case of an error */
void adjust_idle_timing(struct idle_proxy_info *proxy,
static void adjust_idle_timing(struct idle_proxy_info *proxy,
Target *target, int testcount,
int realcount) {
@@ -622,7 +622,7 @@ void adjust_idle_timing(struct idle_proxy_info *proxy,
They can be NULL if you don't want to use them. The purpose is for
timing adjustments if the numbers turn out to be accurate */
int idlescan_countopen2(struct idle_proxy_info *proxy,
static int idlescan_countopen2(struct idle_proxy_info *proxy,
Target *target, u16 *ports, int numports,
struct timeval *sent_time, struct timeval *rcv_time)
{
@@ -777,7 +777,7 @@ int idlescan_countopen2(struct idle_proxy_info *proxy,
/* The job of this function is to use the Idlescan technique to count
the number of open ports in the given list. Under the covers, this
function just farms out the hard work to another function */
int idlescan_countopen(struct idle_proxy_info *proxy,
static int idlescan_countopen(struct idle_proxy_info *proxy,
Target *target, u16 *ports, int numports,
struct timeval *sent_time, struct timeval *rcv_time) {
int tries = 0;
@@ -818,7 +818,7 @@ int idlescan_countopen(struct idle_proxy_info *proxy,
/* Recursively Idlescans scans a group of ports using a depth-first
divide-and-conquer strategy to find the open one(s) */
int idle_treescan(struct idle_proxy_info *proxy, Target *target,
static int idle_treescan(struct idle_proxy_info *proxy, Target *target,
u16 *ports, int numports, int expectedopen) {
int firstHalfSz = (numports + 1)/2;

481
nmap.cc
View File

@@ -192,6 +192,240 @@ static int parse_bounce_argument(struct ftpinfo *ftp, char *url) {
return 1;
}
static void printusage(char *name, int rc) {
printf("%s %s ( %s )\n"
"Usage: nmap [Scan Type(s)] [Options] {target specification}\n"
"TARGET SPECIFICATION:\n"
" Can pass hostnames, IP addresses, networks, etc.\n"
" Ex: scanme.nmap.org, microsoft.com/24, 192.168.0.1; 10.0.0-255.1-254\n"
" -iL <inputfilename>: Input from list of hosts/networks\n"
" -iR <num hosts>: Choose random targets\n"
" --exclude <host1[,host2][,host3],...>: Exclude hosts/networks\n"
" --excludefile <exclude_file>: Exclude list from file\n"
"HOST DISCOVERY:\n"
" -sL: List Scan - simply list targets to scan\n"
" -sP: Ping Scan - go no further than determining if host is online\n"
" -P0: Treat all hosts as online -- skip host discovery\n"
" -PS/PA/PU [portlist]: TCP SYN/ACK or UDP discovery to given ports\n"
" -PE/PP/PM: ICMP echo, timestamp, and netmask request discovery probes\n"
" -n/-R: Never do DNS resolution/Always resolve [default: sometimes]\n"
" --dns-servers <serv1[,serv2],...>: Specify custom DNS servers\n"
" --system-dns: Use OS's DNS resolver\n"
"SCAN TECHNIQUES:\n"
" -sS/sT/sA/sW/sM: TCP SYN/Connect()/ACK/Window/Maimon scans\n"
" -sN/sF/sX: TCP Null, FIN, and Xmas scans\n"
" --scanflags <flags>: Customize TCP scan flags\n"
" -sI <zombie host[:probeport]>: Idlescan\n"
" -sO: IP protocol scan\n"
" -b <ftp relay host>: FTP bounce scan\n"
"PORT SPECIFICATION AND SCAN ORDER:\n"
" -p <port ranges>: Only scan specified ports\n"
" Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080\n"
" -F: Fast - Scan only the ports listed in the nmap-services file)\n"
" -r: Scan ports consecutively - don't randomize\n"
"SERVICE/VERSION DETECTION:\n"
" -sV: Probe open ports to determine service/version info\n"
" --version-intensity <level>: Set from 0 (light) to 9 (try all probes)\n"
" --version-light: Limit to most likely probes (intensity 2)\n"
" --version-all: Try every single probe (intensity 9)\n"
" --version-trace: Show detailed version scan activity (for debugging)\n"
"OS DETECTION:\n"
" -O: Enable OS detection\n"
" --osscan-limit: Limit OS detection to promising targets\n"
" --osscan-guess: Guess OS more aggressively\n"
"TIMING AND PERFORMANCE:\n"
" Options which take <time> are in milliseconds, unless you append 's'\n"
" (seconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30m).\n"
" -T[0-5]: Set timing template (higher is faster)\n"
" --min-hostgroup/max-hostgroup <size>: Parallel host scan group sizes\n"
" --min-parallelism/max-parallelism <time>: Probe parallelization\n"
" --min-rtt-timeout/max-rtt-timeout/initial-rtt-timeout <time>: Specifies\n"
" probe round trip time.\n"
" --max-retries <tries>: Caps number of port scan probe retransmissions.\n"
" --host-timeout <time>: Give up on target after this long\n"
" --scan-delay/--max-scan-delay <time>: Adjust delay between probes\n"
"FIREWALL/IDS EVASION AND SPOOFING:\n"
" -f; --mtu <val>: fragment packets (optionally w/given MTU)\n"
" -D <decoy1,decoy2[,ME],...>: Cloak a scan with decoys\n"
" -S <IP_Address>: Spoof source address\n"
" -e <iface>: Use specified interface\n"
" -g/--source-port <portnum>: Use given port number\n"
" --data-length <num>: Append random data to sent packets\n"
" --ttl <val>: Set IP time-to-live field\n"
" --spoof-mac <mac address/prefix/vendor name>: Spoof your MAC address\n"
" --badsum: Send packets with a bogus TCP/UDP checksum\n"
"OUTPUT:\n"
" -oN/-oX/-oS/-oG <file>: Output scan in normal, XML, s|<rIpt kIddi3,\n"
" and Grepable format, respectively, to the given filename.\n"
" -oA <basename>: Output in the three major formats at once\n"
" -v: Increase verbosity level (use twice for more effect)\n"
" -d[level]: Set or increase debugging level (Up to 9 is meaningful)\n"
" --packet-trace: Show all packets sent and received\n"
" --iflist: Print host interfaces and routes (for debugging)\n"
" --log-errors: Log errors/warnings to the normal-format output file\n"
" --append-output: Append to rather than clobber specified output files\n"
" --resume <filename>: Resume an aborted scan\n"
" --stylesheet <path/URL>: XSL stylesheet to transform XML output to HTML\n"
" --webxml: Reference stylesheet from Insecure.Org for more portable XML\n"
" --no-stylesheet: Prevent associating of XSL stylesheet w/XML output\n"
"MISC:\n"
" -6: Enable IPv6 scanning\n"
" -A: Enables OS detection and Version detection\n"
" --datadir <dirname>: Specify custom Nmap data file location\n"
" --send-eth/--send-ip: Send using raw ethernet frames or IP packets\n"
" --privileged: Assume that the user is fully privileged\n"
" -V: Print version number\n"
" -h: Print this help summary page.\n"
"EXAMPLES:\n"
" nmap -v -A scanme.nmap.org\n"
" nmap -v -sP 192.168.0.0/16 10.0.0.0/8\n"
" nmap -v -iR 10000 -P0 -p 80\n"
"SEE THE MAN PAGE FOR MANY MORE OPTIONS, DESCRIPTIONS, AND EXAMPLES\n", NMAP_NAME, NMAP_VERSION, NMAP_URL);
exit(rc);
}
/**
* Returns 1 if this is a reserved IP address, where "reserved" means
* either a private address, non-routable address, or even a non-reserved
* but unassigned address which has an extremely high probability of being
* black-holed.
*
* We try to optimize speed when ordering the tests. This optimization
* assumes that all byte values are equally likely in the input.
*
* Warning: This function could easily become outdated if the IANA
* starts to assign some more IPv4 ranges to RIPE, etc. as they have
* started doing this year (2001), for example 80.0.0.0/4 used to be
* completely unassigned until they gave 80.0.0.0/7 to RIPE in April
* 2001 (www.junk.org is an example of a new address in this range).
*
* Check <http://www.iana.org/assignments/ipv4-address-space> for
* the most recent assigments and
* <http://www.cymru.com/Documents/bogon-bn-nonagg.txt> for bogon
* netblocks.
*/
static int ip_is_reserved(struct in_addr *ip)
{
char *ipc = (char *) &(ip->s_addr);
unsigned char i1 = ipc[0], i2 = ipc[1], i3 = ipc[2], i4 = ipc[3];
/* do all the /7's and /8's with a big switch statement, hopefully the
* compiler will be able to optimize this a little better using a jump table
* or what have you
*/
switch (i1)
{
case 0: /* 000/8 is IANA reserved */
case 1: /* 001/8 is IANA reserved */
case 2: /* 002/8 is IANA reserved */
case 5: /* 005/8 is IANA reserved */
case 6: /* USA Army ISC */
case 7: /* used for BGP protocol */
case 10: /* the infamous 10.0.0.0/8 */
case 23: /* 023/8 is IANA reserved */
case 27: /* 027/8 is IANA reserved */
case 31: /* 031/8 is IANA reserved */
case 36: /* 036/8 is IANA reserved */
case 37: /* 037/8 is IANA reserved */
case 39: /* 039/8 is IANA reserved */
case 42: /* 042/8 is IANA reserved */
case 49: /* 049/8 is IANA reserved */
case 50: /* 050/8 is IANA reserved */
case 55: /* misc. U.S.A. Armed forces */
case 127: /* 127/8 is reserved for loopback */
case 197: /* 197/8 is IANA reserved */
case 223: /* 223/8 is IANA reserved */
return 1;
default:
break;
}
/* 077-079/8 is IANA reserved */
if (i1 >= 77 && i1 <= 79)
return 1;
/* 092-123/8 is IANA reserved */
if (i1 >= 92 && i1 <= 123)
return 1;
/* 172.16.0.0/12 is reserved for private nets by RFC1819 */
if (i1 == 172 && i2 >= 16 && i2 <= 31)
return 1;
/* 173-187/8 is IANA reserved */
if (i1 >= 173 && i1 <= 187)
return 1;
/* 192.168.0.0/16 is reserved for private nets by RFC1819 */
/* 192.0.2.0/24 is reserved for documentation and examples */
/* 192.88.99.0/24 is used as 6to4 Relay anycast prefix by RFC3068 */
if (i1 == 192) {
if (i2 == 168)
return 1;
if (i2 == 0 && i3 == 2)
return 1;
if (i2 == 88 && i3 == 99)
return 1;
}
/* 198.18.0.0/15 is used for benchmark tests by RFC2544 */
if (i1 == 198 && i2 == 18 && i3 >= 1 && i3 <= 64) {
return 1;
}
/* reserved for DHCP clients seeking addresses, not routable outside LAN */
if (i1 == 169 && i2 == 254)
return 1;
/* believe it or not, 204.152.64.0/23 is some bizarre Sun proprietary
* clustering thing */
if (i1 == 204 && i2 == 152 && (i3 == 64 || i3 == 65))
return 1;
/* 224-239/8 is all multicast stuff */
/* 240-255/8 is IANA reserved */
if (i1 >= 224)
return 1;
/* 255.255.255.255, note we already tested for i1 in this range */
if (i2 == 255 && i3 == 255 && i4 == 255)
return 1;
return 0;
}
static char *grab_next_host_spec(FILE *inputfd, int argc, char **fakeargv) {
static char host_spec[1024];
unsigned int host_spec_index;
int ch;
struct in_addr ip;
if (o.generate_random_ips) {
do {
ip.s_addr = get_random_u32();
} while (ip_is_reserved(&ip));
Strncpy(host_spec, inet_ntoa(ip), sizeof(host_spec));
} else if (!inputfd) {
return( (optind < argc)? fakeargv[optind++] : NULL);
} else {
host_spec_index = 0;
while((ch = getc(inputfd)) != EOF) {
if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t' || ch == '\0') {
if (host_spec_index == 0) continue;
host_spec[host_spec_index] = '\0';
return host_spec;
} else if (host_spec_index < sizeof(host_spec) / sizeof(char) -1) {
host_spec[host_spec_index++] = (char) ch;
} else fatal("One of the host_specifications from your input file is too long (> %d chars)", (int) sizeof(host_spec));
}
host_spec[host_spec_index] = '\0';
}
if (!*host_spec) return NULL;
return host_spec;
}
int nmap_main(int argc, char *argv[]) {
char *p, *q;
int i, arg;
@@ -1629,98 +1863,6 @@ struct scan_lists *getpts(char *origexpr) {
return ports;
}
void printusage(char *name, int rc) {
printf("%s %s ( %s )\n"
"Usage: nmap [Scan Type(s)] [Options] {target specification}\n"
"TARGET SPECIFICATION:\n"
" Can pass hostnames, IP addresses, networks, etc.\n"
" Ex: scanme.nmap.org, microsoft.com/24, 192.168.0.1; 10.0.0-255.1-254\n"
" -iL <inputfilename>: Input from list of hosts/networks\n"
" -iR <num hosts>: Choose random targets\n"
" --exclude <host1[,host2][,host3],...>: Exclude hosts/networks\n"
" --excludefile <exclude_file>: Exclude list from file\n"
"HOST DISCOVERY:\n"
" -sL: List Scan - simply list targets to scan\n"
" -sP: Ping Scan - go no further than determining if host is online\n"
" -P0: Treat all hosts as online -- skip host discovery\n"
" -PS/PA/PU [portlist]: TCP SYN/ACK or UDP discovery to given ports\n"
" -PE/PP/PM: ICMP echo, timestamp, and netmask request discovery probes\n"
" -n/-R: Never do DNS resolution/Always resolve [default: sometimes]\n"
" --dns-servers <serv1[,serv2],...>: Specify custom DNS servers\n"
" --system-dns: Use OS's DNS resolver\n"
"SCAN TECHNIQUES:\n"
" -sS/sT/sA/sW/sM: TCP SYN/Connect()/ACK/Window/Maimon scans\n"
" -sN/sF/sX: TCP Null, FIN, and Xmas scans\n"
" --scanflags <flags>: Customize TCP scan flags\n"
" -sI <zombie host[:probeport]>: Idlescan\n"
" -sO: IP protocol scan\n"
" -b <ftp relay host>: FTP bounce scan\n"
"PORT SPECIFICATION AND SCAN ORDER:\n"
" -p <port ranges>: Only scan specified ports\n"
" Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080\n"
" -F: Fast - Scan only the ports listed in the nmap-services file)\n"
" -r: Scan ports consecutively - don't randomize\n"
"SERVICE/VERSION DETECTION:\n"
" -sV: Probe open ports to determine service/version info\n"
" --version-intensity <level>: Set from 0 (light) to 9 (try all probes)\n"
" --version-light: Limit to most likely probes (intensity 2)\n"
" --version-all: Try every single probe (intensity 9)\n"
" --version-trace: Show detailed version scan activity (for debugging)\n"
"OS DETECTION:\n"
" -O: Enable OS detection\n"
" --osscan-limit: Limit OS detection to promising targets\n"
" --osscan-guess: Guess OS more aggressively\n"
"TIMING AND PERFORMANCE:\n"
" Options which take <time> are in milliseconds, unless you append 's'\n"
" (seconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30m).\n"
" -T[0-5]: Set timing template (higher is faster)\n"
" --min-hostgroup/max-hostgroup <size>: Parallel host scan group sizes\n"
" --min-parallelism/max-parallelism <time>: Probe parallelization\n"
" --min-rtt-timeout/max-rtt-timeout/initial-rtt-timeout <time>: Specifies\n"
" probe round trip time.\n"
" --max-retries <tries>: Caps number of port scan probe retransmissions.\n"
" --host-timeout <time>: Give up on target after this long\n"
" --scan-delay/--max-scan-delay <time>: Adjust delay between probes\n"
"FIREWALL/IDS EVASION AND SPOOFING:\n"
" -f; --mtu <val>: fragment packets (optionally w/given MTU)\n"
" -D <decoy1,decoy2[,ME],...>: Cloak a scan with decoys\n"
" -S <IP_Address>: Spoof source address\n"
" -e <iface>: Use specified interface\n"
" -g/--source-port <portnum>: Use given port number\n"
" --data-length <num>: Append random data to sent packets\n"
" --ttl <val>: Set IP time-to-live field\n"
" --spoof-mac <mac address/prefix/vendor name>: Spoof your MAC address\n"
" --badsum: Send packets with a bogus TCP/UDP checksum\n"
"OUTPUT:\n"
" -oN/-oX/-oS/-oG <file>: Output scan in normal, XML, s|<rIpt kIddi3,\n"
" and Grepable format, respectively, to the given filename.\n"
" -oA <basename>: Output in the three major formats at once\n"
" -v: Increase verbosity level (use twice for more effect)\n"
" -d[level]: Set or increase debugging level (Up to 9 is meaningful)\n"
" --packet-trace: Show all packets sent and received\n"
" --iflist: Print host interfaces and routes (for debugging)\n"
" --log-errors: Log errors/warnings to the normal-format output file\n"
" --append-output: Append to rather than clobber specified output files\n"
" --resume <filename>: Resume an aborted scan\n"
" --stylesheet <path/URL>: XSL stylesheet to transform XML output to HTML\n"
" --webxml: Reference stylesheet from Insecure.Org for more portable XML\n"
" --no-stylesheet: Prevent associating of XSL stylesheet w/XML output\n"
"MISC:\n"
" -6: Enable IPv6 scanning\n"
" -A: Enables OS detection and Version detection\n"
" --datadir <dirname>: Specify custom Nmap data file location\n"
" --send-eth/--send-ip: Send using raw ethernet frames or IP packets\n"
" --privileged: Assume that the user is fully privileged\n"
" -V: Print version number\n"
" -h: Print this help summary page.\n"
"EXAMPLES:\n"
" nmap -v -A scanme.nmap.org\n"
" nmap -v -sP 192.168.0.0/16 10.0.0.0/8\n"
" nmap -v -iR 10000 -P0 -p 80\n"
"SEE THE MAN PAGE FOR MANY MORE OPTIONS, DESCRIPTIONS, AND EXAMPLES\n", NMAP_NAME, NMAP_VERSION, NMAP_URL);
exit(rc);
}
void printinteractiveusage() {
printf(
@@ -1819,148 +1961,7 @@ char *tsseqclass2ascii(int seqclass) {
}
/**
* Returns 1 if this is a reserved IP address, where "reserved" means
* either a private address, non-routable address, or even a non-reserved
* but unassigned address which has an extremely high probability of being
* black-holed.
*
* We try to optimize speed when ordering the tests. This optimization
* assumes that all byte values are equally likely in the input.
*
* Warning: This function could easily become outdated if the IANA
* starts to assign some more IPv4 ranges to RIPE, etc. as they have
* started doing this year (2001), for example 80.0.0.0/4 used to be
* completely unassigned until they gave 80.0.0.0/7 to RIPE in April
* 2001 (www.junk.org is an example of a new address in this range).
*
* Check <http://www.iana.org/assignments/ipv4-address-space> for
* the most recent assigments and
* <http://www.cymru.com/Documents/bogon-bn-nonagg.txt> for bogon
* netblocks.
*/
int ip_is_reserved(struct in_addr *ip)
{
char *ipc = (char *) &(ip->s_addr);
unsigned char i1 = ipc[0], i2 = ipc[1], i3 = ipc[2], i4 = ipc[3];
/* do all the /7's and /8's with a big switch statement, hopefully the
* compiler will be able to optimize this a little better using a jump table
* or what have you
*/
switch (i1)
{
case 0: /* 000/8 is IANA reserved */
case 1: /* 001/8 is IANA reserved */
case 2: /* 002/8 is IANA reserved */
case 5: /* 005/8 is IANA reserved */
case 6: /* USA Army ISC */
case 7: /* used for BGP protocol */
case 10: /* the infamous 10.0.0.0/8 */
case 23: /* 023/8 is IANA reserved */
case 27: /* 027/8 is IANA reserved */
case 31: /* 031/8 is IANA reserved */
case 36: /* 036/8 is IANA reserved */
case 37: /* 037/8 is IANA reserved */
case 39: /* 039/8 is IANA reserved */
case 42: /* 042/8 is IANA reserved */
case 49: /* 049/8 is IANA reserved */
case 50: /* 050/8 is IANA reserved */
case 55: /* misc. U.S.A. Armed forces */
case 127: /* 127/8 is reserved for loopback */
case 197: /* 197/8 is IANA reserved */
case 223: /* 223/8 is IANA reserved */
return 1;
default:
break;
}
/* 077-079/8 is IANA reserved */
if (i1 >= 77 && i1 <= 79)
return 1;
/* 092-123/8 is IANA reserved */
if (i1 >= 92 && i1 <= 123)
return 1;
/* 172.16.0.0/12 is reserved for private nets by RFC1819 */
if (i1 == 172 && i2 >= 16 && i2 <= 31)
return 1;
/* 173-187/8 is IANA reserved */
if (i1 >= 173 && i1 <= 187)
return 1;
/* 192.168.0.0/16 is reserved for private nets by RFC1819 */
/* 192.0.2.0/24 is reserved for documentation and examples */
/* 192.88.99.0/24 is used as 6to4 Relay anycast prefix by RFC3068 */
if (i1 == 192) {
if (i2 == 168)
return 1;
if (i2 == 0 && i3 == 2)
return 1;
if (i2 == 88 && i3 == 99)
return 1;
}
/* 198.18.0.0/15 is used for benchmark tests by RFC2544 */
if (i1 == 198 && i2 == 18 && i3 >= 1 && i3 <= 64) {
return 1;
}
/* reserved for DHCP clients seeking addresses, not routable outside LAN */
if (i1 == 169 && i2 == 254)
return 1;
/* believe it or not, 204.152.64.0/23 is some bizarre Sun proprietary
* clustering thing */
if (i1 == 204 && i2 == 152 && (i3 == 64 || i3 == 65))
return 1;
/* 224-239/8 is all multicast stuff */
/* 240-255/8 is IANA reserved */
if (i1 >= 224)
return 1;
/* 255.255.255.255, note we already tested for i1 in this range */
if (i2 == 255 && i3 == 255 && i4 == 255)
return 1;
return 0;
}
char *grab_next_host_spec(FILE *inputfd, int argc, char **fakeargv) {
static char host_spec[1024];
unsigned int host_spec_index;
int ch;
struct in_addr ip;
if (o.generate_random_ips) {
do {
ip.s_addr = get_random_u32();
} while (ip_is_reserved(&ip));
Strncpy(host_spec, inet_ntoa(ip), sizeof(host_spec));
} else if (!inputfd) {
return( (optind < argc)? fakeargv[optind++] : NULL);
} else {
host_spec_index = 0;
while((ch = getc(inputfd)) != EOF) {
if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t' || ch == '\0') {
if (host_spec_index == 0) continue;
host_spec[host_spec_index] = '\0';
return host_spec;
} else if (host_spec_index < sizeof(host_spec) / sizeof(char) -1) {
host_spec[host_spec_index++] = (char) ch;
} else fatal("One of the host_specifications from your input file is too long (> %d chars)", (int) sizeof(host_spec));
}
host_spec[host_spec_index] = '\0';
}
if (!*host_spec) return NULL;
return host_spec;
}
/* Just a routine for obtaining a string for printing based on the scantype */
char *scantype2str(stype scantype) {
@@ -2147,6 +2148,13 @@ void sigdie(int signo) {
exit(1);
}
static int fileexistsandisreadable(char *pathname) {
FILE *fp;
/* We check this the easy way! */
fp = fopen(pathname, "r");
if (fp) fclose(fp);
return (fp == NULL)? 0 : 1;
}
int nmap_fetchfile(char *filename_returned, int bufferlen, char *file) {
char *dirptr;
@@ -2260,11 +2268,4 @@ int nmap_fetchfile(char *filename_returned, int bufferlen, char *file) {
}
int fileexistsandisreadable(char *pathname) {
FILE *fp;
/* We check this the easy way! */
fp = fopen(pathname, "r");
if (fp) fclose(fp);
return (fp == NULL)? 0 : 1;
}

4
nmap.h
View File

@@ -426,8 +426,6 @@ void *realloc();
/***********************PROTOTYPES**********************************/
/* print usage information and exit */
void printusage(char *name, int rc);
/* print Interactive usage information */
void printinteractiveusage();
@@ -454,7 +452,6 @@ int listen_icmp(int icmpsock, unsigned short outports[],
int nmap_main(int argc, char *argv[]);
/* general helper functions */
char *grab_next_host_spec(FILE *inputfd, int argc, char **fakeargv);
int parse_targets(struct targets *targets, char *h);
char *statenum2str(int state);
char *scantype2str(stype scantype);
@@ -469,7 +466,6 @@ char *tsseqclass2ascii(int seqclass);
into a difficulty string like "Worthy Challenge */
const char *seqidx2difficultystr(unsigned long idx);
int nmap_fetchfile(char *filename_returned, int bufferlen, char *file);
int fileexistsandisreadable(char *pathname);
int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv);
/* From glibc 2.0.6 because Solaris doesn't seem to have this function */

View File

@@ -199,7 +199,7 @@ extern NmapOps o;
// In milliseconds
// Each row MUST be terminated with -1
int read_timeouts[][4] = {
static int read_timeouts[][4] = {
{ 4000, 4000, 5000, -1 }, // 1 server
{ 2500, 4000, -1, -1 }, // 2 servers
{ 2500, 3000, -1, -1 }, // 3+ servers
@@ -275,7 +275,6 @@ static std::list<request *> cname_reqs;
static int total_reqs;
static nsock_pool dnspool=NULL;
static int etchosts_filled=0;
static std::list<host_elem *> etchosts[HASH_TABLE_SIZE];
static int stat_actual, stat_ok, stat_nx, stat_sf, stat_trans, stat_dropped, stat_cname;
@@ -288,10 +287,7 @@ static ScanProgressMeter *SPM;
//------------------- Prototypes and macros ---------------------
void close_dns_servers();
void write_evt_handler(nsock_pool nsp, nsock_event evt, void *req_v);
void do_possible_writes();
int deal_with_timedout_reads();
void put_dns_packet_on_wire(request *req);
#define ACTION_FINISHED 0
#define ACTION_CNAME_LIST 1
@@ -301,7 +297,7 @@ int deal_with_timedout_reads();
//------------------- Misc code ---------------------
void output_summary() {
static void output_summary() {
int tp = stat_ok + stat_nx + stat_dropped;
struct timeval now;
@@ -314,22 +310,206 @@ void output_summary() {
(unsigned long) servs.size(), stat_ok, stat_nx, stat_dropped, stat_sf, stat_trans);
}
void check_capacities(dns_server *tpserv) {
static void check_capacities(dns_server *tpserv) {
if (tpserv->capacity < CAPACITY_MIN) tpserv->capacity = CAPACITY_MIN;
if (tpserv->capacity > CAPACITY_MAX) tpserv->capacity = CAPACITY_MAX;
if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "CAPACITY <%s> = %d\n", tpserv->hostname, tpserv->capacity);
}
// Closes all nsis created in connect_dns_servers()
static void close_dns_servers() {
std::list<dns_server *>::iterator serverI;
for(serverI = servs.begin(); serverI != servs.end(); serverI++) {
if ((*serverI)->connected) {
nsi_delete((*serverI)->nsd, NSOCK_PENDING_SILENT);
(*serverI)->connected = 0;
(*serverI)->to_process.clear();
(*serverI)->in_process.clear();
}
}
}
// Inserts an integer (endian non-specifically) into a DNS packet.
// Returns number of bytes written
static int add_integer_to_dns_packet(char *packet, int c) {
char tpnum[4];
int tplen;
//------------------- Read handling code ---------------------
sprintf(tpnum, "%d", c);
tplen = strlen(tpnum);
packet[0] = (char) tplen;
memcpy(packet+1, tpnum, tplen);
return tplen+1;
}
// Puts as many packets on the line as capacity will allow
static void do_possible_writes() {
std::list<dns_server *>::iterator servI;
dns_server *tpserv;
request *tpreq;
for(servI = servs.begin(); servI != servs.end(); servI++) {
tpserv = *servI;
if (tpserv->write_busy == 0 && tpserv->reqs_on_wire < tpserv->capacity) {
tpreq = NULL;
if (!tpserv->to_process.empty()) {
tpreq = tpserv->to_process.front();
tpserv->to_process.pop_front();
} else if (!new_reqs.empty()) {
tpreq = new_reqs.front();
tpreq->first_server = tpreq->curr_server = tpserv;
new_reqs.pop_front();
}
if (tpreq) {
if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: TRANSMITTING for <%s> (server <%s>)\n", tpreq->targ->targetipstr() , tpserv->hostname);
stat_trans++;
put_dns_packet_on_wire(tpreq);
}
}
}
}
// nsock write handler
static void write_evt_handler(nsock_pool nsp, nsock_event evt, void *req_v) {
request *req = (request *) req_v;
req->curr_server->write_busy = 0;
req->curr_server->in_process.push_front(req);
do_possible_writes();
}
// Takes a DNS request structure and actually puts it on the wire
// (calls nsock_write()). Does various other tasks like recording
// the time for the timeout.
void put_dns_packet_on_wire(request *req) {
char packet[512];
int plen=0;
u32 ip;
struct timeval now, timeout;
ip = (u32) ntohl(req->targ->v4host().s_addr);
packet[0] = (req->id >> 8) & 0xFF;
packet[1] = req->id & 0xFF;
plen += 2;
memcpy(packet+plen, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00", 10);
plen += 10;
plen += add_integer_to_dns_packet(packet+plen, ip & 0xFF);
plen += add_integer_to_dns_packet(packet+plen, (ip>>8) & 0xFF);
plen += add_integer_to_dns_packet(packet+plen, (ip>>16) & 0xFF);
plen += add_integer_to_dns_packet(packet+plen, (ip>>24) & 0xFF);
memcpy(packet+plen, "\x07in-addr\004arpa\x00\x00\x0c\x00\x01", 18);
plen += 18;
req->curr_server->write_busy = 1;
req->curr_server->reqs_on_wire++;
memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval));
TIMEVAL_MSEC_ADD(timeout, now, read_timeouts[read_timeout_index][req->tries]);
memcpy(&req->timeout, &timeout, sizeof(struct timeval));
req->tries++;
nsock_write(dnspool, req->curr_server->nsd, write_evt_handler, WRITE_TIMEOUT, req, packet, plen);
}
// Processes DNS packets that have timed out
// Returns time until next read timeout
static int deal_with_timedout_reads() {
std::list<dns_server *>::iterator servI;
std::list<dns_server *>::iterator servItemp;
std::list<request *>::iterator reqI;
std::list<request *>::iterator nextI;
dns_server *tpserv;
request *tpreq;
struct timeval now;
int tp, min_timeout = INT_MAX;
memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval));
if (keyWasPressed())
SPM->printStats((double) (stat_ok + stat_nx + stat_dropped) / stat_actual, &now);
for(servI = servs.begin(); servI != servs.end(); servI++) {
tpserv = *servI;
nextI = tpserv->in_process.begin();
if (nextI == tpserv->in_process.end()) continue;
do {
reqI = nextI++;
tpreq = *reqI;
tp = TIMEVAL_MSEC_SUBTRACT(tpreq->timeout, now);
if (tp > 0 && tp < min_timeout) min_timeout = tp;
if (tp <= 0) {
tpserv->capacity = (int) (tpserv->capacity * CAPACITY_MINOR_DOWN_SCALE);
check_capacities(tpserv);
tpserv->in_process.erase(reqI);
tpserv->reqs_on_wire--;
// If we've tried this server enough times, move to the next one
if (read_timeouts[read_timeout_index][tpreq->tries] == -1) {
tpserv->capacity = (int) (tpserv->capacity * CAPACITY_MAJOR_DOWN_SCALE);
check_capacities(tpserv);
servItemp = servI;
servItemp++;
if (servItemp == servs.end()) servItemp = servs.begin();
tpreq->curr_server = *servItemp;
tpreq->tries = 0;
tpreq->servers_tried++;
if (tpreq->curr_server == tpreq->first_server || tpreq->servers_tried == SERVERS_TO_TRY) {
// Either give up on the IP
// or, for maximum reliability, put the server back into processing
// Note it's possible that this will never terminate.
// FIXME: Find a good compromise
// **** We've already tried all servers... give up
if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: *DR*OPPING <%s>\n", tpreq->targ->targetipstr());
output_summary();
stat_dropped++;
total_reqs--;
delete tpreq;
// **** OR We start at the back of this server's queue
//(*servItemp)->to_process.push_back(tpreq);
} else {
(*servItemp)->to_process.push_back(tpreq);
}
} else {
tpserv->to_process.push_back(tpreq);
}
}
} while (nextI != tpserv->in_process.end());
}
if (min_timeout > 500) return 500;
else return min_timeout;
}
// After processing a DNS response, we search through the IPs we're
// looking for and update their results as necessary.
// Returns non-zero if this matches a query we're looking for
int process_result(u32 ia, char *result, int action, u16 id) {
static int process_result(u32 ia, char *result, int action, u16 id) {
std::list<dns_server *>::iterator servI;
std::list<request *>::iterator reqI;
dns_server *tpserv;
@@ -381,7 +561,7 @@ int process_result(u32 ia, char *result, int action, u16 id) {
// encoded string inside a packet.
// maxlen is the very maximum length (in total bytes)
// that should be processed
u32 parse_inaddr_arpa(unsigned char *buf, int maxlen) {
static u32 parse_inaddr_arpa(unsigned char *buf, int maxlen) {
u32 ip=0;
int i, j;
@@ -431,7 +611,7 @@ int encoded_name_to_normal(unsigned char *buf, char *output, int outputsize){
// Takes a pointer to the start of a DNS name inside a packet. It makes
// sure that there is enough space in the name, deals with compression, etc.
int advance_past_dns_name(u8 *buf, int buflen, int curbuf,
static int advance_past_dns_name(u8 *buf, int buflen, int curbuf,
int *nameloc) {
int compression=0;
@@ -458,10 +638,9 @@ int advance_past_dns_name(u8 *buf, int buflen, int curbuf,
else return curbuf+1;
}
// Nsock read handler. One nsock read for each DNS server exists at each
// time. This function uses various helper functions as defined above.
void read_evt_handler(nsock_pool nsp, nsock_event evt, void *nothing) {
static void read_evt_handler(nsock_pool nsp, nsock_event evt, void *nothing) {
u8 *buf;
int buflen, curbuf=0;
int i, nameloc, rdlen, atype, aclass;
@@ -592,205 +771,14 @@ void read_evt_handler(nsock_pool nsp, nsock_event evt, void *nothing) {
}
//------------------- Write handling code ---------------------
// Inserts an integer (endian non-specifically) into a DNS packet.
// Returns number of bytes written
int add_integer_to_dns_packet(char *packet, int c) {
char tpnum[4];
int tplen;
sprintf(tpnum, "%d", c);
tplen = strlen(tpnum);
packet[0] = (char) tplen;
memcpy(packet+1, tpnum, tplen);
return tplen+1;
}
// Takes a DNS request structure and actually puts it on the wire
// (calls nsock_write()). Does various other tasks like recording
// the time for the timeout.
void put_dns_packet_on_wire(request *req) {
char packet[512];
int plen=0;
u32 ip;
struct timeval now, timeout;
ip = (u32) ntohl(req->targ->v4host().s_addr);
packet[0] = (req->id >> 8) & 0xFF;
packet[1] = req->id & 0xFF;
plen += 2;
memcpy(packet+plen, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00", 10);
plen += 10;
plen += add_integer_to_dns_packet(packet+plen, ip & 0xFF);
plen += add_integer_to_dns_packet(packet+plen, (ip>>8) & 0xFF);
plen += add_integer_to_dns_packet(packet+plen, (ip>>16) & 0xFF);
plen += add_integer_to_dns_packet(packet+plen, (ip>>24) & 0xFF);
memcpy(packet+plen, "\x07in-addr\004arpa\x00\x00\x0c\x00\x01", 18);
plen += 18;
req->curr_server->write_busy = 1;
req->curr_server->reqs_on_wire++;
memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval));
TIMEVAL_MSEC_ADD(timeout, now, read_timeouts[read_timeout_index][req->tries]);
memcpy(&req->timeout, &timeout, sizeof(struct timeval));
req->tries++;
nsock_write(dnspool, req->curr_server->nsd, write_evt_handler, WRITE_TIMEOUT, req, packet, plen);
}
// Processes DNS packets that have timed out
// Returns time until next read timeout
int deal_with_timedout_reads() {
std::list<dns_server *>::iterator servI;
std::list<dns_server *>::iterator servItemp;
std::list<request *>::iterator reqI;
std::list<request *>::iterator nextI;
dns_server *tpserv;
request *tpreq;
struct timeval now;
int tp, min_timeout = INT_MAX;
memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval));
if (keyWasPressed())
SPM->printStats((double) (stat_ok + stat_nx + stat_dropped) / stat_actual, &now);
for(servI = servs.begin(); servI != servs.end(); servI++) {
tpserv = *servI;
nextI = tpserv->in_process.begin();
if (nextI == tpserv->in_process.end()) continue;
do {
reqI = nextI++;
tpreq = *reqI;
tp = TIMEVAL_MSEC_SUBTRACT(tpreq->timeout, now);
if (tp > 0 && tp < min_timeout) min_timeout = tp;
if (tp <= 0) {
tpserv->capacity = (int) (tpserv->capacity * CAPACITY_MINOR_DOWN_SCALE);
check_capacities(tpserv);
tpserv->in_process.erase(reqI);
tpserv->reqs_on_wire--;
// If we've tried this server enough times, move to the next one
if (read_timeouts[read_timeout_index][tpreq->tries] == -1) {
tpserv->capacity = (int) (tpserv->capacity * CAPACITY_MAJOR_DOWN_SCALE);
check_capacities(tpserv);
servItemp = servI;
servItemp++;
if (servItemp == servs.end()) servItemp = servs.begin();
tpreq->curr_server = *servItemp;
tpreq->tries = 0;
tpreq->servers_tried++;
if (tpreq->curr_server == tpreq->first_server || tpreq->servers_tried == SERVERS_TO_TRY) {
// Either give up on the IP
// or, for maximum reliability, put the server back into processing
// Note it's possible that this will never terminate.
// FIXME: Find a good compromise
// **** We've already tried all servers... give up
if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: *DR*OPPING <%s>\n", tpreq->targ->targetipstr());
output_summary();
stat_dropped++;
total_reqs--;
delete tpreq;
// **** OR We start at the back of this server's queue
//(*servItemp)->to_process.push_back(tpreq);
} else {
(*servItemp)->to_process.push_back(tpreq);
}
} else {
tpserv->to_process.push_back(tpreq);
}
}
} while (nextI != tpserv->in_process.end());
}
if (min_timeout > 500) return 500;
else return min_timeout;
}
// Puts as many packets on the line as capacity will allow
void do_possible_writes() {
std::list<dns_server *>::iterator servI;
dns_server *tpserv;
request *tpreq;
for(servI = servs.begin(); servI != servs.end(); servI++) {
tpserv = *servI;
if (tpserv->write_busy == 0 && tpserv->reqs_on_wire < tpserv->capacity) {
tpreq = NULL;
if (!tpserv->to_process.empty()) {
tpreq = tpserv->to_process.front();
tpserv->to_process.pop_front();
} else if (!new_reqs.empty()) {
tpreq = new_reqs.front();
tpreq->first_server = tpreq->curr_server = tpserv;
new_reqs.pop_front();
}
if (tpreq) {
if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: TRANSMITTING for <%s> (server <%s>)\n", tpreq->targ->targetipstr() , tpserv->hostname);
stat_trans++;
put_dns_packet_on_wire(tpreq);
}
}
}
}
// nsock write handler
void write_evt_handler(nsock_pool nsp, nsock_event evt, void *req_v) {
request *req = (request *) req_v;
req->curr_server->write_busy = 0;
req->curr_server->in_process.push_front(req);
do_possible_writes();
}
//------------------- DNS Server handling code ---------------------
// nsock connect handler - Empty because it doesn't really need to do anything...
void connect_evt_handler(nsock_pool nsp, nsock_event evt, void *servers) {
static void connect_evt_handler(nsock_pool nsp, nsock_event evt, void *servers) {
}
// Adds DNS servers to the dns_server list. They can be separated by
// commas or spaces - NOTE this doesn't actually do any connecting!
void add_dns_server(char *ipaddrs) {
static void add_dns_server(char *ipaddrs) {
std::list<dns_server *>::iterator servI;
dns_server *tpserv;
char *hostname;
@@ -846,21 +834,6 @@ void connect_dns_servers() {
}
// Closes all nsis created in connect_dns_servers()
void close_dns_servers() {
std::list<dns_server *>::iterator serverI;
for(serverI = servs.begin(); serverI != servs.end(); serverI++) {
if ((*serverI)->connected) {
nsi_delete((*serverI)->nsd, NSOCK_PENDING_SILENT);
(*serverI)->connected = 0;
(*serverI)->to_process.clear();
(*serverI)->in_process.clear();
}
}
}
#ifdef WIN32
void win32_read_registry(char *controlset) {
HKEY hKey;
@@ -921,7 +894,7 @@ void win32_read_registry(char *controlset) {
// Parses /etc/resolv.conf (unix) or the registry (win32) and adds
// all the nameservers found via the add_dns_server() function.
void parse_resolvdotconf() {
static void parse_resolvdotconf() {
#ifndef WIN32
@@ -956,7 +929,7 @@ void parse_resolvdotconf() {
}
void parse_etchosts(char *fname) {
static void parse_etchosts(char *fname) {
FILE *fp;
char buf[2048], hname[256], ipaddrstr[16], *tp;
struct in_addr ia;
@@ -990,7 +963,7 @@ void parse_etchosts(char *fname) {
}
char *lookup_etchosts(u32 ip) {
static char *lookup_etchosts(u32 ip) {
std::list<host_elem *>::iterator hostI;
host_elem *tpelem;
@@ -1003,13 +976,41 @@ char *lookup_etchosts(u32 ip) {
}
static void etchosts_init(void) {
static int initialized = 0;
if (initialized) return;
initialized = 1;
#ifdef WIN32
char windows_dir[1024];
char tpbuf[2048];
int has_backslash;
if (!GetWindowsDirectory(windows_dir, sizeof(windows_dir)))
fatal("Failed to determine your windows directory");
// If it has a backslash it's C:\, otherwise something like C:\WINNT
has_backslash = (windows_dir[strlen(windows_dir)-1] == '\\');
// Windows 95/98/Me:
snprintf(tpbuf, sizeof(tpbuf), "%s%shosts", windows_dir, has_backslash ? "" : "\\");
parse_etchosts(tpbuf);
// Windows NT/2000/XP/2K3:
snprintf(tpbuf, sizeof(tpbuf), "%s%ssystem32\\drivers\\etc\\hosts", windows_dir, has_backslash ? "" : "\\");
parse_etchosts(tpbuf);
#else
parse_etchosts("/etc/hosts");
#endif
}
//------------------- Main loops ---------------------
// Actual main loop
void nmap_mass_rdns_core(Target **targets, int num_targets) {
static void nmap_mass_rdns_core(Target **targets, int num_targets) {
Target **hostI;
std::list<request *>::iterator reqI;
@@ -1066,32 +1067,7 @@ void nmap_mass_rdns_core(Target **targets, int num_targets) {
// If necessary, set up the /etc/hosts hashtable
if (etchosts_filled == 0) {
#ifdef WIN32
char windows_dir[1024];
char tpbuf[2048];
int has_backslash;
if (!GetWindowsDirectory(windows_dir, sizeof(windows_dir)))
fatal("Failed to determine your windows directory");
// If it has a backslash it's C:\, otherwise something like C:\WINNT
has_backslash = (windows_dir[strlen(windows_dir)-1] == '\\');
// Windows 95/98/Me:
snprintf(tpbuf, sizeof(tpbuf), "%s%shosts", windows_dir, has_backslash ? "" : "\\");
parse_etchosts(tpbuf);
// Windows NT/2000/XP/2K3:
snprintf(tpbuf, sizeof(tpbuf), "%s%ssystem32\\drivers\\etc\\hosts", windows_dir, has_backslash ? "" : "\\");
parse_etchosts(tpbuf);
#else
parse_etchosts("/etc/hosts");
#endif
etchosts_filled = 1;
}
etchosts_init();
total_reqs = 0;

View File

@@ -106,7 +106,6 @@
#include "NmapOps.h"
extern NmapOps o;
static int services_initialized = 0;
static struct rpc_info ri;
static int udp_rpc_socket = -1;
static int tcp_rpc_socket = -1;
@@ -119,13 +118,16 @@ static size_t tcp_readlen=0; /* used in get_rpc_results but can be reset in
send_rpc_query */
static void rpc_services_init() {
static int services_initialized = 0;
if (services_initialized) return;
services_initialized = 1;
char filename[512];
FILE *fp;
char *tmpptr, *p;
char line[1024];
int lineno = 0;
services_initialized = 1;
ri.num_alloc = 256;
ri.num_used = 0;
ri.names = (char **) cp_alloc(ri.num_alloc * sizeof(char *));
@@ -182,9 +184,7 @@ static void rpc_services_init() {
char *nmap_getrpcnamebynum(unsigned long num) {
int i;
if (!services_initialized) {
rpc_services_init();
}
for(i=0; i < ri.num_used; i++) {
if (ri.numbers[i] == num)
@@ -194,9 +194,7 @@ char *nmap_getrpcnamebynum(unsigned long num) {
}
int get_rpc_procs(unsigned long **programs, unsigned long *num_programs) {
if (!services_initialized) {
rpc_services_init();
}
*programs = ri.numbers;
*num_programs = ri.num_used;
@@ -332,7 +330,7 @@ int send_rpc_query(const struct in_addr *target_host, unsigned short portno,
return 0;
}
int rpc_are_we_done(char *msg, int msg_len, Target *target,
static int rpc_are_we_done(char *msg, int msg_len, Target *target,
struct portinfo *scan, struct scanstats *ss,
struct portinfolist *pil, struct rpcscaninfo *rsi) {

795
osscan.cc
View File

@@ -121,7 +121,7 @@ extern NmapOps o;
/* Note that a sport of 0 really will (try to) use zero as the source
port rather than choosing a random one */
struct udpprobeinfo *send_closedudp_probe(int sd, struct eth_nfo *eth,
static struct udpprobeinfo *send_closedudp_probe(int sd, struct eth_nfo *eth,
const struct in_addr *victim,
u16 sport, u16 dport) {
@@ -216,10 +216,6 @@ for(decoy=0; decoy < o.numdecoys; decoy++) {
upi.patternbyte = patternbyte;
upi.target.s_addr = ip->ip_dst.s_addr;
}
if (TCPIP_DEBUGGING > 1) {
log_write(LOG_STDOUT, "Raw UDP packet creation completed! Here it is:\n");
readudppacket(packet,1);
}
if ((res = send_ip_packet(sd, eth, packet, ntohs(ip->ip_len))) == -1)
{
@@ -231,8 +227,261 @@ for(decoy=0; decoy < o.numdecoys; decoy++) {
return &upi;
}
static struct AVal *fingerprint_iptcppacket(struct ip *ip, int mss, u32 syn) {
struct AVal *AVs;
int length;
int opcode;
u16 tmpshort;
char *p,*q;
struct tcphdr *tcp = ((struct tcphdr *) (((char *) ip) + 4 * ip->ip_hl));
FingerPrint *get_fingerprint(Target *target, struct seq_info *si) {
AVs = (struct AVal *) malloc(6 * sizeof(struct AVal));
/* Link them together */
AVs[0].next = &AVs[1];
AVs[1].next = &AVs[2];
AVs[2].next = &AVs[3];
AVs[3].next = &AVs[4];
AVs[4].next = &AVs[5];
AVs[5].next = NULL;
/* First we give the "response" flag to say we did actually receive
a packet -- this way we won't match a template with Resp=N */
AVs[0].attribute = "Resp";
strcpy(AVs[0].value, "Y");
/* Next we check whether the Don't Fragment bit is set */
AVs[1].attribute = "DF";
if(ntohs(ip->ip_off) & 0x4000) {
strcpy(AVs[1].value,"Y");
} else strcpy(AVs[1].value, "N");
/* Now we do the TCP Window size */
AVs[2].attribute = "W";
sprintf(AVs[2].value, "%hX", ntohs(tcp->th_win));
/* Time for the ACK, the codes are:
S = same as syn
S++ = syn + 1
O = other
*/
AVs[3].attribute = "ACK";
if (ntohl(tcp->th_ack) == syn + 1)
strcpy(AVs[3].value, "S++");
else if (ntohl(tcp->th_ack) == syn)
strcpy(AVs[3].value, "S");
else strcpy(AVs[3].value, "O");
/* Now time for the flags ... they must be in this order:
B = Bogus (64, not a real TCP flag)
U = Urgent
A = Acknowledgement
P = Push
R = Reset
S = Synchronize
F = Final
*/
AVs[4].attribute = "Flags";
p = AVs[4].value;
if (tcp->th_flags & TH_ECE) *p++ = 'B';
if (tcp->th_flags & TH_URG) *p++ = 'U';
if (tcp->th_flags & TH_ACK) *p++ = 'A';
if (tcp->th_flags & TH_PUSH) *p++ = 'P';
if (tcp->th_flags & TH_RST) *p++ = 'R';
if (tcp->th_flags & TH_SYN) *p++ = 'S';
if (tcp->th_flags & TH_FIN) *p++ = 'F';
*p++ = '\0';
/* Now for the TCP options ... */
AVs[5].attribute = "Ops";
p = AVs[5].value;
/* Partly swiped from /usr/src/linux/net/ipv4/tcp_input.c in Linux kernel */
length = (tcp->th_off * 4) - sizeof(struct tcphdr);
q = ((char *)tcp) + sizeof(struct tcphdr);
while(length > 0 &&
((p - AVs[5].value) < (int) (sizeof(AVs[5].value) - 3))) {
opcode=*q++;
length--;
if (!opcode) {
*p++ = 'L'; /* End of List */
break;
} else if (opcode == 1) {
*p++ = 'N'; /* No Op */
} else if (opcode == 2) {
*p++ = 'M'; /* MSS */
q++;
memcpy(&tmpshort, q, 2);
if(ntohs(tmpshort) == mss)
*p++ = 'E'; /* Echoed */
q += 2;
length -= 3;
} else if (opcode == 3) { /* Window Scale */
*p++ = 'W';
q += 2;
length -= 2;
} else if (opcode == 8) { /* Timestamp */
*p++ = 'T';
q += 9;
length -= 9;
}
}
*p++ = '\0';
return AVs;
}
static struct AVal *fingerprint_portunreach(struct ip *ip, struct udpprobeinfo *upi) {
struct icmp *icmp;
struct ip *ip2;
int numtests = 10;
unsigned short checksum;
unsigned short *checksumptr;
udphdr_bsd *udp;
struct AVal *AVs;
int i;
int current_testno = 0;
unsigned char *datastart, *dataend;
/* The very first thing we do is make sure this is the correct
response */
if (ip->ip_p != IPPROTO_ICMP) {
error("fingerprint_portunreach handed a non-ICMP packet!");
return NULL;
}
if (ip->ip_src.s_addr != upi->target.s_addr)
return NULL; /* Not the person we sent to */
icmp = ((struct icmp *) (((char *) ip) + 4 * ip->ip_hl));
if (icmp->icmp_type != 3 || icmp->icmp_code != 3)
return NULL; /* Not a port unreachable */
ip2 = (struct ip*) ((char *)icmp + 8);
udp = (udphdr_bsd *) ((char *)ip2 + 20);
/* The ports better match as well ... */
if (ntohs(udp->uh_sport) != upi->sport || ntohs(udp->uh_dport) != upi->dport) {
return NULL;
}
/* Create the Avals */
AVs = (struct AVal *) safe_zalloc(numtests * sizeof(struct AVal));
/* Link them together */
for(i=0; i < numtests - 1; i++)
AVs[i].next = &AVs[i+1];
/* First of all, if we got this far the response was yes */
AVs[current_testno].attribute = "Resp";
strcpy(AVs[current_testno].value, "Y");
current_testno++;
/* Now let us do an easy one, Don't fragment */
AVs[current_testno].attribute = "DF";
if(ntohs(ip->ip_off) & 0x4000) {
strcpy(AVs[current_testno].value,"Y");
} else strcpy(AVs[current_testno].value, "N");
current_testno++;
/* Now lets do TOS of the response (note, I've never seen this be
useful */
AVs[current_testno].attribute = "TOS";
sprintf(AVs[current_testno].value, "%hX", ip->ip_tos);
current_testno++;
/* Now we look at the IP datagram length that was returned, some
machines send more of the original packet back than others */
AVs[current_testno].attribute = "IPLEN";
sprintf(AVs[current_testno].value, "%hX", ntohs(ip->ip_len));
current_testno++;
/* OK, lets check the returned IP length, some systems @$@ this
up */
AVs[current_testno].attribute = "RIPTL";
sprintf(AVs[current_testno].value, "%hX", ntohs(ip2->ip_len));
current_testno++;
/* This next test doesn't work on Solaris because the lamers
overwrite our ip_id */
#if !defined(SOLARIS) && !defined(SUNOS) && !defined(IRIX) && !defined(HPUX)
/* Now lets see how they treated the ID we sent ... */
AVs[current_testno].attribute = "RID";
if (ntohs(ip2->ip_id) == 0)
strcpy(AVs[current_testno].value, "0");
else if (ip2->ip_id == upi->ipid)
strcpy(AVs[current_testno].value, "E"); /* The "expected" value */
else strcpy(AVs[current_testno].value, "F"); /* They fucked it up */
current_testno++;
#endif
/* Let us see if the IP checksum we got back computes */
AVs[current_testno].attribute = "RIPCK";
/* Thanks to some machines not having struct ip member ip_sum we
have to go with this BS */
checksumptr = (unsigned short *) ((char *) ip2 + 10);
checksum = *checksumptr;
if (checksum == 0)
strcpy(AVs[current_testno].value, "0");
else {
*checksumptr = 0;
if (in_cksum((unsigned short *)ip2, 20) == checksum) {
strcpy(AVs[current_testno].value, "E"); /* The "expected" value */
} else {
strcpy(AVs[current_testno].value, "F"); /* They fucked it up */
}
*checksumptr = checksum;
}
current_testno++;
/* UDP checksum */
AVs[current_testno].attribute = "UCK";
if (udp->uh_sum == 0)
strcpy(AVs[current_testno].value, "0");
else if (udp->uh_sum == upi->udpck)
strcpy(AVs[current_testno].value, "E"); /* The "expected" value */
else strcpy(AVs[current_testno].value, "F"); /* They fucked it up */
current_testno++;
/* UDP length ... */
AVs[current_testno].attribute = "ULEN";
sprintf(AVs[current_testno].value, "%hX", ntohs(udp->uh_ulen));
current_testno++;
/* Finally we ensure the data is OK */
datastart = ((unsigned char *)udp) + 8;
dataend = (unsigned char *) ip + ntohs(ip->ip_len);
while(datastart < dataend) {
if (*datastart != upi->patternbyte) break;
datastart++;
}
AVs[current_testno].attribute = "DAT";
if (datastart < dataend)
strcpy(AVs[current_testno].value, "F"); /* They fucked it up */
else
strcpy(AVs[current_testno].value, "E");
AVs[current_testno].next = NULL;
return AVs;
}
static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) {
FingerPrint *FP = NULL, *FPtmp = NULL;
FingerPrint *FPtests[9];
struct AVal *seq_AVs;
@@ -876,110 +1125,6 @@ for(i=0; i < 9; i++) {
}
struct AVal *fingerprint_iptcppacket(struct ip *ip, int mss, u32 syn) {
struct AVal *AVs;
int length;
int opcode;
u16 tmpshort;
char *p,*q;
struct tcphdr *tcp = ((struct tcphdr *) (((char *) ip) + 4 * ip->ip_hl));
AVs = (struct AVal *) malloc(6 * sizeof(struct AVal));
/* Link them together */
AVs[0].next = &AVs[1];
AVs[1].next = &AVs[2];
AVs[2].next = &AVs[3];
AVs[3].next = &AVs[4];
AVs[4].next = &AVs[5];
AVs[5].next = NULL;
/* First we give the "response" flag to say we did actually receive
a packet -- this way we won't match a template with Resp=N */
AVs[0].attribute = "Resp";
strcpy(AVs[0].value, "Y");
/* Next we check whether the Don't Fragment bit is set */
AVs[1].attribute = "DF";
if(ntohs(ip->ip_off) & 0x4000) {
strcpy(AVs[1].value,"Y");
} else strcpy(AVs[1].value, "N");
/* Now we do the TCP Window size */
AVs[2].attribute = "W";
sprintf(AVs[2].value, "%hX", ntohs(tcp->th_win));
/* Time for the ACK, the codes are:
S = same as syn
S++ = syn + 1
O = other
*/
AVs[3].attribute = "ACK";
if (ntohl(tcp->th_ack) == syn + 1)
strcpy(AVs[3].value, "S++");
else if (ntohl(tcp->th_ack) == syn)
strcpy(AVs[3].value, "S");
else strcpy(AVs[3].value, "O");
/* Now time for the flags ... they must be in this order:
B = Bogus (64, not a real TCP flag)
U = Urgent
A = Acknowledgement
P = Push
R = Reset
S = Synchronize
F = Final
*/
AVs[4].attribute = "Flags";
p = AVs[4].value;
if (tcp->th_flags & TH_ECE) *p++ = 'B';
if (tcp->th_flags & TH_URG) *p++ = 'U';
if (tcp->th_flags & TH_ACK) *p++ = 'A';
if (tcp->th_flags & TH_PUSH) *p++ = 'P';
if (tcp->th_flags & TH_RST) *p++ = 'R';
if (tcp->th_flags & TH_SYN) *p++ = 'S';
if (tcp->th_flags & TH_FIN) *p++ = 'F';
*p++ = '\0';
/* Now for the TCP options ... */
AVs[5].attribute = "Ops";
p = AVs[5].value;
/* Partly swiped from /usr/src/linux/net/ipv4/tcp_input.c in Linux kernel */
length = (tcp->th_off * 4) - sizeof(struct tcphdr);
q = ((char *)tcp) + sizeof(struct tcphdr);
while(length > 0 &&
((p - AVs[5].value) < (int) (sizeof(AVs[5].value) - 3))) {
opcode=*q++;
length--;
if (!opcode) {
*p++ = 'L'; /* End of List */
break;
} else if (opcode == 1) {
*p++ = 'N'; /* No Op */
} else if (opcode == 2) {
*p++ = 'M'; /* MSS */
q++;
memcpy(&tmpshort, q, 2);
if(ntohs(tmpshort) == mss)
*p++ = 'E'; /* Echoed */
q += 2;
length -= 3;
} else if (opcode == 3) { /* Window Scale */
*p++ = 'W';
q += 2;
length -= 2;
} else if (opcode == 8) { /* Timestamp */
*p++ = 'T';
q += 9;
length -= 9;
}
}
*p++ = '\0';
return AVs;
}
// Prints a note if observedFP has a classification and it is not in referenceFP
// Returns 0 if they match, nonzero otherwise
static int compareclassifications(FingerPrint *referenceFP,
@@ -1010,6 +1155,105 @@ static int compareclassifications(FingerPrint *referenceFP,
return 1;
}
static struct AVal *getattrbyname(struct AVal *AV, const char *name) {
if (!AV) return NULL;
do {
if (!strcmp(AV->attribute, name))
return AV;
AV = AV->next;
} while(AV);
return NULL;
}
static struct AVal *gettestbyname(FingerPrint *FP, const char *name) {
if (!FP) return NULL;
do {
if (!strcmp(FP->name, name))
return FP->results;
FP = FP->next;
} while(FP);
return NULL;
}
/* Returns true if perfect match -- if num_subtests &
num_subtests_succeeded are non_null it ADDS THE NEW VALUES to what
is already there. So initialize them to zero first if you only
want to see the results from this match. if shortcircuit is zero,
it does all the tests, otherwise it returns when the first one
fails. */
static int AVal_match(struct AVal *reference, struct AVal *fprint, unsigned long *num_subtests, unsigned long *num_subtests_succeeded, int shortcut) {
struct AVal *current_ref;
struct AVal *current_fp;
unsigned int number;
unsigned int val;
char *p, *q; /* OHHHH YEEEAAAAAHHHH!#!@#$!% */
char valcpy[512];
char *endptr;
int andexp, orexp, expchar, numtrue;
int testfailed;
int subtests = 0, subtests_succeeded=0;
for(current_ref = reference; current_ref; current_ref = current_ref->next) {
current_fp = getattrbyname(fprint, current_ref->attribute);
if (!current_fp) continue;
/* OK, we compare an attribute value in current_fp->value to a
potentially large expression in current_ref->value. The syntax uses
< (less than), > (greather than), + (non-zero), | (or), and & (and)
No parenthesis are allowed and an expression cannot have | AND & */
numtrue = andexp = orexp = 0; testfailed = 0;
Strncpy(valcpy, current_ref->value, sizeof(valcpy));
p = valcpy;
if (strchr(current_ref->value, '|')) {
orexp = 1; expchar = '|';
} else {
andexp = 1; expchar = '&';
}
do {
q = strchr(p, expchar);
if (q) *q = '\0';
if (strcmp(p, "+") == 0) {
if (!*current_fp->value) { if (andexp) { testfailed=1; break; } }
else {
val = strtol(current_fp->value, &endptr, 16);
if (val == 0 || *endptr) { if (andexp) { testfailed=1; break; } }
else { numtrue++; if (orexp) break; }
}
} else if (*p == '<' && isxdigit((int) p[1])) {
if (!*current_fp->value) { if (andexp) { testfailed=1; break; } }
number = strtol(p + 1, &endptr, 16);
val = strtol(current_fp->value, &endptr, 16);
if (val >= number || *endptr) { if (andexp) { testfailed=1; break; } }
else { numtrue++; if (orexp) break; }
} else if (*p == '>' && isxdigit((int) p[1])) {
if (!*current_fp->value) { if (andexp) { testfailed=1; break; } }
number = strtol(p + 1, &endptr, 16);
val = strtol(current_fp->value, &endptr, 16);
if (val <= number || *endptr) { if (andexp) { testfailed=1; break; } }
else { numtrue++; if (orexp) break; }
}
else {
if (strcmp(p, current_fp->value))
{ if (andexp) { testfailed=1; break; } }
else { numtrue++; if (orexp) break; }
}
if (q) p = q + 1;
} while(q);
if (numtrue == 0) testfailed=1;
subtests++;
if (testfailed) {
if (shortcut) {
if (num_subtests) *num_subtests += subtests;
return 0;
}
} else subtests_succeeded++;
/* Whew, we made it past one Attribute alive , on to the next! */
}
if (num_subtests) *num_subtests += subtests;
if (num_subtests_succeeded) *num_subtests_succeeded += subtests_succeeded;
return (subtests == subtests_succeeded)? 1 : 0;
}
/* Compares 2 fingerprints -- a referenceFP (can have expression
attributes) with an observed fingerprint (no expressions). If
verbose is nonzero, differences will be printed. The comparison
@@ -1155,108 +1399,6 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
return;
}
struct AVal *gettestbyname(FingerPrint *FP, const char *name) {
if (!FP) return NULL;
do {
if (!strcmp(FP->name, name))
return FP->results;
FP = FP->next;
} while(FP);
return NULL;
}
struct AVal *getattrbyname(struct AVal *AV, const char *name) {
if (!AV) return NULL;
do {
if (!strcmp(AV->attribute, name))
return AV;
AV = AV->next;
} while(AV);
return NULL;
}
/* Returns true if perfect match -- if num_subtests &
num_subtests_succeeded are non_null it ADDS THE NEW VALUES to what
is already there. So initialize them to zero first if you only
want to see the results from this match. if shortcircuit is zero,
it does all the tests, otherwise it returns when the first one
fails. */
int AVal_match(struct AVal *reference, struct AVal *fprint, unsigned long *num_subtests, unsigned long *num_subtests_succeeded, int shortcut) {
struct AVal *current_ref;
struct AVal *current_fp;
unsigned int number;
unsigned int val;
char *p, *q; /* OHHHH YEEEAAAAAHHHH!#!@#$!% */
char valcpy[512];
char *endptr;
int andexp, orexp, expchar, numtrue;
int testfailed;
int subtests = 0, subtests_succeeded=0;
for(current_ref = reference; current_ref; current_ref = current_ref->next) {
current_fp = getattrbyname(fprint, current_ref->attribute);
if (!current_fp) continue;
/* OK, we compare an attribute value in current_fp->value to a
potentially large expression in current_ref->value. The syntax uses
< (less than), > (greather than), + (non-zero), | (or), and & (and)
No parenthesis are allowed and an expression cannot have | AND & */
numtrue = andexp = orexp = 0; testfailed = 0;
Strncpy(valcpy, current_ref->value, sizeof(valcpy));
p = valcpy;
if (strchr(current_ref->value, '|')) {
orexp = 1; expchar = '|';
} else {
andexp = 1; expchar = '&';
}
do {
q = strchr(p, expchar);
if (q) *q = '\0';
if (strcmp(p, "+") == 0) {
if (!*current_fp->value) { if (andexp) { testfailed=1; break; } }
else {
val = strtol(current_fp->value, &endptr, 16);
if (val == 0 || *endptr) { if (andexp) { testfailed=1; break; } }
else { numtrue++; if (orexp) break; }
}
} else if (*p == '<' && isxdigit((int) p[1])) {
if (!*current_fp->value) { if (andexp) { testfailed=1; break; } }
number = strtol(p + 1, &endptr, 16);
val = strtol(current_fp->value, &endptr, 16);
if (val >= number || *endptr) { if (andexp) { testfailed=1; break; } }
else { numtrue++; if (orexp) break; }
} else if (*p == '>' && isxdigit((int) p[1])) {
if (!*current_fp->value) { if (andexp) { testfailed=1; break; } }
number = strtol(p + 1, &endptr, 16);
val = strtol(current_fp->value, &endptr, 16);
if (val <= number || *endptr) { if (andexp) { testfailed=1; break; } }
else { numtrue++; if (orexp) break; }
}
else {
if (strcmp(p, current_fp->value))
{ if (andexp) { testfailed=1; break; } }
else { numtrue++; if (orexp) break; }
}
if (q) p = q + 1;
} while(q);
if (numtrue == 0) testfailed=1;
subtests++;
if (testfailed) {
if (shortcut) {
if (num_subtests) *num_subtests += subtests;
return 0;
}
} else subtests_succeeded++;
/* Whew, we made it past one Attribute alive , on to the next! */
}
if (num_subtests) *num_subtests += subtests;
if (num_subtests_succeeded) *num_subtests_succeeded += subtests_succeeded;
return (subtests == subtests_succeeded)? 1 : 0;
}
void freeFingerPrint(FingerPrint *FP) {
FingerPrint *currentFP;
FingerPrint *nextFP;
@@ -1389,7 +1531,7 @@ o.scantype = OS_SCAN;
top of a fingerprint. Gives info which might be useful when the
FPrint is submitted (eg Nmap version, etc). Result is written (up
to ostrlen) to the ostr var passed in */
void WriteSInfo(char *ostr, int ostrlen, int openport, int closedport,
static void WriteSInfo(char *ostr, int ostrlen, int openport, int closedport,
const u8 *mac) {
struct tm *ltime;
time_t timep;
@@ -1407,6 +1549,7 @@ void WriteSInfo(char *ostr, int ostrlen, int openport, int closedport,
(int) timep, openport, closedport, macbuf);
}
char *mergeFPs(FingerPrint *FPs[], int numFPs, int openport, int closedport,
const u8 *mac) {
static char str[10240];
@@ -1514,8 +1657,8 @@ return str;
/* Parse a 'Class' line found in the fingerprint file into the current
FP. Classno is the number of 'class' lines found so far in the
current fingerprint. The function quits if there is a parse error */
void parse_classline(FingerPrint *FP, char *thisline, int lineno, int *classno) {
static void parse_classline(FingerPrint *FP, char *thisline, int lineno,
int *classno) {
char *p, *q;
fflush(stdout);
@@ -1614,6 +1757,42 @@ void parse_classline(FingerPrint *FP, char *thisline, int lineno, int *classno)
}
static struct AVal *str2AVal(char *str) {
int i = 1;
int count = 1;
char *q = str, *p=str;
struct AVal *AVs;
if (!*str) return NULL;
/* count the AVals */
while((q = strchr(q, '%'))) {
count++;
q++;
}
AVs = (struct AVal *) safe_zalloc(count * sizeof(struct AVal));
for(i=0; i < count; i++) {
q = strchr(p, '=');
if (!q) {
fatal("Parse error with AVal string (%s) in nmap-os-fingerprints file", str);
}
*q = '\0';
AVs[i].attribute = strdup(p);
p = q+1;
if (i != count - 1) {
q = strchr(p, '%');
if (!q) {
fatal("Parse error with AVal string (%s) in nmap-os-fingerprints file", str);
}
*q = '\0';
AVs[i].next = &AVs[i+1];
}
Strncpy(AVs[i].value, p, sizeof(AVs[i].value));
p = q + 1;
}
return AVs;
}
/* Parses a single fingerprint from the memory region given. If a
non-null fingerprint is returned, the user is in charge of freeing it
when done. This function does not require the fingerprint to be 100%
@@ -1793,192 +1972,6 @@ if (nmap_fetchfile(filename, sizeof(filename), "nmap-os-fingerprints") == -1){
return parse_fingerprint_file(filename);
}
struct AVal *str2AVal(char *str) {
int i = 1;
int count = 1;
char *q = str, *p=str;
struct AVal *AVs;
if (!*str) return NULL;
/* count the AVals */
while((q = strchr(q, '%'))) {
count++;
q++;
}
AVs = (struct AVal *) safe_zalloc(count * sizeof(struct AVal));
for(i=0; i < count; i++) {
q = strchr(p, '=');
if (!q) {
fatal("Parse error with AVal string (%s) in nmap-os-fingerprints file", str);
}
*q = '\0';
AVs[i].attribute = strdup(p);
p = q+1;
if (i != count - 1) {
q = strchr(p, '%');
if (!q) {
fatal("Parse error with AVal string (%s) in nmap-os-fingerprints file", str);
}
*q = '\0';
AVs[i].next = &AVs[i+1];
}
Strncpy(AVs[i].value, p, sizeof(AVs[i].value));
p = q + 1;
}
return AVs;
}
struct AVal *fingerprint_portunreach(struct ip *ip, struct udpprobeinfo *upi) {
struct icmp *icmp;
struct ip *ip2;
int numtests = 10;
unsigned short checksum;
unsigned short *checksumptr;
udphdr_bsd *udp;
struct AVal *AVs;
int i;
int current_testno = 0;
unsigned char *datastart, *dataend;
/* The very first thing we do is make sure this is the correct
response */
if (ip->ip_p != IPPROTO_ICMP) {
error("fingerprint_portunreach handed a non-ICMP packet!");
return NULL;
}
if (ip->ip_src.s_addr != upi->target.s_addr)
return NULL; /* Not the person we sent to */
icmp = ((struct icmp *) (((char *) ip) + 4 * ip->ip_hl));
if (icmp->icmp_type != 3 || icmp->icmp_code != 3)
return NULL; /* Not a port unreachable */
ip2 = (struct ip*) ((char *)icmp + 8);
udp = (udphdr_bsd *) ((char *)ip2 + 20);
/* The ports better match as well ... */
if (ntohs(udp->uh_sport) != upi->sport || ntohs(udp->uh_dport) != upi->dport) {
return NULL;
}
/* Create the Avals */
AVs = (struct AVal *) safe_zalloc(numtests * sizeof(struct AVal));
/* Link them together */
for(i=0; i < numtests - 1; i++)
AVs[i].next = &AVs[i+1];
/* First of all, if we got this far the response was yes */
AVs[current_testno].attribute = "Resp";
strcpy(AVs[current_testno].value, "Y");
current_testno++;
/* Now let us do an easy one, Don't fragment */
AVs[current_testno].attribute = "DF";
if(ntohs(ip->ip_off) & 0x4000) {
strcpy(AVs[current_testno].value,"Y");
} else strcpy(AVs[current_testno].value, "N");
current_testno++;
/* Now lets do TOS of the response (note, I've never seen this be
useful */
AVs[current_testno].attribute = "TOS";
sprintf(AVs[current_testno].value, "%hX", ip->ip_tos);
current_testno++;
/* Now we look at the IP datagram length that was returned, some
machines send more of the original packet back than others */
AVs[current_testno].attribute = "IPLEN";
sprintf(AVs[current_testno].value, "%hX", ntohs(ip->ip_len));
current_testno++;
/* OK, lets check the returned IP length, some systems @$@ this
up */
AVs[current_testno].attribute = "RIPTL";
sprintf(AVs[current_testno].value, "%hX", ntohs(ip2->ip_len));
current_testno++;
/* This next test doesn't work on Solaris because the lamers
overwrite our ip_id */
#if !defined(SOLARIS) && !defined(SUNOS) && !defined(IRIX) && !defined(HPUX)
/* Now lets see how they treated the ID we sent ... */
AVs[current_testno].attribute = "RID";
if (ntohs(ip2->ip_id) == 0)
strcpy(AVs[current_testno].value, "0");
else if (ip2->ip_id == upi->ipid)
strcpy(AVs[current_testno].value, "E"); /* The "expected" value */
else strcpy(AVs[current_testno].value, "F"); /* They fucked it up */
current_testno++;
#endif
/* Let us see if the IP checksum we got back computes */
AVs[current_testno].attribute = "RIPCK";
/* Thanks to some machines not having struct ip member ip_sum we
have to go with this BS */
checksumptr = (unsigned short *) ((char *) ip2 + 10);
checksum = *checksumptr;
if (checksum == 0)
strcpy(AVs[current_testno].value, "0");
else {
*checksumptr = 0;
if (in_cksum((unsigned short *)ip2, 20) == checksum) {
strcpy(AVs[current_testno].value, "E"); /* The "expected" value */
} else {
strcpy(AVs[current_testno].value, "F"); /* They fucked it up */
}
*checksumptr = checksum;
}
current_testno++;
/* UDP checksum */
AVs[current_testno].attribute = "UCK";
if (udp->uh_sum == 0)
strcpy(AVs[current_testno].value, "0");
else if (udp->uh_sum == upi->udpck)
strcpy(AVs[current_testno].value, "E"); /* The "expected" value */
else strcpy(AVs[current_testno].value, "F"); /* They fucked it up */
current_testno++;
/* UDP length ... */
AVs[current_testno].attribute = "ULEN";
sprintf(AVs[current_testno].value, "%hX", ntohs(udp->uh_ulen));
current_testno++;
/* Finally we ensure the data is OK */
datastart = ((unsigned char *)udp) + 8;
dataend = (unsigned char *) ip + ntohs(ip->ip_len);
while(datastart < dataend) {
if (*datastart != upi->patternbyte) break;
datastart++;
}
AVs[current_testno].attribute = "DAT";
if (datastart < dataend)
strcpy(AVs[current_testno].value, "F"); /* They fucked it up */
else
strcpy(AVs[current_testno].value, "E");
AVs[current_testno].next = NULL;
return AVs;
}
/* This function takes an array of "numSamples" IP IDs and analyzes
them to determine their sequenceability classification. It returns
one of the IPID_SEQ_* classifications defined in nmap.h . If the

View File

@@ -120,11 +120,6 @@
/********************** PROTOTYPES ***********************************/
int os_scan(Target *target);
FingerPrint *get_fingerprint(Target *target, struct seq_info *si);
struct AVal *fingerprint_iptcppacket(struct ip *ip, int mss, unsigned int syn);
struct AVal *fingerprint_portunreach(struct ip *ip, struct udpprobeinfo *upi);
unsigned int get_gcd_n_ulong(int numvalues, unsigned int *values);
unsigned int euclid_gcd(unsigned int a, unsigned int b);
char *fp2ascii(FingerPrint *FP);
/* Parses a single fingerprint from the memory region given. If a
@@ -151,30 +146,13 @@ double compare_fingerprints(FingerPrint *referenceFP, FingerPrint *observedFP,
FingerPrintResults class. */
void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
FingerPrint **reference_FPs, double accuracy_threshold);
struct AVal *str2AVal(char *p);
struct AVal *gettestbyname(FingerPrint *FP, const char *name);
/* Returns true if perfect match -- if num_subtests & num_subtests_succeeded are non_null it updates them. if shortcircuit is zero, it does all the tests, otherwise it returns when the first one fails */
/* Returns true if perfect match -- if num_subtests &
num_subtests_succeeded are non_null it ADDS THE NEW VALUES to what
is already there. So initialize them to zero first if you only
want to see the results from this match. if shortcircuit is zero,
it does all the tests, otherwise it returns when the first one
fails */
int AVal_match(struct AVal *reference, struct AVal *fprint, unsigned long *num_subtests, unsigned long *num_subtests_succeeded, int shortcut);
void freeFingerPrint(FingerPrint *FP);
char *mergeFPs(FingerPrint *FPs[], int numFPs, int openport, int closedport,
const u8 *mac);
/* Writes an informational "Test" result suitable for including at the
top of a fingerprint. Gives info which might be useful when the
FPrint is submitted (eg Nmap version, etc). Result is written (up
to ostrlen) to the ostr var passed in */
void WriteSInfo(char *ostr, int ostrlen, int openport, int closedport,
const u8 *mac);
/* This function takes an array of "numSamples" IP IDs and analyzes
them to determine their sequenceability classification. It returns
one of the IPID_SEQ_* classifications defined in nmap.h . If the

View File

@@ -119,7 +119,7 @@ extern NmapOps o;
static char *logtypes[LOG_NUM_FILES]=LOG_NAMES;
/* Used in creating skript kiddie style output. |<-R4d! */
void skid_output(char *s)
static void skid_output(char *s)
{
int i;
for (i=0;s[i];i++)
@@ -824,7 +824,7 @@ int log_open(int logt, int append, char *filename)
/* The items in ports should be
in sequential order for space savings and easier to read output. Outputs
the rangelist to the log stream given (such as LOG_MACHINE or LOG_XML) */
void output_rangelist_given_ports(int logt, unsigned short *ports,
static void output_rangelist_given_ports(int logt, unsigned short *ports,
int numports) {
int i, previous_port = -2, range_start = -2, port;
char outpbuf[128];
@@ -907,6 +907,26 @@ void output_xml_scaninfo_records(struct scan_lists *scanlist) {
log_flush_all();
}
/* Prints the MAC address (if discovered) to XML output */
static void print_MAC_XML_Info(Target *currenths) {
const u8 *mac = currenths->MACAddress();
char macascii[32];
char vendorstr[128];
char *xml_mac = NULL;
if (mac) {
const char *macvendor = MACPrefix2Corp(mac);
snprintf(macascii, sizeof(macascii), "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
if (macvendor) {
xml_mac = xml_convert(macvendor);
snprintf(vendorstr, sizeof(vendorstr), " vendor=\"%s\"", xml_mac);
free(xml_mac);
} else vendorstr[0] = '\0';
log_write(LOG_XML, "<address addr=\"%s\" addrtype=\"mac\"%s />\n", macascii, vendorstr);
}
}
/* Helper function to write the status and address/hostname info of a host
into the XML log */
static void write_xml_initial_hostinfo(Target *currenths,
@@ -1139,25 +1159,6 @@ void printmacinfo(Target *currenths) {
}
}
/* Prints the MAC address (if discovered) to XML output */
void print_MAC_XML_Info(Target *currenths) {
const u8 *mac = currenths->MACAddress();
char macascii[32];
char vendorstr[128];
char *xml_mac = NULL;
if (mac) {
const char *macvendor = MACPrefix2Corp(mac);
snprintf(macascii, sizeof(macascii), "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
if (macvendor) {
xml_mac = xml_convert(macvendor);
snprintf(vendorstr, sizeof(vendorstr), " vendor=\"%s\"", xml_mac);
free(xml_mac);
} else vendorstr[0] = '\0';
log_write(LOG_XML, "<address addr=\"%s\" addrtype=\"mac\"%s />\n", macascii, vendorstr);
}
}
/* Prints the formatted OS Scan output to stdout, logfiles, etc (but only

View File

@@ -136,9 +136,6 @@ void printportoutput(Target *currenths, PortList *plist);
in a certain place to conform to DTD. */
void printmacinfo(Target *currenths);
/* Prints the MAC address (if discovered) to XML output */
void print_MAC_XML_Info(Target *currenths);
/* Write some information (printf style args) to the given log stream(s).
Remember to watch out for format string bugs. */
void log_write(int logt, const char *fmt, ...)
@@ -168,9 +165,6 @@ void log_flush_all();
it already exists. If the file does not exist, it will be created */
int log_open(int logt, int append, char *filename);
/* Used in creating skript kiddie style output. |<-R4d! */
void skid_output(char *s);
/* Output the list of ports scanned to the top of machine parseable
logs (in a comment, unfortunately). The items in ports should be
in sequential order for space savings and easier to read output */
@@ -178,13 +172,6 @@ void output_ports_to_machine_parseable_output(struct scan_lists *ports,
int tcpscan, int udpscan,
int protscan);
/* The items in ports should be
in sequential order for space savings and easier to read output. Outputs
the rangelist to the log stream given (such as LOG_MACHINE or LOG_XML) */
void output_rangelist_given_ports(int logt, unsigned short *ports,
int numports);
/* Similar to output_ports_to_machine_parseable_output, this function
outputs the XML version, which is scaninfo records of each scan
requested and the ports which it will scan for */

View File

@@ -103,11 +103,13 @@
#include "NmapOps.h"
extern NmapOps o;
static int protocols_initialized = 0;
static int numipprots = 0;
static struct protocol_list *protocol_table[PROTOCOL_TABLE_SIZE];
static int nmap_protocols_init() {
static int protocols_initialized = 0;
if (protocols_initialized) return 0;
char filename[512];
FILE *fp;
char protocolname[128];
@@ -179,7 +181,6 @@ static int nmap_protocols_init() {
struct protoent *nmap_getprotbynum(int num) {
struct protocol_list *current;
if (!protocols_initialized)
if (nmap_protocols_init() == -1)
return NULL;
@@ -202,7 +203,6 @@ struct scan_lists *getdefaultprots(void) {
int bucket;
int protsneeded = 256;
if (!protocols_initialized)
if (nmap_protocols_init() == -1)
fatal("getdefaultprots(): Couldn't get protocol numbers");
@@ -224,7 +224,6 @@ struct scan_lists *getfastprots(void) {
int bucket;
int protsneeded = 0;
if (!protocols_initialized)
if (nmap_protocols_init() == -1)
fatal("Getfastprots: Couldn't get protocol numbers");

View File

@@ -576,9 +576,6 @@ private:
};
bool ultrascan_port_pspec_update(UltraScanInfo *USI, HostScanStats *hss,
const probespec *pspec, int newstate);
/* Whether this is storing timing stats for a whole group or an
individual host */
enum ultra_timing_type { TIMING_HOST, TIMING_GROUP };
@@ -590,11 +587,6 @@ static void init_ultra_timing_vals(ultra_timing_vals *timing,
int num_hosts_in_group,
struct ultra_scan_performance_vars *perf,
struct timeval *now);
/* Adjust various timing variables based on pcket receipt. Pass
rcvdtime = NULL if you have given up on a probe and want to count
this as a DROPPED PACKET */
void ultrascan_adjust_times(UltraScanInfo *USI, HostScanStats *hss,
UltraProbe *probe, struct timeval *rcvdtime);
/* Take a buffer, buf, of size bufsz (32 bytes is sufficient) and
writes a short description of the probe (arg1) into buf. It also returns
@@ -1495,189 +1487,10 @@ void HostScanStats::destroyOutstandingProbe(list<UltraProbe *>::iterator probeI)
delete probe;
}
/* Mark an outstanding probe as timedout. Adjusts stats
accordingly. For connect scans, this closes the socket. */
void HostScanStats::markProbeTimedout(list<UltraProbe *>::iterator probeI) {
UltraProbe *probe = *probeI;
assert(!probe->timedout);
assert(!probe->retransmitted);
probe->timedout = true;
assert(num_probes_active > 0);
num_probes_active--;
assert(USI->gstats->num_probes_active > 0);
USI->gstats->num_probes_active--;
if (probe->isPing()) {
ultrascan_adjust_times(USI, this, probe, NULL);
/* I'll leave it in the queue in case some response ever does
come */
} else num_probes_waiting_retransmit++;
if (probe->type == UltraProbe::UP_CONNECT && probe->CP()->sd >= 0 ) {
/* Free the socket as that is a valuable resource, though it is a shame
late responses will not be permitted */
USI->gstats->CSI->clearSD(probe->CP()->sd);
close(probe->CP()->sd);
probe->CP()->sd = -1;
}
}
bool HostScanStats::completed() {
return num_probes_active == 0 && num_probes_waiting_retransmit == 0 &&
probe_bench.empty() && retry_stack.empty() && freshPortsLeft() == 0;
}
/* Encode the trynum into a 32-bit value. A simple checksum is also included
to verify whether a received version is correct. */
static u32 seq32_encode(UltraScanInfo *USI, unsigned int trynum,
unsigned int pingseq) {
u32 seq = 0;
u16 nfo;
/* We'll let pingseq and trynum each be 8 bits */
nfo = (pingseq << 8) + trynum;
seq = (nfo << 16) + nfo; /* Mirror the data to ensure it is reconstructed correctly */
/* Obfuscate it a little */
seq = seq ^ USI->seqmask;
return seq;
}
/* This function provides the proper cwnd and ccthresh to use. It may
differ from versions in timing member var because when no responses
have been received for this host, may look at others in the group.
For CHANGING this host's timing, use the timing memberval
instead. */
void HostScanStats::getTiming(struct ultra_timing_vals *tmng) {
assert(tmng);
/* Use the per-host value if a pingport has been found or very few probes
have been sent */
if (pingprobestate != PORT_UNKNOWN || numprobes_sent < 80) {
*tmng = timing;
return;
}
/* Otherwise, use the global cwnd stats if it has sufficient responses */
if (USI->gstats->timing.num_updates > 1) {
*tmng = USI->gstats->timing;
return;
}
/* Last resort is to use canned values */
tmng->cwnd = USI->perf.host_initial_cwnd;
tmng->ccthresh = USI->perf.initial_ccthresh;
tmng->num_updates = 0;
return;
}
/* Boost the scan delay for this host, usually because too many packet
drops were detected. */
void HostScanStats::boostScanDelay() {
unsigned int maxAllowed = (USI->tcp_scan)? o.maxTCPScanDelay() : o.maxUDPScanDelay();
if (sdn.delayms == 0)
sdn.delayms = (USI->udp_scan)? 50 : 5; // In many cases, a pcap wait takes a minimum of 80ms, so this matters little :(
else sdn.delayms = MIN(sdn.delayms * 2, MAX(sdn.delayms, 1000));
sdn.delayms = MIN(sdn.delayms, maxAllowed);
sdn.last_boost = USI->now;
sdn.droppedRespSinceDelayChanged = 0;
sdn.goodRespSinceDelayChanged = 0;
}
/* Dismiss all probe attempts on bench -- the ports are marked
'filtered' or whatever is appropriate for having no response */
void HostScanStats::dismissBench() {
int newstate;
if (probe_bench.empty()) return;
newstate = scantype_no_response_means(USI->scantype);
while(!probe_bench.empty()) {
ultrascan_port_pspec_update(USI, this, &probe_bench.back(), newstate);
probe_bench.pop_back();
}
bench_tryno = 0;
}
/* Move all members of bench to retry_stack for probe retransmission */
void HostScanStats::retransmitBench() {
int newstate;
if (probe_bench.empty()) return;
/* Move all contents of probe_bench to the end of retry_stack, updating retry_stack_tries accordingly */
retry_stack.insert(retry_stack.end(), probe_bench.begin(), probe_bench.end());
retry_stack_tries.insert(retry_stack_tries.end(), probe_bench.size(),
bench_tryno);
assert(retry_stack.size() == retry_stack_tries.size());
probe_bench.erase(probe_bench.begin(), probe_bench.end());
newstate = scantype_no_response_means(USI->scantype);
bench_tryno = 0;
}
/* Moves the given probe from the probes_outstanding list, to
probe_bench, and decrements num_probes_waiting_retransmit
accordingly */
void HostScanStats::moveProbeToBench(list<UltraProbe *>::iterator probeI) {
UltraProbe *probe = *probeI;
if (!probe_bench.empty())
assert(bench_tryno == probe->tryno);
else {
bench_tryno = probe->tryno;
probe_bench.reserve(128);
}
probe_bench.push_back(*probe->pspec());
probes_outstanding.erase(probeI);
num_probes_waiting_retransmit--;
delete probe;
}
/* Undoes seq32_encode. Returns true if the checksum is correct and
thus trynum was decoded properly. In that case, trynum (if not
null) is filled with the decoded value. If pingseq is not null, it
is filled with the scanping sequence number, which is 0 if this is
not a ping. */
static bool seq32_decode(UltraScanInfo *USI, u32 seq, unsigned int *trynum,
unsigned int *pingseq) {
if (trynum) *trynum = 0;
if (pingseq) *pingseq = 0;
/* Undo the mask xor */
seq = seq ^ USI->seqmask;
/* Check that both sides are the same */
if ((seq >> 16) != (seq & 0xFFFF))
return false;
if (trynum)
*trynum = seq & 0xFF;
if (pingseq)
*pingseq = (seq & 0xFF00) >> 8;
return true;
}
/* Sometimes the trynumber and/or pingseq are stored in a source
portnumber of probes instead. This takes a port number in HOST
BYTE ORDER. Returns true if the numbers seem reasonable, false if
they are bogus. */
bool sport_decode(UltraScanInfo *USI, u16 portno, unsigned int *trynum,
unsigned int *pingseq) {
int tryval;
tryval = portno - o.magic_port;
if (tryval <= USI->perf.tryno_cap) {
if (pingseq) *pingseq = 0;
if (trynum) *trynum = tryval;
} else {
if (pingseq) *pingseq = tryval - USI->perf.tryno_cap;
if (trynum) *trynum = 0;
}
if (tryval > USI->perf.tryno_cap + 256)
return false;
return true;
}
/* Adjust various timing variables based on pcket receipt. Pass
rcvdtime = NULL if you have given up on a probe and want to count
this as a DROPPED PACKET */
void ultrascan_adjust_times(UltraScanInfo *USI, HostScanStats *hss,
static void ultrascan_adjust_times(UltraScanInfo *USI, HostScanStats *hss,
UltraProbe *probe, struct timeval *rcvdtime) {
int ping_magnifier = (probe->isPing())? USI->perf.ping_magnifier : 1;
@@ -1762,48 +1575,87 @@ void ultrascan_adjust_times(UltraScanInfo *USI, HostScanStats *hss,
}
}
/* Called when a ping response is discovered. */
static void ultrascan_ping_update(UltraScanInfo *USI, HostScanStats *hss,
list<UltraProbe *>::iterator probeI,
struct timeval *rcvdtime) {
ultrascan_adjust_times(USI, hss, *probeI, rcvdtime);
hss->destroyOutstandingProbe(probeI);
}
/* Called when a new status is determined for host in hss (eg. it is
found to be up or down by a ping/ping_arp scan. The probe that led
to this new decision is in probeI. This function needs to update
timing information and other stats as appropriate.If rcvdtime is
NULL, packet stats are not updated. */
static void ultrascan_host_update(UltraScanInfo *USI, HostScanStats *hss,
list<UltraProbe *>::iterator probeI,
int newstate, struct timeval *rcvdtime) {
/* Mark an outstanding probe as timedout. Adjusts stats
accordingly. For connect scans, this closes the socket. */
void HostScanStats::markProbeTimedout(list<UltraProbe *>::iterator probeI) {
UltraProbe *probe = *probeI;
if (rcvdtime) ultrascan_adjust_times(USI, hss, probe, rcvdtime);
assert(!probe->timedout);
assert(!probe->retransmitted);
probe->timedout = true;
assert(num_probes_active > 0);
num_probes_active--;
assert(USI->gstats->num_probes_active > 0);
USI->gstats->num_probes_active--;
if (probe->isPing()) {
ultrascan_adjust_times(USI, this, probe, NULL);
/* I'll leave it in the queue in case some response ever does
come */
} else num_probes_waiting_retransmit++;
/* Adjust the target flags to note the new state. */
if ((hss->target->flags & HOST_UP) == 0) {
if (newstate == HOST_UP) {
/* Clear any HOST_DOWN or HOST_FIREWALLED flags */
hss->target->flags &= ~(HOST_DOWN|HOST_FIREWALLED);
hss->target->flags |= HOST_UP;
} else if (newstate == HOST_DOWN) {
hss->target->flags &= ~HOST_FIREWALLED;
hss->target->flags |= HOST_DOWN;
} else assert(0);
if (probe->type == UltraProbe::UP_CONNECT && probe->CP()->sd >= 0 ) {
/* Free the socket as that is a valuable resource, though it is a shame
late responses will not be permitted */
USI->gstats->CSI->clearSD(probe->CP()->sd);
close(probe->CP()->sd);
probe->CP()->sd = -1;
}
}
/* Kill outstanding probes */
while(!hss->probes_outstanding.empty())
hss->destroyOutstandingProbe(hss->probes_outstanding.begin());
bool HostScanStats::completed() {
return num_probes_active == 0 && num_probes_waiting_retransmit == 0 &&
probe_bench.empty() && retry_stack.empty() && freshPortsLeft() == 0;
}
/* Encode the trynum into a 32-bit value. A simple checksum is also included
to verify whether a received version is correct. */
static u32 seq32_encode(UltraScanInfo *USI, unsigned int trynum,
unsigned int pingseq) {
u32 seq = 0;
u16 nfo;
/* We'll let pingseq and trynum each be 8 bits */
nfo = (pingseq << 8) + trynum;
seq = (nfo << 16) + nfo; /* Mirror the data to ensure it is reconstructed correctly */
/* Obfuscate it a little */
seq = seq ^ USI->seqmask;
return seq;
}
/* This function provides the proper cwnd and ccthresh to use. It may
differ from versions in timing member var because when no responses
have been received for this host, may look at others in the group.
For CHANGING this host's timing, use the timing memberval
instead. */
void HostScanStats::getTiming(struct ultra_timing_vals *tmng) {
assert(tmng);
/* Use the per-host value if a pingport has been found or very few probes
have been sent */
if (pingprobestate != PORT_UNKNOWN || numprobes_sent < 80) {
*tmng = timing;
return;
}
/* Otherwise, use the global cwnd stats if it has sufficient responses */
if (USI->gstats->timing.num_updates > 1) {
*tmng = USI->gstats->timing;
return;
}
/* Last resort is to use canned values */
tmng->cwnd = USI->perf.host_initial_cwnd;
tmng->ccthresh = USI->perf.initial_ccthresh;
tmng->num_updates = 0;
return;
}
/* Like ultrascan_port_probe_update(), except it is called with just a
probespec rather than a whole UltraProbe. Returns true if the port
was added or at least the state was changed. */
bool ultrascan_port_pspec_update(UltraScanInfo *USI, HostScanStats *hss,
const probespec *pspec, int newstate) {
static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
HostScanStats *hss,
const probespec *pspec,
int newstate) {
u16 portno;
u8 proto = 0;
int oldstate = PORT_TESTING;
@@ -1904,6 +1756,150 @@ bool ultrascan_port_pspec_update(UltraScanInfo *USI, HostScanStats *hss,
return oldstate != newstate;
}
/* Boost the scan delay for this host, usually because too many packet
drops were detected. */
void HostScanStats::boostScanDelay() {
unsigned int maxAllowed = (USI->tcp_scan)? o.maxTCPScanDelay() : o.maxUDPScanDelay();
if (sdn.delayms == 0)
sdn.delayms = (USI->udp_scan)? 50 : 5; // In many cases, a pcap wait takes a minimum of 80ms, so this matters little :(
else sdn.delayms = MIN(sdn.delayms * 2, MAX(sdn.delayms, 1000));
sdn.delayms = MIN(sdn.delayms, maxAllowed);
sdn.last_boost = USI->now;
sdn.droppedRespSinceDelayChanged = 0;
sdn.goodRespSinceDelayChanged = 0;
}
/* Dismiss all probe attempts on bench -- the ports are marked
'filtered' or whatever is appropriate for having no response */
void HostScanStats::dismissBench() {
int newstate;
if (probe_bench.empty()) return;
newstate = scantype_no_response_means(USI->scantype);
while(!probe_bench.empty()) {
ultrascan_port_pspec_update(USI, this, &probe_bench.back(), newstate);
probe_bench.pop_back();
}
bench_tryno = 0;
}
/* Move all members of bench to retry_stack for probe retransmission */
void HostScanStats::retransmitBench() {
int newstate;
if (probe_bench.empty()) return;
/* Move all contents of probe_bench to the end of retry_stack, updating retry_stack_tries accordingly */
retry_stack.insert(retry_stack.end(), probe_bench.begin(), probe_bench.end());
retry_stack_tries.insert(retry_stack_tries.end(), probe_bench.size(),
bench_tryno);
assert(retry_stack.size() == retry_stack_tries.size());
probe_bench.erase(probe_bench.begin(), probe_bench.end());
newstate = scantype_no_response_means(USI->scantype);
bench_tryno = 0;
}
/* Moves the given probe from the probes_outstanding list, to
probe_bench, and decrements num_probes_waiting_retransmit
accordingly */
void HostScanStats::moveProbeToBench(list<UltraProbe *>::iterator probeI) {
UltraProbe *probe = *probeI;
if (!probe_bench.empty())
assert(bench_tryno == probe->tryno);
else {
bench_tryno = probe->tryno;
probe_bench.reserve(128);
}
probe_bench.push_back(*probe->pspec());
probes_outstanding.erase(probeI);
num_probes_waiting_retransmit--;
delete probe;
}
/* Undoes seq32_encode. Returns true if the checksum is correct and
thus trynum was decoded properly. In that case, trynum (if not
null) is filled with the decoded value. If pingseq is not null, it
is filled with the scanping sequence number, which is 0 if this is
not a ping. */
static bool seq32_decode(UltraScanInfo *USI, u32 seq, unsigned int *trynum,
unsigned int *pingseq) {
if (trynum) *trynum = 0;
if (pingseq) *pingseq = 0;
/* Undo the mask xor */
seq = seq ^ USI->seqmask;
/* Check that both sides are the same */
if ((seq >> 16) != (seq & 0xFFFF))
return false;
if (trynum)
*trynum = seq & 0xFF;
if (pingseq)
*pingseq = (seq & 0xFF00) >> 8;
return true;
}
/* Sometimes the trynumber and/or pingseq are stored in a source
portnumber of probes instead. This takes a port number in HOST
BYTE ORDER. Returns true if the numbers seem reasonable, false if
they are bogus. */
static bool sport_decode(UltraScanInfo *USI, u16 portno, unsigned int *trynum,
unsigned int *pingseq) {
int tryval;
tryval = portno - o.magic_port;
if (tryval <= USI->perf.tryno_cap) {
if (pingseq) *pingseq = 0;
if (trynum) *trynum = tryval;
} else {
if (pingseq) *pingseq = tryval - USI->perf.tryno_cap;
if (trynum) *trynum = 0;
}
if (tryval > USI->perf.tryno_cap + 256)
return false;
return true;
}
/* Called when a ping response is discovered. */
static void ultrascan_ping_update(UltraScanInfo *USI, HostScanStats *hss,
list<UltraProbe *>::iterator probeI,
struct timeval *rcvdtime) {
ultrascan_adjust_times(USI, hss, *probeI, rcvdtime);
hss->destroyOutstandingProbe(probeI);
}
/* Called when a new status is determined for host in hss (eg. it is
found to be up or down by a ping/ping_arp scan. The probe that led
to this new decision is in probeI. This function needs to update
timing information and other stats as appropriate.If rcvdtime is
NULL, packet stats are not updated. */
static void ultrascan_host_update(UltraScanInfo *USI, HostScanStats *hss,
list<UltraProbe *>::iterator probeI,
int newstate, struct timeval *rcvdtime) {
UltraProbe *probe = *probeI;
if (rcvdtime) ultrascan_adjust_times(USI, hss, probe, rcvdtime);
/* Adjust the target flags to note the new state. */
if ((hss->target->flags & HOST_UP) == 0) {
if (newstate == HOST_UP) {
/* Clear any HOST_DOWN or HOST_FIREWALLED flags */
hss->target->flags &= ~(HOST_DOWN|HOST_FIREWALLED);
hss->target->flags |= HOST_UP;
} else if (newstate == HOST_DOWN) {
hss->target->flags &= ~HOST_FIREWALLED;
hss->target->flags |= HOST_DOWN;
} else assert(0);
}
/* Kill outstanding probes */
while(!hss->probes_outstanding.empty())
hss->destroyOutstandingProbe(hss->probes_outstanding.begin());
}
/* This function is called when a new status is determined for a port.
the port in the probeI of host hss is now in newstate. This
function needs to update timing information, other stats, and the
@@ -2276,7 +2272,7 @@ static void doAnyRetryStackRetransmits(UltraScanInfo *USI) {
/* Sends a ping probe to the host. Assumes that caller has already
checked that sending is OK w/congestion control and that pingprobe is
available */
void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
static void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
if (o.debugging > 1) {
char tmpbuf[32];
printf("Ultrascan PING SENT to %s [%s]\n", hss->target->targetipstr(),
@@ -2413,7 +2409,7 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) {
/* Print occasional remaining time estimates, as well as
debugging information */
void printAnyStats(UltraScanInfo *USI) {
static void printAnyStats(UltraScanInfo *USI) {
list<HostScanStats *>::iterator hostI;
HostScanStats *hss;
@@ -2665,7 +2661,7 @@ static bool do_one_select_round(UltraScanInfo *USI, struct timeval *stime) {
match, or if matching seems to be broken for one reason or
another. You can send in HBO or NBO, just as
long as the two values are in the same byte order. */
bool allow_ipid_match(u16 ipid_sent, u16 ipid_rcvd) {
static bool allow_ipid_match(u16 ipid_sent, u16 ipid_rcvd) {
static int numvalid = 0;
static int numbogus = 0;
@@ -3220,7 +3216,7 @@ static void begin_sniffer(UltraScanInfo *USI, vector<Target *> &Targets) {
/* Go through the data structures, making appropriate changes (such as expiring
probes, noting when hosts are complete, etc. */
void processData(UltraScanInfo *USI) {
static void processData(UltraScanInfo *USI) {
list<HostScanStats *>::iterator hostI;
list<UltraProbe *>::iterator probeI, nextProbeI;
HostScanStats *host = NULL;
@@ -3568,7 +3564,7 @@ void bounce_scan(Target *target, u16 *portarray, int numports,
way got overloaded and dropped the last X packets, they are
likely to get through (and flag us a problem if responsive)
if we let them go first in the next round */
void reverse_testing_order(struct portinfolist *pil, struct portinfo *scanarray) {
static void reverse_testing_order(struct portinfolist *pil, struct portinfo *scanarray) {
int currentidx, nextidx;
struct portinfo *current;

View File

@@ -259,7 +259,6 @@ void servicescan_read_handler(nsock_pool nsp, nsock_event nse, void *mydata);
void servicescan_write_handler(nsock_pool nsp, nsock_event nse, void *mydata);
void servicescan_connect_handler(nsock_pool nsp, nsock_event nse, void *mydata);
void end_svcprobe(nsock_pool nsp, enum serviceprobestate probe_state, ServiceGroup *SG, ServiceNFO *svc, nsock_iod nsi);
int launchSomeServiceProbes(nsock_pool nsp, ServiceGroup *SG);
ServiceProbeMatch::ServiceProbeMatch() {
deflineno = -1;
@@ -1044,7 +1043,7 @@ void ServiceProbe::addMatch(const char *match, int lineno) {
}
// Parses the given nmap-service-probes file into the AP class
void parse_nmap_service_probe_file(AllProbes *AP, char *filename) {
static void parse_nmap_service_probe_file(AllProbes *AP, char *filename) {
ServiceProbe *newProbe;
char line[2048];
int lineno = 0;
@@ -1137,6 +1136,17 @@ void parse_nmap_service_probes(AllProbes *AP) {
parse_nmap_service_probe_file(AP, filename);
}
static AllProbes *service_scan_init(void)
{
static AllProbes *AP;
if (AP) return AP;
AP = new AllProbes();
parse_nmap_service_probes(AP);
return AP;
}
// If the buf (of length buflen) matches one of the regexes in this
// ServiceProbe, returns the details of the match (service name,
// version number if applicable, and whether this is a "soft" match.
@@ -1892,6 +1902,52 @@ void end_svcprobe(nsock_pool nsp, enum serviceprobestate probe_state, ServiceGro
return;
}
// This function consults the ServiceGroup to determine whether any
// more probes can be launched at this time. If so, it determines the
// appropriate ones and then starts them up.
static int launchSomeServiceProbes(nsock_pool nsp, ServiceGroup *SG) {
ServiceNFO *svc;
ServiceProbe *nextprobe;
struct sockaddr_storage ss;
size_t ss_len;
while (SG->services_in_progress.size() < SG->ideal_parallelism &&
!SG->services_remaining.empty()) {
// Start executing a probe from the new list and move it to in_progress
svc = SG->services_remaining.front();
if (svc->target->timedOut(nsock_gettimeofday())) {
end_svcprobe(nsp, PROBESTATE_INCOMPLETE, SG, svc, NULL);
continue;
}
nextprobe = svc->nextProbe(true);
// We start by requesting a connection to the target
if ((svc->niod = nsi_new(nsp, svc)) == NULL) {
fatal("Failed to allocate Nsock I/O descriptor in launchSomeServiceProbes()");
}
if (o.debugging > 1) {
printf("Starting probes against new service: %s:%hi (%s)\n", svc->target->targetipstr(), svc->portno, proto2ascii(svc->proto));
}
svc->target->TargetSockAddr(&ss, &ss_len);
if (svc->proto == IPPROTO_TCP)
nsock_connect_tcp(nsp, svc->niod, servicescan_connect_handler,
DEFAULT_CONNECT_TIMEOUT, svc,
(struct sockaddr *)&ss, ss_len,
svc->portno);
else {
assert(svc->proto == IPPROTO_UDP);
nsock_connect_udp(nsp, svc->niod, servicescan_connect_handler,
svc, (struct sockaddr *) &ss, ss_len,
svc->portno);
}
// Now remove it from the remaining service list
SG->services_remaining.pop_front();
// And add it to the in progress list
SG->services_in_progress.push_back(svc);
}
return 0;
}
void servicescan_connect_handler(nsock_pool nsp, nsock_event nse, void *mydata) {
nsock_iod nsi = nse_iod(nse);
enum nse_status status = nse_status(nse);
@@ -2172,8 +2228,7 @@ void servicescan_read_handler(nsock_pool nsp, nsock_event nse, void *mydata) {
// This is used in processResults to determine whether a FP
// should be printed based on type of match, version intensity, etc.
int shouldWePrintFingerprint(ServiceNFO *svc) {
static int shouldWePrintFingerprint(ServiceNFO *svc) {
// Never print FP if hardmatched
if (svc->probe_state == PROBESTATE_FINISHED_HARDMATCHED)
return 0;
@@ -2213,52 +2268,6 @@ list<ServiceNFO *>::iterator svc;
}
}
// This function consults the ServiceGroup to determine whether any
// more probes can be launched at this time. If so, it determines the
// appropriate ones and then starts them up.
int launchSomeServiceProbes(nsock_pool nsp, ServiceGroup *SG) {
ServiceNFO *svc;
ServiceProbe *nextprobe;
struct sockaddr_storage ss;
size_t ss_len;
while (SG->services_in_progress.size() < SG->ideal_parallelism &&
!SG->services_remaining.empty()) {
// Start executing a probe from the new list and move it to in_progress
svc = SG->services_remaining.front();
if (svc->target->timedOut(nsock_gettimeofday())) {
end_svcprobe(nsp, PROBESTATE_INCOMPLETE, SG, svc, NULL);
continue;
}
nextprobe = svc->nextProbe(true);
// We start by requesting a connection to the target
if ((svc->niod = nsi_new(nsp, svc)) == NULL) {
fatal("Failed to allocate Nsock I/O descriptor in launchSomeServiceProbes()");
}
if (o.debugging > 1) {
printf("Starting probes against new service: %s:%hi (%s)\n", svc->target->targetipstr(), svc->portno, proto2ascii(svc->proto));
}
svc->target->TargetSockAddr(&ss, &ss_len);
if (svc->proto == IPPROTO_TCP)
nsock_connect_tcp(nsp, svc->niod, servicescan_connect_handler,
DEFAULT_CONNECT_TIMEOUT, svc,
(struct sockaddr *)&ss, ss_len,
svc->portno);
else {
assert(svc->proto == IPPROTO_UDP);
nsock_connect_udp(nsp, svc->niod, servicescan_connect_handler,
svc, (struct sockaddr *) &ss, ss_len,
svc->portno);
}
// Now remove it from the remaining service list
SG->services_remaining.pop_front();
// And add it to the in progress list
SG->services_in_progress.push_back(svc);
}
return 0;
}
/* Start the timeout clocks of any targets that have probes. Assumes
that this is called before any probes have been launched (so they
are all in services_remaining */
@@ -2281,7 +2290,7 @@ static void startTimeOutClocks(ServiceGroup *SG) {
// We iterate through SG->services_remaining and remove any with port/protocol
// pairs that are excluded. We use AP->isExcluded() to determine which ports
// are excluded.
void remove_excluded_ports(AllProbes *AP, ServiceGroup *SG) {
static void remove_excluded_ports(AllProbes *AP, ServiceGroup *SG) {
list<ServiceNFO *>::iterator i, nxt;
ServiceNFO *svc;
@@ -2311,7 +2320,7 @@ void remove_excluded_ports(AllProbes *AP, ServiceGroup *SG) {
Targets specified. */
int service_scan(vector<Target *> &Targets) {
// int service_scan(Target *targets[], int num_targets)
static AllProbes *AP;
AllProbes *AP;
ServiceGroup *SG;
nsock_pool nsp;
struct timeval now;
@@ -2323,10 +2332,7 @@ int service_scan(vector<Target *> &Targets) {
if (Targets.size() == 0)
return 1;
if (!AP) {
AP = new AllProbes();
parse_nmap_service_probes(AP);
}
AP = service_scan_init();
// Now I convert the targets into a new ServiceGroup

View File

@@ -341,8 +341,5 @@ public:
Targets specified. */
int service_scan(std::vector<Target *> &Targets);
// Parses the given nmap-service-probes file into the AP class
void parse_nmap_service_probe_file(AllProbes *AP, char *filename);
#endif /* SERVICE_SCAN_H */

View File

@@ -103,12 +103,14 @@
#include "NmapOps.h"
extern NmapOps o;
static int services_initialized = 0;
static int numtcpports = 0;
static int numudpports = 0;
static struct service_list *service_table[SERVICE_TABLE_SIZE];
static int nmap_services_init() {
static int services_initialized = 0;
if (services_initialized) return 0;
char filename[512];
FILE *fp;
char servicename[128], proto[16];
@@ -216,7 +218,6 @@ static int nmap_services_init() {
struct servent *nmap_getservbyport(int port, const char *proto) {
struct service_list *current;
if (!services_initialized)
if (nmap_services_init() == -1)
return NULL;
@@ -244,7 +245,6 @@ struct scan_lists *getdefaultports(int tcpscan, int udpscan) {
int tcpportsneeded = 0;
int udpportsneeded = 0;
if (!services_initialized)
if (nmap_services_init() == -1)
fatal("Getfastports: Couldn't get port numbers");
@@ -308,7 +308,6 @@ struct scan_lists *getfastports(int tcpscan, int udpscan) {
int tcpportsneeded = 0;
int udpportsneeded = 0;
if (!services_initialized)
if (nmap_services_init() == -1)
fatal("Getfastports: Couldn't get port numbers");

1871
targets.cc

File diff suppressed because it is too large Load Diff

View File

@@ -163,45 +163,12 @@ struct pingtech {
};
int get_ping_results(int sd, pcap_t *pd, Target *hostbatch[],
int pingtype, struct timeval *time, struct pingtune *pt,
struct timeout_info *to, int id, struct pingtech *ptech,
struct scan_lists *ports);
int sendpingqueries(int sd, int rawsd, eth_t *ethsd, Target *target,
u16 seq, unsigned short id, struct scanstats *ss,
struct timeval *time, int pingtype, struct pingtech ptech);
int sendpingquery(int sd, int rawsd, eth_t *ethsd, Target *target,
u16 seq, unsigned short id, struct scanstats *ss,
struct timeval *time, int pingtype, struct pingtech ptech);
int sendrawtcpudppingqueries(int rawsd, eth_t *ethsd, Target *target, int pingtype,
u16 seq, struct timeval *time, struct pingtune *pt);
int sendrawtcppingquery(int rawsd, struct eth_nfo *eth, Target *target, int pingtype, u16 probe_port,
u16 seq, struct timeval *time, struct pingtune *pt);
int sendrawudppingquery(int rawsd, struct eth_nfo *eth, Target *target, u16 probe_port,
u16 seq, struct timeval *time, struct pingtune *pt);
int sendconnecttcpqueries(Target *hostbatch[], struct tcpqueryinfo *tqi, Target *target,
u16 seq, struct timeval *time, struct pingtune *pt, struct timeout_info *to, int max_sockets);
int sendconnecttcpquery(Target *hostbatch[], struct tcpqueryinfo *tqi, Target *target, int probe_port_num,
u16 seq, struct timeval *time, struct pingtune *pt, struct timeout_info *to, int max_sockets);
int get_connecttcpscan_results(struct tcpqueryinfo *tqi,
Target *hostbatch[],
struct timeval *time, struct pingtune *pt,
struct timeout_info *to);
char *readhoststate(int state);
void massping(Target *hostbatch[], int numhosts,
struct scan_lists *ports, int pingtype);
void hoststructfry(Target *hostbatch[], int nelem);
/* Ports is the list of ports the user asked to be scanned (0 terminated),
you can just pass NULL (it is only a stupid optimization that needs it) */
Target *nexthost(HostGroupState *hs, TargetGroup *exclude_group,
struct scan_lists *ports, int *pingtype);
/* loads an exclude file into a excluded target list */
TargetGroup* load_exclude(FILE *fExclude, char *szExclude);
/* is the host we're passed in one that
* should be excluded?
*/
int hostInExclude(struct sockaddr *checksock, size_t checksocklen,
TargetGroup *exclude_group);
/* a debugging routine to dump an exclude list to stdout. */
int dumpExclude(TargetGroup*exclude_group);
/* Returns the last host obtained by nexthost. It will be given again the next

473
tcpip.cc
View File

@@ -256,156 +256,13 @@ void PacketTrace::traceArp(pdirection pdir, const u8 *frame, u32 len,
return;
}
/* Takes an IP PACKET and prints it if packet tracing is enabled.
'packet' must point to the IPv4 header. The direction must be
PacketTrace::SENT or PacketTrace::RCVD . Optional 'now' argument
makes this function slightly more efficient by avoiding a gettimeofday()
call. */
void PacketTrace::trace(pdirection pdir, const u8 *packet, u32 len,
struct timeval *now) {
struct timeval tv;
if (pdir == SENT) {
PktCt.sendPackets++;
PktCt.sendBytes += len;
} else {
PktCt.recvPackets++;
PktCt.recvBytes += len;
}
if (!o.packetTrace()) return;
if (now)
tv = *now;
else gettimeofday(&tv, NULL);
if (len < 20) {
error("Packet tracer: tiny packet encountered");
return;
}
log_write(LOG_STDOUT|LOG_NORMAL, "%s (%.4fs) %s\n", (pdir == SENT)? "SENT" : "RCVD", o.TimeSinceStartMS(&tv) / 1000.0, ippackethdrinfo(packet, len));
return;
}
/* Adds a trace entry when a connect() is attempted if packet tracing
is enabled. Pass IPPROTO_TCP or IPPROTO_UDP as the protocol. The
sock may be a sockaddr_in or sockaddr_in6. The return code of
connect is passed in connectrc. If the return code is -1, get the
errno and pass that as connect_errno. */
void PacketTrace::traceConnect(u8 proto, const struct sockaddr *sock,
int socklen, int connectrc, int connect_errno,
const struct timeval *now) {
struct sockaddr_in *sin = (struct sockaddr_in *) sock;
#if HAVE_IPV6
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sock;
#endif
struct timeval tv;
char errbuf[64] = "";
char targetipstr[INET6_ADDRSTRLEN] = "";
u16 targetport = 0;
if (!o.packetTrace()) return;
if (now)
tv = *now;
else gettimeofday(&tv, NULL);
assert(proto == IPPROTO_TCP || proto == IPPROTO_UDP);
if (connectrc == 0)
Strncpy(errbuf, "Connected", sizeof(errbuf));
else {
snprintf(errbuf, sizeof(errbuf), "%s", strerror(connect_errno));
}
if (sin->sin_family == AF_INET) {
if (inet_ntop(sin->sin_family, (char *) &sin->sin_addr, targetipstr,
sizeof(targetipstr)) == NULL)
fatal("Failed to convert target IPv4 address to presentation format!?!");
targetport = ntohs(sin->sin_port);
} else {
#if HAVE_IPV6
assert(sin->sin_family == AF_INET6);
if (inet_ntop(sin->sin_family, (char *) &sin6->sin6_addr, targetipstr,
sizeof(targetipstr)) == NULL)
fatal("Failed to convert target IPv4 address to presentation format!?!");
targetport = ntohs(sin6->sin6_port);
#else
assert(0);
#endif
}
log_write(LOG_STDOUT|LOG_NORMAL, "CONN (%.4fs) %s localhost > %s:%d => %s\n",
o.TimeSinceStartMS(&tv) / 1000.0,
(proto == IPPROTO_TCP)? "TCP" : "UDP", targetipstr, targetport,
errbuf);
}
/* Converts an IP address given in a sockaddr_storage to an IPv4 or
IPv6 IP address string. Since a static buffer is returned, this is
not thread-safe and can only be used once in calls like printf()
*/
const char *inet_socktop(struct sockaddr_storage *ss) {
static char buf[INET6_ADDRSTRLEN];
struct sockaddr_in *sin = (struct sockaddr_in *) ss;
#if HAVE_IPV6
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss;
#endif
if (inet_ntop(sin->sin_family, (sin->sin_family == AF_INET)?
(char *) &sin->sin_addr :
#if HAVE_IPV6
(char *) &sin6->sin6_addr,
#else
(char *) NULL,
#endif /* HAVE_IPV6 */
buf, sizeof(buf)) == NULL) {
fatal("Failed to convert target address to presentation format in inet_socktop!?! Error: %s", strerror(socket_errno()));
}
return buf;
}
/* Tries to resolve the given name (or literal IP) into a sockaddr
structure. The af should be PF_INET (for IPv4) or PF_INET6. Returns 0
if hostname cannot be resolved. It is OK to pass in a sockaddr_in or
sockaddr_in6 casted to a sockaddr_storage as long as you use the matching
pf.*/
int resolve(char *hostname, struct sockaddr_storage *ss, size_t *sslen,
int pf) {
struct addrinfo hints;
struct addrinfo *result;
int rc;
assert(ss);
assert(sslen);
memset(&hints, 0, sizeof(hints));
hints.ai_family = pf;
rc = getaddrinfo(hostname, NULL, &hints, &result);
if (rc != 0)
return 0;
assert(result->ai_addrlen > 0 && result->ai_addrlen <= (int) sizeof(struct sockaddr_storage));
*sslen = result->ai_addrlen;
memcpy(ss, result->ai_addr, *sslen);
freeaddrinfo(result);
return 1;
}
/* Returns a buffer of ASCII information about a packet that may look
like "TCP 127.0.0.1:50923 > 127.0.0.1:3 S ttl=61 id=39516 iplen=40
seq=625950769" or "ICMP PING (0/1) ttl=61 id=39516 iplen=40".
Since this is a static buffer, don't use threads or call twice
within (say) printf(). And certainly don't try to free() it! The
returned buffer is NUL-terminated */
const char *ippackethdrinfo(const u8 *packet, u32 len) {
static const char *ippackethdrinfo(const u8 *packet, u32 len) {
static char protoinfo[256];
struct ip *ip = (struct ip *) packet;
struct tcphdr *tcp;
@@ -619,6 +476,148 @@ const char *ippackethdrinfo(const u8 *packet, u32 len) {
return protoinfo;
}
/* Takes an IP PACKET and prints it if packet tracing is enabled.
'packet' must point to the IPv4 header. The direction must be
PacketTrace::SENT or PacketTrace::RCVD . Optional 'now' argument
makes this function slightly more efficient by avoiding a gettimeofday()
call. */
void PacketTrace::trace(pdirection pdir, const u8 *packet, u32 len,
struct timeval *now) {
struct timeval tv;
if (pdir == SENT) {
PktCt.sendPackets++;
PktCt.sendBytes += len;
} else {
PktCt.recvPackets++;
PktCt.recvBytes += len;
}
if (!o.packetTrace()) return;
if (now)
tv = *now;
else gettimeofday(&tv, NULL);
if (len < 20) {
error("Packet tracer: tiny packet encountered");
return;
}
log_write(LOG_STDOUT|LOG_NORMAL, "%s (%.4fs) %s\n", (pdir == SENT)? "SENT" : "RCVD", o.TimeSinceStartMS(&tv) / 1000.0, ippackethdrinfo(packet, len));
return;
}
/* Adds a trace entry when a connect() is attempted if packet tracing
is enabled. Pass IPPROTO_TCP or IPPROTO_UDP as the protocol. The
sock may be a sockaddr_in or sockaddr_in6. The return code of
connect is passed in connectrc. If the return code is -1, get the
errno and pass that as connect_errno. */
void PacketTrace::traceConnect(u8 proto, const struct sockaddr *sock,
int socklen, int connectrc, int connect_errno,
const struct timeval *now) {
struct sockaddr_in *sin = (struct sockaddr_in *) sock;
#if HAVE_IPV6
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sock;
#endif
struct timeval tv;
char errbuf[64] = "";
char targetipstr[INET6_ADDRSTRLEN] = "";
u16 targetport = 0;
if (!o.packetTrace()) return;
if (now)
tv = *now;
else gettimeofday(&tv, NULL);
assert(proto == IPPROTO_TCP || proto == IPPROTO_UDP);
if (connectrc == 0)
Strncpy(errbuf, "Connected", sizeof(errbuf));
else {
snprintf(errbuf, sizeof(errbuf), "%s", strerror(connect_errno));
}
if (sin->sin_family == AF_INET) {
if (inet_ntop(sin->sin_family, (char *) &sin->sin_addr, targetipstr,
sizeof(targetipstr)) == NULL)
fatal("Failed to convert target IPv4 address to presentation format!?!");
targetport = ntohs(sin->sin_port);
} else {
#if HAVE_IPV6
assert(sin->sin_family == AF_INET6);
if (inet_ntop(sin->sin_family, (char *) &sin6->sin6_addr, targetipstr,
sizeof(targetipstr)) == NULL)
fatal("Failed to convert target IPv4 address to presentation format!?!");
targetport = ntohs(sin6->sin6_port);
#else
assert(0);
#endif
}
log_write(LOG_STDOUT|LOG_NORMAL, "CONN (%.4fs) %s localhost > %s:%d => %s\n",
o.TimeSinceStartMS(&tv) / 1000.0,
(proto == IPPROTO_TCP)? "TCP" : "UDP", targetipstr, targetport,
errbuf);
}
/* Converts an IP address given in a sockaddr_storage to an IPv4 or
IPv6 IP address string. Since a static buffer is returned, this is
not thread-safe and can only be used once in calls like printf()
*/
const char *inet_socktop(struct sockaddr_storage *ss) {
static char buf[INET6_ADDRSTRLEN];
struct sockaddr_in *sin = (struct sockaddr_in *) ss;
#if HAVE_IPV6
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss;
#endif
if (inet_ntop(sin->sin_family, (sin->sin_family == AF_INET)?
(char *) &sin->sin_addr :
#if HAVE_IPV6
(char *) &sin6->sin6_addr,
#else
(char *) NULL,
#endif /* HAVE_IPV6 */
buf, sizeof(buf)) == NULL) {
fatal("Failed to convert target address to presentation format in inet_socktop!?! Error: %s", strerror(socket_errno()));
}
return buf;
}
/* Tries to resolve the given name (or literal IP) into a sockaddr
structure. The af should be PF_INET (for IPv4) or PF_INET6. Returns 0
if hostname cannot be resolved. It is OK to pass in a sockaddr_in or
sockaddr_in6 casted to a sockaddr_storage as long as you use the matching
pf.*/
int resolve(char *hostname, struct sockaddr_storage *ss, size_t *sslen,
int pf) {
struct addrinfo hints;
struct addrinfo *result;
int rc;
assert(ss);
assert(sslen);
memset(&hints, 0, sizeof(hints));
hints.ai_family = pf;
rc = getaddrinfo(hostname, NULL, &hints, &result);
if (rc != 0)
return 0;
assert(result->ai_addrlen > 0 && result->ai_addrlen <= (int) sizeof(struct sockaddr_storage));
*sslen = result->ai_addrlen;
memcpy(ss, result->ai_addr, *sslen);
freeaddrinfo(result);
return 1;
}
int islocalhost(const struct in_addr * const addr) {
char dev[128];
@@ -937,6 +936,87 @@ int send_tcp_raw( int sd, struct eth_nfo *eth, const struct in_addr *source,
return res;
}
/* Create and send all fragments of a pre-built IPv4 packet
* Minimal MTU for IPv4 is 68 and maximal IPv4 header size is 60
* which gives us a right to cut TCP header after 8th byte
* (shouldn't we inflate the header to 60 bytes too?) */
int send_frag_ip_packet(int sd, struct eth_nfo *eth, u8 *packet,
unsigned int packetlen, unsigned int mtu)
{
struct ip *ip = (struct ip *) packet;
int headerlen = ip->ip_hl * 4; // better than sizeof(struct ip)
unsigned int datalen = packetlen - headerlen;
int fdatalen = 0, res = 0;
assert(headerlen <= (int) packetlen);
assert(headerlen >= 20 && headerlen <= 60); // sanity check (RFC791)
assert(mtu > 0 && mtu % 8 == 0); // otherwise, we couldn't set Fragment offset (ip->ip_off) correctly
if (datalen <= mtu) {
error("Warning: fragmentation (mtu=%i) requested but the payload is too small already (%i)", mtu, datalen);
return send_ip_packet(sd, eth, packet, packetlen);
}
u8 *fpacket = (u8 *) safe_malloc(headerlen + mtu);
memcpy(fpacket, packet, headerlen + mtu);
ip = (struct ip *) fpacket;
// create fragments and send them
for (int fragment = 1; fragment * mtu < datalen + mtu; fragment++) {
fdatalen = (fragment * mtu <= datalen ? mtu : datalen % mtu);
ip->ip_len = htons(headerlen + fdatalen);
ip->ip_off = htons((fragment-1) * mtu / 8);
if ((fragment-1) * mtu + fdatalen < datalen)
ip->ip_off |= htons(IP_MF);
#if HAVE_IP_IP_SUM
ip->ip_sum = in_cksum((unsigned short *)ip, headerlen);
#endif
if (fragment > 1) // copy data payload
memcpy(fpacket + headerlen, packet + headerlen + (fragment - 1) * mtu, fdatalen);
res = send_ip_packet(sd, eth, fpacket, headerlen + fdatalen);
if (res == -1)
break;
}
free(fpacket);
return res;
}
static int Sendto(char *functionname, int sd, const unsigned char *packet,
int len, unsigned int flags, struct sockaddr *to, int tolen) {
struct sockaddr_in *sin = (struct sockaddr_in *) to;
int res;
int retries = 0;
int sleeptime = 0;
do {
if ((res = sendto(sd, (const char *) packet, len, flags, to, tolen)) == -1) {
int err = socket_errno();
error("sendto in %s: sendto(%d, packet, %d, 0, %s, %d) => %s",
functionname, sd, len, inet_ntoa(sin->sin_addr), tolen,
strerror(err));
#if WIN32
return -1;
#else
if (retries > 2 || err == EPERM || err == EACCES || err == EADDRNOTAVAIL
|| err == EINVAL)
return -1;
sleeptime = 15 * (1 << (2 * retries));
error("Sleeping %d seconds then retrying", sleeptime);
fflush(stderr);
sleep(sleeptime);
#endif
}
retries++;
} while( res == -1);
PacketTrace::trace(PacketTrace::SENT, packet, len);
return res;
}
/* Send a pre-built IPv4 packet */
int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet, unsigned int packetlen) {
struct sockaddr_in sock;
@@ -1007,53 +1087,6 @@ int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet, unsigned int packetl
return res;
}
/* Create and send all fragments of a pre-built IPv4 packet
* Minimal MTU for IPv4 is 68 and maximal IPv4 header size is 60
* which gives us a right to cut TCP header after 8th byte
* (shouldn't we inflate the header to 60 bytes too?) */
int send_frag_ip_packet(int sd, struct eth_nfo *eth, u8 *packet,
unsigned int packetlen, unsigned int mtu)
{
struct ip *ip = (struct ip *) packet;
int headerlen = ip->ip_hl * 4; // better than sizeof(struct ip)
unsigned int datalen = packetlen - headerlen;
int fdatalen = 0, res = 0;
assert(headerlen <= (int) packetlen);
assert(headerlen >= 20 && headerlen <= 60); // sanity check (RFC791)
assert(mtu > 0 && mtu % 8 == 0); // otherwise, we couldn't set Fragment offset (ip->ip_off) correctly
if (datalen <= mtu) {
error("Warning: fragmentation (mtu=%i) requested but the payload is too small already (%i)", mtu, datalen);
return send_ip_packet(sd, eth, packet, packetlen);
}
u8 *fpacket = (u8 *) safe_malloc(headerlen + mtu);
memcpy(fpacket, packet, headerlen + mtu);
ip = (struct ip *) fpacket;
// create fragments and send them
for (int fragment = 1; fragment * mtu < datalen + mtu; fragment++) {
fdatalen = (fragment * mtu <= datalen ? mtu : datalen % mtu);
ip->ip_len = htons(headerlen + fdatalen);
ip->ip_off = htons((fragment-1) * mtu / 8);
if ((fragment-1) * mtu + fdatalen < datalen)
ip->ip_off |= htons(IP_MF);
#if HAVE_IP_IP_SUM
ip->ip_sum = in_cksum((unsigned short *)ip, headerlen);
#endif
if (fragment > 1) // copy data payload
memcpy(fpacket + headerlen, packet + headerlen + (fragment - 1) * mtu, fdatalen);
res = send_ip_packet(sd, eth, fpacket, headerlen + fdatalen);
if (res == -1)
break;
}
free(fpacket);
return res;
}
/* Builds an ICMP packet (including an IP header) by packing the fields
with the given information. It allocates a new buffer to store the
packet contents, and then returns that buffer. The packet is not
@@ -1113,19 +1146,6 @@ return build_ip_raw(source, victim, o.ttl, IPPROTO_ICMP, get_random_u16(),
ping, icmplen, packetlen);
}
void readippacket(const u8 *packet, int readdata) {
struct ip *ip = (struct ip *) packet;
switch(ip->ip_p) {
case IPPROTO_UDP:
readudppacket(packet, readdata);
break;
/* Should add ICMP here at some point */
default:
readtcppacket(packet, readdata);
break;
}
}
/* A simple function I wrote to help in debugging, shows the important fields
of a TCP packet*/
@@ -1659,7 +1679,9 @@ bool pcap_recv_timeval_valid() {
with the given ip (ss) and mac address. An existing entry for the
IP ss will be overwritten with the new MAC address. true is always
returned for the set command. */
bool NmapArpCache(int command, struct sockaddr_storage *ss, u8 *mac) {
#define ARPCACHE_GET 1
#define ARPCACHE_SET 2
static bool NmapArpCache(int command, struct sockaddr_storage *ss, u8 *mac) {
struct sockaddr_in *sin = (struct sockaddr_in *) ss;
struct ArpCache {
u32 ip; /* Network byte order */
@@ -1856,7 +1878,7 @@ int setTargetMACIfAvailable(Target *target, struct link_header *linkhdr,
broadcast MAC address. The transmission is attempted up to 3
times. If none of these elicit a response, false will be returned.
If the mac is determined, true is returned. */
bool doArp(const char *dev, const u8 *srcmac,
static bool doArp(const char *dev, const u8 *srcmac,
const struct sockaddr_storage *srcip,
const struct sockaddr_storage *targetip, u8 *targetmac) {
/* timeouts in microseconds ... the first ones are retransmit times, while
@@ -2084,7 +2106,7 @@ struct dnet_collector_route_nfo {
int numifaces;
};
int collect_dnet_routes(const struct route_entry *entry, void *arg) {
static int collect_dnet_routes(const struct route_entry *entry, void *arg) {
struct dnet_collector_route_nfo *dcrn = (struct dnet_collector_route_nfo *) arg;
int i;
@@ -2122,7 +2144,7 @@ int collect_dnet_routes(const struct route_entry *entry, void *arg) {
return 0;
}
int collect_dnet_interfaces(const struct intf_entry *entry, void *arg) {
static int collect_dnet_interfaces(const struct intf_entry *entry, void *arg) {
struct dnet_collector_route_nfo *dcrn = (struct dnet_collector_route_nfo *) arg;
int i;
int numifaces = dcrn->numifaces;
@@ -2840,41 +2862,6 @@ if (echots) *echots = 0;
return 0;
}
int Sendto(char *functionname, int sd, const unsigned char *packet, int len,
unsigned int flags, struct sockaddr *to, int tolen) {
struct sockaddr_in *sin = (struct sockaddr_in *) to;
int res;
int retries = 0;
int sleeptime = 0;
do {
if ((res = sendto(sd, (const char *) packet, len, flags, to, tolen)) == -1) {
int err = socket_errno();
error("sendto in %s: sendto(%d, packet, %d, 0, %s, %d) => %s",
functionname, sd, len, inet_ntoa(sin->sin_addr), tolen,
strerror(err));
#if WIN32
return -1;
#else
if (retries > 2 || err == EPERM || err == EACCES || err == EADDRNOTAVAIL
|| err == EINVAL)
return -1;
sleeptime = 15 * (1 << (2 * retries));
error("Sleeping %d seconds then retrying", sleeptime);
fflush(stderr);
sleep(sleeptime);
#endif
}
retries++;
} while( res == -1);
PacketTrace::trace(PacketTrace::SENT, packet, len);
return res;
}
IPProbe::IPProbe() {
packetbuflen = 0;
packetbuf = NULL;

38
tcpip.h
View File

@@ -629,11 +629,6 @@ u8 *build_ip_raw(const struct in_addr *source, const struct in_addr *victim,
int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet,
unsigned int packetlen);
/* Create and send all fragments of the pre-built packet */
/* mtu = MTU - ipv4_headerlen */
int send_frag_ip_packet(int sd, struct eth_nfo *eth, u8 *packet,
unsigned int packetlen, unsigned int mtu);
/* Decoy versions of the raw packet sending functions ... */
int send_tcp_raw_decoys( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl,
@@ -656,15 +651,6 @@ pcap_t *my_pcap_open_live(const char *device, int snaplen, int promisc,
// invalid (Windows and Amiga), readip_pcap returns the time you called it.
bool pcap_recv_timeval_valid();
/* Returns a buffer of ASCII information about a packet that may look
like "TCP 127.0.0.1:50923 > 127.0.0.1:3 S ttl=61 id=39516 iplen=40
seq=625950769" or "ICMP PING (0/1) ttl=61 id=39516 iplen=40".
Since this is a static buffer, don't use threads or call twice
within (say) printf(). And certainly don't try to free() it! The
returned buffer is NUL-terminated */
const char *ippackethdrinfo(const u8 *packet, u32 len);
/* Shows the most important fields of an IP packet (including dissecting TCP/UDP headers. packet should point to the beginning of the IP header */
void readippacket(const u8 *packet, int readdata);
/* A simple function I wrote to help in debugging, shows the important fields
of a TCP packet*/
int readtcppacket(const u8 *packet, int readdata);
@@ -726,8 +712,6 @@ bool setTargetNextHopMAC(Target *target);
int islocalhost(const struct in_addr * const addr);
int unblock_socket(int sd);
int Sendto(char *functionname, int sd, const unsigned char *packet, int len,
unsigned int flags, struct sockaddr *to, int tolen);
// Takes a protocol number like IPPROTO_TCP, IPPROTO_UDP, or
// IPPROTO_TCP and returns a ascii representation (or "unknown" if it
@@ -744,19 +728,6 @@ int get_link_offset(char *device);
char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
struct timeval *rcvdtime, struct link_header *linknfo);
/* A trivial functon that maintains a cache of IP to MAC Address
entries. If the command is ARPCACHE_GEt, this func looks for the
IPv4 address in ss and fills in the 'mac' parameter and returns
true if it is found. Otherwise (not found), the function returns
false. If the command is ARPCACHE_SET, the function adds an entry
with the given ip (ss) and mac address. An existing entry for the
IP ss will be overwritten with the new MAC address. true is always
returned for the set command. */
#define ARPCACHE_GET 1
#define ARPCACHE_SET 2
bool NmapArpCache(int command, struct sockaddr_storage *ss, u8 *mac);
/* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap
descriptor pd. If it receives one, fills in sendermac (must pass
in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
@@ -767,15 +738,6 @@ bool NmapArpCache(int command, struct sockaddr_storage *ss, u8 *mac);
int read_arp_reply_pcap(pcap_t *pd, u8 *sendermac, struct in_addr *senderIP,
long to_usec, struct timeval *rcvdtime);
/* Issues an ARP request for the MAC of targetss (which will be placed
in targetmac if obtained) from the source IP (srcip) and source mac
(srcmac) given. "The request is ussued using device dev to the
broadcast MAC address. The transmission is attempted up to 3
times. If none of these elicit a response, false will be returned.
If the mac is determined, true is returned. */
bool doArp(const char *dev, u8 *srcmac, struct sockaddr_storage *srcip,
struct sockaddr_storage *targetip, u8 *targetmac);
#ifndef HAVE_INET_ATON
int inet_aton(register const char *, struct in_addr *);
#endif

66
tty.cc
View File

@@ -127,7 +127,7 @@ extern NmapOps o;
// Microsoft's runtime makes this fairly simple. :)
void tty_init() { return; }
static int tty_getchar() { return _kbhit() ? getch() : -1; }
void tty_done() { return; }
static void tty_done() { return; }
#else
#if !defined(O_NONBLOCK) && defined(O_NDELAY)
@@ -146,33 +146,6 @@ extern int tcsetattr(int fd, int actions, struct termios *termios_p);
static int tty_fd = 0;
static struct termios saved_ti;
void tty_init()
{
int fd;
struct termios ti;
if ((fd = open("/dev/tty", O_RDONLY | O_NONBLOCK)) < 0) return;
#ifndef __CYGWIN32__
if (tcgetpgrp(fd) != getpid()) {
close(fd); return;
}
#endif
tcgetattr(fd, &ti);
if (tty_fd == 0)
saved_ti = ti;
ti.c_lflag &= ~(ICANON | ECHO);
ti.c_cc[VMIN] = 1;
ti.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &ti);
if (tty_fd == 0)
tty_fd = fd;
atexit(tty_done);
}
static int tty_getchar()
{
int c, numChars;
@@ -200,7 +173,7 @@ static int tty_getchar()
return -1;
}
void tty_done()
static void tty_done()
{
int fd;
@@ -212,14 +185,45 @@ void tty_done()
close(fd);
}
/*
* 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()
{
int fd;
struct termios ti;
if ((fd = open("/dev/tty", O_RDONLY | O_NONBLOCK)) < 0) return;
#ifndef __CYGWIN32__
if (tcgetpgrp(fd) != getpid()) {
close(fd); return;
}
#endif
tcgetattr(fd, &ti);
if (tty_fd == 0)
saved_ti = ti;
ti.c_lflag &= ~(ICANON | ECHO);
ti.c_cc[VMIN] = 1;
ti.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &ti);
if (tty_fd == 0)
tty_fd = fd;
atexit(tty_done);
}
#endif //!win32
/* This is the best method here. It will catch all of the predefined
/* 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()
{
int c;

16
tty.h
View File

@@ -97,15 +97,15 @@
***************************************************************************/
/*
* Initializes the terminal for unbuffered non-blocking input. Also registers
* tty_done() via atexit().
* 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();
/*
* Restores the terminal parameters and closes the file descriptor.
*/
void tty_done();
/* This is the best method here. It will catch 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 */
/* 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();

View File

@@ -371,71 +371,6 @@ int Send(int sd, const void *msg, size_t len, int flags) {
return (res < 0)? -1 : (int) len;
}
// Write data to a file descriptor, keep retrying until an error or the full length
// is written. Returns -1 if there is an error, or len if the full length was sent.
// Note that this does NOT work well on Windows using sockets -- so use Send() above
// for those. I don't know if it works with regular files on Windows with files).
ssize_t Write(int fd, const void *buf, size_t count) {
int res;
unsigned int len;
len = 0;
do {
res = write(fd,(char *) buf + len,count - len);
if (res > 0)
len += res;
} while(len < count && (res != -1 || socket_errno() == EINTR));
return (res == -1)? -1 : (int) count;
}
/* gcd_1 and gcd_n_long were sent in by Peter Kosinar <goober@gjh.sk>
Not needed for gcd_n_long, just for the case you'd want to have gcd
for two arguments too. */
unsigned long gcd_ulong(unsigned long a, unsigned long b)
{
/* Shorter
while (b) { a%=b; if (!a) return b; b%=a; } */
/* Faster */
unsigned long c;
if (a<b) { c=a; a=b; b=c; }
while (b) { c=a%b; a=b; b=c; }
/* Common for both */
return a;
}
unsigned long gcd_n_ulong(long nvals, unsigned long *val)
{
unsigned long a,b,c;
if (!nvals) return 1;
a=*val;
for (nvals--;nvals;nvals--)
{
b=*++val;
if (a<b) { c=a; a=b; b=c; }
while (b) { c=a%b; a=b; b=c; }
}
return a;
}
unsigned int gcd_uint(unsigned int a, unsigned int b)
{
/* Shorter
while (b) { a%=b; if (!a) return b; b%=a; } */
/* Faster */
unsigned int c;
if (a<b) { c=a; a=b; b=c; }
while (b) { c=a%b; a=b; b=c; }
/* Common for both */
return a;
}
unsigned int gcd_n_uint(int nvals, unsigned int *val)
{
unsigned int a,b,c;

View File

@@ -207,11 +207,6 @@ char *chomp(char *string);
// is sent. Returns -1 if there is an error, or len if the full length was sent.
int Send(int sd, const void *msg, size_t len, int flags);
ssize_t Write(int fd, const void *buf, size_t count);
unsigned long gcd_ulong(unsigned long a, unsigned long b);
unsigned int gcd_uint(unsigned int a, unsigned int b);
unsigned long gcd_n_ulong(long nvals, unsigned long *val);
unsigned int gcd_n_uint(int nvals, unsigned int *val);
int arg_parse(const char *command, char ***argv);