1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-10 07:51:32 +00:00

Add -ip-options support

This commit is contained in:
fyodor
2006-08-29 03:26:00 +00:00
parent 426a6d36db
commit 9cbae88f44
13 changed files with 769 additions and 244 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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;

View File

@@ -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? &eth : 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? &eth : 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);

20
nmap.cc
View File

@@ -257,6 +257,7 @@ printf("%s %s ( %s )\n"
" -e <iface>: Use specified interface\n"
" -g/--source-port <portnum>: Use given port number\n"
" --data-length <num>: Append random data to sent packets\n"
" --ip-options <options>: Send packets with specified ip options\n"
" --ttl <val>: Set IP time-to-live field\n"
" --spoof-mac <mac address/prefix/vendor name>: Spoof your MAC address\n"
" --badsum: Send packets with a bogus TCP/UDP checksum\n"
@@ -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)

View File

@@ -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,

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}
}

339
tcpip.cc
View File

@@ -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);

73
tcpip.h
View File

@@ -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.

355
utils.cc
View File

@@ -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<i; j++){
*d++ = lc;
if(d == dataend) // check for overflow
goto after;
}
s = NONE;
break;
case RR:
if(*c==' ' || *c==',')
break;
n = buf;
while(*c=='.' || (*c>='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<dataend);
}
if(sourcerouting){
if(*len<37){
*len+=4;
*lasthopoff = d - data;
*d++ = 0;*d++ = 0;*d++ = 0;*d++ = 0;
}else
fatal("When using source routing you must leave at least one slot for target's ip.");
}
if(s == RR)
return(*len+1); // because we inject NOP before
if(s == TIME)
return(*len);
after:
return(d - data);
}
void bintohexstr(char *buf, int buflen, char *src, int srclen){
int bp=0;
int i;
for(i=0; i<srclen; i++){
bp += snprintf(buf+bp, buflen-bp, "\\x%02hhx",src[i]);
if(bp >= 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){ // for every char in ipopt
// read ip option header
if(option_type == UNKNOWN) {
option_sta = pt;
option_type = ipopt[pt++];
if(option_type != 0 && option_type != 1) { // should we be interested in length field?
if(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<s; i++)
STRAPP("\\x%02x", ipopt[pt++]);
option_pt -= i;
// okay, now we can start printing ip's
CHECK(pt+3);
tptr = &ipopt[pt]; pt+=4;
if(inet_ntop(AF_INET, (char *) tptr, ipstring, sizeof(ipstring)) == NULL)
fatal("Failed to convert target address to presentation format!?! Error: %s", strerror(socket_errno()));
STRAPP("%c%s",(pt-3-option_sta)==option_pt?'#':' ', ipstring);
if(pt == option_end)
STRAPP("%s",(pt-option_sta)==(option_pt-1)?"#":""); // pointer in the end?
}else BREAK();
break;
case 68: // IPOPT_TS -> 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<s; i++)
STRAPP("\\x%02x", ipopt[pt++]);
option_pt-=i;
// print pt
STRAPP("%c",(pt+1-option_sta)==option_pt?'#':' ');
// okay, first grab ip.
if(option_fl!=0){
CHECK(pt+3);
tptr = &ipopt[pt]; pt+=4;
if(inet_ntop(AF_INET, (char *) tptr, ipstring, sizeof(ipstring)) == NULL)
fatal("Failed to convert target address to presentation format!?! Error: %s", strerror(socket_errno()));
STRAPP("%s@", ipstring);
}
CHECK(pt+3);
tint = (u32*)&ipopt[pt]; pt+=4;
STRAPP("%u", ntohl(*tint));
if(pt == option_end)
STRAPP("%s",(pt-option_sta)==(option_pt-1)?"#":" ");
}else BREAK();
break;
case 136: // IPOPT_SATID -> (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

18
utils.h
View File

@@ -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