diff --git a/Makefile.in b/Makefile.in index c1c71075d..240300f48 100644 --- a/Makefile.in +++ b/Makefile.in @@ -98,11 +98,11 @@ NSE_OBJS+=nse_openssl.o nse_ssl_cert.o endif endif -export SRCS = charpool.cc FingerPrintResults.cc FPEngine.cc FPModel.cc idle_scan.cc MACLookup.cc main.cc nmap.cc nmap_dns.cc nmap_error.cc nmap_ftp.cc NmapOps.cc NmapOutputTable.cc nmap_tty.cc osscan2.cc osscan.cc output.cc payload.cc portlist.cc portreasons.cc protocols.cc scan_engine.cc scan_engine_connect.cc scan_engine_raw.cc service_scan.cc services.cc Target.cc TargetGroup.cc targets.cc tcpip.cc timing.cc traceroute.cc utils.cc xml.cc $(NSE_SRC) +export SRCS = charpool.cc FingerPrintResults.cc FPEngine.cc FPModel.cc idle_scan.cc MACLookup.cc main.cc nmap.cc nmap_dns.cc nmap_error.cc nmap_ftp.cc NmapOps.cc NmapOutputTable.cc nmap_tty.cc osscan2.cc osscan.cc output.cc payload.cc portlist.cc portreasons.cc protocols.cc scan_engine.cc scan_engine_connect.cc scan_engine_raw.cc scan_lists.cc service_scan.cc services.cc Target.cc TargetGroup.cc targets.cc tcpip.cc timing.cc traceroute.cc utils.cc xml.cc $(NSE_SRC) -export HDRS = charpool.h FingerPrintResults.h FPEngine.h idle_scan.h MACLookup.h nmap_amigaos.h nmap_dns.h nmap_error.h nmap.h nmap_ftp.h NmapOps.h NmapOutputTable.h nmap_tty.h nmap_winconfig.h osscan2.h osscan.h output.h payload.h portlist.h portreasons.h protocols.h scan_engine.h scan_engine_connect.h scan_engine_raw.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h traceroute.h utils.h xml.h $(NSE_HDRS) +export HDRS = charpool.h FingerPrintResults.h FPEngine.h idle_scan.h MACLookup.h nmap_amigaos.h nmap_dns.h nmap_error.h nmap.h nmap_ftp.h NmapOps.h NmapOutputTable.h nmap_tty.h nmap_winconfig.h osscan2.h osscan.h output.h payload.h portlist.h portreasons.h protocols.h scan_engine.h scan_engine_connect.h scan_engine_raw.h service_scan.h scan_lists.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h traceroute.h utils.h xml.h $(NSE_HDRS) -OBJS = charpool.o FingerPrintResults.o FPEngine.o FPModel.o idle_scan.o MACLookup.o nmap_dns.o nmap_error.o nmap.o nmap_ftp.o NmapOps.o NmapOutputTable.o nmap_tty.o osscan2.o osscan.o output.o payload.o portlist.o portreasons.o protocols.o scan_engine.o scan_engine_connect.o scan_engine_raw.o service_scan.o services.o TargetGroup.o Target.o targets.o tcpip.o timing.o traceroute.o utils.o xml.o $(NSE_OBJS) +OBJS = charpool.o FingerPrintResults.o FPEngine.o FPModel.o idle_scan.o MACLookup.o nmap_dns.o nmap_error.o nmap.o nmap_ftp.o NmapOps.o NmapOutputTable.o nmap_tty.o osscan2.o osscan.o output.o payload.o portlist.o portreasons.o protocols.o scan_engine.o scan_engine_connect.o scan_engine_raw.o scan_lists.o service_scan.o services.o TargetGroup.o Target.o targets.o tcpip.o timing.o traceroute.o utils.o xml.o $(NSE_OBJS) # %.o : %.cc -- nope this is a GNU extension .cc.o: diff --git a/NmapOps.h b/NmapOps.h index 58df18c80..be8d85567 100644 --- a/NmapOps.h +++ b/NmapOps.h @@ -133,7 +133,8 @@ #ifndef NMAP_OPS_H #define NMAP_OPS_H -#include "nmap.h" +#include "nmap.h" /* MAX_DECOYS */ +#include "scan_lists.h" #include "output.h" #include #include diff --git a/idle_scan.cc b/idle_scan.cc index 1f0f01918..8411313ed 100644 --- a/idle_scan.cc +++ b/idle_scan.cc @@ -164,6 +164,7 @@ #include "timing.h" #include "osscan2.h" #include "nmap.h" +#include "scan_lists.h" #include "NmapOps.h" #include "services.h" #include "Target.h" diff --git a/nmap.cc b/nmap.cc index 8328d6c2e..d906d8f07 100644 --- a/nmap.cc +++ b/nmap.cc @@ -153,6 +153,7 @@ #include "nmap_error.h" #include "utils.h" #include "xml.h" +#include "scan_lists.h" #ifndef NOLUA #include "nse_main.h" @@ -2443,446 +2444,6 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) { } - -/* Convert a string like "-100,n*tp,200-1024,3000-4000,[60000-]" into an array - * of port numbers. Note that one trailing comma is OK -- this is actually - * useful for machine generated lists - * - * Fyodor - Wrote original - * William McVey - Added T:, U:, P: directives - * Doug Hoyte - Added [], name lookups, and wildcard expansion - * - * getpts() handles [] - * Any port ranges included inside square brackets will have all - * their ports looked up in nmap-services or nmap-protocols - * and will only be included if they are found. - * Returns a scan_list* with all the ports that should be scanned. - * - * getpts() handles service/protocol name lookups and wildcard expansion. - * The service name can be specified instead of the port number. - * For example, "ssh" can be used instead of "22". You can use wildcards - * like "*" and "?". See the function wildtest() for the exact details. - * For example, - * - * nmap -p http* host - * - * Will scan http (80), http-mgmt (280), http-proxy (8080), https (443), etc. - * - * Matching is case INsensitive but the first character in a match MUST - * be lowercase so it doesn't conflict with the T:, U:, and P: directives. - * - * getpts() is unable to match service names that start with a digit - * like 3com-tsmux (106/udp). Use a pattern like "?com-*" instead. - * - * BE CAREFUL ABOUT SHELL EXPANSIONS!!! - * If you are trying to match the services nmsp (537/tcp) and nms (1429/tcp) - * and you execute the command - * - * ./nmap -p nm* host - * - * You will see - * - * Found no matches for the service mask 'nmap' and your specified protocols - * QUITTING! - * - * This is because nm* was expanded to the name of the binary file nmap in - * the current directory by your shell. When unsure, quote your port strings - * to be safe: - * - * ./nmap -p 'nm*' host - * - * getpts() is smart enough to keep the T: U: and P: directives nested - * and working in a logical manner. For instance, - * - * nmap -sTU -p [U:1025-],1-1024 host - * - * Will scan UDP ports 1025 and up that are found in the service file - * and all TCP/UDP ports below <= 1024. Notice that the U doesn't affect - * the outer part of the port expression. It's "closed". - */ - -static void getpts_aux(const char *origexpr, int nested, u8 *porttbl, int range_type, - int *portwarning, bool change_range_type = true); - -void getpts(const char *origexpr, struct scan_lists *ports) { - u8 *porttbl; - int range_type = 0; - int portwarning = 0; - int i, tcpi, udpi, sctpi, proti; - - if (o.TCPScan()) - range_type |= SCAN_TCP_PORT; - if (o.UDPScan()) - range_type |= SCAN_UDP_PORT; - if (o.SCTPScan()) - range_type |= SCAN_SCTP_PORT; - if (o.ipprotscan) - range_type |= SCAN_PROTOCOLS; - if (o.noportscan && o.exclude_portlist) { // We want to exclude from ping scans in this case but we take port list normally and then removepts() handles it - range_type |= SCAN_TCP_PORT; - range_type |= SCAN_UDP_PORT; - range_type |= SCAN_SCTP_PORT; - } - - porttbl = (u8 *) safe_zalloc(65536); - - getpts_aux(origexpr, // Pass on the expression - 0, // Don't start off nested - porttbl, // Our allocated port table - range_type, // Defaults to TCP/UDP/SCTP/Protos - &portwarning); // No, we haven't warned them about dup ports yet - - ports->tcp_count = 0; - ports->udp_count = 0; - ports->sctp_count = 0; - ports->prot_count = 0; - for (i = 0; i <= 65535; i++) { - if (porttbl[i] & SCAN_TCP_PORT) - ports->tcp_count++; - if (porttbl[i] & SCAN_UDP_PORT) - ports->udp_count++; - if (porttbl[i] & SCAN_SCTP_PORT) - ports->sctp_count++; - if (porttbl[i] & SCAN_PROTOCOLS && i < 256) - ports->prot_count++; - } - - if (range_type != 0 && 0 == (ports->tcp_count + ports->udp_count + ports->sctp_count + ports->prot_count)) - fatal("No ports specified -- If you really don't want to scan any ports use ping scan..."); - - if (ports->tcp_count) { - ports->tcp_ports = (unsigned short *)safe_zalloc(ports->tcp_count * sizeof(unsigned short)); - } - if (ports->udp_count) { - ports->udp_ports = (unsigned short *)safe_zalloc(ports->udp_count * sizeof(unsigned short)); - } - if (ports->sctp_count) { - ports->sctp_ports = (unsigned short *)safe_zalloc(ports->sctp_count * sizeof(unsigned short)); - } - if (ports->prot_count) { - ports->prots = (unsigned short *)safe_zalloc(ports->prot_count * sizeof(unsigned short)); - } - - for (i = tcpi = udpi = sctpi = proti = 0; i <= 65535; i++) { - if (porttbl[i] & SCAN_TCP_PORT) - ports->tcp_ports[tcpi++] = i; - if (porttbl[i] & SCAN_UDP_PORT) - ports->udp_ports[udpi++] = i; - if (porttbl[i] & SCAN_SCTP_PORT) - ports->sctp_ports[sctpi++] = i; - if (porttbl[i] & SCAN_PROTOCOLS && i < 256) - ports->prots[proti++] = i; - } - - free(porttbl); -} - -/* This function is like getpts except it only allocates space for and stores - values into one unsigned short array, instead of an entire scan_lists struct - For that reason, T:, U:, S: and P: restrictions are not allowed and only one - bit in range_type may be set. */ -void getpts_simple(const char *origexpr, int range_type, - unsigned short **list, int *count) { - u8 *porttbl; - int portwarning = 0; - int i, j; - - /* Make sure that only one bit in range_type is set (or that range_type is 0, - which is useless but not incorrect). */ - assert((range_type & (range_type - 1)) == 0); - - porttbl = (u8 *) safe_zalloc(65536); - - /* Get the ports but do not allow changing the type with T:, U:, or P:. */ - getpts_aux(origexpr, 0, porttbl, range_type, &portwarning, false); - - /* Count how many are set. */ - *count = 0; - for (i = 0; i <= 65535; i++) { - if (porttbl[i] & range_type) - (*count)++; - } - - if (*count == 0) { - free(porttbl); - return; - } - - *list = (unsigned short *) safe_zalloc(*count * sizeof(unsigned short)); - - /* Fill in the list. */ - for (i = 0, j = 0; i <= 65535; i++) { - if (porttbl[i] & range_type) - (*list)[j++] = i; - } - - free(porttbl); -} - -/* removepts() takes a port specification and removes any matching ports - from the given scan_lists struct. */ - -static int remaining_ports(unsigned short int *ports, int count, unsigned short int *exclude_ports, int exclude_count, const char *type = ""); - -void removepts(const char *expr, struct scan_lists * ports) { - static struct scan_lists exclude_ports; - - if (!expr) - return; - - getpts(expr, &exclude_ports); - - #define SUBTRACT_PORTS(type,excludetype) \ - ports->type##_count = remaining_ports(ports->type##_ports, \ - ports->type##_count, \ - exclude_ports.excludetype##_ports, \ - exclude_ports.excludetype##_count, \ - #type) - - SUBTRACT_PORTS(tcp, tcp); - SUBTRACT_PORTS(udp, udp); - SUBTRACT_PORTS(sctp, sctp); - SUBTRACT_PORTS(syn_ping, tcp); - SUBTRACT_PORTS(ack_ping, tcp); - SUBTRACT_PORTS(udp_ping, udp); - SUBTRACT_PORTS(sctp_ping, sctp); - - #define prot_ports prots - SUBTRACT_PORTS(prot, prot); - SUBTRACT_PORTS(proto_ping, prot); - #undef prot_ports - - #undef SUBTRACT_PORTS - - free_scan_lists(&exclude_ports); -} - -/* This function returns the number of ports that remain after the excluded ports - are removed from the ports. It places these ports at the start of the ports array. */ -static int remaining_ports(unsigned short int *ports, int count, unsigned short int *exclude_ports, int exclude_count, const char *type) { - static bool has_been_excluded[65536]; - int i, j; - - if (count == 0 || exclude_count == 0) - return count; - - if (o.debugging > 1) - log_write(LOG_STDOUT, "Removed %s ports: ", type); - - for (i = 0; i < 65536; i++) - has_been_excluded[i] = false; - for (i = 0; i < exclude_count; i++) - has_been_excluded[exclude_ports[i]] = true; - for (i = 0, j = 0; i < count; i++) - if (!has_been_excluded[ports[i]]) - ports[j++] = ports[i]; - else if (o.debugging > 1) - log_write(LOG_STDOUT, "%d ", ports[i]); - - if (o.debugging > 1) { - if (count-j) { - log_write(LOG_STDOUT, "\n"); - } else { - log_write(LOG_STDOUT, "None\n"); - } - } - if (o.debugging && count-j) { - log_write(LOG_STDOUT, "Removed %d %s ports that would have been considered for scanning otherwise.\n", count-j, type); - } - - return j; -} - -/* getpts() and getpts_simple() (see above) are wrappers for this function */ - -static void getpts_aux(const char *origexpr, int nested, u8 *porttbl, int range_type, int *portwarning, bool change_range_type) { - long rangestart = -2343242, rangeend = -9324423; - const char *current_range; - char *endptr; - char servmask[128]; // A protocol name can be up to 127 chars + nul byte - int i; - - /* An example of proper syntax to use in error messages. */ - const char *syntax_example; - if (change_range_type) - syntax_example = "-100,200-1024,T:3000-4000,U:60000-"; - else - syntax_example = "-100,200-1024,3000-4000,60000-"; - - current_range = origexpr; - do { - while (isspace((int) (unsigned char) *current_range)) - current_range++; /* I don't know why I should allow spaces here, but I will */ - - if (change_range_type) { - if (*current_range == 'T' && *(current_range+1) == ':') { - current_range += 2; - range_type = SCAN_TCP_PORT; - continue; - } - if (*current_range == 'U' && *(current_range+1) == ':') { - current_range += 2; - range_type = SCAN_UDP_PORT; - continue; - } - if (*current_range == 'S' && *(current_range+1) == ':') { - current_range += 2; - range_type = SCAN_SCTP_PORT; - continue; - } - if (*current_range == 'P' && *(current_range+1) == ':') { - current_range += 2; - range_type = SCAN_PROTOCOLS; - continue; - } - } - - if (*current_range == '[') { - if (nested) - fatal("Can't nest [] brackets in port/protocol specification"); - - getpts_aux(++current_range, 1, porttbl, range_type, portwarning); - - // Skip past the ']'. This is OK because we can't nest []s - while (*current_range != ']' && *current_range != '\0') - current_range++; - if (*current_range == ']') - current_range++; - - // Skip over a following ',' so we're ready to keep parsing - if (*current_range == ',') - current_range++; - - continue; - } else if (*current_range == ']') { - if (!nested) - fatal("Unexpected ] character in port/protocol specification"); - - return; - } else if (*current_range == '-') { - if (range_type & SCAN_PROTOCOLS) - rangestart = 0; - else - rangestart = 1; - } else if (isdigit((int) (unsigned char) *current_range)) { - rangestart = strtol(current_range, &endptr, 10); - if (range_type & SCAN_PROTOCOLS) { - if (rangestart < 0 || rangestart > 255) - fatal("Protocols specified must be between 0 and 255 inclusive"); - } else { - if (rangestart < 0 || rangestart > 65535) - fatal("Ports specified must be between 0 and 65535 inclusive"); - } - current_range = endptr; - while (isspace((int) (unsigned char) *current_range)) current_range++; - } else if (islower((int) (unsigned char) *current_range) || *current_range == '*' || *current_range == '?') { - i = 0; - - while (*current_range && !isspace((int) (unsigned char) *current_range) && *current_range != ',' && *current_range != ']') { - servmask[i++] = *(current_range++); - if (i >= ((int)sizeof(servmask) - 1)) - fatal("A service mask in the port/protocol specification is either malformed or too long"); - } - - if (*current_range && *current_range != ']') current_range++; // We want the '] character to be picked up on the next pass - servmask[i] = '\0'; // Finish the string - - i = addportsfromservmask(servmask, porttbl, range_type); - if (range_type & SCAN_PROTOCOLS) - i += addprotocolsfromservmask(servmask, porttbl); - - if (i == 0) - fatal("Found no matches for the service mask '%s' and your specified protocols", servmask); - - continue; - - } else { - fatal("Error #485: Your port specifications are illegal. Example of proper form: \"%s\"", syntax_example); - } - /* Now I have a rangestart, time to go after rangeend */ - if (!*current_range || *current_range == ',' || *current_range == ']') { - /* Single port specification */ - rangeend = rangestart; - } else if (*current_range == '-') { - current_range++; - if (!*current_range || *current_range == ',' || *current_range == ']') { - /* Ended with a -, meaning up until the last possible port */ - if (range_type & SCAN_PROTOCOLS) - rangeend = 255; - else - rangeend = 65535; - } else if (isdigit((int) (unsigned char) *current_range)) { - rangeend = strtol(current_range, &endptr, 10); - if (range_type & SCAN_PROTOCOLS) { - if (rangeend < 0 || rangeend > 255) - fatal("Protocols specified must be between 0 and 255 inclusive"); - } else { - if (rangeend < 0 || rangeend > 65535) - fatal("Ports specified must be between 0 and 65535 inclusive"); - } - current_range = endptr; - } else { - fatal("Error #486: Your port specifications are illegal. Example of proper form: \"%s\"", syntax_example); - } - if (rangeend < rangestart) { - fatal("Your %s range %ld-%ld is backwards. Did you mean %ld-%ld?", - (range_type & SCAN_PROTOCOLS) ? "protocol" : "port", - rangestart, rangeend, rangeend, rangestart); - } - } else { - fatal("Error #487: Your port specifications are illegal. Example of proper form: \"%s\"", syntax_example); - } - - /* Now I have a rangestart and a rangeend, so I can add these ports */ - while (rangestart <= rangeend) { - if (porttbl[rangestart] & range_type) { - if (!(*portwarning)) { - error("WARNING: Duplicate port number(s) specified. Are you alert enough to be using Nmap? Have some coffee or Jolt(tm)."); - (*portwarning)++; - } - } else { - if (nested) { - if ((range_type & SCAN_TCP_PORT) && - nmap_getservbyport(rangestart, "tcp")) { - porttbl[rangestart] |= SCAN_TCP_PORT; - } - if ((range_type & SCAN_UDP_PORT) && - nmap_getservbyport(rangestart, "udp")) { - porttbl[rangestart] |= SCAN_UDP_PORT; - } - if ((range_type & SCAN_SCTP_PORT) && - nmap_getservbyport(rangestart, "sctp")) { - porttbl[rangestart] |= SCAN_SCTP_PORT; - } - if ((range_type & SCAN_PROTOCOLS) && - nmap_getprotbynum(rangestart)) { - porttbl[rangestart] |= SCAN_PROTOCOLS; - } - } else { - porttbl[rangestart] |= range_type; - } - } - rangestart++; - } - - /* Find the next range */ - while (isspace((int) (unsigned char) *current_range)) current_range++; - - if (*current_range == ']') { - if (!nested) - fatal("Unexpected ] character in port/protocol specification"); - return; - } - - if (*current_range && *current_range != ',') { - fatal("Error #488: Your port specifications are illegal. Example of proper form: \"%s\"", syntax_example); - } - if (*current_range == ',') - current_range++; - } while (current_range && *current_range); - -} - void free_scan_lists(struct scan_lists *ports) { if (ports->tcp_ports) free(ports->tcp_ports); diff --git a/nmap.h b/nmap.h index 13347b58b..b7f3e805c 100644 --- a/nmap.h +++ b/nmap.h @@ -341,53 +341,11 @@ # define recvfrom6_t int #endif -/***********************STRUCTURES**********************************/ - -/* The various kinds of port/protocol scans we can have - * Each element is to point to an array of port/protocol numbers - */ -struct scan_lists { - /* The "synprobes" are also used when doing a connect() ping */ - unsigned short *syn_ping_ports; - unsigned short *ack_ping_ports; - unsigned short *udp_ping_ports; - unsigned short *sctp_ping_ports; - unsigned short *proto_ping_ports; - int syn_ping_count; - int ack_ping_count; - int udp_ping_count; - int sctp_ping_count; - int proto_ping_count; - //the above fields are only used for host discovery - //the fields below are only used for port scanning - unsigned short *tcp_ports; - int tcp_count; - unsigned short *udp_ports; - int udp_count; - unsigned short *sctp_ports; - int sctp_count; - unsigned short *prots; - int prot_count; -}; - -typedef enum { STYPE_UNKNOWN, HOST_DISCOVERY, ACK_SCAN, SYN_SCAN, FIN_SCAN, XMAS_SCAN, UDP_SCAN, CONNECT_SCAN, NULL_SCAN, WINDOW_SCAN, SCTP_INIT_SCAN, SCTP_COOKIE_ECHO_SCAN, MAIMON_SCAN, IPPROT_SCAN, PING_SCAN, PING_SCAN_ARP, IDLE_SCAN, BOUNCE_SCAN, SERVICE_SCAN, OS_SCAN, SCRIPT_PRE_SCAN, SCRIPT_SCAN, SCRIPT_POST_SCAN, TRACEROUTE, PING_SCAN_ND }stype; - /***********************PROTOTYPES**********************************/ -/* port manipulators */ -void getpts(const char *expr, struct scan_lists * ports); /* someone stole the name getports()! */ -void getpts_simple(const char *origexpr, int range_type, - unsigned short **list, int *count); -void removepts(const char *expr, struct scan_lists * ports); -void free_scan_lists(struct scan_lists *ports); - /* Renamed main so that interactive mode could preprocess when necessary */ int nmap_main(int argc, char *argv[]); -/* general helper functions */ -const char *statenum2str(int state); -const char *scantype2str(stype scantype); - int nmap_fetchfile(char *filename_returned, int bufferlen, const char *file); int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv); diff --git a/nmap_ftp.h b/nmap_ftp.h index f333ceef9..75039bcf9 100644 --- a/nmap_ftp.h +++ b/nmap_ftp.h @@ -132,6 +132,7 @@ #ifndef NMAP_FTP_H #define NMAP_FTP_H +#include "scan_lists.h" #include "nbase.h" /* u16 */ class Target; diff --git a/nse_main.h b/nse_main.h index 25106caed..2cf735b07 100644 --- a/nse_main.h +++ b/nse_main.h @@ -11,7 +11,7 @@ extern "C" { #include "lualib.h" } -#include "nmap.h" +#include "scan_lists.h" class ScriptResult { diff --git a/output.h b/output.h index 4a8429242..0a556a247 100644 --- a/output.h +++ b/output.h @@ -169,7 +169,7 @@ "think Solaris can support advanced localhost scans. You can probably "\ "use \"-Pn -sT localhost\" though.\n\n" -#include "nmap.h" +#include "scan_lists.h" #ifndef NOLUA #include "nse_main.h" #endif diff --git a/scan_engine.h b/scan_engine.h index 99582bca5..2c8ec0187 100644 --- a/scan_engine.h +++ b/scan_engine.h @@ -134,7 +134,7 @@ #ifndef SCAN_ENGINE_H #define SCAN_ENGINE_H -#include "nmap.h" /* stype */ +#include "scan_lists.h" #include diff --git a/service_scan.cc b/service_scan.cc index 1bc85aea1..c184562da 100644 --- a/service_scan.cc +++ b/service_scan.cc @@ -139,6 +139,7 @@ #include "Target.h" #include "utils.h" #include "protocols.h" +#include "scan_lists.h" #include "nmap_tty.h" diff --git a/services.cc b/services.cc index db18973bc..b22bdc0cd 100644 --- a/services.cc +++ b/services.cc @@ -130,7 +130,7 @@ /* $Id$ */ -#include "nmap.h" +#include "scan_lists.h" #include "services.h" #include "NmapOps.h" #include "charpool.h"