[Javanetsim-cvs] IceScan COPYING, NONE, 1.1 Makefile, NONE, 1.1 csubtarget.h, NONE, 1.1 ctarget.h,
Status: Beta
Brought to you by:
darkkey
From: Alexander B. <da...@us...> - 2006-11-28 17:57:58
|
Update of /cvsroot/javanetsim/IceScan In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv7124 Added Files: COPYING Makefile csubtarget.h ctarget.h icedebug.h icediscover.h iceoutput.h iceparams.h icescan.cc iceservice.h iceversion.h nbt_wrapper.h services Log Message: --- NEW FILE: icescan.cc --- #include "icesockets/csocket.h" #include "iceparams.h" #include "iceversion.h" #include "iceoutput.h" #include "iceservice.h" #include "ctarget.h" void print_help(char *name){ printf("\nUSAGE: %s [options] [Scan type] target\n" "\t target can be hostname or IP address.\n" "WHOLE PROGRAM:\n" "\t-v[v[v[v]]]]: verbose levels\n" "HOST DISCOVERY:\n" "\t-P0: skip host discovery\n" "\t-PA: ACK Ping host discovery\n" "\t-PE: ICMP Echo (aka standart ping) host discovery)\n" "SCAN TYPES:\n" "\t-ST: tcp connect() scan\n" "PORTS SPECIFICATION:\n" "\t-p <port range>: specify port range to scan (default 1-1024).\n" "\t You can use: 1-10; 1; 1-10,12-14; etc.\n" "MISC:\n" "\t-V: print version and exit\n" "\t-?: this message\n\n", name); } bool parse_input(int argc, char *argv[], iceparams *par){ int c; int digit_optind = 0; if(argc>=2){ for(int i = 1; i<argc; i++){ if(argv[i][0] == '-'){ if(strlen(argv[i]) >= 2){ if(argv[i][1] == '-'){ //DBGOUTPUT("Long option is :" << argv[i]); }else{ //DBGOUTPUT("Option is :" << argv[i]); switch(argv[i][1]){ case 'v': par->verbose++; for(int k=2; k<strlen(argv[i]); k++) if(argv[i][k] == 'v') par->verbose++; else { std::cout << "Invalid option: -" << argv[i] << std::endl; print_help(argv[0]); exit(1); } break; case 'V': exit(0); break; case '?': print_help(argv[0]); exit(0); break; case 'S': if(strlen(argv[i])<3){ std::cout << "Invalid scan type." << std::endl; exit(0); //UGLY } switch(argv[i][2]){ case 'T': par->scan_type = TCP_CONNECT_SCAN; break; case 'B': par->scan_type = NBT_SCAN; break; default: std::cout << "Invalid scan type: -S" << argv[i][2] << std::endl; } break; case 'P': if(strlen(argv[i])<3){ std::cout << "Invalid discovery type." << std::endl; exit(0); //UGLY } switch(argv[i][2]){ case '0': par->no_host_discovery = true; break; case 'A': par->ack_ping_discovery = true; break; case 'I': par->icmp_echo_ping_discovery = true; break; default: std::cout << "Invalid discovery type: -P" << argv[i][2] << std::endl; print_help(argv[0]); exit(1); } break; case 'p': if(i+1 < argc){ if(! pcrecpp::RE("(\\d|\\,|\\-)+").FullMatch(argv[i+1]) ){ std::cout << "Invalid port range definition format." << std::endl; print_help(argv[0]); exit(1); }else{ pcrecpp::StringPiece input(argv[i+1]); pcrecpp::RE re("(\\d+(-\\d+)*),*"); string var, var2 = ""; while (re.Consume(&input, &var, &var2)) { struct port_range pr; if(var2 == ""){ sscanf(var.c_str(), "%d", &pr.lower_port); pr.upper_port = pr.lower_port; }else{ sscanf(var.c_str(), "%d-%d", &pr.lower_port, &pr.upper_port); } par->ports.push_back(pr); } i++; } }else{ std::cout << "Invalid port range definition format." << std::endl; print_help(argv[0]); exit(1); } break; default: std::cout << "Invalid option: -" << argv[i][1] << std::endl; print_help(argv[0]); exit(1); } } }else{ std::cout << "Invalid option format..." << std::endl; } }else{ //DBGOUTPUT("Target is: " << argv[i]); par->target = (char *) malloc( strlen(argv[i]) ); strcpy(par->target, argv[i]); } } }else{ std::cout << "Invalid number of arguments." << std::endl; print_help(argv[0]); exit(0); print_help(argv[0]); } return true; } int main(int argc, char *argv[]){ iceoutput out; iceparams par; ice_service_name_database isnd("services"); char version_string[255]; sprintf(version_string, "%s v %s %s, %s", ICENAME, ICEVERSION, ICEWEBSITE, ICEDATE); std::cout << version_string << std::endl; if(! parse_input(argc, argv, &par) ) return 1; //return 0; //DBGOUTPUT((par.verbose)); par.by_default_init(); ctarget t(par.target, &par, &out, &isnd); t.discover(); t.scan(); //DBGOUTPUT("Finishing...."); return 0; } --- NEW FILE: csubtarget.h --- #ifndef CSUBTARGET_H #define CSUBTARGET_H #include <cstdio> #include <cstdlib> #include <map> #include <errno.h> #include <pthread.h> #include "iceoutput.h" #include "iceparams.h" #include "icediscover.h" #include "nbt_wrapper.h" #define CONNECT_TIMEOUT 24 #define ICE_FD_SETSIZE (1024) #define MAX_CLOSED 7 enum port_status { PORT_UNKNOWN = -1, PORT_OPEN = 0, PORT_CLOSED = 1, PORT_FILTERED = 2 }; struct scanned_port{ public: int port_number; enum port_status status; }; class scan_socket{ public: csocket *c; bool busy; scan_socket(){ c = NULL; } }; class scanning_port{ public: char hostname[24]; int port_number; csocket *c; bool done; long time; int socket_ptr; scanning_port(){ c = NULL; } }; class csubtarget{ iceoutput *out; iceparams *par; char *hostname; ice_service_name_database *isnd; public: bool discovered; std::vector<scanned_port> subtarget_ports; csubtarget(char *hostname, iceparams *par, iceoutput *out, ice_service_name_database *isnd){ this->hostname = (char *) malloc(strlen(hostname)); strcpy(this->hostname, hostname); this->par = par; this->out = out; this->isnd = isnd; discovered = false; init_scan_sockets(); } bool discover(){ discovered = host_discover(hostname, par, out); return discovered; } void scan(){ if(par->scan_type == TCP_CONNECT_SCAN) connect_scan(); if(par->scan_type == NBT_SCAN) nbt_scan(); } int nbt_scan(){ // NetBIOS scan, -SB char output_buf[255]; if(par->verbose>0){ sprintf(output_buf, "Starting NetBIOS scan against %s...", hostname); out->line(output_buf); } cnbtwrapper wrap(par); wrap.test(hostname, 137); if(par->verbose>0){ bzero(output_buf, 255); sprintf(output_buf, "NetBIOS scan finished.", hostname); out->line(output_buf); } } int connect_scan(){ // connect scan, -ST char output_buf[255]; //DBGOUTPUT("!!!"); std::map <int, scanning_port> scanning_ports; init_scanning_ports(hostname, par, (int) SOCK_STREAM, scanning_ports); if(par->verbose>0){ sprintf(output_buf, "Starting tcp connect() scan against %s...", hostname); out->line(output_buf); } int j = initiate_connect(scanning_ports); //DBGOUTPUT(j); while( ! do_select_round(scanning_ports, subtarget_ports) ) usleep(1000); show_ports(); if(par->verbose>0){ bzero(output_buf, 255); sprintf(output_buf, "Connect() scan finished.", hostname); out->line(output_buf); } scanning_ports.clear(); } private: fd_set fd_r, fd_w, fd_x; std::vector<scan_socket> scan_sockets; int free_sockets; int maxfd; void init_scan_sockets(){ for(int i = 0; i< ICE_FD_SETSIZE*2/3; i++){ struct scan_socket st; st.c = NULL; st.busy = false; scan_sockets.push_back(st); } free_sockets = 0; } int get_first_free_socket(){ int f; for(f = 0; f < scan_sockets.size(); f++) if(!scan_sockets.at(f).busy && scan_sockets.at(f).c == NULL) return f; return -1; } void init_scanning_ports(char *hostname, iceparams *par, int domain, std::map <int, scanning_port> &scanning_ports){ for(int j = 0; j<par->ports.size(); j++){ port_range pr = par->ports[j]; for(int i = pr.lower_port; i <= pr.upper_port; i++){ if(scanning_ports.find(i) == scanning_ports.end()){ struct scanning_port sp; sp.port_number = i; scanning_ports[i] = sp; strcpy(scanning_ports[i].hostname, hostname); scanning_ports[i].done = false; } } } std::map <int, scanning_port>::iterator i; int j; for(i = scanning_ports.begin(), j = 0; i!= scanning_ports.end(); ++i, j++){ if(j < scan_sockets.size()){ scan_sockets[j].c = new csocket(AF_INET, domain); (*i).second.c = scan_sockets[j].c; maxfd = scan_sockets[j].c->get_socketid(); scan_sockets[j].busy = true; (*i).second.socket_ptr = j; }else{ (*i).second.c = NULL; (*i).second.socket_ptr = -1; } } } int initiate_connect(std::map <int, scanning_port> &scanning_ports){ std::map <int, scanning_port>::iterator i; FD_ZERO(&fd_r); FD_ZERO(&fd_w); FD_ZERO(&fd_x); int j; for(i = scanning_ports.begin(); i!= scanning_ports.end(); ++i){ //check FD_SET if((*i).second.c != NULL){ (*i).second.c->nonblock(true); FD_SET((*i).second.c->get_socketid(), &fd_w); FD_SET((*i).second.c->get_socketid(), &fd_r); FD_SET((*i).second.c->get_socketid(), &fd_x); (*i).second.time = time(0); int rc = (*i).second.c->connect((*i).second.hostname, (*i).first, 0); free_sockets--; } } return j; } void shutdown_scansocket(csocket *c, int ptr){ //DBGOUTPUT("ptr = " << ptr); FD_CLR(c->get_socketid(), &fd_w); FD_CLR(c->get_socketid(), &fd_r); FD_CLR(c->get_socketid(), &fd_x); //DBGOUTPUT(c->get_socketid() << " shutdowned."); c->shutdown(); c->close(); delete c; free_sockets++; scan_sockets[ptr].busy = false; scan_sockets[ptr].c = NULL; //DBGOUTPUT("Freeing socket " << ptr); } int get_first_idle_scanning_port(std::map <int, scanning_port> &scanning_ports){ std::map <int, scanning_port>::iterator i; //DBGOUTPUT("GFISP"); for(i = --scanning_ports.end(); i!= scanning_ports.begin(); --i){ if((*i).second.c == NULL && (! (*i).second.done)) return (*i).first; } return -1; } void idle_status_dispatcher(std::map <int, scanning_port> &scanning_ports, int prt){ if(prt>=0 && free_sockets < 1){ int f = get_first_free_socket(); //DBGOUTPUT(f << " " << free_sockets); if(f < 0) return; //if(scan_sockets[f].c ) return; scan_sockets[f].c = new csocket(AF_INET, (int) SOCK_STREAM); scan_sockets[f].busy = true; scanning_ports[prt].c = scan_sockets[f].c; free_sockets--; scanning_ports[prt].socket_ptr = f; //DBGOUTPUT(prt); scanning_ports[prt].c->nonblock(true); //DBGOUTPUT("!!!"); FD_SET(scanning_ports[prt].c->get_socketid(), &fd_w); FD_SET(scanning_ports[prt].c->get_socketid(), &fd_r); FD_SET(scanning_ports[prt].c->get_socketid(), &fd_x); scanning_ports[prt].time = time(0); //DBGOUTPUT(scanning_ports[prt].hostname); int rc = scanning_ports[prt].c->connect(scanning_ports[prt].hostname, prt, 0); switch(rc){ case EINPROGRESS: case EAGAIN: break; case ECONNREFUSED: DBGOUTPUT("Connection refused."); perror("Strange error"); exit(0); break; default: perror("Strange error"); exit(0); break; } //DBGOUTPUT("Connecting to " << prt << " using socket id " << scanning_ports[prt].c->get_socketid()); //DBGOUTPUT("!!!"); //usleep(10000); } } void print_port_status(int port, enum port_status ps){ char output_buf[255]; if(ps == PORT_OPEN && par->verbose >= 1){ sprintf(output_buf, "Discovered open port %d/tcp on %s.", port, hostname); out->line(output_buf); }else if(ps == PORT_CLOSED && par->verbose > 1){ sprintf(output_buf, "Discovered closed port %d/tcp on %s.", port, hostname); out->line(output_buf); }else if(ps == PORT_FILTERED && par->verbose > 2){ sprintf(output_buf, "Discovered filtered port %d/tcp on %s.", port, hostname); out->line(output_buf); } } // return true if scanning_ports are empty bool do_select_round(std::map <int, scanning_port> &scanning_ports, std::vector<scanned_port> &subtarget_ports){ fd_set fd_rtmp, fd_wtmp, fd_xtmp; struct timeval tv; int s, err; int sopt, soptlen; int res; bool done = true; fd_rtmp = fd_r; fd_wtmp = fd_w; fd_xtmp = fd_x; std::map <int, scanning_port>::iterator i,j; do{ tv.tv_sec = 0; tv.tv_usec = 10000; s = select(maxfd + 1, &fd_rtmp, &fd_wtmp, &fd_xtmp, &tv); //(++scanning_ports.rend())->second.c->get_socketid() err = errno; //perror("select"); DBGOUTPUT(s); }while(s = -1 && err == EINTR); int curtime = time(0); for(i = scanning_ports.begin(); i!= scanning_ports.end(); ++i){ if((*i).second.done) continue; if( (*i).second.c == NULL){ idle_status_dispatcher(scanning_ports, (*i).first); done = false; continue; } enum port_status status = PORT_UNKNOWN; //DBGOUTPUT("..."); if(s >= 0 && (FD_ISSET((*i).second.c->get_socketid(), &fd_rtmp) || FD_ISSET((*i).second.c->get_socketid(), &fd_wtmp) || FD_ISSET((*i).second.c->get_socketid(), &fd_xtmp))){ (*i).second.c->getsockopt(SOL_SOCKET, SO_ERROR, (char *) &sopt, (socklen_t *) &soptlen); switch(sopt){ case 0: if(FD_ISSET((*i).second.c->get_socketid(), &fd_r)){ status = PORT_OPEN; }else{ //DBGOUTPUT("WRITE"); usleep(20000); res = (*i).second.c->write("", 0, 0); //DBGOUTPUT("/WRITE" << res); if(res < 0){ status = PORT_CLOSED; }else{ status = PORT_OPEN; //UGLY, pls add additional checkup } } break; case ECONNREFUSED: status = PORT_CLOSED; break; case EHOSTUNREACH: case ETIMEDOUT: case EHOSTDOWN: case ENETUNREACH: status = PORT_FILTERED; break; default: //add here more errors, pls status = PORT_UNKNOWN; } struct scanned_port sp; sp.port_number = (*i).first; sp.status = status; subtarget_ports.push_back(sp); print_port_status((*i).first, status); (*i).second.done = true; shutdown_scansocket((*i).second.c, (*i).second.socket_ptr); (*i).second.c = NULL; //DBGOUTPUT("Erasing... :" << status); //scanning_ports.erase(i++); //idle_status_dispatcher(scanning_ports, get_first_idle_scanning_port(scanning_ports) ); }else{ if( ( curtime - (*i).second.time) >= CONNECT_TIMEOUT ){ struct scanned_port sp; sp.port_number = (*i).first; sp.status = status = PORT_FILTERED; subtarget_ports.push_back(sp); (*i).second.done = true; print_port_status((*i).first, sp.status); shutdown_scansocket((*i).second.c, (*i).second.socket_ptr); (*i).second.c = NULL; //scanning_ports.erase(i++); //idle_status_dispatcher(scanning_ports, get_first_idle_scanning_port(scanning_ports)); }else done &= false; } done &= true; } //DBGOUTPUT(done); return done; } void show_ports(){ int filtered = 0, closed = 0, open = 0, total = 0; bool show_closed = false; char output_buf[255]; std::vector <scanned_port>::iterator i; for(i = subtarget_ports.begin(); i!= subtarget_ports.end(); ++i){ total++; if((*i).status == PORT_OPEN){ open++; }else if((*i).status == PORT_CLOSED){ //if(closed++ > MAX_CLOSED) subtarget_ports.erase(i++); closed++; }else if((*i).status == PORT_FILTERED){ filtered++; //subtarget_ports.erase(i++); } } if(open!= 0 && closed/open == 0) show_closed = true; else if(open == 0 && closed <= MAX_CLOSED) show_closed = true; bzero(output_buf, 255); sprintf(output_buf, "Interesting ports on %s:", hostname); out->line(output_buf); //DBGOUTPUT(filtered); bzero(output_buf, 255); if(filtered > 0){ if(show_closed){ sprintf(output_buf, "Not shown: %d filtered ports.", filtered); }else{ sprintf(output_buf, "Not shown: %d filtered && %d closed ports.", closed); } out->line(output_buf); }else{ if(!show_closed){ sprintf(output_buf, "Not shown: %d closed ports.", closed); out->line(output_buf); } } out->line("PORT STATE SERVICE"); for(int j = 0; j < subtarget_ports.size(); j++){ bzero(output_buf, 255); if(subtarget_ports[j].status == PORT_OPEN){ sprintf(output_buf, "%5d/tcp open %s", subtarget_ports[j].port_number, isnd->get_tcp_service(subtarget_ports[j].port_number).c_str()); out->line(output_buf); }else if(subtarget_ports[j].status == PORT_CLOSED && show_closed){ sprintf(output_buf, "%5d/tcp closed %s", subtarget_ports[j].port_number, isnd->get_tcp_service(subtarget_ports[j].port_number).c_str()); out->line(output_buf); } } out->line(""); } public: ~csubtarget(){ //DBGOUTPUT("Entering destructor..."); free(hostname); scan_sockets.clear(); subtarget_ports.clear(); //DBGOUTPUT("Leaving destructor..."); } }; #endif --- NEW FILE: nbt_wrapper.h --- #ifndef NBTWRAP_H #define NBTWRAP_H #include <sys/types.h> #define my_uint16_t uint16_t #define my_uint32_t uint32_t #define my_uint8_t uint8_t #define NBT_MSGSIZE 1024 /* This file contains a portions of code from Samba package, * /* which contains the following license: * / Unix SMB/Netbios implementation Version 1.9 Main SMB server routine Copyright (C) Andrew Tridgell 1992-199 This program is free software; you can redistribute it and/or modif it under the terms of the GNU General Public License as published b the Free Software Foundation; either version 2 of the License, o (at your option) any later version This program is distributed in the hope that it will be useful but WITHOUT ANY WARRANTY; without even the implied warranty o MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See th GNU General Public License for more details You should have received a copy of the GNU General Public Licens along with this program; if not, write to the Free Softwar Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA */ /* start of code from Samba */ #define FL_REQUEST 0x8000 #define FL_QUERY 0x7800 #define FL_NON_AUTH_ANSWER 0x0400 #define FL_DGRAM_NOT_TRUNCATED 0x0200 #define FL_RECURSION_NOT_DESIRED 0x0100 #define FL_RECURSION_NOT_AVAIl 0x0080 #define FL_RESERVED1 0x0040 #define FL_RESERVED2 0x0020 #define FL_BROADCAST 0x0010 #define FL_SUCCESS 0x000F #define QT_NODE_STATUS_REQUEST 0x0021 #define QC_INTERNET 0x0001 struct nbname { char ascii_name [16] ; my_uint16_t rr_flags; }; struct nbname_request { my_uint16_t transaction_id; my_uint16_t flags; my_uint16_t question_count; my_uint16_t answer_count; my_uint16_t name_service_count; my_uint16_t additional_record_count; char question_name[34]; my_uint16_t question_type; my_uint16_t question_class; }; #define NBNAME_REQUEST_SIZE 50 #define UDP_HEADER_SIZE 8 #define IP_HEADER_SIZE 20 typedef struct nbname_response_header { my_uint16_t transaction_id; my_uint16_t flags; my_uint16_t question_count; my_uint16_t answer_count; my_uint16_t name_service_count; my_uint16_t additional_record_count; char question_name[34]; my_uint16_t question_type; my_uint16_t question_class; my_uint32_t ttl; my_uint16_t rdata_length; my_uint8_t number_of_names; } nbname_response_header_t; /* #define NBNAME_RESPONSE_NUMBER_OF_NAMES_OFFSET 56 */ #define NBNAME_RESPONSE_HEADER_SIZE 57 typedef struct nbname_response_footer { my_uint8_t adapter_address [6]; my_uint8_t version_major; my_uint8_t version_minor; my_uint16_t duration; my_uint16_t frmps_received; my_uint16_t frmps_transmitted; my_uint16_t iframe_receive_errors; my_uint16_t transmit_aborts; my_uint32_t transmitted; my_uint32_t received; my_uint16_t iframe_transmit_errors; my_uint16_t no_receive_buffer; my_uint16_t tl_timeouts; my_uint16_t ti_timeouts; my_uint16_t free_ncbs; my_uint16_t ncbs; my_uint16_t max_ncbs; my_uint16_t no_transmit_buffers; my_uint16_t max_datagram; my_uint16_t pending_sessions; my_uint16_t max_sessions; my_uint16_t packet_sessions; } nbname_response_footer_t ; #define NBNAME_RESPONSE_FOOTER_SIZE 50 struct nb_host_info { struct nbname_response_header* header; struct nbname* names; struct nbname_response_footer* footer; int is_broken; }; typedef struct nb_service { char nb_name[16]; my_uint8_t service_number; int unique; char* service_name; } nb_service_t ; /* end of code from Samba */ #include "icesockets/csocket.h" class cnbtwrapper{ /* start of code from Samba */ int name_mangle( char *In, char *Out, char name_type ) { int i; int c; int len; char buf[20]; char *p = Out; char* scope=""; /* Safely copy the input string, In, into buf[]. */ (void)memset( buf, 0, 20 ); if (strcmp(In,"*") == 0) buf[0] = '*'; else #ifdef HAVE_SNPRINTF (void)snprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type ); #else (void)sprintf( buf, "%-15.15s%c", In, name_type ); #endif /* HAVE_SNPRINTF */ /* Place the length of the first field into the output buffer. */ p[0] = 32; p++; /* Now convert the name to the rfc1001/1002 format. */ for( i = 0; i < 16; i++ ) { c = toupper( buf[i] ); p[i*2] = ( (c >> 4) & 0x000F ) + 'A'; p[(i*2)+1] = (c & 0x000F) + 'A'; } p += 32; p[0] = '\0'; /* Add the scope string. */ for( i = 0, len = 0; NULL != scope; i++, len++ ) { switch( scope[i] ) { case '\0': p[0] = len; if( len > 0 ) p[len+1] = 0; return( strlen(Out) ); case '.': p[0] = len; p += (len + 1); len = 0; break; default: p[len+1] = scope[i]; break; } } return( strlen(Out) ); } /* end of code from Samba */ iceparams *par; public: cnbtwrapper(iceparams *par){ this->par = par; } int test(char *hostname, int port){ char message[NBT_MSGSIZE]; char local_hostname[80]; int size = -1; int attempt = 5; int rc; fd_set sset; struct sockaddr_in src_sockaddr; int addr_size; struct nb_host_info *hostinfo; csocket c(AF_INET, SOCK_DGRAM); if(gethostname(local_hostname, 80)) exit(-1); c.bind(local_hostname, par->netbios_port, 0); //set local interface //beginning of repeater while(size<0 && attempt--!=0){ struct timeval tv; send_query(c, hostname, port, time(0)); c.nonblock(true); FD_ZERO(&sset); FD_SET(c.get_socketid(), &sset); tv.tv_sec = 0; tv.tv_usec = 500000; rc = select(c.get_socketid() + 1, &sset, NULL, NULL, &tv); if(rc>0) size = c.recvfrom(message, NBT_MSGSIZE, 0, NULL, NULL); else size = -1; } c.close(); if(size > 0){ hostinfo = (struct nb_host_info *)parse_response(message, size); v_print_hostinfo(hostname, hostinfo, !par->verbose); }else{ printf("No response from %s: may be no NetBIOS service exists on host.\n", hostname); } } private: int v_print_hostinfo(char *hostname, const struct nb_host_info* hostinfo, int v) { int i, unique; my_uint8_t service; char name[16]; char* sname; printf("NetBIOS Name Table for %s:\n", hostname); if(hostinfo->is_broken && !v) printf("Incomplete packet, %d bytes long.\n", hostinfo->is_broken); if(!v) printf("%-17s%-17s%-17s\n", "Name", "Service", "Type"); else printf("%-17s%-17s\n", "Name", "Service"); if(hostinfo->header && hostinfo->names) { for(i=0; i< hostinfo->header->number_of_names; i++) { service = hostinfo->names[i].ascii_name[15]; strncpy(name, hostinfo->names[i].ascii_name, 15); name[16]=0; unique = !(hostinfo->names[i].rr_flags & 0x0080); printf("%-17s", name); if(v) printf("%s\n", (char*)getnbservicename(service, unique, name)); else { printf("<%02x>", service); if(unique) printf(" UNIQUE\n"); else printf(" GROUP\n"); } } } printf("\n"); return 1; } int send_query(csocket &sock, char *hostname, int port, my_uint32_t rtt_base) { struct nbname_request request; int status; struct timeval tv; char errmsg[80]; request.flags = htons(FL_BROADCAST); request.question_count = htons(1); request.answer_count = 0; request.name_service_count = 0; request.additional_record_count = 0; name_mangle("*", request.question_name,0); request.question_type = htons(0x21); request.question_class = htons(0x01); gettimeofday(&tv, NULL); request.transaction_id = htons((tv.tv_sec-rtt_base)*1000+tv.tv_usec/1000); status = sock.sendto(hostname, port, (char*)&request, sizeof(request), 0); if(status==-1) { snprintf(errmsg, 80, "Sendto failed: %s:%d", hostname, port); err_print(errmsg, ICEDEBUG); return(-1); } } my_uint32_t get32(void* data) { union { char bytes[4]; my_uint32_t all; } x; memcpy(x.bytes, data, 4); return(ntohl(x.all)); } my_uint16_t get16(void* data) { union { char bytes[2]; my_uint16_t all; } x; memcpy(x.bytes, data, 2); return(ntohs(x.all)); } struct nb_host_info* parse_response(char* buff, int buffsize) { struct nb_host_info* hostinfo = NULL; nbname_response_footer_t* response_footer; nbname_response_header_t* response_header; int name_table_size; int offset = 0; if((response_header = (nbname_response_header_t*) malloc(sizeof(nbname_response_header_t)))==NULL) return NULL; if((response_footer = (nbname_response_footer_t*) malloc(sizeof(nbname_response_footer_t)))==NULL) return NULL; bzero(response_header, sizeof(nbname_response_header_t)); bzero(response_footer, sizeof(nbname_response_footer_t)); if((hostinfo = (nb_host_info*)malloc(sizeof(struct nb_host_info)))==NULL) return NULL; hostinfo->header = NULL; hostinfo->names = NULL; hostinfo->footer = NULL; if( offset+sizeof(response_header->transaction_id) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->transaction_id = get16(buff+offset); offset+=sizeof(response_header->transaction_id); hostinfo->header = response_header; if( offset+sizeof(response_header->flags) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->flags = get16(buff+offset); offset+=sizeof(response_header->flags); if( offset+sizeof(response_header->question_count) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->question_count = get16(buff+offset); offset+=sizeof(response_header->question_count); if( offset+sizeof(response_header->answer_count) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->answer_count = get16(buff+offset); offset+=sizeof(response_header->answer_count); if( offset+sizeof(response_header->name_service_count) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->name_service_count = get16(buff+offset); offset+=sizeof(response_header->name_service_count); if( offset+sizeof(response_header->additional_record_count) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->additional_record_count = get16(buff+offset); offset+=sizeof(response_header->additional_record_count); if( offset+sizeof(response_header->question_name) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } strncpy(response_header->question_name, buff+offset, sizeof(response_header->question_name)); offset+=sizeof(response_header->question_name); if( offset+sizeof(response_header->question_type) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->question_type = get16(buff+offset); offset+=sizeof(response_header->question_type); if( offset+sizeof(response_header->question_class) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->question_class = get16(buff+offset); offset+=sizeof(response_header->question_class); if( offset+sizeof(response_header->ttl) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->ttl = get32(buff+offset); offset+=sizeof(response_header->ttl); if( offset+sizeof(response_header->rdata_length) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->rdata_length = get16(buff+offset); offset+=sizeof(response_header->rdata_length); if( offset+sizeof(response_header->number_of_names) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_header->number_of_names = *(typeof(response_header->number_of_names)*)(buff+offset); offset+=sizeof(response_header->number_of_names); name_table_size = (response_header->number_of_names) * (sizeof(struct nbname)); if( offset+name_table_size >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } if((hostinfo->names = (nbname*) malloc(name_table_size))==NULL) return NULL; memcpy(hostinfo->names, buff + offset, name_table_size); offset+=name_table_size; if( offset+sizeof(response_footer->adapter_address) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } memcpy(response_footer->adapter_address, (buff+offset), sizeof(response_footer->adapter_address)); offset+=sizeof(response_footer->adapter_address); hostinfo->footer=response_footer; if( offset+sizeof(response_footer->version_major) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->version_major = *(typeof(response_footer->version_major)*)(buff+offset); offset+=sizeof(response_footer->version_major); if( offset+sizeof(response_footer->version_minor) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->version_minor = *(typeof(response_footer->version_minor)*)(buff+offset); offset+=sizeof(response_footer->version_minor); if( offset+sizeof(response_footer->duration) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->duration = get16(buff+offset); offset+=sizeof(response_footer->duration); if( offset+sizeof(response_footer->frmps_received) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->frmps_received= get16(buff+offset); offset+=sizeof(response_footer->frmps_received); if( offset+sizeof(response_footer->frmps_transmitted) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->frmps_transmitted = get16(buff+offset); offset+=sizeof(response_footer->frmps_transmitted); if( offset+sizeof(response_footer->iframe_receive_errors) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->iframe_receive_errors = get16(buff+offset); offset+=sizeof(response_footer->iframe_receive_errors); if( offset+sizeof(response_footer->transmit_aborts) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->transmit_aborts = get16(buff+offset); offset+=sizeof(response_footer->transmit_aborts); if( offset+sizeof(response_footer->transmitted) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->transmitted = get32(buff+offset); offset+=sizeof(response_footer->transmitted); if( offset+sizeof(response_footer->received) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->received = get32(buff+offset); offset+=sizeof(response_footer->received); if( offset+sizeof(response_footer->iframe_transmit_errors) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->iframe_transmit_errors = get16(buff+offset); offset+=sizeof(response_footer->iframe_transmit_errors); if( offset+sizeof(response_footer->no_receive_buffer) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->no_receive_buffer = get16(buff+offset); offset+=sizeof(response_footer->no_receive_buffer); if( offset+sizeof(response_footer->tl_timeouts) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->tl_timeouts = get16(buff+offset); offset+=sizeof(response_footer->tl_timeouts); if( offset+sizeof(response_footer->ti_timeouts) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->ti_timeouts = get16(buff+offset); offset+=sizeof(response_footer->ti_timeouts); if( offset+sizeof(response_footer->free_ncbs) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->free_ncbs = get16(buff+offset); offset+=sizeof(response_footer->free_ncbs); if( offset+sizeof(response_footer->ncbs) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->ncbs = get16(buff+offset); offset+=sizeof(response_footer->ncbs); if( offset+sizeof(response_footer->max_ncbs) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->max_ncbs = get16(buff+offset); offset+=sizeof(response_footer->max_ncbs); if( offset+sizeof(response_footer->no_transmit_buffers) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->no_transmit_buffers = get16(buff+offset); offset+=sizeof(response_footer->no_transmit_buffers); if( offset+sizeof(response_footer->max_datagram) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->max_datagram = get16(buff+offset); offset+=sizeof(response_footer->max_datagram); if( offset+sizeof(response_footer->pending_sessions) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->pending_sessions = get16(buff+offset); offset+=sizeof(response_footer->pending_sessions); if( offset+sizeof(response_footer->max_sessions) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->max_sessions = get16(buff+offset); offset+=sizeof(response_footer->max_sessions); if( offset+sizeof(response_footer->packet_sessions) >= buffsize) { hostinfo->is_broken = offset; return hostinfo; } response_footer->packet_sessions = get16(buff+offset); offset+=sizeof(response_footer->packet_sessions); return hostinfo; } char* getnbservicename(my_uint8_t service, int unique, char* name) { int i; char *unknown; nb_service_t services[] = { "__MSBROWSE__", 0x01, 0, "Master Browser", "INet~Services", 0x1C, 0, "IIS", "IS~", 0x00, 1, "IIS", "", 0x00, 1, "Workstation Service", "", 0x01, 1, "Messenger Service", "", 0x03, 1, "Messenger Service", "", 0x06, 1, "RAS Server Service", "", 0x1F, 1, "NetDDE Service", "", 0x20, 1, "File Server Service", "", 0x21, 1, "RAS Client Service", "", 0x22, 1, "Microsoft Exchange Interchange(MSMail Connector)", "", 0x23, 1, "Microsoft Exchange Store", "", 0x24, 1, "Microsoft Exchange Directory", "", 0x30, 1, "Modem Sharing Server Service", "", 0x31, 1, "Modem Sharing Client Service", "", 0x43, 1, "SMS Clients Remote Control", "", 0x44, 1, "SMS Administrators Remote Control Tool", "", 0x45, 1, "SMS Clients Remote Chat", "", 0x46, 1, "SMS Clients Remote Transfer", "", 0x4C, 1, "DEC Pathworks TCPIP service on Windows NT", "", 0x52, 1, "DEC Pathworks TCPIP service on Windows NT", "", 0x87, 1, "Microsoft Exchange MTA", "", 0x6A, 1, "Microsoft Exchange IMC", "", 0xBE, 1, "Network Monitor Agent", "", 0xBF, 1, "Network Monitor Application", "", 0x03, 1, "Messenger Service", "", 0x00, 0, "Domain Name", "", 0x1B, 1, "Domain Master Browser", "", 0x1C, 0, "Domain Controllers", "", 0x1D, 1, "Master Browser", "", 0x1E, 0, "Browser Service Elections", "", 0x2B, 1, "Lotus Notes Server Service", "IRISMULTICAST", 0x2F, 0, "Lotus Notes", "IRISNAMESERVER", 0x33, 0, "Lotus Notes", "Forte_$ND800ZA", 0x20, 1, "DCA IrmaLan Gateway Server Service" }; unknown = (char*)malloc(100); for(i=0; i < 35; i++) { if(strstr(name, services[i].nb_name) && service == services[i].service_number && unique == services[i].unique) return services[i].service_name; } snprintf(unknown, 100, "Unknown service (code %x)", service); return(unknown); } }; #endif --- NEW FILE: iceservice.h --- #ifndef ICESERVICE_H #define ICESERVICE_H #include <pcrecpp.h> #include <iostream> #include <fstream> #include <map> #include "icedebug.h" class ice_service_name_database{ std::map <int, string> tcp_services; std::map <int, string> udp_services; public: ice_service_name_database(char *db_fname){ std::ifstream in; in.open(db_fname); if(!in){ std::cout << "Can't open service names database!" << std::endl; } else { while(!in.eof()){ char tmpbuf[256]; in.getline(tmpbuf,256); if(! pcrecpp::RE("^(#.*|\\s*)$").FullMatch(tmpbuf) ){ pcrecpp::RE re("^([-a-z1-9]+)\\s*\\W*([0-9]+)/(tcp|udp)"); string sname = "", protocol = ""; int port; pcrecpp::StringPiece input(tmpbuf); re.Consume(&input, &sname, &port, &protocol); if(sname == "") continue; //DBGOUTPUT("::" << sname << port << protocol); if(protocol == "tcp") tcp_services[port] = sname; else udp_services[port] = sname; }//else DBGOUTPUT("#comment"); } } } string get_tcp_service(int port){ if(tcp_services.find(port) != tcp_services.end()) return udp_services[port]; else return ""; } string get_udp_service(int port){ } }; #endif --- NEW FILE: icedebug.h --- #ifndef ICEDEBUG_H #define ICEDEBUG_H #include <iostream> #define DBGOUTPUT(TEXT) std::cout << TEXT << std::endl #endif --- NEW FILE: icediscover.h --- #ifndef ICEDISCOVER_H #define ICEDISCOVER_H #include <pthread.h> #include <signal.h> #include <sys/time.h> #include "icesockets/csocket.h" #include "icesockets/crawsocket.h" #include "iceparams.h" #include "iceoutput.h" #include "icedebug.h" #define ACK_PING_STANDART_PORT 80 #define ECHO_ATTEMPTS 5 struct discover_thread_params{ char *hostname; const iceparams *par; iceoutput *out; crawsocket *r; }; bool tcp_ack_ping(char *hostname, iceparams *par, iceoutput *out){ csocket s(AF_INET, (int) SOCK_STREAM); if(par->verbose>0) out->line("Starting ack host discovery (aka ACK ping)..."); int rc = s.connect(hostname, ACK_PING_STANDART_PORT, 4); s.shutdown(); if(!rc){ if(par->verbose>0) out->line("Ack host discovery successfull!"); return true; }else if(par->verbose>0) out->line("Ack host discovery failed!"); return false; } void *send_icmp_echo(void *arg){ struct discover_thread_params *dtp = (struct discover_thread_params *) arg; crawsocket *r = dtp->r; char *hostname = dtp->hostname; iceoutput *out = dtp->out; const iceparams *par = dtp->par; char buftosend[1500]; int nsent = 1; for(int i=0; i<ECHO_ATTEMPTS; i++){ bzero(buftosend, 1500); struct icmp *icmp = (struct icmp *) buftosend; icmp->icmp_type = ICMP_ECHO; icmp->icmp_code = 0; icmp->icmp_id = getpid(); gettimeofday( ( struct timeval *) icmp->icmp_data, NULL); icmp->icmp_seq = nsent++; int len = 8 + 56; // icmp header + icmp data icmp->icmp_cksum = crawsocket::in_chksum( (unsigned short * ) icmp, len); if(par->verbose>0) out->line("Sending icmp ping host discovery request (echo_request)..."); r->sendto(hostname, buftosend, len, 0); icesleep(0, 100); } pthread_exit(NULL); } bool icmp_echo_ping(char *hostname, iceparams *par, iceoutput *out){ if(!getuid()){ //we're root, so can work with raw sockets if(par->verbose>0) out->line("Starting icmp ping host discovery..."); crawsocket r(AF_INET, SOCK_RAW, IPPROTO_ICMP); int size = 60 * 1024; int attempts = 0; r.setsockopt(SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); struct discover_thread_params dtp; dtp.hostname = hostname; dtp.par = par; dtp.out = out; dtp.r = &r; pthread_t send_thread; pthread_create(&send_thread, NULL, send_icmp_echo, (void *) &dtp); while(attempts++ < ECHO_ATTEMPTS){ char hostname[1024]; char buf[1500]; //1500 == standart IP Packet size int len = r.recvfrom(buf, sizeof(buf), 0, hostname); //DBGOUTPUT(hostname); struct ip *ip = (struct ip *) buf; int hdrlen = ip->ip_hl << 2; struct icmp *icmp = (struct icmp *) (buf + hdrlen); int icmplen = len - hdrlen; if(icmp -> icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == getpid() && icmplen < 16){ if(par->verbose>0) out->line("Recieved icmp ping host discovery reply (echo_reply)..."); return true; } } //pthread_join(send_thread, NULL); --- is it needed here? }else if(par->verbose>0) out->line("UID isn't 0, so can't create raw socket => no ICMP ping..."); return false; } bool host_discover(char *hostname, iceparams *par, iceoutput *out){ char output_line[1024]; if(par->verbose>0){ bzero(output_line, 1024); sprintf(output_line, "Starting discovery of host %s...", hostname); out->line(output_line); } if( tcp_ack_ping(hostname, par, out) ) return true; if( icmp_echo_ping(hostname, par, out) ) return true; return false; } #endif --- NEW FILE: Makefile --- CXXFLAGS=-g -lpthread -lpcrecpp LDFLAGS=-g -lpthread -lpcrecpp all: icescan clean: rm -f icescan.o icescan .PHONY: clean all icescan: icescan.o --- NEW FILE: iceversion.h --- #ifndef ICEVERSION_H #define ICEVERSION_H #define ICENAME "IceScan" #define ICEVERSION "0.0.2" #define ICEWEBSITE "" // (http://sf.net/projects/...) #define ICEDATE "28 November 2006" #endif --- NEW FILE: iceparams.h --- #ifndef ICEPARAMS_H #define ICEPARAMS_H #include <vector> #define NBT_PORT 137 struct port_range{ int lower_port; int upper_port; }; enum Scan_type {NO_SCAN, TCP_CONNECT_SCAN, NBT_SCAN}; // -S0 -ST -SB class iceparams{ public: //Global settings int verbose; //-v -vv -vvv - Verbose params int UID; // we're root or not? // Target char *target; // PreScan settings bool reverse_dns; //-RY (default); -RN params: resolve given ip to hostname or not? // Host discovery (default: -PA, -PI) bool no_host_discovery; // -P0, skip host discovery bool ack_ping_discovery; // -PA, ACK Ping std::vector <int> pa_ports; bool syn_ping_discovery; // -PS, SYN Ping std::vector <int> ps_ports; bool icmp_echo_ping_discovery; // -PE, ICMP Echo (standart) Ping bool icmp_mask_ping_discovery; // -PM, ICMP GetNetMask Ping bool icmp_timestamp_ping_discovery; // -PT, ICMP TimeStamp Ping bool udp_ping_discovery; // -PU, UDP send + ICMP reply Ping std::vector <int> pu_ports; // Scan Options ( default: -ST ) enum Scan_type scan_type; int sim_connects; int netbios_port; // Scan Port Range std::vector <port_range> ports; private: // Set default settings void default_init(){ verbose = 0; reverse_dns = true; no_host_discovery = false; ack_ping_discovery = false; syn_ping_discovery = false; icmp_echo_ping_discovery = false; icmp_mask_ping_discovery = false; icmp_timestamp_ping_discovery = false; udp_ping_discovery = false; scan_type = TCP_CONNECT_SCAN; sim_connects = 25; netbios_port = NBT_PORT + 10000; } public: iceparams(){ default_init(); } ~iceparams(){ delete target; } void by_default_init(){ if( ! (no_host_discovery || ack_ping_discovery || syn_ping_discovery || icmp_echo_ping_discovery || icmp_mask_ping_discovery || icmp_timestamp_ping_discovery || udp_ping_discovery) ){ ack_ping_discovery = true; icmp_echo_ping_discovery = true; } init_default_ports(); } void init_default_ports(){ const int ranges_cnt = 1; int ranges[ranges_cnt][2] = { {1, 1024} }; if(ports.empty()){ struct port_range pr; for(int i = 0; i < ranges_cnt; i++){ pr.lower_port = ranges[i][0]; pr.upper_port = ranges[i][1]; ports.push_back(pr); } } } int calc_ports_count(){ int cnt = 0; for(int i = 0; i < ports.size(); i++){ cnt += (ports[i].upper_port - ports[i].lower_port) + 1; } return cnt; } }; #endif --- NEW FILE: COPYING --- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a writte... [truncated message content] |