4 proc debug {level str} {
6 if {$level <= $debug_level} { puts stderr "debug\[$level] $str" }
9 proc manyset {list args} {
10 foreach val $list var $args {
17 proc start_gen {seed} {
19 random-bytes-init $seed
23 proc packet-len {p} { expr {[string length $p]/2} }
25 proc packet-csum-ip {packet} {
28 while {[regexp {^([0-9a-f]{4})(.*)$} $packet dummy this packet]} {
29 set cs [expr "\$cs + 0x$this"]
30 debug 7 [format "0x%s 0x%08x" $this $cs]
32 return [expr {(($cs & 0xffff) + (($cs >> 16) & 0xffff)) ^ 0xffff}]
35 proc packet-fromstring {s} {
40 namespace eval Random-Bytes {
41 namespace export random-bytes random-bytes-init
43 proc random-bytes-init {seed} {
45 catch { set h $fh; unset fh; close $h }
46 set fh [open |[list openssl bf-ofb < /dev/zero -e -k " $seed"] r]
47 fconfigure $fh -translation binary
49 proc random-bytes {n} {
52 if {[string length $x] != $n} {
53 set h $fh; unset fh; close $h
54 error "openssl bf-ofb exited unexpectedly"
56 set y [packet-fromstring $x]
61 namespace import Random-Bytes::*
63 proc choice-int {min max} {
64 set rv 0x[random-bytes 3]
66 int( double($rv) / double(0x1000000) * double($max+1-$min) )
71 proc choice-prob {cv def} {
72 set prob [config $cv $def]
73 set rv 0x[random-bytes 3]
74 return [expr {$rv < double($prob)*0x1000000}]
77 proc choice-mult {args} {
78 if {!([llength $args] % 2)} { error "choice-mult must have default" }
79 set h 0x[random-bytes 3]
80 set x [expr { double($h) / double(0x1000000) }]
82 set def [lindex $args end]
83 set args [lreplace $args end end]
84 foreach {val p} $args {
85 set cump [expr {$cump + double($p)}]
86 if {$x < $cump} { return $val }
92 upvar #0 getlog_log log
97 proc config {cv def} {
99 if {[info exists v]} { return $v }
104 proc define {enum val name argnames body} {
105 upvar #0 enum/val2name/$enum v2n
106 upvar #0 enum/name2val/$enum n2v
109 proc enum/val/$enum/$val $argnames $body
112 proc depending-on {scope enum_and_var mtu mtuadjust args} {
113 upvar 1 $enum_and_var val
114 set mtu [expr {$mtu + $mtuadjust}]
115 set procname enum/val/$scope-$enum_and_var/[format %d $val]
116 if {[choice-prob $enum_and_var-unstruct 0.1] ||
117 [catch { info body $procname }]} {
120 get data rand 0 $mtu 1
123 uplevel 1 [list $procname] $mtu $args
128 proc get-for {scope} {
133 proc get {variable kind args} {
134 upvar 1 get/scope scope
135 upvar 1 $variable var
136 set var [eval [list get/$kind $scope $variable] $args]
139 proc get-config/number {val min max} { return $val }
140 proc get-config/v4addr {val} {
141 if {![regexp {^(\d+)\.(\d+)\.(\d+)\.(\d+)$} $val dummy a b c d]} {
142 error "bad v4addr ?$val?"
144 return [format 0x%02x%02x%02x%02x $a $b $c $d]
147 proc get-config {variable def kind args} {
148 # args currently ignored
149 upvar 1 get/scope scope
150 upvar 1 $variable var
151 set val [config $scope-$variable $def]
152 set var [eval [list get-config/$kind $val] $args]
155 proc get-enum-got {s v rv} {
156 upvar #0 enum/val2name/$s-$v v2n
157 if {[info exists v2n($rv)]} {
158 getlog "$v=$v2n($rv)\[$rv]"
165 proc get/enum-rand {s v min max} {
166 set rv [choice-int $min $max]
167 return [get-enum-got $s $v $rv]
170 proc get/enum-def {s v} {
171 upvar #0 enum/val2name/$s-$v v2n
172 set rv [choice-int 1 [array size v2n]]
173 set rv [lindex [lsort [array names v2n]] [expr {$rv-1}]]
174 return [get-enum-got $s $v $rv]
177 proc get/enum {s v min max prand} {
179 get any choice $prand
181 return [get/enum-rand $s $v $min $max]
183 return [get/enum-def $s $v]
187 proc get/number {s v min max} {
188 set rv [choice-int $min $max]
193 proc get/hex {s v min max} {
194 set rv [choice-int $min $max]
195 getlog [format %s=0x%x $v $rv]
199 proc get/hex32 {s v} {
200 set rv [random-bytes 4]
205 proc get/flag {s v defprob} {
206 set rv [choice-prob $s-$v $defprob]
207 if {$rv} { getlog "$v" } else { getlog "!$v" }
211 proc get/choice {s v defprob} {
212 set rv [choice-prob $s-$v $defprob]
213 if {$rv} { getlog "($v)" } else { getlog "(!$v)" }
217 proc get/rand {s v minlen maxlen blockbytes} {
219 if {$maxlen<0} { getlog (full!); return {} }
220 get l number [expr {$minlen/$blockbytes}] [expr {$maxlen/$blockbytes}]
221 return [random-bytes [expr {$l*$blockbytes}]]
224 proc get/ip-timestamp {s v} {
225 set rv [expr {[clock seconds] | 0x80000000}]
226 getlog "$v=[format %x $rv]"
230 proc get/v4addr {s v} {
234 for {set i 0} {$i<4} {incr i} {
235 set b [random-bytes 1]
237 append p $d [format %d 0x$b]
244 proc get/choice-mult {s v args} {
245 set rv [eval choice-mult $args]
250 proc get/string {s v minlen maxlen first rest} {
253 for {set l [choice-int $minlen $maxlen]} {$l>0} {incr l -1} {
254 set cn [choice-int 0 [expr {[string length $now]-1}]]
255 append o [string index $now $cn]
259 return [packet-fromstring $o]
262 proc get/ntstring {s v minlen maxlen first rest} {
263 set s [get/string $s $v $minlen $maxlen $first $rest]
265 append s [random-bytes $maxlen]
266 return [string range $s 0 [expr {$maxlen*2-1}]]
269 namespace eval Assembler {
270 namespace export assemble assembly-overwrite
272 proc assemble {outvarname format} {
273 # format should look like those RFC diagrams. +-+-+ stuff and
274 # good formatting is mandatory. You can have a single data
275 # item at the end ending in ..., which means append that data
278 # Field names are converted to lowercase; internal spaces
279 # are replaced with _. They are then assumed to be
280 # variable names in the caller's scope. The packet is
281 # assembled from those values (which must all be set)
282 # and stored in $varname in the caller's scope.
284 # Variables ?_whatever will be *set* with the location of the
285 # field in the string (in internal format); the corresponding
286 # `whatever' (with the ?_ stripped) will be read when assembling.
288 # Field names starting with digits are literal values instead.
291 upvar 1 $outvarname out
292 if {[catch { set parsed $cache($format) }]} {
293 set parsed [parse $format]
294 set cache($format) $parsed
297 manyset $parsed outbytes lout
298 set out [string repeat 00 $outbytes]
299 foreach {?_location varname locvarname} $lout {
300 if {[regexp {^[0-9]} $varname]} {
303 set value [uplevel 1 [list set $varname]]
305 if {[string length $locvarname]} {
306 upvar 1 $locvarname lv
310 assembly-overwrite out location $value
312 global errorInfo errorCode
314 "$errorInfo\n setting\n$varname at ${?_location}" \
320 proc parse {format} {
324 debug 7 "ASSEMBLY $format"
325 set format [exec expand << $format]
326 foreach l [split $format "\n"] {
328 if {[regexp -nocase {^ *\| +\| *$} $l]} {
329 if {![info exists wordbits]} {
330 error "vspace not in data @$lno\n?$l?"
333 } elseif {[regexp -nocase {^ *[|? a-z0-9.]+$} $l]} {
334 if {[info exists words]} {
335 error "data without delimline @$lno\n?$l?"
339 } elseif {[regexp {^ *[-+]+ *$} $l]} {
342 while {[regexp {^([-= ]+)\+(.*)$} $l dummy before after]} {
343 set atpos([string length $before]) $wordbits
345 set l "$before=$after"
346 append newlineform "@[string length $before]:$wordbits "
349 append newlineform $wordbits
350 if {[info exists lineform]} {
351 if {"$newlineform" != "$lineform"} {
352 error "format change @$lno\n?$l?\n$wordformat != $oldwordformat"
354 if {![info exists words] || $words<0} {
355 error "consecutive delimlines @$lno\n?$l?"
357 incr outbytes [expr {$words*$wordbits/8}]
359 while {[regexp -nocase \
360 {^([ =]*)\|( *[? a-z0-9]*[a-z0-9] *\.* *)\|(.*)$} \
361 $l dummy before midpart after]} {
362 debug 7 "RWORKG ?$l?"
364 error "two things at end @$lno\n?$l?"
366 set varname [string tolower [string trim $midpart]]
367 if {[regexp {(.*[a-z0-9])\s*\.\.\.$} $varname \
368 dummy realvarname]} {
369 set varname $realvarname
372 set varname [string map {{ } _} $varname]
373 set p1 [string length $before]
375 [string length $before] +
376 [string length $midpart] + 1
378 if {![info exists atpos($p1)] ||
379 ![info exists atpos($p2)]} {
380 error "vdelims not found @$lno $varname $p1 $p2 -- $lineform ?$cue?"
388 $atpos($p2) - $atpos($p1) + ($words-1)*$wordbits
392 error "atend not at byte @$lno\n?$l?"
394 set outbytes [expr {$bit1/8}]
395 set location [list $bit1 0 $varname]
397 set location [list $bit1 $bitlen $varname]
399 if {[regexp {^\?_(.*)} $varname dummy realvarname]} {
400 debug 7 "LOCATING $varname $location"
401 set locvarname $varname
402 set varname $realvarname
406 lappend lout $location $varname $locvarname
408 append l [string repeat = [string length $midpart]]
411 debug 7 "REMAIN ?$l?"
412 if {![regexp {^[ =]*\|? *$} $l]} {
413 error "unclear @$lno\n?$l?"
416 if {$wordbits % 8 || $wordbits >32} {
417 error "bad wordbits $wordbits @$lno ?$l? $newlineform"
419 set lineform $newlineform
421 catch { unset words }
422 } elseif {[regexp {^ *$} $l]} {
424 error "huh? @$lno ?$l?"
427 debug 7 "ASSEMBLY\n$outbytes\n$lout\n"
428 return [list $outbytes $lout]
431 proc assembly-overwrite {outvarname locvarnameex value} {
432 upvar 1 $outvarname out
433 upvar 1 ?_$locvarnameex location
434 manyset $location bit1 bitlen diag
435 if {$bitlen > 0 && $bitlen != 32 && $value >= (1<<$bitlen)} {
436 error "$diag $value >= 2**$bitlen"
438 if {!($bit1 % 8) && !($bitlen % 8)} {
439 set char0no [expr {$bit1/4}]
440 set charlen [expr {$bitlen/4}]
441 set chareno [expr {$char0no + $charlen -1}]
443 debug 8 "ASSEMBLY $diag == $value == 0x[format %x $value] (@$bit1+$bitlen)"
444 set repl [format %0${charlen}x $value]
445 set out [string replace $out $char0no $chareno $repl]
447 debug 8 "ASSEMBLY-ADD $diag (@$bit1)"
448 # bitlen==0 => append
449 set out [string range $out 0 $chareno]
453 while {$bitlen > 0} {
454 set byteno [expr {$bit1 / 8}]
455 set char0no [expr {$byteno*2}]
456 set char1no [expr {$char0no+1}]
457 set bytebit [expr {128>>($bit1 % 8)}]
458 set byte 0x[string range $out $char0no $char1no]
459 debug 7 "< $bit1+$bitlen $byteno $char0no $bytebit $byte $out"
461 ($value & (1<<($bitlen-1)))
463 : ($byte & ~$bytebit)
465 set out [string replace $out $char0no $char1no \
467 debug 8 "> $bit1+$bitlen $byteno $char0no $bytebit 0x[format %02x $byte] $out"
474 namespace import Assembler::*
476 proc gen_1_ip {mtu source_spec dest_spec} {
478 upvar #0 ip_proto proto
479 upvar #0 ip_source source
480 upvar #0 ip_dest dest
482 set source $source_spec
487 get tos hex 0x00 0xff
488 get id number 0x0000 0xffff
490 if {$df || ![choice-prob ip-midfrag 0.05]} {
495 get frag number 0 0x1fff
497 get-config ttl 255 number 0 255
498 get proto enum 1 255 0.05
499 set flags [expr {$df*2 + $mf}]
501 set header_checksum 0
505 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
506 |Version| ? IHL |TOS | ? Total Length |
507 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
509 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510 | TTL | Proto | ? Header Checksum |
511 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
513 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
515 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
517 # we don't do any IP options
519 set ihl [packet-len $ip]
520 if {$ihl % 4} { error "ihl not mult of 4 bytes" }
521 assembly-overwrite ip ihl [expr {$ihl / 4}]
523 set body [depending-on ip proto $mtu -$ihl]
524 set total_length [expr {[packet-len $ip] + [packet-len $body]}]
526 assembly-overwrite ip total_length $total_length
527 assembly-overwrite ip header_checksum [packet-csum-ip $ip]
533 define ip-proto 1 icmp {mtu} {
536 get type enum 0 255 0.2
537 manyset [depending-on icmp type $mtu -4] body code
538 if {![string length $code]} { get code number 0 255 }
541 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542 | Type | Code | ? Checksum |
543 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
545 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
547 assembly-overwrite icmp checksum [packet-csum-ip $icmp]
551 proc define-icmp-type-vanilla {num name} {
552 define icmp-type $num $name {mbl} "icmp-vanilla \$mbl [list $name]"
554 proc icmp-vanilla {mbl typename} {
555 get-for icmp-$typename
556 get code enum 0 255 0.4
557 get body rand 0 $mbl 1
558 return [list $body $code]
561 define-icmp-type-vanilla 3 unreach
562 define icmp-unreach-code 0 net {} {}
563 define icmp-unreach-code 1 host {} {}
564 define icmp-unreach-code 2 proto {} {}
565 define icmp-unreach-code 3 port {} {}
566 define icmp-unreach-code 4 fragneeded {} {}
567 define icmp-unreach-code 5 sourceroutefail {} {}
569 define-icmp-type-vanilla 11 timeout
570 define icmp-timeout-code 0 intransit {} {}
571 define icmp-timeout-code 1 fragment {} {}
573 define-icmp-type-vanilla 12 parameters
574 define icmp-parameters-code 0 seepointer {} {}
576 define-icmp-type-vanilla 4 sourcequench
577 define icmp-sourcequench-code 0 quench {} {}
579 define icmp-type 5 redirect {mbl} {
580 get-for icmp-redirect
581 get code enum 0 255 0.4
583 get data rand 0 [expr {$mbl-4}] 1
585 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
587 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
589 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591 return [list $body $code]
594 define icmp-redirect-code 0 net {} {}
595 define icmp-redirect-code 1 host {} {}
596 define icmp-redirect-code 2 net+tos {} {}
597 define icmp-redirect-code 3 host+tos {} {}
599 define icmp-type 8 ping {mbl} { icmp-echo $mbl }
600 define icmp-type 0 pong {mbl} { icmp-echo $mbl }
601 proc icmp-echo {mbl} {
603 get code enum 0 255 0.4
606 get data rand 0 [expr {$mbl-8}] 1
608 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
610 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
612 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
614 return [list $body $code]
616 define icmp-echo-code 0 echo {} {}
618 define icmp-type 13 timestamp {mbl} { icmp-timestamp }
619 define icmp-type 14 timestampreply {mbl} { icmp-timestamp }
620 proc icmp-timestamp {} {
621 get-for icmp-timestamp
622 get code enum 0 255 0.4
625 get originate ip-timestamp
626 get receive ip-timestamp
627 get transmit ip-timestamp
629 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
631 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
633 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
635 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
637 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
639 return [list $body $code]
641 define icmp-timestamp-code 0 timestamp {} {}
643 define icmp-type 15 inforequest {mbl} { icmp-inforeq }
644 define icmp-type 16 inforeply {mbl} { icmp-inforeq }
645 proc icmp-inforeq {} {
647 get code enum 0 255 0.4
651 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
653 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
655 return [list $body $code]
657 define icmp-inforeq-code 0 timestamp {} {}
659 # MAYADD ICMP traceroute RFC1393
660 # MAYADD ICMP router discovery RFC1256
662 proc port-pair {scope} {
665 get style choice-mult \
671 if {"$style" != "random"} {
677 if {"$style" != "servers"} {
678 get port enum-rand 0 0xffff
681 switch -exact $style {
682 random { set source_port $rand_port; set dest_port $rand_port }
683 request { set source_port $rand_port; set dest_port $def_port }
684 reply { set source_port $def_port; set dest_port $rand_port }
685 servers { set source_port $def_port; set dest_port $def_port }
687 return [list $source_port $dest_port $def_port $style]
691 define ip-proto 4 ip {mtu} {
696 gen_1_ip $mtu $source $dest
700 define ip-proto 2 igmp {mtu} {
702 get type enum 0 255 0.5
703 get timeout number 0 255
708 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
709 | Type | Timeout | ? Checksum |
710 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
712 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
714 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
717 if {[choice-prob igmp-extra 0.3]} {
718 get extra rand 1 [expr {$mtu - [packet-len $igmp]}] 1
719 assembly-overwrite igmp extra $extra
722 assembly-overwrite igmp checksum [packet-csum-ip $igmp]
726 define igmp-type 17 membquery {} {}
727 define igmp-type 16 membreport {} {}
728 define igmp-type 23 leavegroup {} {}
729 define igmp-type 18 membreport {} {}
732 define ip-proto 51 ah {mtu} {
735 get next number 0 255
736 get reserved hex 0 0xffff
738 get auth_data rand 0 [expr {$mtu-8}] 4
739 set length [packet-len $auth_data]
741 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
742 | Next | Length | RESERVED |
743 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
745 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
747 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
749 get payload rand 0 [expr {$mtu - [packet-len $ah]}] 1
755 define ip-proto 17 udp {mtu} {
759 set csum_mode [choice-mult \
763 manyset [port-pair udp] source_port dest_port def_port style
765 if {"$style" != "random"} {
767 set data [depending-on udp port $mtu -8 $style]
769 get data rand 0 [expr {$mtu-8}] 1
775 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
776 | Source Port | Dest Port |
777 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
778 | ? Length | ? Checksum |
779 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
781 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
783 set udp_length [packet-len $udp]
784 assembly-overwrite udp length $udp_length
786 if {"$csum_mode" == "checksum_none"} {
790 global ip_source ip_dest ip_proto
792 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
794 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
796 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
797 | 0 | IP Proto | UDP length |
798 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
800 set checksum [packet-csum-ip "$pseudo$udp"]
801 if {!$checksum} { set checksum 0xffff }
802 if {"$csum_mode" == "checksum_bad"} {
803 get csumerror hex 1 0xffff
804 set checksum [expr {$checksum ^ $csumerror}]
807 assembly-overwrite udp checksum $checksum
811 define udp-port 50 remailck {mtu style} {
814 if {"$style" == "request"} {
815 get what choice-mult \
822 get what choice-mult \
829 switch -exact $what {
832 get user string 1 8 \
833 abcdefghijklmnopqrustuvwxyz \
834 abcdefghijklmnopqrustuvwxyz-0123456789_
838 get user rand 0 [expr {$mtu - 4}] 1
841 get auth enum 0 31 0.5
842 set user [depending-on remailck auth $mtu -4]
845 get auth hex 0 0xffff
850 get mail choice-mult \
856 switch -exact $mail {
870 get modified number 1 600
871 get read number 1 600
873 default { error "mail? $mail" }
876 default { error "what? $what" }
881 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
883 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
885 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
890 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
892 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
894 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
896 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
899 default { error "what?? $what" }
904 define remailck-auth 31 passwd {mtu} {
905 get-for remailck-passwd
906 get passwd string 6 8 \
907 0123456789abcdefghijklmnopqrstuvxwyz \
908 0123456789abcdefghijklmnopqrstuvxwyz
912 define udp-port 67 dhcpserv {mtu style} { return [dhcp $mtu] }
913 define udp-port 68 dhcpclient {mtu style} { return [dhcp $mtu] }
916 get op enum 0 255 0.2
917 get htype enum 0 255 0.2
919 get hops number 0 255
921 get secs number 0 300
927 set chaddr [random-bytes 16]
928 get sname ntstring 0 64 \
929 0123456789abcdefghijklmnopqrstuvwxyz \
930 0123456789abcdefghijklmnopqrstuvwxyz.-+
931 get file ntstring 0 128 / \
932 0123456789abcdefghijklmnopqrstuvwxyz.-+/_
935 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
936 | op | htype | hlen | hops |
937 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
941 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
943 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
945 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
947 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
949 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
951 append dhcp $chaddr $sname $file
955 define dhcp-op 1 request {} {}
956 define dhcp-op 2 reply {} {}
957 define dhcp-htype 1 ethernet {} {}
960 define ip-proto 6 tcp {mtu} {
964 get source_port number 0 65535
965 get dest_port number 0 65535
966 get event choice-mult \
977 switch -exact $event {
978 connect { set s 1; set a 0 }
981 reset { set a 0; set r 1 }
989 default { error "event? $event" }
993 if {[choice-prob tcp-smallwindow 0.7]} {
994 get window number 0 1
996 get window hex 0 0xffff
1000 get urg hex 0 0xffff
1003 get optmode choice-mult badopt 0.3 opt 0.6 noopt
1004 switch -exact $optmode {
1007 get options rand 1 60 1
1010 while {[choice-prob tcp-opts-more 0.4]} {
1011 get opt enum 1 255 0.5
1019 set data [depending-on tcp opt 6 0]
1022 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1023 | Opt | ? Option Len |
1024 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1026 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1028 assembly-overwrite option option_len [packet-len $option]
1030 append options $option
1035 if {[choice-prob reserved-nonzero 0.25]} {
1036 get reserved hex 0 0x3f
1041 if {[packet-len $options] % 4 || [get optxpad choice 0.15]} {
1042 if {"$optmode" != "badopt"} { append options 00 }
1043 set padlen [expr {3 - ([packet-len $options] + 3) % 4}]
1044 append options [random-bytes $padlen]
1050 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1051 | Source Port | Dest Port |
1052 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1054 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1056 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1057 |? D Off| Reserved |U|A|P|R|S|F| Window |
1058 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1059 | ? Checksum | Urg |
1060 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1062 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1065 set d_off [expr {([packet-len $packet]/4) & 0x0f}]
1066 assembly-overwrite packet d_off $d_off
1068 if {!($s || $r) || [get unexpdata flag 0.2]} {
1069 get data rand 0 [expr {$mtu - [packet-len $packet]}] 1
1072 set tcp_length [packet-len $packet]
1074 global ip_source ip_dest ip_proto
1076 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1078 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1080 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1081 | 0 | IP Proto | TCP length |
1082 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1085 set csum [packet-csum-ip "$pseudo$packet"]
1086 if {[choice-prob tcp-badcsum 0.1]} {
1087 get csumerror hex 1 0xffff
1088 set csum [expr {$csum ^ $csumerror}]
1090 assembly-overwrite packet checksum $csum
1094 define tcp-opt 2 mss {mdl} {
1096 get mss hex 0 0xffff
1098 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1100 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1106 namespace eval PCap {
1107 namespace export pcap_open pcap_write pcap_write_raw pcap_close
1109 proc pcap_open {fn} {
1113 fconfigure $fh -translation binary
1116 proc pcap_close {} {
1118 if {![info exists fh]} return
1123 proc pcap_write_raw {packet} {
1125 if {![info exists fh]} return
1126 puts -nonewline $fh [binary format H* $packet]
1129 proc pcap_write {valdeflist} {
1130 foreach {kind valvar} $valdeflist {
1131 if {![regexp {^([usx])([0-9]+)} $kind dummy mode bits]} {
1132 error "unknown kind $kind for $valvar"
1134 set value [uplevel 1 [list set $valvar]]
1135 if {$bits % 8} { error "bits must be mult 8 in $kind for $valvar" }
1136 if {"$mode" != "x"} {
1139 for {set i 0} {$i<$bits/8} {incr i} {
1140 append v [format %02x [expr {$value & 0xff}]]
1141 set value [expr {$value >> 8}]
1143 if {$value != 0 && $value != -1} {
1144 error "value $ov more than $bits bits (residue=$value)"
1148 if {[string length $value] != $bits/4} {
1149 error "$valvar value $value wrong length, not $bits bits"
1151 pcap_write_raw $value
1155 namespace import PCap::*
1158 global getlog_log errorInfo mtu
1161 get-config source 127.0.0.1 v4addr
1162 get-config dest 127.0.0.1 v4addr
1166 set packet [gen_1_ip $mtu $source $dest]
1167 puts stdout "[format %6s $seed] $getlog_log\n $packet"
1169 puts stderr "\nERROR\n$seed\n\n$emsg\n\n$errorInfo\n\n"
1170 puts stdout "[format %6s $seed] error"
1172 set ts_sec [clock seconds]
1175 set llpkt [random-bytes 12] ;# ether addrs
1176 append llpkt 0800 ;# eth ip type
1177 append llpkt $packet
1179 set len [packet-len "$llpkt"]
1186 pcap_write_raw $llpkt
1193 if {![llength $argv]} { error "need another arg" }
1194 set a [lindex $argv 0]
1195 set argv [lrange $argv 1 end]
1199 proc nextarg_num {} { return [expr {[nextarg] + 0}] }
1205 while {[regexp {^\-\-} [lindex $argv 0]]} {
1207 switch -exact -- $o {
1208 --infinite { set upto -1 }
1209 --debug { set debug_level [nextarg_num] }
1210 --upto { set upto [nextarg_num] }
1211 --write { pcap_open [nextarg] }
1212 --mtu { set mtu [nextarg_num] }
1213 --xseed { set xseed [nextarg] }
1214 --source { set config/ip-source [nextarg] }
1215 --dest { set config/ip-dest [nextarg] }
1216 default { error "bad option $o" }
1238 if {[llength $argv]} {
1239 foreach count $argv { emit "$xseed$count" }
1241 if {![string length $upto]} { set upto 100 }
1242 for {set count 1} {$upto<0 || $count<=$upto} {incr count} {