1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-10 08:51:36 +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 o Worked with Zhao to improve the new OS detection system with
better algorithms, some probe changes, and some bug fixes. 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 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 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 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; dns_servers = NULL;
noninteractive = false; noninteractive = false;
current_scantype = STYPE_UNKNOWN; current_scantype = STYPE_UNKNOWN;
ipoptions = NULL;
ipoptionslen = 0;
ipopt_firsthop = 0;
ipopt_lasthop = 0;
release_memory = false; release_memory = false;
} }
@@ -446,6 +450,12 @@ void NmapOps::ValidateOptions() {
if (min_parallelism > max_parallelism) if (min_parallelism > max_parallelism)
max_parallelism = min_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) void NmapOps::setMaxRttTimeout(int rtt)

View File

@@ -293,6 +293,13 @@ class NmapOps {
char *dns_servers; char *dns_servers;
bool log_errors; 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 // Statistics Options set in nmap.cc
int numhosts_scanned; int numhosts_scanned;
int numhosts_up; 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); gettimeofday(&tv_sent[tries], NULL);
/* Time to send the pr0be!*/ /* Time to send the pr0be!*/
send_tcp_raw(proxy->rawsd, proxy->ethptr, proxy->host.v4sourceip(), send_tcp_raw(proxy->rawsd, proxy->ethptr,
proxy->host.v4hostip(), o.ttl, false, base_port + tries, proxy->host.v4sourceip(), proxy->host.v4hostip(),
proxy->probe_port, o.ttl, false,
seq_base + (packet_send_count++ * 500) + 1, ack, 0, o.ipoptions, o.ipoptionslen,
TH_SYN|TH_ACK, 0, 0, base_port + tries, proxy->probe_port,
(u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); seq_base + (packet_send_count++ * 500) + 1, ack, 0, TH_SYN|TH_ACK, 0, 0,
(u8 *) "\x02\x04\x05\xb4", 4,
NULL, 0);
sent++; sent++;
tries++; 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 a response with the exact request for timing purposes. So I
think I'll use TH_SYN, although it is a tough call. */ think I'll use TH_SYN, although it is a tough call. */
/* We can't use decoys 'cause that would screw up the IPIDs */ /* We can't use decoys 'cause that would screw up the IPIDs */
send_tcp_raw(proxy->rawsd, proxy->ethptr, proxy->host.v4sourceip(), send_tcp_raw(proxy->rawsd, proxy->ethptr,
proxy->host.v4hostip(), o.ttl, false, proxy->host.v4sourceip(), proxy->host.v4hostip(),
o.ttl, false,
o.ipoptions, o.ipoptionslen,
o.magic_port + probes_sent + 1, proxy->probe_port, o.magic_port + probes_sent + 1, proxy->probe_port,
sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, 0, 0,
0, 0, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); (u8 *) "\x02\x04\x05\xb4",4,
NULL, 0);
gettimeofday(&probe_send_times[probes_sent], NULL); gettimeofday(&probe_send_times[probes_sent], NULL);
probes_sent++; probes_sent++;
@@ -523,11 +528,14 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
if (first_target) { if (first_target) {
for (probes_sent = 0; probes_sent < 4; probes_sent++) { for (probes_sent = 0; probes_sent < 4; probes_sent++) {
if (probes_sent) usleep(50000); if (probes_sent) usleep(50000);
send_tcp_raw(proxy->rawsd, proxy->ethptr, first_target, send_tcp_raw(proxy->rawsd, proxy->ethptr,
proxy->host.v4hostip(), first_target, proxy->host.v4hostip(),
o.ttl, false,o.magic_port, proxy->probe_port, o.ttl, false,
sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, o.ipoptions, o.ipoptionslen,
0, 0, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); 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 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 we use in probing the proxy box is risky. I'll have to think
about this more. */ about this more. */
send_tcp_raw(proxy->rawsd, eth.ethsd? &eth : NULL, proxy->host.v4hostip(), send_tcp_raw(proxy->rawsd, eth.ethsd? &eth : NULL,
target->v4hostip(), proxy->host.v4hostip(), target->v4hostip(),
o.ttl, false, proxy->probe_port, ports[pr0be], seq, 0, 0, TH_SYN, 0, 0, o.ttl, false,
(u8 *) "\x02\x04\x05\xb4", 4, o.extra_payload, o.extra_payload_length); 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); gettimeofday(&end, NULL);

20
nmap.cc
View File

@@ -257,6 +257,7 @@ printf("%s %s ( %s )\n"
" -e <iface>: Use specified interface\n" " -e <iface>: Use specified interface\n"
" -g/--source-port <portnum>: Use given port number\n" " -g/--source-port <portnum>: Use given port number\n"
" --data-length <num>: Append random data to sent packets\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" " --ttl <val>: Set IP time-to-live field\n"
" --spoof-mac <mac address/prefix/vendor name>: Spoof your MAC address\n" " --spoof-mac <mac address/prefix/vendor name>: Spoof your MAC address\n"
" --badsum: Send packets with a bogus TCP/UDP checksum\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}, {"log-errors", no_argument, 0, 0},
{"dns_servers", required_argument, 0, 0}, {"dns_servers", required_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} {0, 0, 0, 0}
}; };
@@ -792,6 +795,13 @@ int nmap_main(int argc, char *argv[]) {
o.fragscan = atoi(optarg); o.fragscan = atoi(optarg);
if (o.fragscan <= 0 || o.fragscan % 8 != 0) if (o.fragscan <= 0 || o.fragscan % 8 != 0)
fatal("Data payload MTU must be >0 and multiple of 8"); 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 { } else {
fatal("Unknown long option (%s) given@#!$#$", long_options[option_index].name); fatal("Unknown long option (%s) given@#!$#$", long_options[option_index].name);
} }
@@ -1102,6 +1112,16 @@ int nmap_main(int argc, char *argv[]) {
o.ValidateOptions(); 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 /* Open the log files, now that we know whether the user wants them appended
or overwritten */ or overwritten */
if (normalfilename) if (normalfilename)

View File

@@ -613,7 +613,7 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) {
/* Test 1 */ /* Test 1 */
if (!FPtests[1]) { if (!FPtests[1]) {
if (o.scan_delay) enforce_scan_delay(NULL); 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, 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); 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 */ /* Test 2 */
if (!FPtests[2]) { if (!FPtests[2]) {
if (o.scan_delay) enforce_scan_delay(NULL); 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, 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); 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 */ /* Test 3 */
if (!FPtests[3]) { if (!FPtests[3]) {
if (o.scan_delay) enforce_scan_delay(NULL); 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, 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); 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 */ /* Test 4 */
if (!FPtests[4]) { if (!FPtests[4]) {
if (o.scan_delay) enforce_scan_delay(NULL); 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, 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); 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 */ /* Test 5 */
if (!FPtests[5]) { if (!FPtests[5]) {
if (o.scan_delay) enforce_scan_delay(NULL); 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, 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); 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 */ /* Test 6 */
if (!FPtests[6]) { if (!FPtests[6]) {
if (o.scan_delay) enforce_scan_delay(NULL); 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, 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); 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 */ /* Test 7 */
if (!FPtests[7]) { if (!FPtests[7]) {
if (o.scan_delay) enforce_scan_delay(NULL); 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, 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); 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); 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, o.magic_port + seq_packets_sent + 1,
openport, openport,
sequence_base + seq_packets_sent + 1, 0, 0, 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; 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, tcpPortBase + probeNo, hss->openTCPPort,
tcpSeqBase + probeNo, tcpAck, 0, tcpSeqBase + probeNo, tcpAck, 0,
TH_SYN, prbWindowSz[probeNo], 0, prbOpts[probeNo].val, prbOpts[probeNo].len, 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; 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, tcpPortBase + NUM_SEQ_SAMPLES + probeNo,
hss->openTCPPort, tcpSeqBase, tcpAck, 0, TH_SYN, hss->openTCPPort, tcpSeqBase, tcpAck, 0, TH_SYN,
prbWindowSz[probeNo], 0, prbOpts[probeNo].val, prbWindowSz[probeNo], 0, prbOpts[probeNo].val,
@@ -1304,7 +1304,7 @@ void HostOsScan::sendTEcnProbe(HostOsScanStats *hss) {
if(hss->openTCPPort == -1) return; 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, tcpPortBase + NUM_SEQ_SAMPLES + 6, hss->openTCPPort,
tcpSeqBase, 0, 8, TH_CWR|TH_ECE|TH_SYN, prbWindowSz[6], tcpSeqBase, 0, 8, TH_CWR|TH_ECE|TH_SYN, prbWindowSz[6],
63477, prbOpts[6].val, prbOpts[6].len, NULL, 0); 63477, prbOpts[6].val, prbOpts[6].len, NULL, 0);
@@ -1319,51 +1319,52 @@ void HostOsScan::sendT1_7Probe(HostOsScanStats *hss, int probeNo) {
switch(probeNo) { switch(probeNo) {
case 0: /* T1 */ case 0: /* T1 */
if(hss->openTCPPort == -1) return; 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, port_base, hss->openTCPPort, tcpSeqBase, tcpAck, 0,
TH_SYN, prbWindowSz[0], 0, prbOpts[0].val, TH_SYN, prbWindowSz[0], 0, prbOpts[0].val,
prbOpts[0].len, NULL, 0); prbOpts[0].len, NULL, 0);
break; break;
case 1: /* T2 */ case 1: /* T2 */
if(hss->openTCPPort == -1) return; 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, 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; break;
case 2: /* T3 */ case 2: /* T3 */
if(hss->openTCPPort == -1) return; 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, port_base + 2, hss->openTCPPort, tcpSeqBase, tcpAck, 0,
TH_SYN|TH_FIN|TH_URG|TH_PUSH, prbWindowSz[8], 0, TH_SYN|TH_FIN|TH_URG|TH_PUSH, prbWindowSz[8], 0, prbOpts[8].val,
prbOpts[8].val, prbOpts[8].len, NULL, 0); prbOpts[8].len, NULL, 0);
break; break;
case 3: /* T4 */ case 3: /* T4 */
if(hss->openTCPPort == -1) return; 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, port_base + 3, hss->openTCPPort, tcpSeqBase, tcpAck, 0,
TH_ACK, prbWindowSz[9], 0, prbOpts[9].val, TH_ACK, prbWindowSz[9], 0, prbOpts[9].val,
prbOpts[9].len, NULL, 0); prbOpts[9].len, NULL, 0);
break; break;
case 4: /* T5 */ case 4: /* T5 */
if(hss->closedTCPPort == -1) return; 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, port_base + 4, hss->closedTCPPort, tcpSeqBase, tcpAck,
0, TH_SYN, prbWindowSz[10], 0, prbOpts[10].val, 0, TH_SYN, prbWindowSz[10], 0, prbOpts[10].val,
prbOpts[10].len, NULL, 0); prbOpts[10].len, NULL, 0);
break; break;
case 5: /* T6 */ case 5: /* T6 */
if(hss->closedTCPPort == -1) return; 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, port_base + 5, hss->closedTCPPort, tcpSeqBase, tcpAck,
0, TH_ACK, prbWindowSz[11], 0, prbOpts[11].val, 0, TH_ACK, prbWindowSz[11], 0, prbOpts[11].val,
prbOpts[11].len, NULL, 0); prbOpts[11].len, NULL, 0);
break; break;
case 6: /* T7 */ case 6: /* T7 */
if(hss->closedTCPPort == -1) return; 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, port_base + 6, hss->closedTCPPort, tcpSeqBase, tcpAck,
0, TH_FIN|TH_PUSH|TH_URG, prbWindowSz[12], 0, 0, TH_FIN|TH_PUSH|TH_URG, prbWindowSz[12], 0, prbOpts[12].val,
prbOpts[12].val, prbOpts[12].len, NULL, 0); prbOpts[12].len, NULL, 0);
break; break;
} }
} }
@@ -2962,9 +2963,11 @@ int send_icmp_echo_probe(int sd, struct eth_nfo *eth,
int res = -1; int res = -1;
for(decoy = 0; decoy < o.numdecoys; decoy++) { for(decoy = 0; decoy < o.numdecoys; decoy++) {
packet = build_icmp_raw(&o.decoys[decoy], victim, o.ttl, packet = build_icmp_raw(&o.decoys[decoy], victim,
get_random_u16(), tos, df, seq, id, ICMP_ECHO, pcode, NULL, o.ttl, get_random_u16(), tos, df,
datalen, &packetlen); NULL, 0,
seq, id, ICMP_ECHO, pcode,
NULL, datalen, &packetlen);
if(!packet) return -1; if(!packet) return -1;
res = send_ip_packet(sd, eth, packet, packetlen); res = send_ip_packet(sd, eth, packet, packetlen);
free(packet); free(packet);

View File

@@ -2134,9 +2134,12 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
} }
for(decoy = 0; decoy < o.numdecoys; decoy++) { for(decoy = 0; decoy < o.numdecoys; decoy++) {
packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, false, packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(),
ipid, sport, pspec->pd.tcp.dport, seq, ack, 0, o.ttl, ipid, IP_TOS_DEFAULT, false,
pspec->pd.tcp.flags, 0, 0, tcpops, tcpopslen, 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, o.extra_payload, o.extra_payload_length,
&packetlen); &packetlen);
if (decoy == o.decoyturn) { if (decoy == o.decoyturn) {
@@ -2148,8 +2151,10 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
} }
} else if (USI->udp_scan) { } else if (USI->udp_scan) {
for(decoy = 0; decoy < o.numdecoys; decoy++) { for(decoy = 0; decoy < o.numdecoys; decoy++) {
packet = build_udp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, packet = build_udp_raw(&o.decoys[decoy], hss->target->v4hostip(),
sport, pspec->pd.udp.dport, ipid, o.ttl, ipid, IP_TOS_DEFAULT, false,
o.ipoptions, o.ipoptionslen,
sport, pspec->pd.udp.dport,
o.extra_payload, o.extra_payload_length, o.extra_payload, o.extra_payload_length,
&packetlen); &packetlen);
if (decoy == o.decoyturn) { if (decoy == o.decoyturn) {
@@ -2164,27 +2169,37 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
switch(pspec->proto) { switch(pspec->proto) {
case IPPROTO_TCP: case IPPROTO_TCP:
packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, false, packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(),
ipid, sport, o.magic_port, get_random_u32(), o.ttl, ipid, IP_TOS_DEFAULT, false,
get_random_u32(), 0, TH_ACK, 0, 0, NULL, o.ipoptions, o.ipoptionslen,
0, o.extra_payload, o.extra_payload_length, 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); &packetlen);
break; break;
case IPPROTO_ICMP: case IPPROTO_ICMP:
packet = build_icmp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, packet = build_icmp_raw(&o.decoys[decoy], hss->target->v4hostip(),
ipid, 0, false, 0, 0, 8, 0, o.extra_payload, o.ttl, ipid, IP_TOS_DEFAULT, false,
o.extra_payload_length, &packetlen); o.ipoptions, o.ipoptionslen,
0, 0, 8, 0,
o.extra_payload, o.extra_payload_length,
&packetlen);
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
packet = build_udp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, packet = build_udp_raw(&o.decoys[decoy], hss->target->v4hostip(),
sport, o.magic_port, ipid, o.ttl, ipid, IP_TOS_DEFAULT, false,
o.ipoptions, o.ipoptionslen,
sport, o.magic_port,
o.extra_payload, o.extra_payload_length, o.extra_payload, o.extra_payload_length,
&packetlen); &packetlen);
break; break;
default: default:
packet = build_ip_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, packet = build_ip_raw(&o.decoys[decoy], hss->target->v4hostip(),
pspec->proto, ipid, 0, false, pspec->proto,
o.ttl, ipid, IP_TOS_DEFAULT, false,
o.ipoptions, o.ipoptionslen,
o.extra_payload, o.extra_payload_length, o.extra_payload, o.extra_payload_length,
&packetlen); &packetlen);
break; 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 /* Tries to get one *good* (finishes a probe) pcap response by the
(absolute) time given in stime. Even if stime is now, try an (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 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; 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; return 0;
@@ -924,11 +928,21 @@ else {
o.decoys[o.decoyturn].s_addr = target->v4source().s_addr; o.decoys[o.decoyturn].s_addr = target->v4source().s_addr;
if (pingtype & PINGTYPE_TCP_USE_SYN) { 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, send_tcp_raw_decoys( rawsd, eth, target->v4hostip(),
o.extra_payload_length); 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 { } 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, send_tcp_raw_decoys( rawsd, eth, target->v4hostip(),
o.extra_payload_length); 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; return 0;
@@ -1068,7 +1082,11 @@ if (ptech.icmpscan) {
fprintf(stderr, "sendto: %s\n", strerror(sock_err)); fprintf(stderr, "sendto: %s\n", strerror(sock_err));
} }
} else { } 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 ip *ip = (struct ip *) packet;
struct tcphdr *tcp; struct tcphdr *tcp;
udphdr_bsd *udp; udphdr_bsd *udp;
char ipinfo[64]; char ipinfo[512];
char srchost[INET6_ADDRSTRLEN], dsthost[INET6_ADDRSTRLEN]; char srchost[INET6_ADDRSTRLEN], dsthost[INET6_ADDRSTRLEN];
char *p; char *p;
struct in_addr saddr, daddr; 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", 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_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) { if (ip->ip_p == IPPROTO_TCP) {
char tflags[10]; char tflags[10];
@@ -1012,18 +1015,69 @@ void eth_close_cached() {
return; 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, int send_tcp_raw_decoys( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl, bool df, const struct in_addr *victim,
u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, int ttl, bool df,
u16 window, u16 urp, u8 *options, int optlen, char *data, u8* ipopt, int ipoptlen,
u16 datalen) 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; int decoy;
for(decoy = 0; decoy < o.numdecoys; decoy++) for(decoy = 0; decoy < o.numdecoys; decoy++)
if (send_tcp_raw(sd, eth, &o.decoys[decoy], victim, ttl, df, sport, dport, if (send_tcp_raw(sd, eth,
seq, ack, reserved, flags, window, urp, options, optlen, data, &o.decoys[decoy], victim,
datalen) == -1) ttl, df,
ipopt, ipoptlen,
sport, dport,
seq, ack, reserved, flags, window, urp,
options, optlen,
data, datalen) == -1)
return -1; return -1;
return 0; 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 actually sent by this function. Caller must delete the buffer when
finished with the packet. The packet length is returned in finished with the packet. The packet length is returned in
packetlen, which must be a valid int pointer. */ packetlen, which must be a valid int pointer. */
u8 *build_tcp_raw(const struct in_addr *source, u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim,
const struct in_addr *victim, int ttl, u16 ipid, bool df, int ttl, u16 ipid, u8 tos, bool df,
u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, u8 *ipopt, int ipoptlen,
u16 window, u16 urp, u8 *options, int optlen, char *data, u16 sport, u16 dport,
u16 datalen, u32 *packetlen) { 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 { struct pseudo_header {
/*for computing TCP checksum, see TCP/IP Illustrated p. 145 */ /*for computing TCP checksum, see TCP/IP Illustrated p. 145 */
@@ -1049,18 +1105,22 @@ struct pseudo_header {
u8 protocol; u8 protocol;
u16 length; 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 ip *ip = (struct ip *) packet;
struct tcphdr *tcp = (struct tcphdr *) (packet + sizeof(struct ip)); struct tcphdr *tcp = (struct tcphdr *) ((u8*)ip + sizeof(struct ip) + ipoptlen);
struct pseudo_header *pseudo = (struct pseudo_header *) (packet + sizeof(struct ip) - sizeof(struct pseudo_header)); struct pseudo_header *pseudo =
(struct pseudo_header *) ((u8*)tcp - sizeof(struct pseudo_header));
static int myttl = 0; static int myttl = 0;
assert(victim); assert(victim);
assert(source); 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 */ /* Time to live */
if (ttl == -1) { if (ttl == -1) {
@@ -1069,19 +1129,19 @@ if (ttl == -1) {
myttl = ttl; myttl = ttl;
} }
memset((char *) packet, 0, sizeof(struct ip) + sizeof(struct tcphdr));
pseudo->s_addy = source->s_addr; pseudo->s_addy = source->s_addr;
pseudo->d_addr = victim->s_addr; pseudo->d_addr = victim->s_addr;
pseudo->zer0 = 0;
pseudo->protocol = IPPROTO_TCP; 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_sport = htons(sport);
tcp->th_dport = htons(dport); tcp->th_dport = htons(dport);
if (seq) { if (seq) {
tcp->th_seq = htonl(seq); tcp->th_seq = htonl(seq);
} } else if (flags & TH_SYN) {
else if (flags & TH_SYN) {
get_random_bytes(&(tcp->th_seq), 4); get_random_bytes(&(tcp->th_seq), 4);
} }
@@ -1092,7 +1152,7 @@ if (ack)
if (reserved) if (reserved)
tcp->th_x2 = reserved & 0x0F; tcp->th_x2 = reserved & 0x0F;
tcp->th_off = 5 + (optlen /4) /*words*/; tcp->th_off = 5 + (tcpoptlen /4) /*words*/;
tcp->th_flags = flags; tcp->th_flags = flags;
if (window) if (window)
@@ -1103,62 +1163,50 @@ else tcp->th_win = htons(1024 * (myttl % 4 + 1)); /* Who cares */
if (urp) if (urp)
tcp->th_urp = htons(urp); tcp->th_urp = htons(urp);
/* We should probably copy the data over too */ /* And the options */
if (data && datalen) if (tcpoptlen)
memcpy(packet + sizeof(struct ip) + sizeof(struct tcphdr) + optlen, data, datalen); memcpy((u8*)tcp + sizeof(struct tcphdr), tcpopt, tcpoptlen);
/* And the options */ /* We should probably copy the data over too */
if (optlen) { if (data && datalen)
memcpy(packet + sizeof(struct ip) + sizeof(struct tcphdr), options, optlen); memcpy((u8*)tcp + sizeof(struct tcphdr) + tcpoptlen, data, datalen);
}
#if STUPID_SOLARIS_CHECKSUM_BUG #if STUPID_SOLARIS_CHECKSUM_BUG
tcp->th_sum = sizeof(struct tcphdr) + optlen + datalen; tcp->th_sum = sizeof(struct tcphdr) + tcpoptlen + datalen;
#else #else
tcp->th_sum = in_cksum((unsigned short *)pseudo, sizeof(struct tcphdr) + tcp->th_sum = in_cksum((unsigned short *)pseudo, sizeof(struct tcphdr) +
optlen + sizeof(struct pseudo_header) + datalen); tcpoptlen + sizeof(struct pseudo_header) + datalen);
#endif #endif
if ( o.badsum ) if ( o.badsum )
--tcp->th_sum; --tcp->th_sum;
/* Now for the ip header */ fill_ip_raw(ip, packetlen, ipopt, ipoptlen,
memset(packet, 0, sizeof(struct ip)); tos, ipid, df?IP_DF:0, myttl, IPPROTO_TCP,
ip->ip_v = 4; source, victim);
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
ip->ip_dst.s_addr= victim->s_addr; *outpacketlen = packetlen;
#if HAVE_IP_IP_SUM
ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip));
#endif
*packetlen = ntohs(ip->ip_len);
return packet; return packet;
} }
/* You need to call sethdrinclude(sd) on the sending sd before calling this */ /* 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, int send_tcp_raw( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl, bool df, const struct in_addr *source, const struct in_addr *victim,
u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, int ttl, bool df,
u16 window, u16 urp, u8 *options, int optlen, char *data, u8* ipops, int ipoptlen,
u16 datalen) 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; unsigned int packetlen;
int res = -1; int res = -1;
u8 *packet = build_tcp_raw(source, victim, ttl, get_random_u16(), df, sport, u8 *packet = build_tcp_raw(source, victim,
dport, seq, ack, reserved, flags, window, urp, options, optlen, ttl, get_random_u16(), IP_TOS_DEFAULT, df,
ipops, ipoptlen,
sport, dport,
seq, ack, reserved, flags, window, urp,
options, optlen,
data, datalen, &packetlen); data, datalen, &packetlen);
if (!packet) return -1; if (!packet) return -1;
res = send_ip_packet(sd, eth, packet, packetlen); 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 packetlen, which must be a valid int pointer. The id/seq will be converted
to network byte order (if it differs from HBO) */ to network byte order (if it differs from HBO) */
u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim,
int ttl, u16 ipid, u8 tos, bool df, u16 seq, int ttl, u16 ipid, u8 tos, bool df,
unsigned short id, u8 ptype, u8 pcode, char *data, u8 *ipopt, int ipoptlen,
u16 datalen, u32 *packetlen) { u16 seq, unsigned short id, u8 ptype, u8 pcode,
char *data, u16 datalen, u32 *packetlen) {
struct ppkt { struct ppkt {
u8 type; u8 type;
@@ -1373,8 +1422,12 @@ pingpkt.checksum = in_cksum((unsigned short *)ping, icmplen);
if ( o.badsum ) if ( o.badsum )
--pingpkt.checksum; --pingpkt.checksum;
return build_ip_raw(source, victim, o.ttl, IPPROTO_ICMP, get_random_u16(), tos, df, return build_ip_raw(source, victim,
ping, icmplen, packetlen); 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, int send_udp_raw_decoys( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl, const struct in_addr *victim,
u16 sport, u16 dport, u16 ipid, char *data, int ttl, u16 ipid,
u16 datalen) { u8* ipops, int ipoptlen,
u16 sport, u16 dport,
char *data, u16 datalen) {
int decoy; int decoy;
for(decoy = 0; decoy < o.numdecoys; decoy++) for(decoy = 0; decoy < o.numdecoys; decoy++)
if (send_udp_raw(sd, eth, &o.decoys[decoy], victim, ttl, sport, dport, ipid, if (send_udp_raw(sd, eth, &o.decoys[decoy], victim,
data, datalen) == -1) ttl, ipid, ipops, ipoptlen,
sport, dport, data, datalen) == -1)
return -1; return -1;
return 0; 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 finished with the packet. The packet length is returned in
packetlen, which must be a valid int pointer. */ packetlen, which must be a valid int pointer. */
u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim, u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim,
int ttl, u16 sport, u16 dport, u16 ipid, char *data, int ttl, u16 ipid, u8 tos, bool df,
u16 datalen, u32 *packetlen) 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; 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; static int myttl = 0;
struct pseudo_udp_hdr { struct pseudo_udp_hdr {
struct in_addr source; struct in_addr source;
struct in_addr dest; struct in_addr dest;
u8 zero; u8 zer0;
u8 proto; u8 proto;
u16 length; 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 */ /* check that required fields are there and not too silly */
if ( !victim) { assert(victim);
fprintf(stderr, "build_udp_raw: One or more of your parameters suck!\n"); assert(source);
free(packet); assert(ipoptlen%4==0);
return NULL;
}
/* Time to live */ /* Time to live */
if (ttl == -1) { if (ttl == -1) {
@@ -1538,19 +1594,19 @@ u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim,
myttl = ttl; myttl = ttl;
} }
memset((char *) packet, 0, sizeof(struct ip) + sizeof(udphdr_bsd));
udp->uh_sport = htons(sport); udp->uh_sport = htons(sport);
udp->uh_dport = htons(dport); 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 */ /* We should probably copy the data over too */
if (data) 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 */ /* Now the pseudo header for checksuming */
pseudo->source.s_addr = source->s_addr; pseudo->source.s_addr = source->s_addr;
pseudo->dest.s_addr = victim->s_addr; pseudo->dest.s_addr = victim->s_addr;
pseudo->zer0 = 0;
pseudo->proto = IPPROTO_UDP; pseudo->proto = IPPROTO_UDP;
pseudo->length = htons(sizeof(udphdr_bsd) + datalen); 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 ) if ( o.badsum )
--udp->uh_sum; --udp->uh_sum;
/* Goodbye, pseudo header! */ fill_ip_raw(ip, packetlen, ipopt, ipoptlen,
memset(pseudo, 0, sizeof(*pseudo)); tos, ipid, df?IP_DF:0, myttl, IPPROTO_UDP,
source, victim);
/* Now for the ip header */ *outpacketlen = packetlen;
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);
return packet; return packet;
} }
int send_udp_raw( int sd, struct eth_nfo *eth, struct in_addr *source, int send_udp_raw( int sd, struct eth_nfo *eth,
const struct in_addr *victim, struct in_addr *source, const struct in_addr *victim,
int ttl, u16 sport, u16 dport, u16 ipid, char *data, int ttl, u16 ipid,
u16 datalen) u8* ipopt, int ipoptlen,
u16 sport, u16 dport,
char *data, u16 datalen)
{ {
unsigned int packetlen; unsigned int packetlen;
int res = -1; int res = -1;
u8 *packet = build_udp_raw(source, victim, ttl, sport, dport, ipid, data, u8 *packet = build_udp_raw(source, victim,
datalen, &packetlen); ttl, ipid, IP_TOS_DEFAULT, false,
ipopt, ipoptlen,
sport, dport,
data, datalen, &packetlen);
if (!packet) return -1; if (!packet) return -1;
res = send_ip_packet(sd, eth, packet, packetlen); 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 finished with the packet. The packet length is returned in
packetlen, which must be a valid int pointer. */ packetlen, which must be a valid int pointer. */
u8 *build_ip_raw(const struct in_addr *source, const struct in_addr *victim, 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,
u32 *packetlen) int ttl, u16 ipid, u8 tos, bool df,
u8 *ipopt, int ipoptlen,
char *data, u16 datalen,
u32 *outpacketlen)
{ {
int packetlen = sizeof(struct ip) + ipoptlen + datalen;
unsigned char *packet = (unsigned char *) safe_malloc(sizeof(struct ip) + datalen); u8 *packet = (u8 *) safe_malloc(packetlen);
struct ip *ip = (struct ip *) packet; struct ip *ip = (struct ip *) packet;
static int myttl = 0; static int myttl = 0;
/* check that required fields are there and not too silly */ /* check that required fields are there and not too silly */
if ( !victim) { assert(source);
fprintf(stderr, "send_ip_raw: One or more of your parameters suck!\n"); assert(victim);
free(packet); assert(ipoptlen%4==0);
return NULL;
}
/* Time to live */ /* Time to live */
if (ttl == -1) { if (ttl == -1) {
@@ -1633,47 +1679,34 @@ if (ttl == -1) {
myttl = ttl; myttl = ttl;
} }
memset((char *) packet, 0, sizeof(struct ip)); fill_ip_raw(ip, packetlen, ipopt, ipoptlen,
tos, ipid, df?IP_DF:0, myttl, proto,
/* Now for the ip header */ source, victim);
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
/* We should probably copy the data over too */ /* We should probably copy the data over too */
if (data) 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; return packet;
} }
/* You need to call sethdrinclude(sd) on the sending sd before calling this */ /* 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, int send_ip_raw( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl, u8 proto, struct in_addr *source, const struct in_addr *victim,
u8 proto, int ttl,
u8* ipopt, int ipoptlen,
char *data, u16 datalen) char *data, u16 datalen)
{ {
unsigned int packetlen; unsigned int packetlen;
int res = -1; int res = -1;
u8 *packet = build_ip_raw(source, victim, ttl, proto, get_random_u16(), u8 *packet = build_ip_raw(source, victim,
IP_TOS_DEFAULT, false, data, datalen, &packetlen); proto,
ttl, get_random_u16(), IP_TOS_DEFAULT, false,
ipopt, ipoptlen,
data, datalen, &packetlen);
if (!packet) return -1; if (!packet) return -1;
res = send_ip_packet(sd, eth, packet, packetlen); 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 /* Build and send a raw tcp packet. If TTL is -1, a partially random
(but likely large enough) one is chosen */ (but likely large enough) one is chosen */
int send_tcp_raw( int sd, struct eth_nfo *eth, const struct in_addr *source, int send_tcp_raw( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl, bool df, const struct in_addr *source, const struct in_addr *victim,
u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, int ttl, bool df,
u16 window, u16 urp, u8 *options, int optlen, char *data, u8* ipopt, int ipoptlen,
u16 datalen); u16 sport, u16 dport,
int send_udp_raw( int sd, struct eth_nfo *eth, struct in_addr *source, u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp,
const struct in_addr *victim, int ttl, u16 sport, u8 *options, int optlen,
u16 dport, u16 ipid, char *data, u16 datalen); 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, int send_ip_raw( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl, u8 proto, struct in_addr *source, const struct in_addr *victim,
u8 proto, int ttl,
u8* ipopt, int ipoptlen,
char *data, u16 datalen); char *data, u16 datalen);
/* Builds a TCP packet (including an IP header) by packing the fields /* 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 finished with the packet. The packet length is returned in
packetlen, which must be a valid int pointer. */ packetlen, which must be a valid int pointer. */
u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim, 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, int ttl, u16 ipid, u8 tos, bool df,
u8 flags, u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen, 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); u32 *packetlen);
/* Builds a UDP packet (including an IP header) by packing the fields /* 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 finished with the packet. The packet length is returned in
packetlen, which must be a valid int pointer. */ packetlen, which must be a valid int pointer. */
u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim, u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim,
int ttl, u16 sport, u16 dport, u16 ipid, char *data, int ttl, u16 ipid, u8 tos, bool df,
u16 datalen, u32 *packetlen); 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 /* Builds an ICMP packet (including an IP header) by packing the
fields with the given information. It allocates a new buffer to 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 id/seq will be converted to network byte order (if it differs from
HBO) */ HBO) */
u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, 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, int ttl, u16 ipid, u8 tos, bool df,
u8 pcode, char *data, u16 datalen, u32 *packetlen); 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 /* Builds an IP packet (including an IP header) by packing the fields
with the given information. It allocates a new buffer to store the 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 finished with the packet. The packet length is returned in
packetlen, which must be a valid int pointer. */ packetlen, which must be a valid int pointer. */
u8 *build_ip_raw(const struct in_addr *source, const struct in_addr *victim, 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); u32 *packetlen);
/* Send a pre-built IPv4 packet */ /* 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 ... */ /* Decoy versions of the raw packet sending functions ... */
int send_tcp_raw_decoys( int sd, struct eth_nfo *eth, int send_tcp_raw_decoys( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl, bool df, const struct in_addr *victim,
u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, int ttl, bool df,
u16 window, u16 urp, u8 *options, int optlen, char *data, u8* ipopt, int ipoptlen,
u16 datalen); 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, int send_udp_raw_decoys( int sd, struct eth_nfo *eth,
const struct in_addr *victim, int ttl, const struct in_addr *victim,
u16 sport, u16 dport, u16 ipid, char *data, int ttl, u16 ipid,
u16 datalen); 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. /* 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$ */ /* $Id$ */
#include "nmap.h"
#include "utils.h" #include "utils.h"
#include "NmapOps.h" #include "NmapOps.h"
@@ -559,6 +560,360 @@ char *cstring_unescape(char *str, unsigned int *newlen) {
return str; 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 /* mmap() an entire file into the address space. Returns a pointer
to the beginning of the file. The mmap'ed length is returned to the beginning of the file. The mmap'ed length is returned
inside the length parameter. If there is a problem, NULL is 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. */ str is returned. */
char *cstring_unescape(char *str, unsigned int *len); 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 #ifndef HAVE_STRERROR
char *strerror(int errnum); char *strerror(int errnum);
#endif #endif