chiark / gitweb /
Specify link addrs.
[vinegar-ip.git] / make-probes.tcl
1 #!/usr/bin/tclsh
2
3 # core packet generator for vinegar-ip
4 #
5 # This file is part of vinegar-ip, tools for IP transparency testing.
6 # vinegar-ip is Copyright (C) 2002 Ian Jackson
7 #
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)
11 # any later version.
12 #
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.
17 #
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. 
21 #
22 # $Id$
23
24 proc debug {level str} {
25     global debug_level
26     if {$level <= $debug_level} { puts stderr "debug\[$level] $str" }
27 }
28
29 proc manyset {list args} {
30     foreach val $list var $args {
31         upvar 1 $var my
32         set my $val
33     }
34 }
35
36
37 proc start_gen {seed} {
38     global getlog_log
39     random-bytes-init $seed
40     set getlog_log {}
41 }
42
43 proc packet-len {p} { expr {[string length $p]/2} }
44
45 proc packet-csum-ip {packet} {
46     set cs 0
47     append packet 00
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]
51     }
52     while {$cs > 0xffff} {
53         set cs [expr {($cs & 0xffff) + (($cs >> 16) & 0xffff)}]
54     }
55     return [expr {$cs ^ 0xffff}]
56 }
57
58 proc packet-fromstring {s} {
59     binary scan $s H* y
60     return $y
61 }
62
63 namespace eval Random-Bytes {
64     namespace export random-bytes random-bytes-init
65
66     proc random-bytes-init {seed} {
67         variable fh
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
71     }
72     proc random-bytes {n} {
73         variable fh
74         set x [read $fh $n]
75         if {[string length $x] != $n} {
76             set h $fh; unset fh; close $h
77             error "openssl bf-ofb exited unexpectedly"
78         }
79         set y [packet-fromstring $x]
80         return $y
81     }
82 }
83
84 namespace import Random-Bytes::*
85
86 proc choice-int {min max} {
87     set rv 0x[random-bytes 3]
88     return [expr {
89         int( double($rv) / double(0x1000000) * double($max+1-$min) )
90         + $min
91     }]
92 }
93
94 proc choice-prob {cv def} {
95     set prob [config $cv $def]
96     set rv 0x[random-bytes 3]
97     return [expr {$rv < double($prob)*0x1000000}]
98 }
99
100 proc choice-mult {args} {
101     if {!([llength $args] % 2)} { error "choice-mult must have default" }
102     set h 0x[random-bytes 3]
103     set x [expr { double($h) / double(0x1000000) }]
104     set cump 0.0
105     set def [lindex $args end]
106     set args [lreplace $args end end]
107     foreach {val p} $args {
108         set cump [expr {$cump + double($p)}]
109         if {$x < $cump} { return $val }
110     }
111     return $def
112 }
113
114 proc getlog {msg} {
115     upvar #0 getlog_log log
116     append log " $msg"
117     debug 2 "getlog $msg"
118 }
119
120 proc config {cv def} {
121     upvar #0 config/$cv v
122     if {[info exists v]} { return $v }
123     return $def
124 }
125
126
127 proc define {enum val name argnames body} {
128     upvar #0 enum/val2name/$enum v2n
129     upvar #0 enum/name2val/$enum n2v
130     set v2n($val) $name
131     set n2v($name) $val
132     proc enum/val/$enum/$val $argnames $body
133 }
134
135 proc depending-on {scope enum_and_var mtu mtuadjust args} {
136     upvar 1 $enum_and_var val
137     set mtu [expr {$mtu + $mtuadjust}]
138     set procname enum/val/$scope-$enum_and_var/[format %d $val]
139     if {[choice-prob $enum_and_var-unstruct 0.1] ||
140             [catch { info body $procname }]} {
141         getlog (junk)
142         get-for $scope-fill
143         get data rand 0 $mtu 1
144         return $data
145     } else {
146         uplevel 1 [list $procname] $mtu $args
147     }
148 }
149
150
151 proc get-for {scope} {
152     upvar 1 get/scope ns
153     set ns $scope
154 }
155
156 proc get {variable kind args} {
157     upvar 1 get/scope scope
158     upvar 1 $variable var
159     set var [eval [list get/$kind $scope $variable] $args]
160 }
161
162 proc get-config/number {val min max} { return $val }
163 proc get-config/v4addr {val} {
164     if {![regexp {^(\d+)\.(\d+)\.(\d+)\.(\d+)$} $val dummy a b c d]} {
165         error "bad v4addr ?$val?"
166     }
167     return [format 0x%02x%02x%02x%02x $a $b $c $d]
168 }
169
170 proc get-config {variable def kind args} {
171     # args currently ignored
172     upvar 1 get/scope scope
173     upvar 1 $variable var
174     set val [config $scope-$variable $def]
175     set var [eval [list get-config/$kind $val] $args]
176 }
177
178 proc get-enum-got {s v rv} {
179     upvar #0 enum/val2name/$s-$v v2n
180     if {[info exists v2n($rv)]} {
181         getlog "$v=$v2n($rv)\[$rv]"
182     } else {
183         getlog "$v=$rv"
184     }
185     return $rv
186 }
187
188 proc get/enum-rand {s v min max} {
189     set rv [choice-int $min $max]
190     return [get-enum-got $s $v $rv]
191 }
192
193 proc get/enum-def {s v} {
194     upvar #0 enum/val2name/$s-$v v2n
195     set rv [choice-int 1 [array size v2n]]
196     set rv [lindex [lsort [array names v2n]] [expr {$rv-1}]]
197     return [get-enum-got $s $v $rv]
198 }
199
200 proc get/enum {s v min max prand} {
201     get-for $s-$v
202     get any choice $prand
203     if {$any} {
204         return [get/enum-rand $s $v $min $max]
205     } else {
206         return [get/enum-def $s $v]
207     }
208 }
209
210 proc get/number {s v min max} {
211     set rv [choice-int $min $max]
212     getlog "$v=$rv"
213     return $rv
214 }
215
216 proc get/hex {s v min max} {
217     set rv [choice-int $min $max]
218     getlog [format %s=0x%x $v $rv]
219     return $rv
220 }
221
222 proc get/hex32 {s v} {
223     set rv [random-bytes 4]
224     getlog "$v=0x$rv"
225     return 0x$rv
226 }
227
228 proc get/flag {s v defprob} {
229     set rv [choice-prob $s-$v $defprob]
230     if {$rv} { getlog "$v" } else { getlog "!$v" }
231     return $rv
232 }
233
234 proc get/choice {s v defprob} {
235     set rv [choice-prob $s-$v $defprob]
236     if {$rv} { getlog "($v)" } else { getlog "(!$v)" }
237     return $rv
238 }
239
240 proc get/rand {s v minlen maxlen blockbytes} {
241     get-for $s-$v
242     if {$maxlen<0} { getlog (full!); return {} }
243     get l number [expr {$minlen/$blockbytes}] [expr {$maxlen/$blockbytes}]
244     return [random-bytes [expr {$l*$blockbytes}]]
245 }
246
247 proc get/ip-timestamp {s v} {
248     set rv [expr {[clock seconds] | 0x80000000}]
249     getlog "$v=[format %x $rv]"
250     return $rv
251 }
252
253 proc get/v4addr {s v} {
254     set rv 0x
255     set p {}
256     set d {}
257     for {set i 0} {$i<4} {incr i} {
258         set b [random-bytes 1]
259         append rv $b
260         append p $d [format %d 0x$b]
261         set d .
262     }
263     getlog "$v=$p"
264     return $rv
265 }
266
267 proc get/choice-mult {s v args} {
268     set rv [eval choice-mult $args]
269     getlog "($rv)"
270     return $rv
271 }
272
273 proc get/string {s v minlen maxlen first rest} {
274     set o {}
275     set now $first
276     for {set l [choice-int $minlen $maxlen]} {$l>0} {incr l -1} {
277         set cn [choice-int 0 [expr {[string length $now]-1}]]
278         append o [string index $now $cn]
279         set now $rest
280     }
281     getlog "$v=\"$o\""
282     return [packet-fromstring $o]
283 }
284
285 proc get/ntstring {s v minlen maxlen first rest} {
286     set s [get/string $s $v $minlen $maxlen $first $rest]
287     append s 00
288     append s [random-bytes $maxlen]
289     return [string range $s 0 [expr {$maxlen*2-1}]]
290 }
291
292 namespace eval Assembler {
293     namespace export assemble assembly-overwrite
294
295     proc assemble {outvarname format} {
296         # format should look like those RFC diagrams.  +-+-+ stuff and
297         # good formatting is mandatory.  You can have a single data
298         # item at the end ending in ..., which means append that data
299         # item.
300         #
301         # Field names are converted to lowercase; internal spaces
302         # are replaced with _.  They are then assumed to be
303         # variable names in the caller's scope.  The packet is
304         # assembled from those values (which must all be set)
305         # and stored in $varname in the caller's scope.
306         #
307         # Variables ?_whatever will be *set* with the location of the
308         # field in the string (in internal format); the corresponding
309         # `whatever' (with the ?_ stripped) will be read when assembling.
310         #
311         # Field names starting with digits are literal values instead.
312
313         variable cache
314         upvar 1 $outvarname out
315         if {[catch { set parsed $cache($format) }]} {
316             set parsed [parse $format]
317             set cache($format) $parsed
318         }
319
320         manyset $parsed outbytes lout
321         set out [string repeat 00 $outbytes]
322         foreach {?_location varname locvarname} $lout {
323             if {[regexp {^[0-9]} $varname]} {
324                 set value $varname
325             } else {
326                 set value [uplevel 1 [list set $varname]]
327             }
328             if {[string length $locvarname]} {
329                 upvar 1 $locvarname lv
330                 set lv ${?_location}
331             }
332             if {[catch {
333                 assembly-overwrite out location $value
334             } emsg]} {
335                 global errorInfo errorCode
336                 error $emsg \
337                         "$errorInfo\n    setting\n$varname at ${?_location}" \
338                         $errorCode
339             }
340         }
341     }
342
343     proc parse {format} {
344         set lno 0
345         set outbytes 0
346         set atend 0
347         debug 7 "ASSEMBLY $format"
348         set format [exec expand << $format]
349         foreach l [split $format "\n"] {
350             incr lno
351             if {[regexp -nocase {^ *\| +\| *$} $l]} {
352                 if {![info exists wordbits]} {
353                     error "vspace not in data @$lno\n?$l?"
354                 }
355                 incr words
356             } elseif {[regexp -nocase {^ *[|? a-z0-9.]+$} $l]} {
357                 if {[info exists words]} {
358                     error "data without delimline @$lno\n?$l?"
359                 }
360                 set words 1
361                 set cue $l
362             } elseif {[regexp {^ *[-+]+ *$} $l]} {
363                 set wordbits 0
364                 set newlineform {}
365                 while {[regexp {^([-= ]+)\+(.*)$} $l dummy before after]} {
366                     set atpos([string length $before]) $wordbits
367                     incr wordbits
368                     set l "$before=$after"
369                     append newlineform "@[string length $before]:$wordbits "
370                 }
371                 incr wordbits -1
372                 append newlineform $wordbits
373                 if {[info exists lineform]} {
374                     if {"$newlineform" != "$lineform"} {
375  error "format change @$lno\n?$l?\n$wordformat != $oldwordformat"
376                     }
377                     if {![info exists words] || $words<0} {
378                         error "consecutive delimlines @$lno\n?$l?"
379                     }
380                     incr outbytes [expr {$words*$wordbits/8}]
381                     set l $cue
382                     while {[regexp -nocase \
383                             {^([ =]*)\|( *[? a-z0-9]*[a-z0-9] *\.* *)\|(.*)$} \
384                             $l dummy before midpart after]} {
385                         debug 7 "RWORKG ?$l?"
386                         if {$atend} {
387                             error "two things at end @$lno\n?$l?"
388                         }
389                         set varname [string tolower [string trim $midpart]]
390                         if {[regexp {(.*[a-z0-9])\s*\.\.\.$} $varname \
391                                 dummy realvarname]} {
392                             set varname $realvarname
393                             set atend 1
394                         }
395                         set varname [string map {{ } _} $varname]
396                         set p1 [string length $before]
397                         set p2 [expr {
398                             [string length $before] +
399                             [string length $midpart] + 1
400                         }]
401                         if {![info exists atpos($p1)] ||
402                             ![info exists atpos($p2)]} {
403  error "vdelims not found @$lno $varname $p1 $p2 -- $lineform ?$cue?"
404                         }
405                         set bit1 [expr {
406                             $outbytes*8
407                             - $words*$wordbits
408                             + $atpos($p1)
409                         }]
410                         set bitlen [expr {
411                             $atpos($p2) - $atpos($p1) + ($words-1)*$wordbits
412                         }]
413                         if {$atend} {
414                             if {$bit1 % 8} {
415                                 error "atend not at byte @$lno\n?$l?"
416                             }
417                             set outbytes [expr {$bit1/8}]
418                             set location [list $bit1 0 $varname]
419                         } else {
420                             set location [list $bit1 $bitlen $varname]
421                         }
422                         if {[regexp {^\?_(.*)} $varname dummy realvarname]} {
423                             debug 7 "LOCATING $varname $location"
424                             set locvarname $varname
425                             set varname $realvarname
426                         } else {
427                             set locvarname {}
428                         }
429                         lappend lout $location $varname $locvarname
430                         set l "$before="
431                         append l [string repeat = [string length $midpart]]
432                         append l |$after
433                     }
434                     debug 7 "REMAIN ?$l?"
435                     if {![regexp {^[ =]*\|? *$} $l]} {
436                         error "unclear @$lno\n?$l?"
437                     }
438                 } else {
439                     if {$wordbits % 8 || $wordbits >32} {
440                         error "bad wordbits $wordbits @$lno ?$l? $newlineform"
441                     }
442                     set lineform $newlineform
443                 }
444                 catch { unset words }
445             } elseif {[regexp {^ *$} $l]} {
446             } else {
447                 error "huh? @$lno ?$l?"
448             }
449         }
450         debug 7 "ASSEMBLY\n$outbytes\n$lout\n"
451         return [list $outbytes $lout]
452     }
453
454     proc assembly-overwrite {outvarname locvarnameex value} {
455         upvar 1 $outvarname out
456         upvar 1 ?_$locvarnameex location
457         manyset $location bit1 bitlen diag
458         if {$bitlen > 0 && $bitlen != 32 && $value >= (1<<$bitlen)} {
459             error "$diag $value >= 2**$bitlen"
460         }
461         if {!($bit1 % 8) && !($bitlen % 8)} {
462             set char0no [expr {$bit1/4}]
463             set charlen [expr {$bitlen/4}]
464             set chareno [expr {$char0no + $charlen -1}]
465             if {$bitlen > 0} {
466  debug 8 "ASSEMBLY $diag == $value == 0x[format %x $value] (@$bit1+$bitlen)"
467                 set repl [format %0${charlen}x $value]
468                 set out [string replace $out $char0no $chareno $repl]
469             } else {
470  debug 8 "ASSEMBLY-ADD $diag (@$bit1)"
471                 # bitlen==0 => append
472                 set out [string range $out 0 $chareno]
473                 append out $value
474             }
475         } else {
476             while {$bitlen > 0} {
477                 set byteno [expr {$bit1 / 8}]
478                 set char0no [expr {$byteno*2}]
479                 set char1no [expr {$char0no+1}]
480                 set bytebit [expr {128>>($bit1 % 8)}]
481                 set byte 0x[string range $out $char0no $char1no]
482                 debug 7 "< $bit1+$bitlen $byteno $char0no $bytebit $byte $out"
483                 set byte [expr {
484                     ($value & (1<<($bitlen-1)))
485                     ? ($byte | $bytebit)
486                     : ($byte & ~$bytebit)
487                 }]
488                 set out [string replace $out $char0no $char1no \
489                         [format %02x $byte]]
490  debug 8 "> $bit1+$bitlen $byteno $char0no $bytebit 0x[format %02x $byte] $out"
491                 incr bitlen -1
492                 incr bit1
493             }
494         }
495     }
496 }
497 namespace import Assembler::*
498
499 proc gen_1_ip {mtu source_spec dest_spec} {
500     # RFC791
501     upvar #0 ip_proto proto
502     upvar #0 ip_source source
503     upvar #0 ip_dest dest
504
505     set source $source_spec
506     set dest $dest_spec
507     
508     get-for ip
509     set version 4
510     get tos hex 0x00 0xff
511     get id number 0x0000 0xffff
512     get df flag 0.5
513     if {$df || ![choice-prob ip-midfrag 0.05]} {
514         set mf 0
515         set frag 0
516     } {
517         get mf flag 0.5
518         get frag number 0 0x1fff
519     }
520     get-config ttl 255 number 0 255
521     get proto enum 1 255 0.05
522     set flags [expr {$df*2 + $mf}]
523
524     set header_checksum 0
525     set ihl 0
526     set total_length 0
527     assemble ip {
528    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
529    |Version| ? IHL |TOS            |       ? Total Length          |
530    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
531    |         Id                    |Flags|      Frag               |
532    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
533    |  TTL          |    Proto      |      ? Header Checksum        |
534    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
535    |                       Source                                  |
536    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537    |                    Dest                                       |
538    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539     }
540     # we don't do any IP options
541
542     set ihl [packet-len $ip]
543     if {$ihl % 4} { error "ihl not mult of 4 bytes" }
544     assembly-overwrite ip ihl [expr {$ihl / 4}]
545
546     set body [depending-on ip proto $mtu -$ihl]
547     set total_length [expr {[packet-len $ip] + [packet-len $body]}]
548
549     assembly-overwrite ip total_length $total_length
550     assembly-overwrite ip header_checksum [packet-csum-ip $ip]
551
552     append ip $body
553     return $ip
554 }
555
556 define ip-proto 1 icmp {mtu} {
557     # RFC792
558     get-for icmp
559     get type enum 0 255 0.2
560     manyset [depending-on icmp type $mtu -4] body code
561     if {![string length $code]} { get code number 0 255 }
562     set checksum 0
563     assemble icmp {
564    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
565    |     Type      |     Code      |        ? Checksum             |
566    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
567    |     Body ...                                                  |
568    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
569     }
570     assembly-overwrite icmp checksum [packet-csum-ip $icmp]
571     return $icmp
572 }
573
574 proc define-icmp-type-vanilla {num name} {
575     define icmp-type $num $name {mbl} "icmp-vanilla \$mbl [list $name]"
576 }
577 proc icmp-vanilla {mbl typename} {
578     get-for icmp-$typename
579     get code enum 0 255 0.4
580     get body rand 0 $mbl 1
581     return [list $body $code]
582 }
583
584 define-icmp-type-vanilla 3 unreach
585 define icmp-unreach-code 0 net {} {}
586 define icmp-unreach-code 1 host {} {}
587 define icmp-unreach-code 2 proto {} {}
588 define icmp-unreach-code 3 port {} {}
589 define icmp-unreach-code 4 fragneeded {} {}
590 define icmp-unreach-code 5 sourceroutefail {} {}
591
592 define-icmp-type-vanilla 11 timeout
593 define icmp-timeout-code 0 intransit {} {}
594 define icmp-timeout-code 1 fragment {} {}
595
596 define-icmp-type-vanilla 12 parameters
597 define icmp-parameters-code 0 seepointer {} {}
598
599 define-icmp-type-vanilla 4 sourcequench
600 define icmp-sourcequench-code 0 quench {} {}
601
602 define icmp-type 5 redirect {mbl} {
603     get-for icmp-redirect
604     get code enum 0 255 0.4
605     get gateway v4addr
606     get data rand 0 [expr {$mbl-4}] 1
607     assemble body {
608    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
609    |                 Gateway                                       |
610    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
611    |     Data ...                                                  |
612    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
613     }
614     return [list $body $code]
615 }
616
617 define icmp-redirect-code 0 net {} {}
618 define icmp-redirect-code 1 host {} {}
619 define icmp-redirect-code 2 net+tos {} {}
620 define icmp-redirect-code 3 host+tos {} {}
621
622 define icmp-type 8 ping {mbl} { icmp-echo $mbl }
623 define icmp-type 0 pong {mbl} { icmp-echo $mbl }
624 proc icmp-echo {mbl} {
625     get-for icmp-echo
626     get code enum 0 255 0.4
627     get id hex 0 0xffff
628     get seq hex 0 0xffff
629     get data rand 0 [expr {$mbl-8}] 1
630     assemble body {
631    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
632    |       Id                      |        Seq                    |
633    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
634    |     Data ...                                                  |
635    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
636     }
637     return [list $body $code]
638 }
639 define icmp-echo-code 0 echo {} {}
640
641 define icmp-type 13 timestamp {mbl} { icmp-timestamp }
642 define icmp-type 14 timestampreply {mbl} { icmp-timestamp }
643 proc icmp-timestamp {} {
644     get-for icmp-timestamp
645     get code enum 0 255 0.4
646     get id hex 0 0xffff
647     get seq hex 0 0xffff
648     get originate ip-timestamp
649     get receive ip-timestamp
650     get transmit ip-timestamp
651     assemble body {
652    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
653    |           Id                  |        Seq                    |
654    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
655    |     Originate                                                 |
656    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
657    |     Receive                                                   |
658    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
659    |     Transmit                                                  |
660    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
661     }
662     return [list $body $code]
663 }
664 define icmp-timestamp-code 0 timestamp {} {}
665
666 define icmp-type 15 inforequest {mbl} { icmp-inforeq }
667 define icmp-type 16 inforeply {mbl} { icmp-inforeq }
668 proc icmp-inforeq {} {
669     get-for icmp-inforeq
670     get code enum 0 255 0.4
671     get id hex 0 0xffff
672     get seq hex 0 0xffff
673     assemble body {
674    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
675    |           Id                  |        Seq                    |
676    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
677     }
678     return [list $body $code]
679 }
680 define icmp-inforeq-code 0 timestamp {} {}
681
682 # MAYADD ICMP traceroute RFC1393
683 # MAYADD ICMP router discovery RFC1256
684
685
686 define ip-proto 4 ip {mtu} {
687     # RFC2003
688     get-for ip-ip
689     get source v4addr
690     get dest v4addr
691     gen_1_ip $mtu $source $dest
692 }
693
694
695 define ip-proto 2 igmp {mtu} {
696     get-for igmp
697     get type enum 0 255 0.5
698     get timeout number 0 255
699     get group v4addr
700     set checksum 0
701     set extra {}
702     assemble igmp {
703    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
704    |      Type     |   Timeout     |         ? Checksum            |
705    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
706    |                         Group                                 |
707    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
708    |                       ? Extra ...                             |
709    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
710     }
711
712     if {[choice-prob igmp-extra 0.3]} {
713         get extra rand 1 [expr {$mtu - [packet-len $igmp]}] 1
714         assembly-overwrite igmp extra $extra
715     }
716     
717     assembly-overwrite igmp checksum [packet-csum-ip $igmp]
718     return $igmp
719 }
720
721 define igmp-type 17 membquery {} {}
722 define igmp-type 16 membreport {} {}
723 define igmp-type 23 leavegroup {} {}
724 define igmp-type 18 membreport {} {}
725
726
727 define ip-proto 51 ah {mtu} {
728     # RFC1826
729     get-for ah
730     get next number 0 255
731     get reserved hex 0 0xffff
732     get spi hex32
733     get auth_data rand 0 [expr {$mtu-8 > 50 ? 50 : $mtu-8}] 4
734     set length [packet-len $auth_data]
735     assemble ah {
736      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
737      | Next          |   Length      |           RESERVED            |
738      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
739      |                    SPI                                        |
740      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
741      |                 Auth Data ...                                 |
742      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
743     }
744     get payload rand 0 [expr {$mtu - [packet-len $ah]}] 1
745     append ah $payload
746     return $ah
747 }
748
749 proc udp-rport {} {
750     get-for udp
751     get port enum-rand 0 0xffff
752     return $port
753 }
754
755 define ip-proto 17 udp {mtu} {
756     # RFC768
757     get-for udp
758
759     set csum_mode [choice-mult \
760             checksum_bad 0.10 \
761             checksum_none 0.20 \
762             checksum_good]
763
764     get style choice-mult \
765             request 0.15 \
766             reply 0.15 \
767             servers 0.20 \
768             random
769
770     if {"$style" != "random"} {
771         get port enum-def
772         set def_port $port
773     } else {
774         set def_port x
775     }
776     switch -exact $style {
777         random  { set source_port [udp-rport]; set dest_port [udp-rport] }
778         request { set source_port [udp-rport]; set dest_port $def_port   }
779         reply   { set source_port $def_port;   set dest_port [udp-rport] }
780         servers { set source_port $def_port;   set dest_port $def_port   }
781     }
782
783     if {"$style" != "random"} {
784         set port $def_port
785         set data [depending-on udp port $mtu -8 $style]
786     } else {
787         get data rand 0 [expr {$mtu-8}] 1
788     }
789
790     set length 0
791     set checksum 0
792     assemble udp {
793    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
794    |       Source Port             |        Dest Port              |
795    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
796    |       ? Length                |      ? Checksum               |
797    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
798    |     Data ...                                                  |
799    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
800     }
801     set udp_length [packet-len $udp]
802     assembly-overwrite udp length $udp_length
803
804     if {"$csum_mode" == "checksum_none"} {
805         set checksum 0
806         getlog (nocsum)
807     } else {
808         global ip_source ip_dest ip_proto
809         assemble pseudo {
810    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
811    |       IP Source                                               |
812    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
813    |       IP Dest                                                 |
814    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
815    |       0       | IP Proto      |        UDP length             |
816    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
817         }
818         set checksum [packet-csum-ip "$pseudo$udp"]
819         if {!$checksum} { set checksum 0xffff }
820         if {"$csum_mode" == "checksum_bad"} {
821             get csumerror hex 1 0xffff
822             set checksum [expr {$checksum ^ $csumerror}]
823         }
824     }
825     assembly-overwrite udp checksum $checksum
826     return $udp
827 }
828
829 define udp-port 50 remailck {mtu style} {
830     # RFC1339
831     get-for remailck
832     if {"$style" == "request"} {
833         get what choice-mult \
834                 req-baduser 0.15 \
835                 req-auth 0.15 \
836                 resp-ok 0.15 \
837                 resp-auth 0.15 \
838                 req-user
839     } else {
840         get what choice-mult \
841                 req-baduser 0.15 \
842                 req-auth 0.15 \
843                 resp-auth 0.15 \
844                 req-user 0.15 \
845                 resp-ok
846     }
847     switch -exact $what {
848         req-user {
849             set auth 0
850             get user string 1 8 \
851                     abcdefghijklmnopqrustuvwxyz \
852                     abcdefghijklmnopqrustuvwxyz-0123456789_
853         }
854         req-baduser {
855             set auth 0
856             get user rand 0 [expr {$mtu - 4}] 1
857         }
858         req-auth {
859             get auth enum 0 31 0.5
860             set user [depending-on remailck auth $mtu -4]
861         }
862         resp-auth {
863             get auth hex 0 0xffff
864             set modified 0
865             set read 0
866         }
867         resp-ok {
868             get mail choice-mult \
869                     newmail 0.15 \
870                     oldmail 0.15 \
871                     nomail 0.20 \
872                     times
873             set auth 0
874             switch -exact $mail {
875                 newmail {
876                     set modified 0
877                     set read 1
878                 }
879                 oldmail {
880                     set modified 1
881                     set read 0
882                 }
883                 nomail {
884                     set modified 0
885                     set read 0
886                 }
887                 times {
888                     get modified number 1 600
889                     get read number 1 600
890                 }
891                 default { error "mail? $mail" }
892             }
893         }
894         default { error "what? $what" }
895     }
896     switch -glob $what {
897         req-* {
898             assemble payload {
899    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
900    |         Auth                                                  |
901    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
902    |     User ...                                                  |
903    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
904             }
905         }
906         resp-* {
907             assemble payload {
908    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
909    |         Auth                                                  |
910    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
911    |         Modified                                              |
912    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
913    |         Read                                                  |
914    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
915             }
916         }
917         default { error "what?? $what" }
918     }
919     return $payload
920 }
921
922 define remailck-auth 31 passwd {mtu} {
923     get-for remailck-passwd
924     get passwd string 6 8 \
925             0123456789abcdefghijklmnopqrstuvxwyz \
926             0123456789abcdefghijklmnopqrstuvxwyz
927     return $passwd
928 }
929
930 define udp-port 67 dhcpserv {mtu style} { return [dhcp $mtu] }
931 define udp-port 68 dhcpclient {mtu style} { return [dhcp $mtu] }
932 proc dhcp {mtu} {
933     get-for dhcp
934     get op enum 0 255 0.2
935     get htype enum 0 255 0.2
936     set hlen 6
937     get hops number 0 255
938     get xid hex32
939     get secs number 0 300
940     get flags hex 0 255
941     get ciaddr v4addr
942     get yiaddr v4addr
943     get siaddr v4addr
944     get giaddr v4addr
945     set chaddr [random-bytes 16]
946     get sname ntstring 0 64 \
947             0123456789abcdefghijklmnopqrstuvwxyz \
948             0123456789abcdefghijklmnopqrstuvwxyz.-+
949     get file ntstring 0 128 / \
950             0123456789abcdefghijklmnopqrstuvwxyz.-+/_
951
952     assemble dhcp {
953    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
954    |     op        |   htype       |   hlen        |   hops        |
955    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
956    |                            xid                                |
957    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
958    |           secs                |           flags               |
959    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
960    |                          ciaddr                               |
961    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
962    |                          yiaddr                               |
963    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
964    |                          siaddr                               |
965    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
966    |                          giaddr                               |
967    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
968     }
969     append dhcp $chaddr $sname $file
970
971     return $dhcp
972 }
973 define dhcp-op 1 request {} {}
974 define dhcp-op 2 reply {} {}
975 define dhcp-htype 1 ethernet {} {}
976
977
978 define ip-proto 6 tcp {mtu} {
979     # RFC793
980     get-for tcp
981
982     get source_port number 0 65535
983     get dest_port number 0 65535
984     get event choice-mult \
985             connect 0.15 \
986             accept 0.15 \
987             close 0.15 \
988             reset 0.15 \
989             weird 0.15 \
990             data
991     set s 0
992     set a 1
993     set f 0
994     set r 0
995     switch -exact $event {
996         connect { set s 1; set a 0 }
997         accept { set s 1 }
998         close { set f 1 }
999         reset { set a 0; set r 1 }
1000         data { }
1001         weird {
1002             get s flag 0.5
1003             get a flag 0.5
1004             get f flag 0.5
1005             get r flag 0.5
1006         }
1007         default { error "event? $event" }
1008     }
1009     get seq hex32
1010     get ack hex32
1011     if {[choice-prob tcp-smallwindow 0.7]} {
1012         get window number 0 1
1013     } else {
1014         get window hex 0 0xffff
1015     }
1016     get p flag 0.5
1017     get u flag 0.3
1018     get urg hex 0 0xffff
1019
1020     set options {}
1021     get optmode choice-mult badopt 0.3 opt 0.3 noopt
1022     switch -exact $optmode {
1023         noopt { }
1024         badopt {
1025             get options rand 1 60 1
1026         }
1027         opt {
1028             set nooi 1
1029             while {$nooi || [choice-prob tcp-opts-more 0.4]} {
1030                 set nooi 0
1031                 get opt enum 1 255 0.5
1032                 if {$opt == 1} {
1033                     assemble option {
1034    +-+-+-+-+-+-+-+-+
1035    |  Opt          |
1036    +-+-+-+-+-+-+-+-+
1037                     }
1038                 } else {
1039                     set data [depending-on tcp opt 6 0]
1040                     set option_len 0
1041                     assemble option {
1042    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1043    |  Opt          | ? Option Len  |
1044    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1045    |      Data ...                 |
1046    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1047                     }
1048                     assembly-overwrite option option_len [packet-len $option]
1049                 }
1050                 append options $option
1051             }
1052         }
1053     }
1054
1055     if {[choice-prob reserved-nonzero 0.25]} {
1056         get reserved hex 0 0x3f
1057     } else {
1058         set reserved 0
1059     }
1060
1061     if {[packet-len $options] % 4 || [get optxpad choice 0.15]} {
1062         if {"$optmode" != "badopt"} { append options 00 }
1063         set padlen [expr {3 - ([packet-len $options] + 3) % 4}]
1064         append options [random-bytes $padlen]
1065     }
1066
1067     set d_off 0
1068     set checksum 0
1069     assemble packet {
1070    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1071    |          Source Port          |       Dest Port               |
1072    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1073    |                        Seq                                    |
1074    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1075    |                    Ack                                        |
1076    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1077    |? D Off| Reserved  |U|A|P|R|S|F|            Window             |
1078    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1079    |         ? Checksum            |         Urg                   |
1080    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1081    |                    Options     ...                            |
1082    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1083     }
1084
1085     set d_off [expr {([packet-len $packet]/4) & 0x0f}]
1086     assembly-overwrite packet d_off $d_off
1087
1088     if {!($s || $r) || [get unexpdata flag 0.2]} {
1089         get data rand 0 [expr {$mtu - [packet-len $packet]}] 1
1090         append packet $data
1091     }
1092     set tcp_length [packet-len $packet]
1093
1094     global ip_source ip_dest ip_proto
1095     assemble pseudo {
1096    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1097    |       IP Source                                               |
1098    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1099    |       IP Dest                                                 |
1100    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1101    |       0       | IP Proto      |        TCP length             |
1102    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1103     }
1104
1105     set csum [packet-csum-ip "$pseudo$packet"]
1106     if {[choice-prob tcp-badcsum 0.1]} {
1107         get csumerror hex 1 0xffff
1108         set csum [expr {$csum ^ $csumerror}]
1109     }
1110     assembly-overwrite packet checksum $csum
1111     return $packet
1112 }
1113
1114 define tcp-opt 2 mss {mdl} {
1115     get-for tcp-opt
1116     get mss hex 0 0xffff
1117     assemble od {
1118    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1119    |        MSS                    |
1120    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1121     }
1122     return $od
1123 }
1124
1125
1126 namespace eval PCap {
1127     namespace export pcap_open pcap_write pcap_write_raw pcap_close
1128
1129     proc pcap_open {fn} {
1130         variable fh
1131         catch { close $fh }
1132         set fh [open $fn w]
1133         fconfigure $fh -translation binary
1134     }
1135
1136     proc pcap_close {} {
1137         variable fh
1138         if {![info exists fh]} return
1139         close $fh
1140         unset fh
1141     }
1142
1143     proc pcap_write_raw {packet} {
1144         variable fh
1145         if {![info exists fh]} return
1146         puts -nonewline $fh [binary format H* $packet]
1147     }
1148
1149     proc pcap_write {valdeflist} {
1150         foreach {kind valvar} $valdeflist {
1151             if {![regexp {^([usx])([0-9]+)} $kind dummy mode bits]} {
1152                 error "unknown kind $kind for $valvar"
1153             }
1154             set value [uplevel 1 [list set $valvar]]
1155             if {$bits % 8} { error "bits must be mult 8 in $kind for $valvar" }
1156             if {"$mode" != "x"} {
1157                 set v {}
1158                 set ov $value
1159                 for {set i 0} {$i<$bits/8} {incr i} {
1160                     append v [format %02x [expr {$value & 0xff}]]
1161                     set value [expr {$value >> 8}]
1162                 }
1163                 if {$value != 0 && $value != -1} {
1164                     error "value $ov more than $bits bits (residue=$value)"
1165                 }
1166                 set value $v
1167             }
1168             if {[string length $value] != $bits/4} {
1169                 error "$valvar value $value wrong length, not $bits bits"
1170             }
1171             pcap_write_raw $value
1172         }
1173     }
1174 }
1175 namespace import PCap::*
1176
1177 proc emit {seed} {
1178     global getlog_log errorInfo mtu fake_time_t
1179     global minframelen linktypename
1180
1181     get-for ip
1182     get-config source 127.0.0.1 v4addr
1183     get-config dest 127.0.0.1 v4addr
1184
1185     if {[catch {
1186         start_gen $seed
1187         set packet [gen_1_ip $mtu $source $dest]
1188         puts stdout "[format %6s $seed] $getlog_log\n       $packet"
1189     } emsg]} {
1190         puts stderr "\nERROR\n$seed\n\n$emsg\n\n$errorInfo\n\n"
1191         puts stdout "[format %6s $seed] error"
1192     } else {
1193         set ts_sec [incr fake_time_t]
1194         set ts_usec 0
1195
1196         set l [packet-len $packet]
1197         if {$l < $minframelen} {
1198             append packet [string repeat 00 [expr {$minframelen - $l}]]
1199         }
1200
1201         set llpkt [link/$linktypename/linkencap $packet]
1202         
1203         set len [packet-len "$llpkt"]
1204         pcap_write {
1205             u32 ts_sec
1206             u32 ts_usec
1207             u32 len
1208             u32 len
1209         }
1210         pcap_write_raw $llpkt
1211     }
1212 }
1213
1214
1215 # link/ether - RFC894
1216 proc link/ether/linkparams {} { return {1 46} }
1217 proc link/ether/defaddr {} { return 00:00:00:00:00:00 }
1218 proc link/ether/procaddr {input sd} {
1219     set v [string tolower $input]
1220     if {[regexp {^([0-9a-f]{2}\:){5}[0-9a-f]{2}$} $v]} {
1221         set v [string map {: {}} $v]
1222     }
1223     if {![regexp -nocase {^[0-9]{12}$} $v]} {
1224         error "invalid $sd ethernet addr $input ($v)"
1225     }
1226     return $v
1227 }
1228 proc link/ether/linkencap {packet} {
1229     global link_source link_dest
1230     set llpkt {}
1231     append llpkt $link_source $link_dest 0800
1232     append llpkt $packet
1233     return $llpkt
1234 }
1235
1236
1237 proc nextarg {} {
1238     global argv
1239     if {![llength $argv]} { error "need another arg" }
1240     set a [lindex $argv 0]
1241     set argv [lrange $argv 1 end]
1242     return $a
1243 }
1244
1245 proc nextarg_num {} { return [expr {[nextarg] + 0}] }
1246 proc nextarg_il {} {
1247     set a [nextarg]
1248     if {![regexp -nocase {^([0-9.]+)/([0-9a-f:]+)$} $a dummy i l]} {
1249         error "--source/--dest needs <ip-addr>/<link-addr>"
1250     }
1251     return [list $i [string map {: {}} $l]]
1252 }
1253
1254 set debug_level 0
1255 set mtu 576
1256 set upto {}
1257 set xseed {}
1258 set linktypename ether
1259 while {[regexp {^\-\-} [lindex $argv 0]]} {
1260     set o [nextarg]
1261     switch -exact -- $o {
1262         --infinite { set upto -1 }
1263         --debug { set debug_level [nextarg_num] }
1264         --upto { set upto [nextarg_num] }
1265         --write { pcap_open [nextarg] }
1266         --mtu { set mtu [nextarg_num] }
1267         --xseed { set xseed [nextarg] }
1268         --linktype { set linktypename [nextarg] }
1269         --source { manyset [nextarg_ih] config/ip-source config/link-source }
1270         --dest { manyset [nextarg_ih] config/ip-dest config/link-dest }
1271         default { error "bad option $o" }
1272     }
1273 }
1274
1275 proc process_linkaddr {sd} {
1276     global linktypename
1277     upvar #0 link_$sd l
1278     link/$linktypename/linktype
1279     get-for link
1280     get-config $sd [link/$linktypename/defaddr] linkaddr
1281     set l [link/$linktypename/procaddr [set $sd] $sd]
1282 }
1283
1284 manyset [link/$linktypename/linkparams] linktype minframelen
1285 process_linkaddr source
1286 process_linkaddr dest
1287
1288 set magic d4c3b2a1
1289 set version_major 2
1290 set version_minor 4
1291 set thiszone 0
1292 set sigfigs 0
1293 set snaplen 131073
1294
1295 pcap_write {
1296     x32 magic
1297     u16 version_major
1298     u16 version_minor
1299     s32 thiszone
1300     s32 sigfigs
1301     s32 snaplen
1302     s32 linktype
1303 }
1304
1305 set fake_time_t [clock seconds]
1306
1307 if {[llength $argv]} {
1308     foreach count $argv { emit "$xseed$count" }
1309 } else {
1310     if {![string length $upto]} { set upto 100 }
1311     for {set count 1} {$upto<0 || $count<=$upto} {incr count} {
1312         emit "$xseed$count"
1313     }
1314 }
1315
1316 pcap_close