diff -Nraup nmap-4.10-orig/nmap.cc nmap-4.10-ipopts/nmap.cc --- nmap-4.10-orig/nmap.cc 2006-05-27 11:01:37.000000000 +0200 +++ nmap-4.10-ipopts/nmap.cc 2006-06-23 00:54:58.000000000 +0200 @@ -576,6 +576,8 @@ int nmap_main(int argc, char *argv[]) { {"log-errors", no_argument, 0, 0}, {"dns_servers", required_argument, 0, 0}, {"dns-servers", required_argument, 0, 0}, + {"ip_options", required_argument, 0, 0}, + {"ip-options", required_argument, 0, 0}, {0, 0, 0, 0} }; @@ -783,6 +785,13 @@ int nmap_main(int argc, char *argv[]) { o.fragscan = atoi(optarg); if (o.fragscan <= 0 || o.fragscan % 8 != 0) fatal("Data payload MTU must be >0 and multiple of 8"); + } else if (strcmp(long_options[option_index].name, "ip-options") == 0){ + o.ipoptions = (u8*) safe_malloc(4*10+1); + o.ipoptionslen = parse_hextobin(optarg, (char*)o.ipoptions, 4*10+1); + if(o.ipoptionslen > 4*10) + fatal("Ip options can't be more than 40 bytes long"); + if(o.ipoptionslen %4 != 0) + fatal("Ip options must be multiple of 4 (read length is %i bytes)", o.ipoptionslen); } else { fatal("Unknown long option (%s) given@#!$#$", long_options[option_index].name); } @@ -1081,6 +1090,13 @@ int nmap_main(int argc, char *argv[]) { o.ValidateOptions(); + // print ip options + if(o.debugging > 0 && o.ipoptionslen){ + char buf[256]; // 256 > 5*41 + bintohexstr(buf, sizeof(buf), (char*)o.ipoptions, o.ipoptionslen); + log_write(LOG_STDOUT, "Parsed ip options:\n%s", buf); + } + /* Open the log files, now that we know whether the user wants them appended or overwritten */ if (normalfilename) diff -Nraup nmap-4.10-orig/NmapOps.cc nmap-4.10-ipopts/NmapOps.cc --- nmap-4.10-orig/NmapOps.cc 2006-05-16 00:43:17.000000000 +0200 +++ nmap-4.10-ipopts/NmapOps.cc 2006-06-23 00:54:58.000000000 +0200 @@ -251,6 +251,8 @@ void NmapOps::Initialize() { dns_servers = NULL; noninteractive = false; current_scantype = STYPE_UNKNOWN; + ipoptions = NULL; + ipoptionslen = 0; } bool NmapOps::TCPScan() { diff -Nraup nmap-4.10-orig/NmapOps.h nmap-4.10-ipopts/NmapOps.h --- nmap-4.10-orig/NmapOps.h 2006-05-16 00:43:17.000000000 +0200 +++ nmap-4.10-ipopts/NmapOps.h 2006-06-23 00:54:58.000000000 +0200 @@ -292,6 +292,11 @@ class NmapOps { char *dns_servers; bool log_errors; + /* ip options used in build_*_raw() */ + u8 *ipoptions; + int ipoptionslen; + + // Statistics Options set in nmap.cc int numhosts_scanned; int numhosts_up; diff -Nraup nmap-4.10-orig/scan_engine.cc nmap-4.10-ipopts/scan_engine.cc --- nmap-4.10-orig/scan_engine.cc 2006-06-10 23:23:34.000000000 +0200 +++ nmap-4.10-ipopts/scan_engine.cc 2006-06-23 00:54:58.000000000 +0200 @@ -2769,6 +2769,191 @@ static bool get_arp_result(UltraScanInfo } +char* STRAPP(char *fmt, ...) { + static char buf[256]; + static int bp; + int l = (int)sizeof(buf)-bp; + if(!fmt) + bp = 0; + va_list ap; + va_start(ap, fmt); + bp += vsnprintf (buf+bp, (l>0 ? l : 0), fmt, ap); + va_end(ap); + + return(buf); +} + +#define BREAK() \ + {option_type = -2; break;} +#define CHECK(tt) \ + if(tt >= option_end) \ + {option_type = -2; break;} +void print_ip_options(u8* ipopt, int ipoptlen) { + int pt = 0; + char ipstring[32]; + int option_type = -1; + int option_len = -1; + int option_pt = -1; + int option_fl = 0; + u8 *tptr; //temp pointer + u32 *tint; //temp int + + int option_end = 0; + int option_sta = 0; + + // clear buffer + STRAPP(NULL,NULL); + + if(!ipoptlen) + return; + + while(pt= ipoptlen){option_type = -2;pt--; option_end = 255; continue;} // no length field, hex dump to the end + option_len = ipopt[pt++]; + option_end = MIN(option_sta + option_len, ipoptlen); + option_end = MAX(option_end, 2); + } + } + switch(option_type){ + case 0: // IPOPT_END + STRAPP(" EOL", NULL); + option_type=-1; + break; + case 1: // IPOPT_NOP + STRAPP(" NOP", NULL); + option_type=-1; + break; + case 130: // IPOPT_SECURITY +// pt++; + break; + case 131: // IPOPT_LSRR -> Loose Source and Record Route + case 137: // IPOPT_SSRR -> Strict Source and Record Route + case 7: // IPOPT_RR -> Record Route + if(pt - option_sta == 2) { + STRAPP(" %s{", option_type==131?"LSRR" : option_type==137?"SSRR" : "RR"); + // pointer + CHECK(pt); + option_pt = ipopt[pt++]; + if(option_pt%4 != 0 || (option_sta + option_pt)>option_end|| option_pt<4) //bad or too big pointer + STRAPP(" [bad ptr=%02i]", option_pt); + } + if(pt - option_sta > 2) {// ip's + int i, s = (option_pt)%4; + // if pointer is mangled, fix it. it's max 3 bytes wrong + CHECK(pt+3); + for(i=0; i Internet Timestamp + if(pt - option_sta == 2){ + STRAPP(" TM{"); + // pointer + CHECK(pt); + option_pt = ipopt[pt++]; + // bad or too big pointer + if(option_pt%4 != 1 || (option_sta + option_pt)>option_end || option_pt<5) + STRAPP(" [bad ptr=%02i]", option_pt); + // flags + overflow + CHECK(pt); + option_fl = ipopt[pt++]; + if((option_fl&0x0C) || (option_fl&0x03)==2) + STRAPP(" [bad flags=\\x%01hhx]", option_fl&0x0F); + STRAPP("[%i hosts not recorded]", option_fl>>4); + option_fl &= 0x03; + + } + if(pt - option_sta > 2) {// ip's + int i, s = (option_pt+3)%(option_fl==0?4:8); + // if pointer is mangled, fix it. it's max 3 bytes wrong + CHECK(pt+(option_fl==0?3:7)); + for(i=0; i (SANET) Stream Identifier + if(pt - option_sta == 2){ + u16 *sh; + STRAPP(" SI{",NULL); + // length + if(option_sta+option_len > ipoptlen || option_len!=4) + STRAPP("[bad len %02i]", option_len); + + // stream id + CHECK(pt+1); + sh = (u16*) &ipopt[pt]; pt+=2; + option_pt = ntohs(*sh); + STRAPP("id=%i", option_pt); + if(pt == option_end){ + STRAPP("}",NULL); + option_type=-1; + }else BREAK(); + }else BREAK(); + break; + default: + STRAPP(" ??{\\x%02hhx\\x%02hhx", option_type, option_len); + option_end = 255; // never end + option_type = -2; + break; + case -2: + assert(pt<=option_end); + if(pt == option_end){ + STRAPP("}",NULL); + option_type=-1; + break; + } + STRAPP("\\x%02hhx", ipopt[pt++]); + break; + } + } + if(option_type != -1) + STRAPP("}"); + STRAPP("\n"); + + //bintohexstr(buf, sizeof(buf), (char*)ipopt, ipoptlen); + log_write(LOG_STDOUT, "Got ip options:\n%s", STRAPP("",NULL)); +} +#undef CHECK +#undef BREAK + + /* Tries to get one *good* (finishes a probe) pcap response by the (absolute) time given in stime. Even if stime is now, try an ultra-quick pcap read just in case. Returns true if a "good" result @@ -2854,6 +3039,7 @@ static bool get_pcap_result(UltraScanInf } } } + print_ip_options((u8*)ip + sizeof(struct ip), (ip->ip_hl-5)*4); if (ip->ip_p == IPPROTO_TCP && !USI->prot_scan) { if ((unsigned) ip->ip_hl * 4 + 20 > bytes) diff -Nraup nmap-4.10-orig/tcpip.cc nmap-4.10-ipopts/tcpip.cc --- nmap-4.10-orig/tcpip.cc 2006-05-16 23:52:34.000000000 +0200 +++ nmap-4.10-ipopts/tcpip.cc 2006-06-23 01:25:15.000000000 +0200 @@ -855,8 +855,8 @@ int send_tcp_raw_decoys( int sd, struct u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim, int ttl, u16 ipid, u16 sport, u16 dport, u32 seq, u32 ack, u8 flags, - u16 window, u8 *options, int optlen, char *data, - u16 datalen, u32 *packetlen) { + u16 window, u8 *tcpopt, int tcpoptlen, char *tcpdata, + u16 tcpdatalen, u32 *outpacketlen) { struct pseudo_header { /*for computing TCP checksum, see TCP/IP Illustrated p. 145 */ @@ -866,17 +866,26 @@ struct pseudo_header { u8 protocol; u16 length; }; -u8 *packet = (u8 *) safe_malloc(sizeof(struct ip) + sizeof(struct tcphdr) + optlen + datalen); +int ipoptlen = o.ipoptionslen; +u8 *ipopt = o.ipoptions; + +int packetlen = sizeof(struct ip) + ipoptlen + + sizeof(struct tcphdr) + tcpoptlen + tcpdatalen; +u8 *packet = (u8 *) safe_malloc(packetlen); + struct ip *ip = (struct ip *) packet; -struct tcphdr *tcp = (struct tcphdr *) (packet + sizeof(struct ip)); -struct pseudo_header *pseudo = (struct pseudo_header *) (packet + sizeof(struct ip) - sizeof(struct pseudo_header)); +struct tcphdr *tcp = (struct tcphdr *) (packet + sizeof(struct ip) + ipoptlen); +struct pseudo_header *pseudo = (struct pseudo_header *) + ((u8*)tcp - sizeof(struct pseudo_header)); static int myttl = 0; assert(victim); assert(source); -if (optlen % 4) { - fatal("build_tcp_raw() called with an option length argument of %d which is illegal because it is not divisible by 4", optlen); +if(ipoptlen % 4) + fatal("build_tcp_raw() called with an ip option length argument of %d which is illegal because it is not divisible by 4", ipoptlen); +if (tcpoptlen % 4) { + fatal("build_tcp_raw() called with an tcp option length argument of %d which is illegal because it is not divisible by 4", tcpoptlen); } /* Time to live */ @@ -886,78 +895,81 @@ if (ttl == -1) { myttl = ttl; } -memset((char *) packet, 0, sizeof(struct ip) + sizeof(struct tcphdr)); - +/* Fill pseudo header */ pseudo->s_addy = source->s_addr; pseudo->d_addr = victim->s_addr; +pseudo->zer0 = 0; pseudo->protocol = IPPROTO_TCP; -pseudo->length = htons(sizeof(struct tcphdr) + optlen + datalen); +pseudo->length = htons(sizeof(struct tcphdr) + tcpoptlen + tcpdatalen); -tcp->th_sport = htons(sport); +memset(tcp, 0, sizeof(struct tcphdr)); +/* Fill tcp header */ tcp->th_dport = htons(dport); +tcp->th_sport = htons(sport); if (seq) { tcp->th_seq = htonl(seq); -} -else if (flags & TH_SYN) { +}else if (flags & TH_SYN) { get_random_bytes(&(tcp->th_seq), 4); -} +}else + tcp->th_seq = 0; if (ack) tcp->th_ack = htonl(ack); /*else if (flags & TH_ACK) tcp->th_ack = rand() + rand();*/ +else + tcp->th_ack = 0; -tcp->th_off = 5 + (optlen /4) /*words*/; +tcp->th_off = 5 + (tcpoptlen /4) /*words*/; tcp->th_flags = flags; if (window) tcp->th_win = htons(window); -else tcp->th_win = htons(1024 * (myttl % 4 + 1)); /* Who cares */ +else + tcp->th_win = htons(1024 * (myttl % 4 + 1)); /* Who cares */ - /* We should probably copy the data over too */ - if (data && datalen) - memcpy(packet + sizeof(struct ip) + sizeof(struct tcphdr) + optlen, data, datalen); /* And the options */ - if (optlen) { - memcpy(packet + sizeof(struct ip) + sizeof(struct tcphdr), options, optlen); - } + if (tcpoptlen && tcpopt) + memcpy((u8*)tcp + sizeof(struct tcphdr), + tcpopt, tcpoptlen); + /* We should probably copy the data over too */ + if (tcpdatalen && tcpdata) + memcpy((u8*)tcp + sizeof(struct tcphdr) + tcpoptlen, + tcpdata, tcpdatalen); #if STUPID_SOLARIS_CHECKSUM_BUG - tcp->th_sum = sizeof(struct tcphdr) + optlen + datalen; + tcp->th_sum = sizeof(struct tcphdr) + tcpoptlen + tcpdatalen; #else -tcp->th_sum = in_cksum((unsigned short *)pseudo, sizeof(struct tcphdr) + - optlen + sizeof(struct pseudo_header) + datalen); + tcp->th_sum = in_cksum((u16 *)pseudo, + sizeof(struct pseudo_header) + sizeof(struct tcphdr) + + tcpoptlen + tcpdatalen); #endif if ( o.badsum ) --tcp->th_sum; + + /* Fill ip header */ + ip->ip_v = 4; + ip->ip_hl = 5 + (ipoptlen/4); + ip->ip_tos = 0; + ip->ip_len = htons(packetlen); + //get_random_bytes(&(ip->ip_id), 2); + ip->ip_id = ipid; + ip->ip_off = 0; + ip->ip_ttl = myttl; + ip->ip_p = IPPROTO_TCP; + ip->ip_sum = 0; + ip->ip_src.s_addr = source->s_addr; + ip->ip_dst.s_addr = victim->s_addr; + + if(ipoptlen && ipopt) + memcpy(packet + sizeof(struct ip), ipopt, ipoptlen); -/* Now for the ip header */ -memset(packet, 0, sizeof(struct ip)); -ip->ip_v = 4; -ip->ip_hl = 5; -ip->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + optlen + datalen); -get_random_bytes(&(ip->ip_id), 2); -ip->ip_ttl = myttl; -ip->ip_p = IPPROTO_TCP; -ip->ip_id = ipid; -ip->ip_src.s_addr = source->s_addr; -#ifdef WIN32 -// I'm not sure why this is --Fyodor -if (source->s_addr == victim->s_addr) ip->ip_src.s_addr++; -#endif - -ip->ip_dst.s_addr= victim->s_addr; #if HAVE_IP_IP_SUM -ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip)); + ip->ip_sum = in_cksum((u16*)ip, sizeof(struct ip)+ipoptlen); #endif -if (TCPIP_DEBUGGING > 1) { - log_write(LOG_STDOUT, "Raw TCP packet creation completed! Here it is:\n"); - readtcppacket(packet,ntohs(ip->ip_len)); -} - - *packetlen = ntohs(ip->ip_len); + *outpacketlen = packetlen; return packet; } @@ -1150,10 +1162,10 @@ struct ppkt { u16 seq; u8 data[1500]; /* Note -- first 4-12 bytes can be used for ICMP header */ } pingpkt; -u32 *datastart = (u32 *) pingpkt.data; -int dlen = sizeof(pingpkt.data); -int icmplen=0; -char *ping = (char *) &pingpkt; + u32 *datastart = (u32 *) pingpkt.data; + int dlen = sizeof(pingpkt.data); + int icmplen=0; + char *ping = (char *) &pingpkt; pingpkt.type = ptype; pingpkt.code = pcode; @@ -1320,30 +1332,31 @@ int send_udp_raw_decoys( int sd, struct finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim, - int ttl, u16 sport, u16 dport, u16 ipid, char *data, - u16 datalen, u32 *packetlen) + int ttl, u16 sport, u16 dport, u16 ipid, char *udpdata, + u16 udpdatalen, u32 *outpacketlen) { - unsigned char *packet = (unsigned char *) safe_malloc(sizeof(struct ip) + sizeof(udphdr_bsd) + datalen); + u8 *ipopt = o.ipoptions; + int ipoptlen = o.ipoptionslen; + int packetlen = sizeof(struct ip) + ipoptlen + sizeof(udphdr_bsd) + udpdatalen; + unsigned char *packet = (unsigned char *) safe_malloc(packetlen); struct ip *ip = (struct ip *) packet; - udphdr_bsd *udp = (udphdr_bsd *) (packet + sizeof(struct ip)); + udphdr_bsd *udp = (udphdr_bsd *) (packet + sizeof(struct ip) + ipoptlen); static int myttl = 0; struct pseudo_udp_hdr { struct in_addr source; struct in_addr dest; - u8 zero; + u8 zer0; u8 proto; u16 length; - } *pseudo = (struct pseudo_udp_hdr *) ((char *)udp - 12) ; + } *pseudo = (struct pseudo_udp_hdr *) ((u8 *)udp - sizeof(struct pseudo_udp_hdr)); - *packetlen = 0; - /* check that required fields are there and not too silly */ - if ( !victim) { - fprintf(stderr, "build_udp_raw: One or more of your parameters suck!\n"); - free(packet); - return NULL; - } + assert(victim); + assert(source); + + if(ipoptlen % 4); + fatal("build_udp_raw() called with an ip option length argument of %d which is illegal because it is not divisible by 4", ipoptlen); /* Time to live */ if (ttl == -1) { @@ -1352,58 +1365,58 @@ u8 *build_udp_raw(struct in_addr *source myttl = ttl; } - memset((char *) packet, 0, sizeof(struct ip) + sizeof(udphdr_bsd)); +// memset((char *) packet, 0, sizeof(struct ip) + sizeof(udphdr_bsd)); + /* Now the pseudo header for checksuming */ + pseudo->source.s_addr = source->s_addr; + pseudo->dest.s_addr = victim->s_addr; + pseudo->zer0 = 0; + pseudo->proto = IPPROTO_UDP; + pseudo->length = htons(sizeof(udphdr_bsd) + udpdatalen); + udp->uh_sport = htons(sport); udp->uh_dport = htons(dport); - udp->uh_ulen = htons(8 + datalen); + udp->uh_sum = 0; + udp->uh_ulen = htons(sizeof(udphdr_bsd) + udpdatalen); /* We should probably copy the data over too */ - if (data) - memcpy(packet + sizeof(struct ip) + sizeof(udphdr_bsd), data, datalen); + if (udpdata) + memcpy((u8*)udp + sizeof(udphdr_bsd), udpdata, udpdatalen); - /* Now the pseudo header for checksuming */ - pseudo->source.s_addr = source->s_addr; - pseudo->dest.s_addr = victim->s_addr; - pseudo->proto = IPPROTO_UDP; - pseudo->length = htons(sizeof(udphdr_bsd) + datalen); /* OK, now we should be able to compute a valid checksum */ #if STUPID_SOLARIS_CHECKSUM_BUG - udp->uh_sum = sizeof(udphdr_bsd) + datalen; + udp->uh_sum = sizeof(udphdr_bsd) + udpdatalen; #else - udp->uh_sum = in_cksum((unsigned short *)pseudo, 20 /* pseudo + UDP headers */ + datalen); + udp->uh_sum = in_cksum((u16*)pseudo, sizeof(pseudo_udp_hdr) + sizeof(udphdr_bsd) + udpdatalen); #endif if ( o.badsum ) --udp->uh_sum; /* Goodbye, pseudo header! */ - memset(pseudo, 0, sizeof(*pseudo)); +// memset(pseudo, 0, sizeof(*pseudo)); /* Now for the ip header */ - ip->ip_v = 4; - ip->ip_hl = 5; - ip->ip_len = htons(sizeof(struct ip) + sizeof(udphdr_bsd) + datalen); - ip->ip_id = htons(ipid); + ip->ip_v = 4; + ip->ip_hl = 5 + ipoptlen/4; + ip->ip_tos = 0; + ip->ip_len = htons(packetlen); + ip->ip_id = htons(ipid); + ip->ip_off = 0; ip->ip_ttl = myttl; - ip->ip_p = IPPROTO_UDP; + ip->ip_p = IPPROTO_UDP; + ip->ip_sum = 0; ip->ip_src.s_addr = source->s_addr; -#ifdef WIN32 - // I'm not exactly sure why this is needed --Fyodor - if(source->s_addr == victim->s_addr) ip->ip_src.s_addr; -#endif - ip->ip_dst.s_addr= victim->s_addr; + ip->ip_dst.s_addr = victim->s_addr; + if(ipoptlen) + memcpy(packet + sizeof(struct ip), ipopt, ipoptlen); + #if HAVE_IP_IP_SUM - ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip)); + ip->ip_sum = in_cksum((u16 *)ip, sizeof(struct ip) + ipoptlen); #endif - if (TCPIP_DEBUGGING > 1) { - printf("Raw UDP packet creation completed! Here it is:\n"); - readudppacket(packet,1); - } - - *packetlen = ntohs(ip->ip_len); + *outpacketlen = packetlen; return packet; } @@ -1430,59 +1443,52 @@ int send_udp_raw( int sd, struct eth_nfo finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ u8 *build_ip_raw(const struct in_addr *source, const struct in_addr *victim, - int ttl, u8 proto, u16 ipid, char *data, u16 datalen, - u32 *packetlen) + int ttl, u8 proto, u16 ipid, char *ipdata, u16 ipdatalen, + u32 *outpacketlen) { + u8 *ipopt = o.ipoptions; + int ipoptlen = o.ipoptionslen; + int packetlen = sizeof(struct ip) + ipoptlen + ipdatalen; + unsigned char *packet = (unsigned char *) safe_malloc(packetlen); + struct ip *ip = (struct ip *) packet; + static int myttl = 0; -unsigned char *packet = (unsigned char *) safe_malloc(sizeof(struct ip) + datalen); -struct ip *ip = (struct ip *) packet; -static int myttl = 0; - -/* check that required fields are there and not too silly */ -if ( !victim) { - fprintf(stderr, "send_ip_raw: One or more of your parameters suck!\n"); - free(packet); - return NULL; -} - -/* Time to live */ -if (ttl == -1) { - myttl = (get_random_uint() % 23) + 37; -} else { - myttl = ttl; -} + assert(victim); + assert(source); -memset((char *) packet, 0, sizeof(struct ip)); + /* Time to live */ + if (ttl == -1) { + myttl = (get_random_uint() % 23) + 37; + } else { + myttl = ttl; + } -/* Now for the ip header */ + /* Now for the ip header */ + ip->ip_v = 4; + ip->ip_hl = 5 + ipoptlen/4; + ip->ip_tos = 0; + ip->ip_len = htons(packetlen); + ip->ip_id = htons(ipid); + ip->ip_off = 0; + ip->ip_ttl = myttl; + ip->ip_p = proto; + ip->ip_sum = 0; + ip->ip_src.s_addr = source->s_addr; + ip->ip_dst.s_addr = victim->s_addr; -ip->ip_v = 4; -ip->ip_hl = 5; -ip->ip_len = htons(sizeof(struct ip) + datalen); -ip->ip_id = htons(ipid); -ip->ip_ttl = myttl; -ip->ip_p = proto; -ip->ip_src.s_addr = source->s_addr; -// #ifdef WIN32 -// TODO: Should this be removed? I'm not sure why this is here -- Fyodor -// if(source->s_addr == victim->s_addr) ip->ip_src.s_addr++; -// #endif -ip->ip_dst.s_addr = victim->s_addr; -#if HAVE_IP_IP_SUM -ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip)); -#endif + if(ipoptlen) + memcpy(packet + sizeof(struct ip), ipopt, ipoptlen); - /* We should probably copy the data over too */ - if (data) - memcpy(packet + sizeof(struct ip), data, datalen); + #if HAVE_IP_IP_SUM + ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip) + ipoptlen); + #endif -if (TCPIP_DEBUGGING > 1) { - printf("Raw IP packet creation completed! Here it is:\n"); - hdump(packet, ntohs(ip->ip_len)); -} + /* We should probably copy the data over too */ + if(ipdata) + memcpy(packet + sizeof(struct ip) + ipoptlen, ipdata, ipdatalen); - *packetlen = ntohs(ip->ip_len); - return packet; + *outpacketlen = packetlen; + return packet; } diff -Nraup nmap-4.10-orig/utils.cc nmap-4.10-ipopts/utils.cc --- nmap-4.10-orig/utils.cc 2006-03-06 01:00:03.000000000 +0100 +++ nmap-4.10-ipopts/utils.cc 2006-06-23 00:54:58.000000000 +0200 @@ -559,6 +559,90 @@ char *cstring_unescape(char *str, unsign return str; } +/* This function converts zero-terminated 'txt' string to binary 'data'. + It is used to parse user input. Some examples of possible input + strings and output results: + '\x01*2\xA2' -> [0x01,0x01,0xA2] // with 'x' number is parsed in hex + '\01*2\255' -> [0x01,0x01,0xFF] // without 'x' its in decimal + '\x00abcd\x00*2' -> [0x00,0x61,0x62,0x63,0x64,0x00,0x00] +*/ +int parse_hextobin(char *txt, char *data, int datalen){ + enum{ + NONE = 0, + SLASH = 1, + MUL = 2, + } s = NONE; + char *n, lc; + char *c = txt; + char *d = data; + int i,j; + int base = 10; + char *dataend = &data[datalen]; + + for(;*c;c++){ + switch(s){ + case SLASH: + // parse \x00 string + if(*c == 'x'){// just ignore this char + base = 16; + break; + } + if(isxdigit(*c)){ + *d++ = strtol(c, &n, base); + c=n-1; + }else + fatal("not a digit after '\\'"); + s = NONE; + break; + case MUL: + if(d==data) + fatal("nothing before '*' char"); + i = strtol(c, &n, 10); + if(i<2) + fatal("bad number after '*'"); + c = n-1; // move current txt pointer + lc = *(d-1); // last char, we'll copy this + for(j=1; j= buflen)break; + if(i%16==7){ + bp += snprintf(&buf[bp], buflen-bp," "); + if(bp >= buflen)break; + } + if(i%16==15){ + bp += snprintf(&buf[bp], buflen-bp,"\n"); + if(bp >= buflen)break; + } + } + if(i%16!=0 && bp < buflen) + bp += snprintf(&buf[bp], buflen-bp,"\n"); +} + /* mmap() an entire file into the address space. Returns a pointer to the beginning of the file. The mmap'ed length is returned inside the length parameter. If there is a problem, NULL is diff -Nraup nmap-4.10-orig/utils.h nmap-4.10-ipopts/utils.h --- nmap-4.10-orig/utils.h 2006-03-26 00:56:16.000000000 +0100 +++ nmap-4.10-ipopts/utils.h 2006-06-23 00:54:58.000000000 +0200 @@ -226,6 +226,17 @@ long tval2msecs(char *tspec); str is returned. */ char *cstring_unescape(char *str, unsigned int *len); +/* This function converts zero-terminated 'txt' string to binary 'data'. + It is used to parse user input. Some examples of possible input + strings and output results: + '\x01*2\x02' -> [0x01,0x01,0x02] + '\01*2\02' -> [0x01,0x01,0x02] // 'x' isn't required + '\x00abcd\x00*2' -> [0x00,0x61,0x62,0x63,0x64,0x00,0x00] +*/ +int parse_hextobin(char *txt, char *data, int datalen); + +void bintohexstr(char *buf, int buflen, char *src, int srclen); + #ifndef HAVE_STRERROR char *strerror(int errnum); #endif