3 # core packet generator for vinegar-ip
5 # This file is part of vinegar-ip, tools for IP transparency testing.
6 # vinegar-ip is Copyright (C) 2002 Ian Jackson
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2, or (at your option)
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software Foundation,
20 # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 proc debug {level str} {
26 if {$level <= $debug_level} { puts stderr "debug\[$level] $str" }
29 proc manyset {list args} {
30 foreach val $list var $args {
37 proc start_gen {seed} {
39 random-bytes-init $seed
43 proc packet-len {p} { expr {[string length $p]/2} }
45 proc packet-csum-ip {packet} {
48 while {[regexp {^([0-9a-f]{4})(.*)$} $packet dummy this packet]} {
49 set cs [expr "\$cs + 0x$this"]
50 debug 7 [format "0x%s 0x%08x" $this $cs]
52 while {$cs > 0xffff} {
53 set cs [expr {($cs & 0xffff) + (($cs >> 16) & 0xffff)}]
55 return [expr {$cs ^ 0xffff}]
58 proc packet-fromstring {s} {
63 namespace eval Random-Bytes {
64 namespace export random-bytes random-bytes-init
66 proc random-bytes-init {seed} {
68 catch { set h $fh; unset fh; close $h }
69 set fh [open |[list openssl bf-ofb < /dev/zero -e -k " $seed"] r]
70 fconfigure $fh -translation binary
72 proc random-bytes {n} {
75 if {[string length $x] != $n} {
76 set h $fh; unset fh; close $h
77 error "openssl bf-ofb exited unexpectedly"
79 set y [packet-fromstring $x]
84 namespace import Random-Bytes::*
86 proc choice-int {min max} {
87 set rv 0x[random-bytes 3]
89 int( double($rv) / double(0x1000000) * double($max+1-$min) )
94 proc choice-prob {cv def} {
95 set prob [config $cv $def]
96 set rv 0x[random-bytes 3]
97 set rv [expr {$rv < double($prob)*0x1000000}]
98 debug 2 "choice-prob $rv <- $prob ($cv)"
102 proc choice-mult {args} {
103 if {!([llength $args] % 2)} { error "choice-mult must have default" }
104 set h 0x[random-bytes 3]
105 set x [expr { double($h) / double(0x1000000) }]
107 set def [lindex $args end]
108 set args [lreplace $args end end]
109 foreach {val p} $args {
110 set cump [expr {$cump + double($p)}]
112 debug 2 "choice-mult $val <= [concat $args [list $def]]"
116 debug 2 "choice-mult $def <- [concat $args [list $def]]"
121 upvar #0 getlog_log log
123 debug 2 "getlog $msg"
126 proc config {cv def} {
127 upvar #0 config/$cv v
128 if {[info exists v]} { return $v }
133 proc define {enum val mult name argnames body} {
135 # * full share of `known' enum values
136 # ? only as often as `random' enum values
137 # Or *<pct> or ?<pct> meaning <pct>/100 times as often as * or ?.
139 upvar #0 enum/val2name/$enum v2n
140 upvar #0 enum/val2mult/$enum v2m
141 upvar #0 enum/name2val/$enum n2v
143 upvar #0 enum/total$kind/$enum total$kind
144 if {![info exists total$kind]} { set total$kind 0 }
147 regsub {^[?*]$} $mult {&100} mult
148 if {![regexp {^([?*])([0-9]+)$} $mult dummy kind times]} {
149 error "invalid mult $mult"
153 set v2m($val) [list $kind $times]
155 incr total$kind $times
157 proc enum/val/$enum/$val $argnames $body
160 proc depending-on {scope enum_and_var mtu mtuadjust args} {
161 upvar 1 $enum_and_var val
162 set mtu [expr {$mtu + $mtuadjust}]
163 set procname enum/val/$scope-$enum_and_var/[format %d $val]
164 if {[choice-prob $enum_and_var-unstruct 0.1] ||
165 [catch { info body $procname }]} {
168 get data rand 0 $mtu 1
171 uplevel 1 [list $procname] $mtu $args
176 proc get-for {scope} {
181 proc get {variable kind args} {
182 upvar 1 get/scope scope
183 upvar 1 $variable var
184 set var [eval [list get/$kind $scope $variable] $args]
187 proc get-config/number {val min max} { return $val }
188 proc get-config/v4addr {val} {
189 if {![regexp {^(\d+)\.(\d+)\.(\d+)\.(\d+)$} $val dummy a b c d]} {
190 error "bad v4addr ?$val?"
192 return [format 0x%02x%02x%02x%02x $a $b $c $d]
194 proc get-config/linkaddr {val} {
198 proc get-config {variable def kind args} {
199 # args currently ignored
200 upvar 1 get/scope scope
201 upvar 1 $variable var
202 set val [config $scope-$variable $def]
203 set var [eval [list get-config/$kind $val] $args]
206 proc get-enum-got {s v rv} {
207 upvar #0 enum/val2name/$s-$v v2n
208 if {[info exists v2n($rv)]} {
209 getlog "$v=$v2n($rv)\[$rv]"
216 proc get/enum-rand {s v min max} {
217 set rv [choice-int $min $max]
218 return [get-enum-got $s $v $rv]
221 proc enum-prepare-choice-list {s v nvalues prand} {
222 upvar #0 "enum/choice-list/$s-${v}($nvalues $prand)" cl
223 upvar #0 enum/val2mult/$s-$v v2m
224 upvar #0 enum/total*/$s-$v total*org
225 upvar #0 enum/total?/$s-$v total?
227 set total* ${total*org}
228 if {!${total*}} { set total* [expr {double(${total*org}) + 0.001}] }
231 if {!${total?}} { set pr 0.0 }
232 set pm? [expr {$pr / (100.0*double($nvalues))}]
233 set pm* [expr {(1.0 - $pr) / double(${total*})}]
234 debug 1 "epcl $s-$v $nvalues $prand: pr $pr ? pm ${pm?} total ${total?} * pm ${pm*} total ${total*}"
237 foreach rv [lsort [array names v2m]] {
238 manyset $v2m($rv) kind times
239 set p [expr { double($times) * [set pm$kind] }]
240 debug 1 "epcl $s-$v $nvalues $prand: $rv $kind$times := $p"
244 set cl [lreplace $cl end end]
250 proc get/enum-def {s v min max prand} {
251 set nvalues [expr {$max-$min+1}]
252 upvar #0 "enum/choice-list/$s-${v}($nvalues $prand)" cl
253 if {![info exists cl]} { enum-prepare-choice-list $s $v $nvalues $prand }
254 set rv [eval choice-mult $cl]
255 if {"$rv" == "*"} { set rv [choice-int $min $max] }
256 return [get-enum-got $s $v $rv]
259 proc get/enum {s v min max prand} {
260 set any [choice-prob $s-$v-any $prand]
262 return [get/enum-rand $s $v $min $max]
264 return [get/enum-def $s $v $min $max $prand]
268 proc get/number {s v min max} {
269 set rv [choice-int $min $max]
274 proc get/hex {s v min max} {
275 set rv [choice-int $min $max]
276 getlog [format %s=0x%x $v $rv]
280 proc get/hex32 {s v} {
281 set rv [random-bytes 4]
286 proc get/flag {s v defprob} {
287 set rv [choice-prob $s-$v $defprob]
288 if {$rv} { getlog "$v" } else { getlog "!$v" }
292 proc get/choice {s v defprob} {
293 set rv [choice-prob $s-$v $defprob]
294 if {$rv} { getlog "($v)" } else { getlog "(!$v)" }
298 proc get/rand {s v minlen maxlen blockbytes} {
300 if {$maxlen<0} { getlog (full!); return {} }
301 get l number [expr {$minlen/$blockbytes}] [expr {$maxlen/$blockbytes}]
302 return [random-bytes [expr {$l*$blockbytes}]]
305 proc get/ip-timestamp {s v} {
307 incr rv [choice-int 100 10000]
308 getlog "$v=[format %x $rv]"
312 proc get/v4addr {s v} {
316 for {set i 0} {$i<4} {incr i} {
317 set b [random-bytes 1]
319 append p $d [format %d 0x$b]
326 proc get/choice-mult {s v args} {
327 set rv [eval choice-mult $args]
332 proc get/string {s v minlen maxlen first rest} {
335 for {set l [choice-int $minlen $maxlen]} {$l>0} {incr l -1} {
336 set cn [choice-int 0 [expr {[string length $now]-1}]]
337 append o [string index $now $cn]
341 return [packet-fromstring $o]
344 proc get/ntstring {s v minlen maxlen first rest} {
345 set s [get/string $s $v $minlen $maxlen $first $rest]
347 append s [random-bytes $maxlen]
348 return [string range $s 0 [expr {$maxlen*2-1}]]
351 namespace eval Assembler {
352 namespace export assemble assembly-overwrite
354 proc assemble {outvarname format} {
355 # format should look like those RFC diagrams. +-+-+ stuff and
356 # good formatting is mandatory. You can have a single data
357 # item at the end ending in ..., which means append that data
360 # Field names are converted to lowercase; internal spaces
361 # are replaced with _. They are then assumed to be
362 # variable names in the caller's scope. The packet is
363 # assembled from those values (which must all be set)
364 # and stored in $varname in the caller's scope.
366 # Variables ?_whatever will be *set* with the location of the
367 # field in the string (in internal format); the corresponding
368 # `whatever' (with the ?_ stripped) will be read when assembling.
370 # Field names starting with digits are literal values instead.
373 upvar 1 $outvarname out
374 if {[catch { set parsed $cache($format) }]} {
375 set parsed [parse $format]
376 set cache($format) $parsed
379 manyset $parsed outbytes lout
380 set out [string repeat 00 $outbytes]
381 foreach {?_location varname locvarname} $lout {
382 if {[regexp {^[0-9]} $varname]} {
385 set value [uplevel 1 [list set $varname]]
387 if {[string length $locvarname]} {
388 upvar 1 $locvarname lv
392 assembly-overwrite out location $value
394 global errorInfo errorCode
396 "$errorInfo\n setting\n$varname at ${?_location}" \
402 proc parse {format} {
406 debug 7 "ASSEMBLY $format"
407 set format [exec expand << $format]
408 foreach l [split $format "\n"] {
410 if {[regexp -nocase {^ *\| +\| *$} $l]} {
411 if {![info exists wordbits]} {
412 error "vspace not in data @$lno\n?$l?"
415 } elseif {[regexp -nocase {^ *[|? a-z0-9.]+$} $l]} {
416 if {[info exists words]} {
417 error "data without delimline @$lno\n?$l?"
421 } elseif {[regexp {^ *[-+]+ *$} $l]} {
424 while {[regexp {^([-= ]+)\+(.*)$} $l dummy before after]} {
425 set atpos([string length $before]) $wordbits
427 set l "$before=$after"
428 append newlineform "@[string length $before]:$wordbits "
431 append newlineform $wordbits
432 if {[info exists lineform]} {
433 if {"$newlineform" != "$lineform"} {
434 error "format change @$lno\n?$l?\n$wordformat != $oldwordformat"
436 if {![info exists words] || $words<0} {
437 error "consecutive delimlines @$lno\n?$l?"
439 incr outbytes [expr {$words*$wordbits/8}]
441 while {[regexp -nocase \
442 {^([ =]*)\|( *[? a-z0-9]*[a-z0-9] *\.* *)\|(.*)$} \
443 $l dummy before midpart after]} {
444 debug 7 "RWORKG ?$l?"
446 error "two things at end @$lno\n?$l?"
448 set varname [string tolower [string trim $midpart]]
449 if {[regexp {(.*[a-z0-9])\s*\.\.\.$} $varname \
450 dummy realvarname]} {
451 set varname $realvarname
454 set varname [string map {{ } _} $varname]
455 set p1 [string length $before]
457 [string length $before] +
458 [string length $midpart] + 1
460 if {![info exists atpos($p1)] ||
461 ![info exists atpos($p2)]} {
462 error "vdelims not found @$lno $varname $p1 $p2 -- $lineform ?$cue?"
470 $atpos($p2) - $atpos($p1) + ($words-1)*$wordbits
474 error "atend not at byte @$lno\n?$l?"
476 set outbytes [expr {$bit1/8}]
477 set location [list $bit1 0 $varname]
479 set location [list $bit1 $bitlen $varname]
481 if {[regexp {^\?_(.*)} $varname dummy realvarname]} {
482 debug 7 "LOCATING $varname $location"
483 set locvarname $varname
484 set varname $realvarname
488 lappend lout $location $varname $locvarname
490 append l [string repeat = [string length $midpart]]
493 debug 7 "REMAIN ?$l?"
494 if {![regexp {^[ =]*\|? *$} $l]} {
495 error "unclear @$lno\n?$l?"
498 if {$wordbits % 8 || $wordbits >32} {
499 error "bad wordbits $wordbits @$lno ?$l? $newlineform"
501 set lineform $newlineform
503 catch { unset words }
504 } elseif {[regexp {^ *$} $l]} {
506 error "huh? @$lno ?$l?"
509 debug 7 "ASSEMBLY\n$outbytes\n$lout\n"
510 return [list $outbytes $lout]
513 proc assembly-overwrite {outvarname locvarnameex value} {
514 upvar 1 $outvarname out
515 upvar 1 ?_$locvarnameex location
516 manyset $location bit1 bitlen diag
517 if {$bitlen > 0 && $bitlen != 32 && $value >= (1<<$bitlen)} {
518 error "$diag $value >= 2**$bitlen"
520 if {!($bit1 % 8) && !($bitlen % 8)} {
521 set char0no [expr {$bit1/4}]
522 set charlen [expr {$bitlen/4}]
523 set chareno [expr {$char0no + $charlen -1}]
525 debug 8 "ASSEMBLY $diag == $value == 0x[format %x $value] (@$bit1+$bitlen)"
526 set repl [format %0${charlen}x $value]
527 set out [string replace $out $char0no $chareno $repl]
529 debug 8 "ASSEMBLY-ADD $diag (@$bit1)"
530 # bitlen==0 => append
531 set out [string range $out 0 $chareno]
535 while {$bitlen > 0} {
536 set byteno [expr {$bit1 / 8}]
537 set char0no [expr {$byteno*2}]
538 set char1no [expr {$char0no+1}]
539 set bytebit [expr {128>>($bit1 % 8)}]
540 set byte 0x[string range $out $char0no $char1no]
541 debug 7 "< $bit1+$bitlen $byteno $char0no $bytebit $byte $out"
543 ($value & (1<<($bitlen-1)))
545 : ($byte & ~$bytebit)
547 set out [string replace $out $char0no $char1no \
549 debug 8 "> $bit1+$bitlen $byteno $char0no $bytebit 0x[format %02x $byte] $out"
556 namespace import Assembler::*
558 proc gen_1_ip {mtu source_spec dest_spec} {
560 upvar #0 ip_proto proto
561 upvar #0 ip_source source
562 upvar #0 ip_dest dest
564 set source $source_spec
569 get tos hex 0x00 0xff
570 get id number 0x0000 0xffff
572 if {$df || ![choice-prob ip-midfrag 0.05]} {
577 get frag number 0 0x1fff
579 get-config ttl 255 number 0 255
580 get proto enum 0 255 0.2
581 set flags [expr {$df*2 + $mf}]
583 set header_checksum 0
587 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588 |Version| ? IHL |TOS | ? Total Length |
589 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
592 | TTL | Proto | ? Header Checksum |
593 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
595 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
597 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
599 # we don't do any IP options
601 set ihl [packet-len $ip]
602 if {$ihl % 4} { error "ihl not mult of 4 bytes" }
603 assembly-overwrite ip ihl [expr {$ihl / 4}]
605 set body [depending-on ip proto $mtu -$ihl]
606 set total_length [expr {[packet-len $ip] + [packet-len $body]}]
608 assembly-overwrite ip total_length $total_length
609 assembly-overwrite ip header_checksum [packet-csum-ip $ip]
615 define ip-proto 1 *50 icmp {mtu} {
618 get type enum 0 255 0.2
619 manyset [depending-on icmp type $mtu -4] body code
620 if {![string length $code]} { get code number 0 255 }
623 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
624 | Type | Code | ? Checksum |
625 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
627 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
629 assembly-overwrite icmp checksum [packet-csum-ip $icmp]
633 proc define-icmp-type-vanilla {num name} {
634 define icmp-type $num * $name {mbl} "icmp-vanilla \$mbl [list $name]"
636 proc icmp-vanilla {mbl typename} {
637 get-for icmp-$typename
638 get code enum 0 255 0.4
639 get body rand 0 $mbl 1
640 return [list $body $code]
643 define-icmp-type-vanilla 3 unreach
644 define icmp-unreach-code 0 * net {} {}
645 define icmp-unreach-code 1 * host {} {}
646 define icmp-unreach-code 2 * proto {} {}
647 define icmp-unreach-code 3 * port {} {}
648 define icmp-unreach-code 4 * fragneeded {} {}
649 define icmp-unreach-code 5 * sourceroutefail {} {}
651 define-icmp-type-vanilla 11 timeout
652 define icmp-timeout-code 0 * intransit {} {}
653 define icmp-timeout-code 1 * fragment {} {}
655 define-icmp-type-vanilla 12 parameters
656 define icmp-parameters-code 0 * seepointer {} {}
658 define-icmp-type-vanilla 4 sourcequench
659 define icmp-sourcequench-code 0 * quench {} {}
661 define icmp-type 5 * redirect {mbl} {
662 get-for icmp-redirect
663 get code enum 0 255 0.4
665 get data rand 0 [expr {$mbl-4}] 1
667 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
669 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
671 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
673 return [list $body $code]
676 define icmp-redirect-code 0 * net {} {}
677 define icmp-redirect-code 1 * host {} {}
678 define icmp-redirect-code 2 * net+tos {} {}
679 define icmp-redirect-code 3 * host+tos {} {}
681 define icmp-type 8 * ping {mbl} { icmp-echo $mbl }
682 define icmp-type 0 * pong {mbl} { icmp-echo $mbl }
683 proc icmp-echo {mbl} {
685 get code enum 0 255 0.4
688 get data rand 0 [expr {$mbl-8}] 1
690 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
692 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
694 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
696 return [list $body $code]
698 define icmp-echo-code 0 * echo {} {}
700 define icmp-type 13 * timestamp {mbl} { icmp-timestamp }
701 define icmp-type 14 * timestampreply {mbl} { icmp-timestamp }
702 proc icmp-timestamp {} {
703 get-for icmp-timestamp
704 get code enum 0 255 0.4
707 get originate ip-timestamp
708 get receive ip-timestamp
709 get transmit ip-timestamp
711 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
713 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
715 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
717 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
719 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
721 return [list $body $code]
723 define icmp-timestamp-code 0 * timestamp {} {}
725 define icmp-type 15 * inforequest {mbl} { icmp-inforeq }
726 define icmp-type 16 * inforeply {mbl} { icmp-inforeq }
727 proc icmp-inforeq {} {
729 get code enum 0 255 0.4
733 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
735 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
737 return [list $body $code]
739 define icmp-inforeq-code 0 * timestamp {} {}
741 # MAYADD ICMP traceroute RFC1393
742 # MAYADD ICMP router discovery RFC1256
745 define ip-proto 4 * ip {mtu} {
750 gen_1_ip $mtu $source $dest
754 define ip-proto 2 ? igmp {mtu} {
756 get type enum 0 255 0.5
757 get timeout number 0 255
762 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
763 | Type | Timeout | ? Checksum |
764 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
766 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
768 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
771 if {[choice-prob igmp-extra 0.3]} {
772 get extra rand 1 [expr {$mtu - [packet-len $igmp]}] 1
773 assembly-overwrite igmp extra $extra
776 assembly-overwrite igmp checksum [packet-csum-ip $igmp]
780 define igmp-type 17 * membquery {} {}
781 define igmp-type 16 * membreport {} {}
782 define igmp-type 23 * leavegroup {} {}
783 define igmp-type 18 * membreport {} {}
786 define ip-proto 51 ? ah {mtu} {
789 get next number 0 255
790 get reserved hex 0 0xffff
792 get auth_data rand 0 [expr {$mtu-8 > 50 ? 50 : $mtu-8}] 4
793 set length [packet-len $auth_data]
795 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
796 | Next | Length | RESERVED |
797 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
799 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
801 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
803 get payload rand 0 [expr {$mtu - [packet-len $ah]}] 1
810 get port enum-rand 0 0xffff
814 define ip-proto 17 * udp {mtu} {
818 set csum_mode [choice-mult \
824 get style choice-mult \
830 if {"$style" != "random"} {
831 get port enum-def 0 255 $prand
836 switch -exact $style {
837 random { set source_port [udp-rport]; set dest_port [udp-rport] }
838 request { set source_port [udp-rport]; set dest_port $def_port }
839 reply { set source_port $def_port; set dest_port [udp-rport] }
840 servers { set source_port $def_port; set dest_port $def_port }
843 if {"$style" != "random"} {
845 set data [depending-on udp port $mtu -8 $style]
847 get data rand 0 [expr {$mtu-8}] 1
853 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
854 | Source Port | Dest Port |
855 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
856 | ? Length | ? Checksum |
857 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
859 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
861 set udp_length [packet-len $udp]
862 assembly-overwrite udp length $udp_length
864 if {"$csum_mode" == "checksum_none"} {
868 global ip_source ip_dest ip_proto
870 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
872 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
874 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
875 | 0 | IP Proto | UDP length |
876 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
878 set checksum [packet-csum-ip "$pseudo$udp"]
879 if {!$checksum} { set checksum 0xffff }
880 if {"$csum_mode" == "checksum_bad"} {
881 get csumerror hex 1 0xffff
882 set checksum [expr {$checksum ^ $csumerror}]
885 assembly-overwrite udp checksum $checksum
889 define udp-port 50 ?200 remailck {mtu style} {
892 if {"$style" == "request"} {
893 get what choice-mult \
900 get what choice-mult \
907 switch -exact $what {
910 get user string 1 8 \
911 abcdefghijklmnopqrustuvwxyz \
912 abcdefghijklmnopqrustuvwxyz-0123456789_
916 get user rand 0 [expr {$mtu - 4}] 1
919 get auth enum 0 31 0.5
920 set user [depending-on remailck auth $mtu -4]
923 get auth hex 0 0xffff
928 get mail choice-mult \
934 switch -exact $mail {
948 get modified number 1 600
949 get read number 1 600
951 default { error "mail? $mail" }
954 default { error "what? $what" }
959 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
961 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
963 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
968 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
970 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
972 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
974 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
977 default { error "what?? $what" }
982 define remailck-auth 31 * passwd {mtu} {
983 get-for remailck-passwd
984 get passwd string 6 8 \
985 0123456789abcdefghijklmnopqrstuvxwyz \
986 0123456789abcdefghijklmnopqrstuvxwyz
990 define udp-port 67 ? dhcpserv {mtu style} { return [dhcp $mtu] }
991 define udp-port 68 ? dhcpclient {mtu style} { return [dhcp $mtu] }
994 get op enum 0 255 0.2
995 get htype enum 0 255 0.2
997 get hops number 0 255
999 get secs number 0 300
1005 set chaddr [random-bytes 16]
1006 get sname ntstring 0 64 \
1007 0123456789abcdefghijklmnopqrstuvwxyz \
1008 0123456789abcdefghijklmnopqrstuvwxyz.-+
1009 get file ntstring 0 128 / \
1010 0123456789abcdefghijklmnopqrstuvwxyz.-+/_
1013 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1014 | op | htype | hlen | hops |
1015 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1017 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1019 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1021 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1023 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1025 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1027 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1029 append dhcp $chaddr $sname $file
1033 define dhcp-op 1 * request {} {}
1034 define dhcp-op 2 * reply {} {}
1035 define dhcp-htype 1 * ethernet {} {}
1038 define ip-proto 6 * tcp {mtu} {
1042 get source_port number 0 65535
1043 get dest_port number 0 65535
1044 get event choice-mult \
1055 switch -exact $event {
1056 connect { set s 1; set a 0 }
1059 reset { set a 0; set r 1 }
1067 default { error "event? $event" }
1071 if {[choice-prob tcp-smallwindow 0.7]} {
1072 get window number 0 1
1074 get window hex 0 0xffff
1078 get urg hex 0 0xffff
1081 get optmode choice-mult badopt 0.3 opt 0.3 noopt
1082 switch -exact $optmode {
1085 get options rand 1 60 1
1089 while {$nooi || [choice-prob tcp-opts-more 0.4]} {
1091 get opt enum 1 255 0.5
1099 set data [depending-on tcp opt 6 0]
1102 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1103 | Opt | ? Option Len |
1104 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1106 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1108 assembly-overwrite option option_len [packet-len $option]
1110 append options $option
1115 if {[choice-prob reserved-nonzero 0.25]} {
1116 get reserved hex 0 0x3f
1121 if {[packet-len $options] % 4 || [get optxpad choice 0.15]} {
1122 if {"$optmode" != "badopt"} { append options 00 }
1123 set padlen [expr {3 - ([packet-len $options] + 3) % 4}]
1124 append options [random-bytes $padlen]
1130 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1131 | Source Port | Dest Port |
1132 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1134 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1136 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1137 |? D Off| Reserved |U|A|P|R|S|F| Window |
1138 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1139 | ? Checksum | Urg |
1140 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1142 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1145 set d_off [expr {([packet-len $packet]/4) & 0x0f}]
1146 assembly-overwrite packet d_off $d_off
1148 if {!($s || $r) || [get unexpdata flag 0.2]} {
1149 get data rand 0 [expr {$mtu - [packet-len $packet]}] 1
1152 set tcp_length [packet-len $packet]
1154 global ip_source ip_dest ip_proto
1156 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1158 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1160 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1161 | 0 | IP Proto | TCP length |
1162 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1165 set csum [packet-csum-ip "$pseudo$packet"]
1166 if {[choice-prob tcp-badcsum 0.1]} {
1167 get csumerror hex 1 0xffff
1168 set csum [expr {$csum ^ $csumerror}]
1170 assembly-overwrite packet checksum $csum
1174 define tcp-opt 2 * mss {mdl} {
1176 get mss hex 0 0xffff
1178 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1180 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1186 namespace eval PCap {
1187 namespace export pcap_open pcap_write pcap_write_raw pcap_close
1189 proc pcap_open {fn} {
1193 fconfigure $fh -translation binary
1196 proc pcap_close {} {
1198 if {![info exists fh]} return
1203 proc pcap_write_raw {packet} {
1205 if {![info exists fh]} return
1206 puts -nonewline $fh [binary format H* $packet]
1209 proc pcap_write {valdeflist} {
1210 foreach {kind valvar} $valdeflist {
1211 if {![regexp {^([usx])([0-9]+)} $kind dummy mode bits]} {
1212 error "unknown kind $kind for $valvar"
1214 set value [uplevel 1 [list set $valvar]]
1215 if {$bits % 8} { error "bits must be mult 8 in $kind for $valvar" }
1216 if {"$mode" != "x"} {
1219 for {set i 0} {$i<$bits/8} {incr i} {
1220 append v [format %02x [expr {$value & 0xff}]]
1221 set value [expr {$value >> 8}]
1223 if {$value != 0 && $value != -1} {
1224 error "value $ov more than $bits bits (residue=$value)"
1228 if {[string length $value] != $bits/4} {
1229 error "$valvar value $value wrong length, not $bits bits"
1231 pcap_write_raw $value
1235 namespace import PCap::*
1238 global getlog_log errorInfo mtu fake_time_t
1239 global minframelen linktypename errors_continue
1242 get-config source 127.0.0.1 v4addr
1243 get-config dest 127.0.0.1 v4addr
1247 set packet [gen_1_ip $mtu $source $dest]
1248 puts stdout "[format %6s $seed] $getlog_log\n $packet"
1250 puts stderr "\nERROR\n$seed\n\n$emsg\n\n$errorInfo\n\n"
1251 puts stdout "[format %6s $seed] error"
1252 if {!$errors_continue} {
1253 error "internal error generating packet - consult author"
1256 set ts_sec [incr fake_time_t]
1259 set l [packet-len $packet]
1260 if {$l < $minframelen} {
1261 append packet [string repeat 00 [expr {$minframelen - $l}]]
1264 set llpkt [link/$linktypename/linkencap $packet]
1266 set len [packet-len "$llpkt"]
1273 pcap_write_raw $llpkt
1278 # link/ether - RFC894
1279 proc link/ether/linkparams {} { return {1 46} }
1280 proc link/ether/defaddr {} { return 00:00:00:00:00:00 }
1281 proc link/ether/procaddr {input sd} {
1282 set v [string tolower $input]
1283 if {[regexp {^([0-9a-f]{1,2}\:){6}$} $v:]} {
1285 foreach b [split $v :] { append o [format %02x 0x$b] }
1288 if {![regexp -nocase {^[0-9a-f]{12}$} $v]} {
1289 error "invalid $sd ethernet addr $input ($v)"
1293 proc link/ether/linkencap {packet} {
1294 global link_source link_dest
1296 append llpkt $link_dest $link_source 0800
1297 append llpkt $packet
1304 if {![llength $argv]} { error "need another arg" }
1305 set a [lindex $argv 0]
1306 set argv [lrange $argv 1 end]
1310 proc nextarg_num {} { return [expr {[nextarg] + 0}] }
1311 proc nextarg_il {} {
1313 if {![regexp -nocase {^([0-9.]+)/(.+)$} $a dummy i l]} {
1314 error "--source/--dest needs <ip-addr>/<link-addr>"
1320 set errors_continue 0
1324 set linktypename ether
1325 while {[regexp {^\-\-} [lindex $argv 0]]} {
1327 switch -exact -- $o {
1328 --infinite { set upto -1 }
1329 --debug { set debug_level [nextarg_num] }
1330 --upto { set upto [nextarg_num] }
1331 --write { pcap_open [nextarg] }
1332 --mtu { set mtu [nextarg_num] }
1333 --xseed { set xseed [nextarg] }
1334 --errors-continue { set errors_continue 1 }
1335 --linktype { set linktypename [nextarg] }
1336 --source { manyset [nextarg_il] config/ip-source config/link-source }
1337 --dest { manyset [nextarg_il] config/ip-dest config/link-dest }
1338 default { error "bad option $o" }
1342 proc process_linkaddr {sd} {
1346 get-config $sd [link/$linktypename/defaddr] linkaddr
1347 set l [link/$linktypename/procaddr [set $sd] $sd]
1350 manyset [link/$linktypename/linkparams] linktype minframelen
1351 process_linkaddr source
1352 process_linkaddr dest
1371 set fake_time_t 1000000000
1376 if {[llength $argv]} {
1377 foreach count $argv { emit "$xseed$count" }
1379 if {![string length $upto]} { set upto 100 }
1380 for {set count 1} {$upto<0 || $count<=$upto} {incr count} {