diff --git a/CHANGELOG b/CHANGELOG index 953dad85c..6a4bafd52 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,14 @@ o Worked with Zhao to improve the new OS detection system with better algorithms, some probe changes, and some bug fixes. +o Nmap now supports IP options with the new --ip-options flag. You + can specify any optiosn in hex, or use "R" (record route), "T" + (record timestamp), "U") (record route & timestamp), "S [route]" + (strict source route), or "L [route]" (loose source route). Specify + --packet-trace to display IP options of responses. For further + information and examples, see http://insecure.org/nmap/man/ and + http://seclists.org/nmap-dev/2006/q3/0052.html . + o Nmap now uses the (relatively) new libpcap pcap_get_selectable_fd API on systems which support it. This means that we no longer need to hack the included Pcap to better support Linux. So Nmap will now diff --git a/NmapOps.cc b/NmapOps.cc index 5151e9934..7bd7f5ad0 100644 --- a/NmapOps.cc +++ b/NmapOps.cc @@ -252,6 +252,10 @@ void NmapOps::Initialize() { dns_servers = NULL; noninteractive = false; current_scantype = STYPE_UNKNOWN; + ipoptions = NULL; + ipoptionslen = 0; + ipopt_firsthop = 0; + ipopt_lasthop = 0; release_memory = false; } @@ -446,6 +450,12 @@ void NmapOps::ValidateOptions() { if (min_parallelism > max_parallelism) max_parallelism = min_parallelism; + if(o.ipoptionslen && ! o.isr00t) + fatal("To use ip options you must be root."); + + if(o.ipoptions && o.osscan) + error("WARNING: Ip options are NOT used while OS scanning!"); + } void NmapOps::setMaxRttTimeout(int rtt) diff --git a/NmapOps.h b/NmapOps.h index ef0e15c7e..9157a11fa 100644 --- a/NmapOps.h +++ b/NmapOps.h @@ -293,6 +293,13 @@ class NmapOps { char *dns_servers; bool log_errors; + /* ip options used in build_*_raw() */ + u8 *ipoptions; + int ipoptionslen; + int ipopt_firsthop; // offset in ipoptions where is first hop for source/strict routing + int ipopt_lasthop; // offset in ipoptions where is space for targets ip for source/strict routing + + // Statistics Options set in nmap.cc int numhosts_scanned; int numhosts_up; diff --git a/idle_scan.cc b/idle_scan.cc index 869b61c8f..0b880d9db 100644 --- a/idle_scan.cc +++ b/idle_scan.cc @@ -186,12 +186,14 @@ static int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent, gettimeofday(&tv_sent[tries], NULL); /* Time to send the pr0be!*/ - send_tcp_raw(proxy->rawsd, proxy->ethptr, proxy->host.v4sourceip(), - proxy->host.v4hostip(), o.ttl, false, base_port + tries, - proxy->probe_port, - seq_base + (packet_send_count++ * 500) + 1, ack, 0, - TH_SYN|TH_ACK, 0, 0, - (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); + send_tcp_raw(proxy->rawsd, proxy->ethptr, + proxy->host.v4sourceip(), proxy->host.v4hostip(), + o.ttl, false, + o.ipoptions, o.ipoptionslen, + base_port + tries, proxy->probe_port, + seq_base + (packet_send_count++ * 500) + 1, ack, 0, TH_SYN|TH_ACK, 0, 0, + (u8 *) "\x02\x04\x05\xb4", 4, + NULL, 0); sent++; tries++; @@ -416,11 +418,14 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName, a response with the exact request for timing purposes. So I think I'll use TH_SYN, although it is a tough call. */ /* We can't use decoys 'cause that would screw up the IPIDs */ - send_tcp_raw(proxy->rawsd, proxy->ethptr, proxy->host.v4sourceip(), - proxy->host.v4hostip(), o.ttl, false, + send_tcp_raw(proxy->rawsd, proxy->ethptr, + proxy->host.v4sourceip(), proxy->host.v4hostip(), + o.ttl, false, + o.ipoptions, o.ipoptionslen, o.magic_port + probes_sent + 1, proxy->probe_port, - sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, - 0, 0, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); + sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, 0, 0, + (u8 *) "\x02\x04\x05\xb4",4, + NULL, 0); gettimeofday(&probe_send_times[probes_sent], NULL); probes_sent++; @@ -523,11 +528,14 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName, if (first_target) { for (probes_sent = 0; probes_sent < 4; probes_sent++) { if (probes_sent) usleep(50000); - send_tcp_raw(proxy->rawsd, proxy->ethptr, first_target, - proxy->host.v4hostip(), - o.ttl, false,o.magic_port, proxy->probe_port, - sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, - 0, 0, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); + send_tcp_raw(proxy->rawsd, proxy->ethptr, + first_target, proxy->host.v4hostip(), + o.ttl, false, + o.ipoptions, o.ipoptionslen, + o.magic_port, proxy->probe_port, + sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, 0, 0, + (u8 *) "\x02\x04\x05\xb4", + 4, NULL, 0); } @@ -680,10 +688,13 @@ static int idlescan_countopen2(struct idle_proxy_info *proxy, but doing it the straightforward way (using the same decoys as we use in probing the proxy box is risky. I'll have to think about this more. */ - send_tcp_raw(proxy->rawsd, eth.ethsd? ð : NULL, proxy->host.v4hostip(), - target->v4hostip(), - o.ttl, false, proxy->probe_port, ports[pr0be], seq, 0, 0, TH_SYN, 0, 0, - (u8 *) "\x02\x04\x05\xb4", 4, o.extra_payload, o.extra_payload_length); + send_tcp_raw(proxy->rawsd, eth.ethsd? ð : NULL, + proxy->host.v4hostip(), target->v4hostip(), + o.ttl, false, + o.ipoptions, o.ipoptionslen, + proxy->probe_port, ports[pr0be], seq, 0, 0, TH_SYN, 0, 0, + (u8 *) "\x02\x04\x05\xb4", 4, + o.extra_payload, o.extra_payload_length); } gettimeofday(&end, NULL); diff --git a/nmap.cc b/nmap.cc index c7f1dfcef..c9b44094e 100644 --- a/nmap.cc +++ b/nmap.cc @@ -257,6 +257,7 @@ printf("%s %s ( %s )\n" " -e : Use specified interface\n" " -g/--source-port : Use given port number\n" " --data-length : Append random data to sent packets\n" + " --ip-options : Send packets with specified ip options\n" " --ttl : Set IP time-to-live field\n" " --spoof-mac : Spoof your MAC address\n" " --badsum: Send packets with a bogus TCP/UDP checksum\n" @@ -583,6 +584,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} }; @@ -792,6 +795,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_ip_options(optarg, o.ipoptions, 4*10+1, &o.ipopt_firsthop, &o.ipopt_lasthop); + 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); } @@ -1102,6 +1112,16 @@ int nmap_main(int argc, char *argv[]) { o.ValidateOptions(); + // print ip options + if((o.debugging || o.packetTrace()) && o.ipoptionslen){ + char buf[256]; // 256 > 5*40 + bintohexstr(buf, sizeof(buf), (char*)o.ipoptions, o.ipoptionslen); + if(o.ipoptionslen>=8) // at least one ip address + log_write(LOG_STDOUT, "Binary ip options to be send:\n%s", buf); + log_write(LOG_STDOUT, "Parsed ip options to be send:\n%s\n", + print_ip_options(o.ipoptions, o.ipoptionslen)); + } + /* Open the log files, now that we know whether the user wants them appended or overwritten */ if (normalfilename) diff --git a/osscan.cc b/osscan.cc index ccaa20bb0..bb9d2503e 100644 --- a/osscan.cc +++ b/osscan.cc @@ -613,7 +613,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Test 1 */ if (!FPtests[1]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, NULL, 0, current_port, openport, sequence_base, 0, 0, TH_ECE|TH_SYN, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000", 20, NULL, 0); } @@ -621,7 +621,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Test 2 */ if (!FPtests[2]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, NULL, 0, current_port +1, openport, sequence_base, 0, 0, 0, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } @@ -629,7 +629,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Test 3 */ if (!FPtests[3]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, NULL, 0, current_port +2, openport, sequence_base, 0, 0, TH_SYN|TH_FIN|TH_URG|TH_PUSH, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } @@ -637,7 +637,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Test 4 */ if (!FPtests[4]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, NULL, 0, current_port +3, openport, sequence_base, 0, 0, TH_ACK, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } @@ -646,7 +646,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Test 5 */ if (!FPtests[5]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, NULL, 0, current_port +4, closedport, sequence_base, 0, 0, TH_SYN, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } @@ -654,7 +654,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Test 6 */ if (!FPtests[6]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, NULL, 0, current_port +5, closedport, sequence_base, 0, 0, TH_ACK, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } @@ -662,7 +662,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Test 7 */ if (!FPtests[7]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, NULL, 0, current_port +6, closedport, sequence_base, 0, 0, TH_FIN|TH_PUSH|TH_URG, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } @@ -749,7 +749,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { usleep(remaining_us); } } - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, NULL, 0, o.magic_port + seq_packets_sent + 1, openport, sequence_base + seq_packets_sent + 1, 0, 0, diff --git a/osscan2.cc b/osscan2.cc index 29abe309c..dc640bb0b 100644 --- a/osscan2.cc +++ b/osscan2.cc @@ -1277,7 +1277,7 @@ void HostOsScan::sendTSeqProbe(HostOsScanStats *hss, int probeNo) { if(hss->openTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, NULL, 0, tcpPortBase + probeNo, hss->openTCPPort, tcpSeqBase + probeNo, tcpAck, 0, TH_SYN, prbWindowSz[probeNo], 0, prbOpts[probeNo].val, prbOpts[probeNo].len, @@ -1292,7 +1292,7 @@ void HostOsScan::sendTOpsProbe(HostOsScanStats *hss, int probeNo) { if(hss->openTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, NULL, 0, tcpPortBase + NUM_SEQ_SAMPLES + probeNo, hss->openTCPPort, tcpSeqBase, tcpAck, 0, TH_SYN, prbWindowSz[probeNo], 0, prbOpts[probeNo].val, @@ -1304,7 +1304,7 @@ void HostOsScan::sendTEcnProbe(HostOsScanStats *hss) { if(hss->openTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, NULL, 0, tcpPortBase + NUM_SEQ_SAMPLES + 6, hss->openTCPPort, tcpSeqBase, 0, 8, TH_CWR|TH_ECE|TH_SYN, prbWindowSz[6], 63477, prbOpts[6].val, prbOpts[6].len, NULL, 0); @@ -1319,51 +1319,52 @@ void HostOsScan::sendT1_7Probe(HostOsScanStats *hss, int probeNo) { switch(probeNo) { case 0: /* T1 */ if(hss->openTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, NULL, 0, port_base, hss->openTCPPort, tcpSeqBase, tcpAck, 0, TH_SYN, prbWindowSz[0], 0, prbOpts[0].val, prbOpts[0].len, NULL, 0); break; case 1: /* T2 */ if(hss->openTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, true, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, true, NULL, 0, port_base + 1, hss->openTCPPort, tcpSeqBase, tcpAck, 0, - 0, prbWindowSz[7], 0, prbOpts[7].val, prbOpts[7].len, NULL, 0); + 0, prbWindowSz[7], 0, prbOpts[7].val, + prbOpts[7].len, NULL, 0); break; case 2: /* T3 */ if(hss->openTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, NULL, 0, port_base + 2, hss->openTCPPort, tcpSeqBase, tcpAck, 0, - TH_SYN|TH_FIN|TH_URG|TH_PUSH, prbWindowSz[8], 0, - prbOpts[8].val, prbOpts[8].len, NULL, 0); + TH_SYN|TH_FIN|TH_URG|TH_PUSH, prbWindowSz[8], 0, prbOpts[8].val, + prbOpts[8].len, NULL, 0); break; case 3: /* T4 */ if(hss->openTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, true, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, true, NULL, 0, port_base + 3, hss->openTCPPort, tcpSeqBase, tcpAck, 0, TH_ACK, prbWindowSz[9], 0, prbOpts[9].val, prbOpts[9].len, NULL, 0); break; case 4: /* T5 */ if(hss->closedTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, NULL, 0, port_base + 4, hss->closedTCPPort, tcpSeqBase, tcpAck, 0, TH_SYN, prbWindowSz[10], 0, prbOpts[10].val, prbOpts[10].len, NULL, 0); break; case 5: /* T6 */ if(hss->closedTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, true, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, true, NULL, 0, port_base + 5, hss->closedTCPPort, tcpSeqBase, tcpAck, 0, TH_ACK, prbWindowSz[11], 0, prbOpts[11].val, prbOpts[11].len, NULL, 0); break; case 6: /* T7 */ if(hss->closedTCPPort == -1) return; - send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, + send_tcp_raw_decoys(rawsd, ethptr, hss->target->v4hostip(), o.ttl, false, NULL, 0, port_base + 6, hss->closedTCPPort, tcpSeqBase, tcpAck, - 0, TH_FIN|TH_PUSH|TH_URG, prbWindowSz[12], 0, - prbOpts[12].val, prbOpts[12].len, NULL, 0); + 0, TH_FIN|TH_PUSH|TH_URG, prbWindowSz[12], 0, prbOpts[12].val, + prbOpts[12].len, NULL, 0); break; } } @@ -2962,9 +2963,11 @@ int send_icmp_echo_probe(int sd, struct eth_nfo *eth, int res = -1; for(decoy = 0; decoy < o.numdecoys; decoy++) { - packet = build_icmp_raw(&o.decoys[decoy], victim, o.ttl, - get_random_u16(), tos, df, seq, id, ICMP_ECHO, pcode, NULL, - datalen, &packetlen); + packet = build_icmp_raw(&o.decoys[decoy], victim, + o.ttl, get_random_u16(), tos, df, + NULL, 0, + seq, id, ICMP_ECHO, pcode, + NULL, datalen, &packetlen); if(!packet) return -1; res = send_ip_packet(sd, eth, packet, packetlen); free(packet); diff --git a/scan_engine.cc b/scan_engine.cc index 0db98a301..c16974b54 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -2134,9 +2134,12 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, } for(decoy = 0; decoy < o.numdecoys; decoy++) { - packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, false, - ipid, sport, pspec->pd.tcp.dport, seq, ack, 0, - pspec->pd.tcp.flags, 0, 0, tcpops, tcpopslen, + packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), + o.ttl, ipid, IP_TOS_DEFAULT, false, + o.ipoptions, o.ipoptionslen, + sport, pspec->pd.tcp.dport, + seq, ack, 0, pspec->pd.tcp.flags, 0, 0, + tcpops, tcpopslen, o.extra_payload, o.extra_payload_length, &packetlen); if (decoy == o.decoyturn) { @@ -2148,8 +2151,10 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, } } else if (USI->udp_scan) { for(decoy = 0; decoy < o.numdecoys; decoy++) { - packet = build_udp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, - sport, pspec->pd.udp.dport, ipid, + packet = build_udp_raw(&o.decoys[decoy], hss->target->v4hostip(), + o.ttl, ipid, IP_TOS_DEFAULT, false, + o.ipoptions, o.ipoptionslen, + sport, pspec->pd.udp.dport, o.extra_payload, o.extra_payload_length, &packetlen); if (decoy == o.decoyturn) { @@ -2164,27 +2169,37 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, switch(pspec->proto) { case IPPROTO_TCP: - packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, false, - ipid, sport, o.magic_port, get_random_u32(), - get_random_u32(), 0, TH_ACK, 0, 0, NULL, - 0, o.extra_payload, o.extra_payload_length, + packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), + o.ttl, ipid, IP_TOS_DEFAULT, false, + o.ipoptions, o.ipoptionslen, + sport, o.magic_port, + get_random_u32(), get_random_u32(), 0, TH_ACK, 0, 0, + NULL,0, + o.extra_payload, o.extra_payload_length, &packetlen); break; case IPPROTO_ICMP: - packet = build_icmp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, - ipid, 0, false, 0, 0, 8, 0, o.extra_payload, - o.extra_payload_length, &packetlen); + packet = build_icmp_raw(&o.decoys[decoy], hss->target->v4hostip(), + o.ttl, ipid, IP_TOS_DEFAULT, false, + o.ipoptions, o.ipoptionslen, + 0, 0, 8, 0, + o.extra_payload, o.extra_payload_length, + &packetlen); break; case IPPROTO_UDP: - packet = build_udp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, - sport, o.magic_port, ipid, + packet = build_udp_raw(&o.decoys[decoy], hss->target->v4hostip(), + o.ttl, ipid, IP_TOS_DEFAULT, false, + o.ipoptions, o.ipoptionslen, + sport, o.magic_port, o.extra_payload, o.extra_payload_length, &packetlen); break; default: - packet = build_ip_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, - pspec->proto, ipid, 0, false, + packet = build_ip_raw(&o.decoys[decoy], hss->target->v4hostip(), + pspec->proto, + o.ttl, ipid, IP_TOS_DEFAULT, false, + o.ipoptions, o.ipoptionslen, o.extra_payload, o.extra_payload_length, &packetlen); break; @@ -2767,6 +2782,8 @@ static bool get_arp_result(UltraScanInfo *USI, struct timeval *stime) { } + + /* 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 diff --git a/targets.cc b/targets.cc index 7f7045b6f..5c07b9346 100644 --- a/targets.cc +++ b/targets.cc @@ -900,7 +900,11 @@ else { o.decoys[o.decoyturn].s_addr = target->v4source().s_addr; - send_udp_raw_decoys( rawsd, eth, target->v4hostip(), o.ttl, sportbase + trynum, probe_port, seq, o.extra_payload, o.extra_payload_length); + send_udp_raw_decoys( rawsd, eth, target->v4hostip(), + o.ttl, seq, + o.ipoptions, o.ipoptionslen, + sportbase + trynum, probe_port, + o.extra_payload, o.extra_payload_length); return 0; @@ -924,11 +928,21 @@ else { o.decoys[o.decoyturn].s_addr = target->v4source().s_addr; if (pingtype & PINGTYPE_TCP_USE_SYN) { - send_tcp_raw_decoys( rawsd, eth, target->v4hostip(), o.ttl, false, sportbase + trynum, probe_port, myseq, myack, 0, TH_SYN, 0, 0, (u8 *) "\x02\x04\x05\xb4", 4, o.extra_payload, - o.extra_payload_length); + send_tcp_raw_decoys( rawsd, eth, target->v4hostip(), + o.ttl, false, + o.ipoptions, o.ipoptionslen, + sportbase + trynum, probe_port, + myseq, myack, 0, TH_SYN, 0, 0, + (u8 *) "\x02\x04\x05\xb4", 4, + o.extra_payload, o.extra_payload_length); } else { - send_tcp_raw_decoys( rawsd, eth, target->v4hostip(), o.ttl, false, sportbase + trynum, probe_port, myseq, myack, 0, TH_ACK, 0, 0, NULL, 0, o.extra_payload, - o.extra_payload_length); + send_tcp_raw_decoys( rawsd, eth, target->v4hostip(), + o.ttl, false, + o.ipoptions, o.ipoptionslen, + sportbase + trynum, probe_port, + myseq, myack, 0, TH_ACK, 0, 0, + NULL, 0, + o.extra_payload, o.extra_payload_length); } return 0; @@ -1068,7 +1082,11 @@ if (ptech.icmpscan) { fprintf(stderr, "sendto: %s\n", strerror(sock_err)); } } else { - send_ip_raw( rawsd, ethptr, &o.decoys[decoy], target->v4hostip(), o.ttl, IPPROTO_ICMP, ping, icmplen); + send_ip_raw(rawsd, ethptr, + &o.decoys[decoy], target->v4hostip(), + IPPROTO_ICMP, o.ttl, + o.ipoptions, o.ipoptionslen, + ping, icmplen); } } diff --git a/tcpip.cc b/tcpip.cc index afedfd7db..dfa4ca184 100644 --- a/tcpip.cc +++ b/tcpip.cc @@ -409,7 +409,7 @@ static const char *ippackethdrinfo(const u8 *packet, u32 len) { struct ip *ip = (struct ip *) packet; struct tcphdr *tcp; udphdr_bsd *udp; - char ipinfo[64]; + char ipinfo[512]; char srchost[INET6_ADDRSTRLEN], dsthost[INET6_ADDRSTRLEN]; char *p; struct in_addr saddr, daddr; @@ -434,8 +434,11 @@ static const char *ippackethdrinfo(const u8 *packet, u32 len) { } - snprintf(ipinfo, sizeof(ipinfo), "ttl=%d id=%d iplen=%d%s", - ip->ip_ttl, ntohs(ip->ip_id), ntohs(ip->ip_len), fragnfo); + snprintf(ipinfo, sizeof(ipinfo), "ttl=%d id=%d iplen=%d%s %s%s%s", + ip->ip_ttl, ntohs(ip->ip_id), ntohs(ip->ip_len), fragnfo, + ip->ip_hl==5?"":"ipopts={", + ip->ip_hl==5?"":print_ip_options((u8*)ip + sizeof(struct ip), MIN((ip->ip_hl-5)*4,len-sizeof(struct ip))), + ip->ip_hl==5?"":"}"); if (ip->ip_p == IPPROTO_TCP) { char tflags[10]; @@ -1012,18 +1015,69 @@ void eth_close_cached() { return; } +// fill ip header. no error check. +// This function is also changing what's needed from host to network order. +static inline int fill_ip_raw( + struct ip *ip, int packetlen, u8* ipopt, int ipoptlen, + int ip_tos, int ip_id, int ip_off, int ip_ttl, int ip_p, + const struct in_addr *ip_src, const struct in_addr *ip_dst) +{ + ip->ip_v = 4; + ip->ip_hl = 5 + (ipoptlen/4); + ip->ip_tos = ip_tos; + ip->ip_len = htons(packetlen); + ip->ip_id = htons(ip_id); + ip->ip_off = htons(ip_off); + ip->ip_ttl = ip_ttl; + ip->ip_p = ip_p; + ip->ip_src.s_addr = ip_src->s_addr; + ip->ip_dst.s_addr = ip_dst->s_addr; + + if (ipoptlen) + memcpy((u8*)ip + sizeof(struct ip), ipopt, ipoptlen); + + // ip options source routing hack: + if(ipoptlen && o.ipopt_firsthop && o.ipopt_lasthop) { + u8* ipo = (u8*)ip + sizeof(struct ip); + struct in_addr *newdst = (struct in_addr *) &ipo[o.ipopt_firsthop]; + struct in_addr *olddst = (struct in_addr *) &ipo[o.ipopt_lasthop]; + // our destination is somewhere else :) + ip->ip_dst.s_addr = newdst->s_addr; + + // and last hop should be destination + olddst->s_addr = ip_dst->s_addr; + } + + + #if HAVE_IP_IP_SUM + ip->ip_sum = 0; + ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip) + ipoptlen); + #endif + return(sizeof(struct ip) + ipoptlen); +} + + + int send_tcp_raw_decoys( int sd, struct eth_nfo *eth, - const struct in_addr *victim, int ttl, bool df, - u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, - u16 window, u16 urp, u8 *options, int optlen, char *data, - u16 datalen) + const struct in_addr *victim, + int ttl, bool df, + u8* ipopt, int ipoptlen, + u16 sport, u16 dport, + u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp, + u8 *options, int optlen, + char *data, u16 datalen) { int decoy; for(decoy = 0; decoy < o.numdecoys; decoy++) - if (send_tcp_raw(sd, eth, &o.decoys[decoy], victim, ttl, df, sport, dport, - seq, ack, reserved, flags, window, urp, options, optlen, data, - datalen) == -1) + if (send_tcp_raw(sd, eth, + &o.decoys[decoy], victim, + ttl, df, + ipopt, ipoptlen, + sport, dport, + seq, ack, reserved, flags, window, urp, + options, optlen, + data, datalen) == -1) return -1; return 0; @@ -1035,11 +1089,13 @@ int send_tcp_raw_decoys( int sd, struct eth_nfo *eth, actually sent by this function. Caller must delete the buffer when finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ -u8 *build_tcp_raw(const struct in_addr *source, - const struct in_addr *victim, int ttl, u16 ipid, bool df, - u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, - u16 window, u16 urp, u8 *options, int optlen, char *data, - u16 datalen, u32 *packetlen) { +u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim, + int ttl, u16 ipid, u8 tos, bool df, + u8 *ipopt, int ipoptlen, + u16 sport, u16 dport, + u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp, + u8 *tcpopt, int tcpoptlen, + char *data, u16 datalen, u32 *outpacketlen) { struct pseudo_header { /*for computing TCP checksum, see TCP/IP Illustrated p. 145 */ @@ -1049,18 +1105,22 @@ struct pseudo_header { u8 protocol; u16 length; }; -u8 *packet = (u8 *) safe_malloc(sizeof(struct ip) + sizeof(struct tcphdr) + optlen + datalen); +int packetlen = sizeof(struct ip) + ipoptlen + + sizeof(struct tcphdr) + tcpoptlen + datalen; +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 *) ((u8*)ip + 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); +assert(ipoptlen%4==0); + +if (tcpoptlen % 4) + fatal("build_tcp_raw() called with an option length argument of %d which is illegal because it is not divisible by 4. Just add \\0 padding to the end.", tcpoptlen); -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. Just add \\0 padding to the end.", optlen); -} /* Time to live */ if (ttl == -1) { @@ -1069,19 +1129,19 @@ if (ttl == -1) { myttl = ttl; } -memset((char *) packet, 0, sizeof(struct ip) + sizeof(struct tcphdr)); - 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 + datalen); +/* Fill tcp header */ +memset(tcp, 0, sizeof(struct tcphdr)); tcp->th_sport = htons(sport); tcp->th_dport = htons(dport); if (seq) { tcp->th_seq = htonl(seq); -} -else if (flags & TH_SYN) { +} else if (flags & TH_SYN) { get_random_bytes(&(tcp->th_seq), 4); } @@ -1092,7 +1152,7 @@ if (ack) if (reserved) tcp->th_x2 = reserved & 0x0F; -tcp->th_off = 5 + (optlen /4) /*words*/; +tcp->th_off = 5 + (tcpoptlen /4) /*words*/; tcp->th_flags = flags; if (window) @@ -1103,62 +1163,50 @@ else tcp->th_win = htons(1024 * (myttl % 4 + 1)); /* Who cares */ if (urp) tcp->th_urp = htons(urp); - /* 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); - } +/* And the options */ +if (tcpoptlen) + memcpy((u8*)tcp + sizeof(struct tcphdr), tcpopt, tcpoptlen); +/* We should probably copy the data over too */ +if (data && datalen) + memcpy((u8*)tcp + sizeof(struct tcphdr) + tcpoptlen, data, datalen); #if STUPID_SOLARIS_CHECKSUM_BUG - tcp->th_sum = sizeof(struct tcphdr) + optlen + datalen; +tcp->th_sum = sizeof(struct tcphdr) + tcpoptlen + datalen; #else tcp->th_sum = in_cksum((unsigned short *)pseudo, sizeof(struct tcphdr) + - optlen + sizeof(struct pseudo_header) + datalen); + tcpoptlen + sizeof(struct pseudo_header) + datalen); #endif if ( o.badsum ) --tcp->th_sum; -/* 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; -if(df) ip->ip_off |= htons(IP_DF); -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 + fill_ip_raw(ip, packetlen, ipopt, ipoptlen, + tos, ipid, df?IP_DF:0, myttl, IPPROTO_TCP, + source, victim); -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 - - *packetlen = ntohs(ip->ip_len); + *outpacketlen = packetlen; return packet; - } /* You need to call sethdrinclude(sd) on the sending sd before calling this */ -int send_tcp_raw( int sd, struct eth_nfo *eth, const struct in_addr *source, - const struct in_addr *victim, int ttl, bool df, - u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, - u16 window, u16 urp, u8 *options, int optlen, char *data, - u16 datalen) +int send_tcp_raw( int sd, struct eth_nfo *eth, + const struct in_addr *source, const struct in_addr *victim, + int ttl, bool df, + u8* ipops, int ipoptlen, + u16 sport, u16 dport, + u32 seq, u32 ack, u8 reserved, u8 flags,u16 window, u16 urp, + u8 *options, int optlen, + char *data, u16 datalen) { unsigned int packetlen; int res = -1; - u8 *packet = build_tcp_raw(source, victim, ttl, get_random_u16(), df, sport, - dport, seq, ack, reserved, flags, window, urp, options, optlen, + u8 *packet = build_tcp_raw(source, victim, + ttl, get_random_u16(), IP_TOS_DEFAULT, df, + ipops, ipoptlen, + sport, dport, + seq, ack, reserved, flags, window, urp, + options, optlen, data, datalen, &packetlen); if (!packet) return -1; res = send_ip_packet(sd, eth, packet, packetlen); @@ -1325,9 +1373,10 @@ int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet, unsigned int packetl packetlen, which must be a valid int pointer. The id/seq will be converted to network byte order (if it differs from HBO) */ u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, - int ttl, u16 ipid, u8 tos, bool df, u16 seq, - unsigned short id, u8 ptype, u8 pcode, char *data, - u16 datalen, u32 *packetlen) { + int ttl, u16 ipid, u8 tos, bool df, + u8 *ipopt, int ipoptlen, + u16 seq, unsigned short id, u8 ptype, u8 pcode, + char *data, u16 datalen, u32 *packetlen) { struct ppkt { u8 type; @@ -1373,8 +1422,12 @@ pingpkt.checksum = in_cksum((unsigned short *)ping, icmplen); if ( o.badsum ) --pingpkt.checksum; -return build_ip_raw(source, victim, o.ttl, IPPROTO_ICMP, get_random_u16(), tos, df, - ping, icmplen, packetlen); +return build_ip_raw(source, victim, + IPPROTO_ICMP, + o.ttl, get_random_u16(), tos, df, + ipopt, ipoptlen, + ping, icmplen, + packetlen); } @@ -1485,14 +1538,17 @@ if (ip->ip_p== IPPROTO_UDP) { } int send_udp_raw_decoys( int sd, struct eth_nfo *eth, - const struct in_addr *victim, int ttl, - u16 sport, u16 dport, u16 ipid, char *data, - u16 datalen) { + const struct in_addr *victim, + int ttl, u16 ipid, + u8* ipops, int ipoptlen, + u16 sport, u16 dport, + char *data, u16 datalen) { int decoy; for(decoy = 0; decoy < o.numdecoys; decoy++) - if (send_udp_raw(sd, eth, &o.decoys[decoy], victim, ttl, sport, dport, ipid, - data, datalen) == -1) + if (send_udp_raw(sd, eth, &o.decoys[decoy], victim, + ttl, ipid, ipops, ipoptlen, + sport, dport, data, datalen) == -1) return -1; return 0; @@ -1506,30 +1562,30 @@ int send_udp_raw_decoys( int sd, struct eth_nfo *eth, 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 ipid, u8 tos, bool df, + u8 *ipopt, int ipoptlen, + u16 sport, u16 dport, + char *data, u16 datalen, u32 *outpacketlen) { - unsigned char *packet = (unsigned char *) safe_malloc(sizeof(struct ip) + sizeof(udphdr_bsd) + datalen); + int packetlen = sizeof(struct ip) + ipoptlen + sizeof(udphdr_bsd) + datalen; + u8 *packet = (u8 *) safe_malloc(packetlen); struct ip *ip = (struct ip *) packet; - udphdr_bsd *udp = (udphdr_bsd *) (packet + sizeof(struct ip)); + udphdr_bsd *udp = (udphdr_bsd *) ((u8*)ip + 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); + assert(ipoptlen%4==0); /* Time to live */ if (ttl == -1) { @@ -1538,19 +1594,19 @@ u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim, myttl = ttl; } - memset((char *) packet, 0, sizeof(struct ip) + sizeof(udphdr_bsd)); - 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) + datalen); /* We should probably copy the data over too */ if (data) - memcpy(packet + sizeof(struct ip) + sizeof(udphdr_bsd), data, datalen); + memcpy((u8*)udp + sizeof(udphdr_bsd), data, datalen); /* 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) + datalen); @@ -1564,39 +1620,28 @@ u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim, if ( o.badsum ) --udp->uh_sum; - /* Goodbye, pseudo header! */ - memset(pseudo, 0, sizeof(*pseudo)); + fill_ip_raw(ip, packetlen, ipopt, ipoptlen, + tos, ipid, df?IP_DF:0, myttl, IPPROTO_UDP, + source, victim); - /* 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_ttl = myttl; - ip->ip_p = IPPROTO_UDP; - 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; -#if HAVE_IP_IP_SUM - ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip)); -#endif - - *packetlen = ntohs(ip->ip_len); + *outpacketlen = packetlen; return packet; } -int send_udp_raw( int sd, struct eth_nfo *eth, struct in_addr *source, - const struct in_addr *victim, - int ttl, u16 sport, u16 dport, u16 ipid, char *data, - u16 datalen) +int send_udp_raw( int sd, struct eth_nfo *eth, + struct in_addr *source, const struct in_addr *victim, + int ttl, u16 ipid, + u8* ipopt, int ipoptlen, + u16 sport, u16 dport, + char *data, u16 datalen) { unsigned int packetlen; int res = -1; - u8 *packet = build_udp_raw(source, victim, ttl, sport, dport, ipid, data, - datalen, &packetlen); + u8 *packet = build_udp_raw(source, victim, + ttl, ipid, IP_TOS_DEFAULT, false, + ipopt, ipoptlen, + sport, dport, + data, datalen, &packetlen); if (!packet) return -1; res = send_ip_packet(sd, eth, packet, packetlen); @@ -1611,20 +1656,21 @@ int send_udp_raw( int sd, struct eth_nfo *eth, struct in_addr *source, 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, u8 tos, bool df, char *data, u16 datalen, - u32 *packetlen) + u8 proto, + int ttl, u16 ipid, u8 tos, bool df, + u8 *ipopt, int ipoptlen, + char *data, u16 datalen, + u32 *outpacketlen) { - -unsigned char *packet = (unsigned char *) safe_malloc(sizeof(struct ip) + datalen); +int packetlen = sizeof(struct ip) + ipoptlen + datalen; +u8 *packet = (u8 *) safe_malloc(packetlen); 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; -} +assert(source); +assert(victim); +assert(ipoptlen%4==0); /* Time to live */ if (ttl == -1) { @@ -1633,47 +1679,34 @@ if (ttl == -1) { myttl = ttl; } -memset((char *) packet, 0, sizeof(struct ip)); - -/* Now for the ip header */ - -ip->ip_v = 4; -ip->ip_hl = 5; -ip->ip_tos = tos; -ip->ip_len = htons(sizeof(struct ip) + datalen); -ip->ip_id = htons(ipid); -if(df) ip->ip_off |= htons(IP_DF); -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 + fill_ip_raw(ip, packetlen, ipopt, ipoptlen, + tos, ipid, df?IP_DF:0, myttl, proto, + source, victim); /* We should probably copy the data over too */ if (data) - memcpy(packet + sizeof(struct ip), data, datalen); + memcpy((u8*)ip + sizeof(struct ip) + ipoptlen, data, datalen); - *packetlen = ntohs(ip->ip_len); + *outpacketlen = packetlen; return packet; } /* You need to call sethdrinclude(sd) on the sending sd before calling this */ -int send_ip_raw( int sd, struct eth_nfo *eth, struct in_addr *source, - const struct in_addr *victim, int ttl, u8 proto, +int send_ip_raw( int sd, struct eth_nfo *eth, + struct in_addr *source, const struct in_addr *victim, + u8 proto, int ttl, + u8* ipopt, int ipoptlen, char *data, u16 datalen) { unsigned int packetlen; int res = -1; - u8 *packet = build_ip_raw(source, victim, ttl, proto, get_random_u16(), - IP_TOS_DEFAULT, false, data, datalen, &packetlen); + u8 *packet = build_ip_raw(source, victim, + proto, + ttl, get_random_u16(), IP_TOS_DEFAULT, false, + ipopt, ipoptlen, + data, datalen, &packetlen); if (!packet) return -1; res = send_ip_packet(sd, eth, packet, packetlen); diff --git a/tcpip.h b/tcpip.h index 2fd5ee89a..95c1b5ae2 100644 --- a/tcpip.h +++ b/tcpip.h @@ -515,17 +515,25 @@ unsigned short in_cksum(u16 *ptr,int nbytes); /* Build and send a raw tcp packet. If TTL is -1, a partially random (but likely large enough) one is chosen */ -int send_tcp_raw( int sd, struct eth_nfo *eth, const struct in_addr *source, - const struct in_addr *victim, int ttl, bool df, - u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, - u16 window, u16 urp, u8 *options, int optlen, char *data, - u16 datalen); -int send_udp_raw( int sd, struct eth_nfo *eth, struct in_addr *source, - const struct in_addr *victim, int ttl, u16 sport, - u16 dport, u16 ipid, char *data, u16 datalen); +int send_tcp_raw( int sd, struct eth_nfo *eth, + const struct in_addr *source, const struct in_addr *victim, + int ttl, bool df, + u8* ipopt, int ipoptlen, + u16 sport, u16 dport, + u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp, + u8 *options, int optlen, + char *data, u16 datalen); +int send_udp_raw( int sd, struct eth_nfo *eth, + struct in_addr *source, const struct in_addr *victim, + int ttl, u16 ipid, + u8* ipopt, int ipoptlen, + u16 sport, u16 dport, + char *data, u16 datalen); -int send_ip_raw( int sd, struct eth_nfo *eth, struct in_addr *source, - const struct in_addr *victim, int ttl, u8 proto, +int send_ip_raw( int sd, struct eth_nfo *eth, + struct in_addr *source, const struct in_addr *victim, + u8 proto, int ttl, + u8* ipopt, int ipoptlen, char *data, u16 datalen); /* Builds a TCP packet (including an IP header) by packing the fields @@ -535,8 +543,12 @@ int send_ip_raw( int sd, struct eth_nfo *eth, struct in_addr *source, finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim, - int ttl, u16 ipid, bool df, u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, - u8 flags, u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen, + int ttl, u16 ipid, u8 tos, bool df, + u8* ipopt, int ipoptlen, + u16 sport, u16 dport, + u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp, + u8 *options, int optlen, + char *data, u16 datalen, u32 *packetlen); /* Builds a UDP packet (including an IP header) by packing the fields @@ -546,8 +558,11 @@ u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim, 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 ipid, u8 tos, bool df, + u8* ipopt, int ipoptlen, + u16 sport, u16 dport, + char *data, u16 datalen, + u32 *packetlen); /* Builds an ICMP packet (including an IP header) by packing the fields with the given information. It allocates a new buffer to @@ -558,8 +573,10 @@ u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim, id/seq will be converted to network byte order (if it differs from HBO) */ u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, - int ttl, u16 ipid, u8 tos, bool df, u16 seq, unsigned short id, u8 ptype, - u8 pcode, char *data, u16 datalen, u32 *packetlen); + int ttl, u16 ipid, u8 tos, bool df, + u8* ipopt, int ipoptlen, + u16 seq, unsigned short id, u8 ptype, u8 pcode, + char *data, u16 datalen, u32 *packetlen); /* Builds an IP packet (including an IP header) by packing the fields with the given information. It allocates a new buffer to store the @@ -568,7 +585,10 @@ u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, 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, u8 tos, bool df, char *data, u16 datalen, + u8 proto, + int ttl, u16 ipid, u8 tos, bool df, + u8* ipopt, int ipoptlen, + char *data, u16 datalen, u32 *packetlen); /* Send a pre-built IPv4 packet */ @@ -577,15 +597,20 @@ int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet, /* 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, bool df, - u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, - u16 window, u16 urp, u8 *options, int optlen, char *data, - u16 datalen); + const struct in_addr *victim, + int ttl, bool df, + u8* ipopt, int ipoptlen, + u16 sport, u16 dport, + u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp, + u8 *options, int optlen, + char *data, u16 datalen); int send_udp_raw_decoys( int sd, struct eth_nfo *eth, - const struct in_addr *victim, int ttl, - u16 sport, u16 dport, u16 ipid, char *data, - u16 datalen); + const struct in_addr *victim, + int ttl, u16 ipid, + u8* ipops, int ip, + u16 sport, u16 dport, + char *data, u16 datalen); /* Calls pcap_open_live and spits out an error (and quits) if the call fails. diff --git a/utils.cc b/utils.cc index bc2747370..da3a98855 100644 --- a/utils.cc +++ b/utils.cc @@ -99,6 +99,7 @@ /* $Id$ */ +#include "nmap.h" #include "utils.h" #include "NmapOps.h" @@ -559,6 +560,360 @@ char *cstring_unescape(char *str, unsigned int *newlen) { return str; } +/* This function converts zero-terminated 'txt' string to binary 'data'. + It is used to parse user input for ip options. Some examples of possible input + strings and results: + '\x01*2\xA2' -> [0x01,0x01,0xA2] // with 'x' number is parsed in hex + '\01\01\255' -> [0x01,0x01,0xFF] // without 'x' its in decimal + '\x01\x00*2' -> [0x01,0x00,0x00] // '*' is copying char + 'R' -> Record Route with 9 slots + 'S 192.168.0.1 172.16.0.1' -> Strict Route with 2 slots + 'L 192.168.0.1 172.16.0.1' -> Loose Route with 2 slots + 'T' -> Record Timestamp with 9 slots + 'U' -> Record Timestamp and Ip Address with 4 slots +*/ +int parse_ip_options(char *txt, u8 *data, int datalen, int* firsthopoff, int* lasthopoff){ + enum{ + NONE = 0, + SLASH = 1, + MUL = 2, + RR = 3, + TIME = 4, + } s = NONE; + char *n, lc; + char *c = txt; + u8 *d = data; + int i,j; + int base = 10; + u8 *dataend = &data[datalen]; + u8 *len = NULL; + char buf[32]; + memset(data, 0, datalen); + bool sourcerouting = false; + + + 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='0' && *c<='9') && n-buf <= ((int)sizeof(buf)-1)) + *n++ = *c++; + *n = '\0'; c--; + if(d+4>=dataend) + fatal("Buffer too small. Or input data too big :)"); + i = inet_pton(AF_INET, buf, d); + if(i<1) + fatal("Not a valid ipv4 address '%s'",buf); + // remember offset of first hop + if(sourcerouting && !*firsthopoff) + *firsthopoff = d - data; + d+=4; + if(*len<37) + *len += 4; + break; + case TIME: + fatal("No more arguments allowed!"); + default: + switch(*c){ + case '\\':s = SLASH;base=10;break; + case '*':s = MUL;break; + case 'R': + case 'S': + case 'L': + if(d != data) + fatal("This option can't be used in that way"); + *d++ = '\x01';//NOP + switch(*c){ + case 'R':*d++ = 7;break; + case 'S':*d++ = 137; sourcerouting=true; break; + case 'L':*d++ = 131; sourcerouting=true; break; + } + len = d; + *d++ = (*c=='R')? 39 : 3; // length: 3+4*9 bytes + *d++ = 4; //pointer + s = RR; + break; + case 'T': + case 'U': + if(d != data) + fatal("This option can't be used in that way"); + *d++ = 68; // option type + len = d; + *d++ = (*c=='U') ? 36 : 40; // length: 3+4*9 bytes or 4+4*9 bytes + *d++ = 5; // pointer + *d++ = (*c=='U') ? 1 : 0; // flag: address and Time fields + s = TIME; + break; + default://*d++ = *c; + fatal("Bad character in ip option '%c'",*c); + } + } + if(d == dataend) + break; + assert(d= 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"); +} + +static inline char* STRAPP(char *fmt, ...) { + static char buf[256]; + static int bp; + int left = (int)sizeof(buf)-bp; + if(!fmt){ + bp = 0; + return(buf); + } + va_list ap; + va_start(ap, fmt); + bp += vsnprintf (buf+bp, (left>0 ? left : 0), fmt, ap); + va_end(ap); + + return(buf); +} + +#define HEXDUMP -2 +#define UNKNOWN -1 + +#define BREAK() \ + {option_type = HEXDUMP; break;} +#define CHECK(tt) \ + if(tt >= option_end) \ + {option_type = HEXDUMP; break;} +/* It tries to decode ip options. + Returns static buffer. watch out. */ +char* print_ip_options(u8* ipopt, int ipoptlen) { + char ipstring[32]; + int option_type = UNKNOWN;// option type + int option_len = 0; // option length + int option_pt = 0; // option pointer + int option_fl = 0; // option flag + u8 *tptr; // temp pointer + u32 *tint; // temp int + + int option_sta = 0; // option start offset + int option_end = 0; // option end offset + int pt = 0; // current offset + + // clear buffer + STRAPP(NULL,NULL); + + if(!ipoptlen) + return(NULL); + + while(pt= ipoptlen) // no more chars + {option_type = HEXDUMP;pt--; option_end = 255; continue;} // no length field, hex dump to the end + option_len = ipopt[pt++]; + // end must not be greater than length + option_end = MIN(option_sta + option_len, ipoptlen); + // end must not be smaller than current position + option_end = MAX(option_end, option_sta+2); + } + } + switch(option_type) { + case 0: // IPOPT_END + STRAPP(" EOL", NULL); + option_type = UNKNOWN; + break; + case 1: // IPOPT_NOP + STRAPP(" NOP", NULL); + option_type = UNKNOWN; + break; +/* case 130: // IPOPT_SECURITY + option_type=-1; + 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%s{", (option_type==131)?"LS":(option_type==137)?"SS":"", "RR"); + // option pointer + CHECK(pt); + option_pt = ipopt[pt++]; + if(option_pt%4 != 0 || (option_sta + option_pt-1)>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-1)>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) + BREAK(); + }else BREAK(); + break; + case UNKNOWN: + default: + // we read option_type and option_len, print them. + STRAPP(" ??{\\x%02hhx\\x%02hhx", option_type, option_len); + // check option_end once more: + if(option_len < ipoptlen) + option_end = MIN(MAX(option_sta+option_len, option_sta+2),ipoptlen); + else + option_end = 255; + option_type = HEXDUMP; + break; + case HEXDUMP: + assert(pt<=option_end); + if(pt == option_end){ + STRAPP("}",NULL); + option_type=-1; + break; + } + STRAPP("\\x%02hhx", ipopt[pt++]); + break; + } + if(pt == option_end && option_type != UNKNOWN) { + STRAPP("}",NULL); + option_type = UNKNOWN; + } + } // while + if(option_type != UNKNOWN) + STRAPP("}"); + + return(STRAPP("",NULL)); +} +#undef CHECK +#undef BREAK +#undef UNKNOWN +#undef HEXDUMP + + /* 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 --git a/utils.h b/utils.h index 8e8515f4b..e29f01369 100644 --- a/utils.h +++ b/utils.h @@ -226,6 +226,24 @@ 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 for ip options. Some examples of possible input + strings and results: + '\x01*2\xA2' -> [0x01,0x01,0xA2] // with 'x' number is parsed in hex + '\01\01\255' -> [0x01,0x01,0xFF] // without 'x' its in decimal + '\x01\x00*2' -> [0x01,0x00,0x00] // '*' is copying char + 'R' -> Record Route with 9 slots + 'S 192.168.0.1 172.16.0.1' -> Strict Route with 2 slots + 'L 192.168.0.1 172.16.0.1' -> Loose Route with 2 slots + 'T' -> Record Timestamp with 9 slots + 'U' -> Record Timestamp and Ip Address with 4 slots +*/ +int parse_ip_options(char *txt, u8 *data, int datalen, int* firsthopoff, int* lasthopoff); + +void bintohexstr(char *buf, int buflen, char *src, int srclen); + +char* print_ip_options(u8* ipopt, int ipoptlen); + #ifndef HAVE_STRERROR char *strerror(int errnum); #endif