# # A simple NAT toy with alteration filters. # package require profiler ::profiler::init ################################### CONFIG ##################################### source "hpingstdlib.htcl" set target [hping resolve 192.168.0.3] set myip [hping outifa $target] set fakeip 192.168.10.100 set outlist {} set inlist {} if {1} { set input_modules { {mod_dup .2} {mod_loss .2} {mod_print "input: "} {mod_send 100} {mod_zap} } set output_modules { {mod_dup .0} {mod_loss .0} {mod_corrupt_data 1 .1} {mod_print "output: "} {mod_send 0} {mod_zap} } } if {0} { set output_modules { {mod_shuffle 5 500 input} {mod_send 0} {mod_zap} } set input_modules { {mod_send 0} {mod_zap} } } if {0} { set output_modules { {mod_tcp_daytona_dupack 50} {mod_send 0} {mod_zap} } set input_modules { {mod_send 0} {mod_zap} } } if {0} { set output_modules { {mod_tcp_frag 1} {mod_send 0} {mod_zap} } set input_modules { {mod_send 0} {mod_zap} } } #################################### CORE ###################################### proc donat {} { global target myip fakeip outlist inlist set packets [hping recv -hexdata eth0 0 10] foreach p $packets { DelApdField ip cksum p DelApdField tcp cksum p DelApdField tcp off p #puts "[GetIpSaddr $p] -> [GetIpDaddr $p]" if {[GetIpSaddr $p] == $myip && [GetIpDaddr $p] == $fakeip} { SetApdField ip saddr $fakeip p SetApdField ip daddr $target p lappend outlist $p puts -nonewline O; flush stdout } elseif {[GetIpSaddr $p] == $target && [GetIpDaddr $p] == $fakeip} { SetApdField ip saddr $fakeip p SetApdField ip daddr $myip p lappend inlist $p puts -nonewline I; flush stdout } } after idle donat } proc runmodules {} { global outlist inlist input_modules output_modules if {[llength $inlist]} { foreach m $input_modules { lappend m $inlist set inlist [eval $m] } } if {[llength $outlist]} { foreach m $output_modules { lappend m $outlist set outlist [eval $m] } } after idle runmodules } #################################### MODULES ################################### ### DUP ### proc mod_dup {rate packets} { foreach p $packets { lappend l $p if {rand() < $rate} { puts -nonewline D; flush stdout lappend l $p } } return $l } ### LOSS ### proc mod_loss {rate packets} { set l {} foreach p $packets { if {rand() >= $rate} { lappend l $p } else { puts -nonewline L; flush stdout } } return $l } ### SEND ### proc mod_send {maxdelay packets} { set len [llength $packets] for {set i [expr $len-1]} {$i >= 0} {incr i -1} { set p [lindex $packets $i] puts -nonewline W; flush stdout if {$maxdelay} { set ms [expr int(rand()*($maxdelay+1))] after $ms "hping send $p" } else { hping send $p } } return $packets } ### ZAP ### proc mod_zap packets { return {} } ### PRINT ### proc mod_print {tag packets} { foreach p $packets { puts "$tag $p" } return $packets } ### CORRUPT_DATA ### proc mod_corrupt_data {num rate packets} { # return $packets foreach p $packets { set mod 0 set data [GetApdField data hex $p] set len [string length $data] if {$len} { for {set i 0} {$i < $num} {incr i} { if {rand() < $rate} { set byte [format "%02x" [expr int(rand()*256)]] set x [expr $len/2] set offset [expr int(rand()*$x)] set data [string replace $data [expr $offset*2] [expr ($offset*2)+1] $byte] } } SetApdField data hex $data p } lappend l $p } return $l } ### SHUFFLE AND HELPER FUNCTIONS ### proc K { x y } { set x } proc shuffle { list } { set n [llength $list] while {$n > 0} { set j [expr {int(rand()*$n)}] lappend slist [lindex $list $j] incr n -1 set temp [lindex $list $n] set list [lreplace [K $list [set list {}]] $j $j $temp] } return $slist } proc shuffle_flush {tag packets} { global shuffle_list_$tag shuffle_startms_$tag pending_flush_$tag unset shuffle_list_$tag unset shuffle_startms_$tag set pending_flush_$tag 0 mod_send 0 $packets } proc mod_shuffle {count timeout tag packets} { global shuffle_list_$tag shuffle_startms_$tag pending_flush_$tag global pending_flush_id_$tag if {! [info exists shuffle_list_$tag]} { set shuffle_list_$tag {} set shuffle_startms_$tag [clock clicks -milliseconds] set pending_flush_$tag 0 } if {[info exists pending_flush_$tag] && [set pending_flush_$tag]} { after cancel [set pending_flush_id_$tag] set pending_flush_$tag 0 } set shuffle_list_$tag [concat [set shuffle_list_$tag] $packets] set len [llength [set shuffle_list_$tag]] if {$len >= $count} { set x [shuffle [set shuffle_list_$tag]] unset shuffle_list_$tag unset shuffle_startms_$tag return $x } elseif {$len} { set elapsed [expr [clock clicks -milliseconds] - [set shuffle_startms_$tag]] set flush_delay [expr $timeout - $elapsed] if {$flush_delay <= 0} {set flush_delay 1} set pending_flush_id_$tag [after $flush_delay [list shuffle_flush $tag [set shuffle_list_$tag]]] set pending_flush_$tag 1 return {} } return {} } ### DUP ACK ### proc mod_tcp_daytona_dupack {count packets} { foreach p $packets { if {[string match [hping getfield tcp flags $p] "a"] && [string length [hping getfield data hex $p]] == 0} { puts -nonewline .DUPACK.; flush stdout for {set i 0} {$i < $count} {incr i} { lappend l $p } } else { lappend l $p } } return $l } ### TCP FRAG ### proc mod_tcp_frag {size packets} { foreach p $packets { if {[GetIpProto $p] != 6} { lappend temp $p continue } set data [GetDataHex $p] if {[llength $data] == 0} { lappend temp $p continue } set datalen [string length $data] if {$datalen <= $size} { lappend temp $p continue } set seq [GetTcpSeq $p] set size [expr {$size*2}] set xtemp {} while {$datalen} { set l [if {$datalen >= $size} {set size} {set datalen}] set load [string range $data 0 [expr {$l-1}]] set data [string range $data $l end] incr datalen -$l set p [hping setfield tcp seq $seq $p] set p [hping setfield data hex $load $p] set p [hping delfield ip totlen $p] set p [hping delfield ip cksum $p] set p [hping delfield tcp cksum $p] set p [hping delfield tcp off $p] puts "$seq $load" lappend xtemp $p incr seq [expr {$l/2}] } set xtl [expr {[llength $xtemp]-1}] for {set j $xtl} {$j >= 0} {incr j -1} { lappend temp [lindex $xtemp $j] } } return $temp } # vim: filetype=tcl ### PROFILER HELPER ### proc prof {} { puts [::profiler::print] puts [::profiler::sortFunctions exclusiveRuntime] after 1000 prof } ################################# EVENT LOOP ################################### after 1 donat after 1 runmodules #after 1 prof vwait forever # vim: filetype=tcl