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 {use_gen_counter} {
18 global gen_counter rand_counter getlog_log rand_buf
19 random-bytes-init $use_gen_counter
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} {
46 catch { set h $fh; unset fh; close $h }
48 set fh [open |[list openssl bf-ofb < /dev/zero -e -k " $seed"] r]
49 fconfigure $fh -translation binary
51 proc random-bytes {n} {
54 if {[string length $x] != $n} {
55 set h $fh; unset fh; close $h
56 error "openssl bf-ofb exited unexpectedly"
58 set y [packet-fromstring $x]
63 namespace import Random-Bytes::*
65 proc choice-int {min max} {
66 set rv 0x[random-bytes 3]
68 int( double($rv) / double(0x1000000) * double($max+1-$min) )
73 proc choice-prob {cv def} {
74 set prob [config $cv $def]
75 set rv 0x[random-bytes 3]
76 return [expr {$rv < double($prob)*0x1000000}]
79 proc choice-mult {args} {
80 if {!([llength $args] % 2)} { error "choice-mult must have default" }
81 set x 0x[random-bytes 3]
82 set x [expr { double($x) / double(0x1000000) }]
84 set def [lindex $args end]
85 set args [lreplace $args end end]
86 foreach {val p} $args {
87 set cump [expr {$cump + double($p)}]
88 if {$x < $cump} { return $val }
94 upvar #0 getlog_log log
99 proc config {cv def} {
100 upvar #0 config/$cv v
101 if {[info exists v]} { return $v }
106 proc define {enum val name argnames body} {
107 upvar #0 enum/val2name/$enum v2n
108 upvar #0 enum/name2val/$enum n2v
111 proc enum/val/$enum/$val $argnames $body
114 proc depending-on {scope enum_and_var mtu mtuadjust args} {
115 upvar 1 $enum_and_var val
116 set mtu [expr {$mtu + $mtuadjust}]
117 set procname enum/val/$scope-$enum_and_var/[format %d $val]
118 if {[choice-prob $enum_and_var-unstruct 0.1] ||
119 [catch { info body $procname }]} {
125 uplevel 1 [list $procname] $mtu $args
130 proc get-for {scope} {
135 proc get {variable kind args} {
136 upvar 1 get/scope scope
137 upvar 1 $variable var
138 set var [eval [list get/$kind $scope $variable] $args]
141 proc get-config/number {val min max} { return $val }
142 proc get-config/v4addr {val} {
143 if {![regexp {^(\d+)\.(\d+)\.(\d+)\.(\d+)$} $val dummy a b c d]} {
144 error "bad v4addr ?$val?"
146 return [format 0x%02x%02x%02x%02x $a $b $c $d]
149 proc get-config {variable def kind args} {
150 # args currently ignored
151 upvar 1 get/scope scope
152 upvar 1 $variable var
153 set val [config $scope-$variable $def]
154 set var [eval [list get-config/$kind $val] $args]
157 proc get-enum-got {s v rv} {
158 upvar #0 enum/val2name/$s-$v v2n
159 if {[info exists v2n($rv)]} {
160 getlog "$v=$v2n($rv)\[$rv]"
167 proc get/enum-rand {s v min max} {
168 set rv [choice-int $min $max]
169 return [get-enum-got $s $v $rv]
172 proc get/enum-def {s v} {
173 upvar #0 enum/val2name/$s-$v v2n
174 set rv [choice-int 1 [array size v2n]]
175 set rv [lindex [array names v2n] [expr {$rv-1}]]
176 return [get-enum-got $s $v $rv]
179 proc get/enum {s v min max prand} {
181 get any choice $prand
183 return [get/enum-rand $s $v $min $max]
185 return [get/enum-def $s $v]
189 proc get/number {s v min max} {
190 set rv [choice-int $min $max]
195 proc get/hex {s v min max} {
196 set rv [choice-int $min $max]
197 getlog [format %s=0x%x $v $rv]
201 proc get/hex32 {s v} {
202 set rv [random-bytes 4]
207 proc get/flag {s v defprob} {
208 set rv [choice-prob $s-$v $defprob]
209 if {$rv} { getlog "$v" } else { getlog "!$v" }
213 proc get/choice {s v defprob} {
214 set rv [choice-prob $s-$v $defprob]
215 if {$rv} { getlog "($v)" } else { getlog "(!$v)" }
219 proc get/rand {s v minlen maxlen} {
221 if {$maxlen<0} { getlog (full!); return {} }
222 get l number $minlen $maxlen
223 return [random-bytes $l]
226 proc get/ip-timestamp {s v} {
227 set rv [expr {[clock seconds] | 0x80000000}]
228 getlog "$v=[format %x $rv]"
232 proc get/v4addr {s v} {
236 for {set i 0} {$i<4} {incr i} {
237 set b [random-bytes 1]
239 append p $d [format %d 0x$b]
246 proc get/choice-mult {s v args} {
247 set rv [eval choice-mult $args]
252 proc get/string {s v minlen maxlen first rest} {
255 for {set l [choice-int $minlen $maxlen]} {$l>0} {incr l -1} {
256 set cn [choice-int 0 [expr {[string length $now]-1}]]
257 append o [string index $now $cn]
261 return [packet-fromstring $o]
265 namespace eval Assembler {
266 namespace export assemble assembly-overwrite
268 proc assemble {outvarname format} {
269 # format should look like those RFC diagrams. +-+-+ stuff and
270 # good formatting is mandatory. You can have a single data
271 # item at the end ending in ..., which means append that data
274 # Field names are converted to lowercase; internal spaces
275 # are replaced with _. They are then assumed to be
276 # variable names in the caller's scope. The packet is
277 # assembled from those values (which must all be set)
278 # and stored in $varname in the caller's scope.
280 # Variables ?_whatever will be *set* with the location of the
281 # field in the string (in internal format); the corresponding
282 # `whatever' (with the ?_ stripped) will be read when assembling.
284 # Field names starting with digits are literal values instead.
287 upvar 1 $outvarname out
288 if {[catch { set parsed $cache($format) }]} {
289 set parsed [parse $format]
290 set cache($format) $parsed
293 manyset $parsed outbytes lout
294 set out [string repeat 00 $outbytes]
295 foreach {?_location varname locvarname} $lout {
296 if {[regexp {^[0-9]} $varname]} {
299 set value [uplevel 1 [list set $varname]]
301 if {[string length $locvarname]} {
302 upvar 1 $locvarname lv
306 assembly-overwrite out location $value
308 global errorInfo errorCode
310 "$errorInfo\n setting\n$varname at ${?_location}" \
316 proc parse {format} {
320 debug 7 "ASSEMBLY $format"
321 set format [exec expand << $format]
322 foreach l [split $format "\n"] {
324 if {[regexp -nocase {^ *\| +\| *$} $l]} {
325 if {![info exists wordbits]} {
326 error "vspace not in data @$lno\n?$l?"
329 } elseif {[regexp -nocase {^ *[|? a-z0-9.]+$} $l]} {
330 if {[info exists words]} {
331 error "data without delimline @$lno\n?$l?"
335 } elseif {[regexp {^ *[-+]+ *$} $l]} {
338 while {[regexp {^([-= ]+)\+(.*)$} $l dummy before after]} {
339 set atpos([string length $before]) $wordbits
341 set l "$before=$after"
342 append newlineform "@[string length $before]:$wordbits "
345 append newlineform $wordbits
346 if {[info exists lineform]} {
347 if {"$newlineform" != "$lineform"} {
348 error "format change @$lno\n?$l?\n$wordformat != $oldwordformat"
350 if {![info exists words] || $words<0} {
351 error "consecutive delimlines @$lno\n?$l?"
353 incr outbytes [expr {$words*$wordbits/8}]
355 while {[regexp -nocase \
356 {^([ =]*)\|( *[? a-z0-9]*[a-z0-9] *\.* *)\|(.*)$} \
357 $l dummy before midpart after]} {
358 debug 7 "RWORKG ?$l?"
360 error "two things at end @$lno\n?$l?"
362 set varname [string tolower [string trim $midpart]]
363 if {[regexp {(.*[a-z0-9])\s*\.\.\.$} $varname \
364 dummy realvarname]} {
365 set varname $realvarname
368 set varname [string map {{ } _} $varname]
369 set p1 [string length $before]
371 [string length $before] +
372 [string length $midpart] + 1
374 if {![info exists atpos($p1)] ||
375 ![info exists atpos($p2)]} {
376 error "vdelims not found @$lno $varname $p1 $p2 -- $lineform ?$cue?"
384 $atpos($p2) - $atpos($p1) + ($words-1)*$wordbits
388 error "atend not at byte @$lno\n?$l?"
390 set outbytes [expr {$bit1/8}]
391 set location [list $bit1 0 $varname]
393 set location [list $bit1 $bitlen $varname]
395 if {[regexp {^\?_(.*)} $varname dummy realvarname]} {
396 debug 7 "LOCATING $varname $location"
397 set locvarname $varname
398 set varname $realvarname
402 lappend lout $location $varname $locvarname
404 append l [string repeat = [string length $midpart]]
407 debug 7 "REMAIN ?$l?"
408 if {![regexp {^[ =]*\|? *$} $l]} {
409 error "unclear @$lno\n?$l?"
412 if {$wordbits % 8 || $wordbits >32} {
413 error "bad wordbits $wordbits @$lno ?$l? $newlineform"
415 set lineform $newlineform
417 catch { unset words }
418 } elseif {[regexp {^ *$} $l]} {
420 error "huh? @$lno ?$l?"
423 debug 7 "ASSEMBLY\n$outbytes\n$lout\n"
424 return [list $outbytes $lout]
427 proc assembly-overwrite {outvarname locvarnameex value} {
428 upvar 1 $outvarname out
429 upvar 1 ?_$locvarnameex location
430 manyset $location bit1 bitlen diag
431 if {$bitlen > 0 && $bitlen != 32 && $value >= (1<<$bitlen)} {
432 error "$diag $value >= 2**$bitlen"
434 if {!($bit1 % 8) && !($bitlen % 8)} {
435 set char0no [expr {$bit1/4}]
436 set charlen [expr {$bitlen/4}]
437 set chareno [expr {$char0no + $charlen -1}]
439 debug 8 "ASSEMBLY $diag == $value == 0x[format %x $value] (@$bit1+$bitlen)"
440 set repl [format %0${charlen}x $value]
441 set out [string replace $out $char0no $chareno $repl]
443 debug 8 "ASSEMBLY-ADD $diag (@$bit1)"
444 # bitlen==0 => append
445 set out [string range $out 0 $chareno]
449 while {$bitlen > 0} {
450 set byteno [expr {$bit1 / 8}]
451 set char0no [expr {$byteno*2}]
452 set char1no [expr {$char0no+1}]
453 set bytebit [expr {128>>($bit1 % 8)}]
454 set byte 0x[string range $out $char0no $char1no]
455 debug 7 "< $bit1+$bitlen $byteno $char0no $bytebit $byte $out"
457 ($value & (1<<($bitlen-1)))
459 : ($byte & ~$bytebit)
461 set out [string replace $out $char0no $char1no \
463 debug 8 "> $bit1+$bitlen $byteno $char0no $bytebit 0x[format %02x $byte] $out"
470 namespace import Assembler::*
472 proc gen_1_ip {mtu} {
474 upvar #0 ip_proto proto
475 upvar #0 ip_source source
476 upvar #0 ip_dest dest
479 get tos hex 0x00 0xff
480 get id number 0x0000 0xffff
482 if {$df || ![choice-prob ip-midfrag 0.05]} {
487 get frag number 0 0x1fff
489 get-config ttl 255 number 0 255
490 get proto enum 1 255 0.05
491 get-config source 127.0.0.1 v4addr
492 get-config dest 127.0.0.1 v4addr
493 set flags [expr {$df*2 + $mf}]
495 set header_checksum 0
499 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
500 |Version| ? IHL |TOS | ? Total Length |
501 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
503 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
504 | TTL | Proto | ? Header Checksum |
505 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
507 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
509 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
511 # we don't do any IP options
513 set ihl [packet-len $ip]
514 if {$ihl % 4} { error "ihl not mult of 4 bytes" }
515 assembly-overwrite ip ihl [expr {$ihl / 4}]
517 set body [depending-on ip proto $mtu -$ihl]
518 set total_length [expr {[packet-len $ip] + [packet-len $body]}]
520 assembly-overwrite ip total_length $total_length
521 assembly-overwrite ip header_checksum [packet-csum-ip $ip]
527 define ip-proto 1 icmp {mtu} {
530 get type enum 0 255 0.2
531 manyset [depending-on icmp type $mtu -4] body code
532 if {![string length $code]} { get code number 0 255 }
535 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
536 | Type | Code | ? Checksum |
537 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541 assembly-overwrite icmp checksum [packet-csum-ip $icmp]
545 proc define-icmp-type-vanilla {num name} {
546 define icmp-type $num $name {mbl} "icmp-vanilla \$mbl [list $name]"
548 proc icmp-vanilla {mbl typename} {
549 get-for icmp-$typename
550 get code enum 0 255 0.4
552 return [list $body $code]
555 define-icmp-type-vanilla 3 unreach
556 define icmp-unreach-code 0 net {} {}
557 define icmp-unreach-code 1 host {} {}
558 define icmp-unreach-code 2 proto {} {}
559 define icmp-unreach-code 3 port {} {}
560 define icmp-unreach-code 4 fragneeded {} {}
561 define icmp-unreach-code 5 sourceroutefail {} {}
563 define-icmp-type-vanilla 11 timeout
564 define icmp-timeout-code 0 intransit {} {}
565 define icmp-timeout-code 1 fragment {} {}
567 define-icmp-type-vanilla 12 parameters
568 define icmp-parameters-code 0 seepointer {} {}
570 define-icmp-type-vanilla 4 sourcequench
571 define icmp-sourcequench-code 0 quench {} {}
573 define icmp-type 5 redirect {mbl} {
574 get-for icmp-redirect
575 get code enum 0 255 0.4
577 get data rand 0 [expr {$mbl-4}]
579 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
581 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
583 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585 return [list $body $code]
588 define icmp-redirect-code 0 net {} {}
589 define icmp-redirect-code 1 host {} {}
590 define icmp-redirect-code 2 net+tos {} {}
591 define icmp-redirect-code 3 host+tos {} {}
593 define icmp-type 8 ping {mbl} { icmp-echo $mbl }
594 define icmp-type 0 pong {mbl} { icmp-echo $mbl }
595 proc icmp-echo {mbl} {
597 get code enum 0 255 0.4
600 get data rand 0 [expr {$mbl-8}]
602 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
604 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
606 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
608 return [list $body $code]
610 define icmp-echo-code 0 echo {} {}
612 define icmp-type 13 timestamp {mbl} { icmp-timestamp }
613 define icmp-type 14 timestampreply {mbl} { icmp-timestamp }
614 proc icmp-timestamp {} {
615 get-for icmp-timestamp
616 get code enum 0 255 0.4
619 get originate ip-timestamp
620 get receive ip-timestamp
621 get transmit ip-timestamp
623 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
625 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
627 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
629 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
631 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
633 return [list $body $code]
635 define icmp-timestamp-code 0 timestamp {} {}
637 define icmp-type 15 inforequest {mbl} { icmp-inforeq }
638 define icmp-type 16 inforeply {mbl} { icmp-inforeq }
639 proc icmp-inforeq {} {
641 get code enum 0 255 0.4
645 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
647 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
649 return [list $body $code]
651 define icmp-inforeq-code 0 timestamp {} {}
653 # MAYADD ICMP traceroute RFC1393
654 # MAYADD ICMP router discovery RFC1256
656 proc port-pair {scope} {
659 get style choice-mult \
665 if {"$style" != "random"} {
671 if {"$style" != "servers"} {
672 get port enum-rand 0 0xffff
675 switch -exact $style {
676 random { set source_port $rand_port; set dest_port $rand_port }
677 request { set source_port $rand_port; set dest_port $def_port }
678 reply { set source_port $def_port; set dest_port $rand_port }
679 servers { set source_port $def_port; set dest_port $def_port }
681 return [list $source_port $dest_port $def_port $style]
684 define ip-proto 17 udp {mtu} {
687 get checksum choice-mult \
691 manyset [port-pair udp] source_port dest_port def_port style
693 if {"$style" != "random"} {
695 set data [depending-on udp port $mtu -8 $style]
697 get data rand 0 [expr {$mtu-8}]
703 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
704 | Source Port | Dest Port |
705 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
706 | ? Length | ? Checksum |
707 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
709 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
711 set udp_length [packet-len $udp]
712 assembly-overwrite udp length $udp_length
714 if {"$checksum" != "none"} {
715 global ip_source ip_dest ip_proto
717 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
719 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
721 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
722 | 0 | IP Proto | UDP length |
723 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
725 set csum [packet-csum-ip "$pseudo$udp"]
726 if {!$csum} { set csum 0xffff }
727 if {"$checksum" == "bad"} {
728 get csumerror hex 1 0xffff
729 set csum [expr {$csum ^ $csumerror}]
734 assembly-overwrite udp checksum $csum
738 define udp-port 50 remailck {mtu style} {
740 if {"$style" == "request"} {
741 get what choice-mult \
748 get what choice-mult \
755 switch -exact $what {
758 get user string 1 8 \
759 abcdefghijklmnopqrustuvwxyz \
760 abcdefghijklmnopqrustuvwxyz-0123456789_
764 get user rand 0 [expr {$mtu - 4}]
767 get auth enum 0 31 0.5
768 set user [depending-on remailck auth $mtu -4]
771 get auth hex 0 0xffff
776 get mail choice-mult \
782 switch -exact $mail {
796 get modified number 1 600
797 get read number 1 600
799 default { error "mail? $mail" }
802 default { error "what? $what" }
807 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
809 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
811 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
816 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
818 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
820 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
822 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
825 default { error "what?? $what" }
830 define remailck-auth 31 passwd {mtu} {
831 get-for remailck-passwd
832 get passwd string 6 8 \
833 0123456789abcdefghijklmnopqrstuvxwyz \
834 0123456789abcdefghijklmnopqrstuvxwyz
838 define ip-proto 6 tcp {mtu} {
841 get source_port number 0 65535
842 get dest_port number 0 65535
843 get event choice-mult \
854 switch -exact $event {
855 connect { set s 1; set a 0 }
858 reset { set a 0; set r 1 }
866 default { error "event? $event" }
870 if {[choice-prob tcp-smallwindow 0.7]} {
871 get window number 0 1
873 get window hex 0 0xffff
880 get optmode choice-mult badopt 0.3 opt 0.6 noopt
881 switch -exact $optmode {
884 get options rand 1 60
887 while {[choice-prob tcp-opts-more 0.4]} {
888 get opt enum 1 255 0.5
896 set data [depending-on tcp opt 6 0]
899 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
900 | Opt | ? Option Len |
901 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
903 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
905 assembly-overwrite option option_len [packet-len $option]
907 append options $option
912 if {[choice-prob reserved-nonzero 0.25]} {
913 get reserved hex 0 0x3f
918 if {[packet-len $options] % 4 || [get optxpad choice 0.15]} {
919 if {"$optmode" != "badopt"} { append options 00 }
920 set padlen [expr {3 - ([packet-len $options] + 3) % 4}]
921 append options [random-bytes $padlen]
927 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
928 | Source Port | Dest Port |
929 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
931 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
933 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
934 |? D Off| Reserved |U|A|P|R|S|F| Window |
935 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
937 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
942 set d_off [expr {([packet-len $packet]/4) & 0x0f}]
943 assembly-overwrite packet d_off $d_off
945 if {!($s || $r) || [get unexpdata flag 0.2]} {
946 get data rand 0 [expr {$mtu - [packet-len $packet]}]
949 set tcp_length [packet-len $packet]
951 global ip_source ip_dest ip_proto
953 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
955 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
957 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
958 | 0 | IP Proto | TCP length |
959 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
962 set csum [packet-csum-ip "$pseudo$packet"]
963 if {[choice-prob tcp-badcsum 0.1]} {
964 get csumerror hex 1 0xffff
965 set csum [expr {$csum ^ $csumerror}]
967 assembly-overwrite packet checksum $csum
971 define tcp-opt 2 mss {mdl} {
975 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
977 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
983 namespace eval PCap {
984 namespace export pcap_open pcap_write pcap_write_raw pcap_close
986 proc pcap_open {fn} {
990 fconfigure $fh -translation binary
995 if {![info exists fh]} return
1000 proc pcap_write_raw {packet} {
1002 if {![info exists fh]} return
1003 puts -nonewline $fh [binary format H* $packet]
1006 proc pcap_write {valdeflist} {
1007 foreach {kind valvar} $valdeflist {
1008 if {![regexp {^([usx])([0-9]+)} $kind dummy mode bits]} {
1009 error "unknown kind $kind for $valvar"
1011 set value [uplevel 1 [list set $valvar]]
1012 if {$bits % 8} { error "bits must be mult 8 in $kind for $valvar" }
1013 if {"$mode" != "x"} {
1016 for {set i 0} {$i<$bits/8} {incr i} {
1017 append v [format %02x [expr {$value & 0xff}]]
1018 set value [expr {$value >> 8}]
1020 if {$value != 0 && $value != -1} {
1021 error "value $ov more than $bits bits (residue=$value)"
1025 if {[string length $value] != $bits/4} {
1026 error "$valvar value $value wrong length, not $bits bits"
1028 pcap_write_raw $value
1032 namespace import PCap::*
1035 global getlog_log errorInfo mtu
1038 set packet [gen_1_ip $mtu]
1039 puts stdout "[format %6d $count] $getlog_log\n $packet"
1041 puts stderr "\nERROR\n$count\n\n$emsg\n\n$errorInfo\n\n"
1042 puts stdout "[format %06d $count] error"
1044 set ts_sec [clock seconds]
1047 set llpkt [random-bytes 12] ;# ether addrs
1048 append llpkt 0800 ;# eth ip type
1049 append llpkt $packet
1051 set len [packet-len "$llpkt"]
1058 pcap_write_raw $llpkt
1065 if {![llength $argv]} { error "need another arg" }
1066 set a [lindex $argv 0]
1067 set argv [lrange $argv 1 end]
1071 proc nextarg_num {} { return [expr {[nextarg] + 0}] }
1077 while {[regexp {^\-\-} [lindex $argv 0]]} {
1079 switch -exact -- $o {
1080 --infinite { set upto -1 }
1081 --debug { set debug_level [nextarg_num] }
1082 --upto { set upto [nextarg_num] }
1083 --write { pcap_open [nextarg] }
1084 --mtu { set mtu [nextarg_num] }
1085 --xseed { set xseed [nextarg] }
1086 default { error "bad option $o" }
1108 if {[llength $argv] && ![string length $upto]} {
1109 foreach count $argv { emit "$xseed$count" }
1110 } elseif {![llength $argv]} {
1111 if {![string length $upto]} { set upto 100 }
1112 for {set count 1} {$upto<0 || $count<=$upto} {incr count} {