chiark / gitweb /
stest: Move puts $argl into divert branches
[secnet.git] / stest / common.tcl
1 source test-common.tcl
2
3 package require Tclx
4
5 load chiark_tcl_hbytes-1.so
6 load chiark_tcl_dgram-1.so
7
8 set netlink(inside) {
9     local-address "172.18.232.9";
10     secnet-address "172.18.232.10";
11     remote-networks "172.18.232.0/28";
12 }
13 set netlink(outside) {
14     local-address "172.18.232.1";
15     secnet-address "172.18.232.2";
16     remote-networks "172.18.232.0/28";
17 }
18
19 set ports(inside) {16913 16910}
20 set ports(outside) 16900
21
22 set extra(inside) {
23     local-mobile True;
24     mtu-target 1260;
25 }
26 set extra(outside) {}
27
28 set privkey(inside) test-example/inside.privkeys/
29 set privkey(outside) test-example/outside.privkeys/
30
31 set initiator inside
32
33 proc sitesconf_hook {l} { return $l }
34
35 proc oldsecnet {site} {
36     upvar #0 oldsecnet($site) oldsecnet
37     expr {[info exists oldsecnet] && [set oldsecnet]}
38 }
39
40 proc mkconf {location site} {
41     global tmp
42     global builddir
43     global netlink
44     global ports
45     global extra
46     global netlinkfh
47     upvar #0 privkey($site) privkey
48     set pipefp $tmp/$site.netlink
49     foreach tr {t r} {
50         file delete $pipefp.$tr
51         exec mkfifo -m600 $pipefp.$tr
52         set netlinkfh($site.$tr) [set fh [open $pipefp.$tr r+]]
53         fconfigure $fh -blocking 0 -buffering none -translation binary
54     }
55     fileevent $netlinkfh($site.r) readable \
56         [list netlink-readable $location $site]
57     set fakeuf $tmp/$site.fake-userv
58     set fakeuh [open $fakeuf w 0755]
59     puts $fakeuh "#!/bin/sh
60 set -e
61 exec 3<&0
62 cat <&3 3<&- >$pipefp.r &
63 exec 3<>$pipefp.t
64 exec <$pipefp.t
65 exec 3<&-
66 exec cat
67 "
68     close $fakeuh
69     set cfg "
70         hash sha1;
71         netlink userv-ipif {
72             name \"netlink\";
73             userv-path \"$fakeuf\";
74         $netlink($site)
75             mtu 1400;
76             buffer sysbuffer(2048);
77             interface \"secnet-test-[string range $site 0 0]\";
78         };
79         comm
80 "
81     set delim {}
82     foreach port $ports($site) {
83         append cfg "$delim
84             udp {
85                 port $port;
86                 address \"::1\", \"127.0.0.1\";
87                 buffer sysbuffer(4096);
88             }
89         "
90         set delim ,
91     }
92     append cfg ";
93         local-name \"test-example/$location/$site\";
94 "
95     switch -glob $privkey {
96         */ {
97             set sitesconf sites.conf
98             append cfg "
99                 key-cache priv-cache({
100                     privkeys \"$builddir/${privkey}priv.\";
101                 });
102 "
103         }
104         {load-private *} {
105             set sitesconf sites-nonego.conf
106             append cfg "
107                 local-key load-private(\"[lindex $privkey 1]\",\"$builddir/[lindex $privkey 2]\");
108 "
109         }
110         * {
111             set sitesconf sites-nonego.conf
112             append cfg "
113                 local-key rsa-private(\"$builddir/$privkey\");
114 "
115         }
116     }
117     set sitesconf $builddir/test-example/$sitesconf
118     
119     append cfg $extra($site)
120     append cfg "
121         log logfile {
122             prefix \"$site\";
123             class \"debug\",\"info\",\"notice\",\"warning\",\"error\",\"security\",\"fatal\";
124     "
125     if {[oldsecnet $site]} { append cfg "
126             filename \"/dev/stderr\";
127     " }
128     append cfg "
129         };
130     "
131     append cfg {
132         system {
133         };
134         resolver adns {
135         };
136         log-events "all";
137         random randomfile("/dev/urandom",no);
138         transform eax-serpent { }, serpent256-cbc { };
139     }
140
141     set pubkeys $tmp/$site.pubkeys
142     file delete -force $pubkeys
143     exec cp -rl $builddir/test-example/pubkeys $pubkeys
144
145     set f [open $sitesconf r]
146     while {[gets $f l] >= 0} {
147         regsub {\"[^\"]*test-example/pubkeys/} $l "\"$pubkeys/" l
148         set l [sitesconf_hook $l]
149         append cfg $l "\n"
150     }
151     set sites [read $f]
152     close $f
153     append cfg $sites
154     append cfg {
155         sites map(site,all-sites);
156     }
157
158     return $cfg
159 }
160
161 proc spawn-secnet {location site} {
162     global tmp
163     global builddir
164     global netlinkfh
165     global env
166     global pidmap
167     global readbuf
168     upvar #0 pids($site) pid
169     set readbuf($site) {}
170     set cf $tmp/$site.conf
171     set ch [open $cf w]
172     puts $ch [mkconf $location $site]
173     close $ch
174     set secnet $builddir/secnet
175     if {[oldsecnet $site]} {
176         set secnet $env(OLD_SECNET_DIR)/secnet
177     }
178     set argl [list $secnet -dvnc $cf]
179     set divertk SECNET_STEST_DIVERT_$site
180     puts -nonewline "spawn"
181     foreach k [array names env] {
182         switch -glob $k {
183             SECNET_STEST_DIVERT_* -
184             SECNET_TEST_BUILDDIR - OLD_SECNET_DIR { }
185             *SECNET* -
186             *PRELOAD* { puts -nonewline " $k=$env($k)" }
187         }
188     }
189     if {[info exists env($divertk)]} {
190         switch -glob $env($divertk) {
191             i {
192                 puts " $argl"
193                 puts -nonewline "run ^ command, hit return "
194                 flush stdout
195                 gets stdin
196                 set argl {}
197             }
198             0 - "" {
199                 puts " $argl"
200             }
201             * {
202                 puts " $argl"
203                 set argl [split $env($divertk)]
204             }
205         }
206     }
207     if {[llength $argl]} { 
208         set pid [fork]
209         set pidmap($pid) "secnet $location/$site"
210         if {!$pid} {
211             execl [lindex $argl 0] [lrange $argl 1 end]
212         }
213     }
214     puts -nonewline $netlinkfh($site.t) [hbytes h2raw c0]
215 }
216
217 proc netlink-readable {location site} {
218     global ok
219     upvar #0 readbuf($site) buf
220     upvar #0 netlinkfh($site.r) fh
221     while 1 {
222         set x [read $fh]
223         set h [hbytes raw2h $x]
224         if {![hbytes length $h]} return
225         append buf $h
226         #puts "READABLE $site buf=$buf"
227         while {[regexp {^((?:..)*?)c0(.*)$} $buf dummy now buf]} {
228             #puts "READABLE $site now=$now (buf=$buf)"
229             regsub -all {^((?:..)*?)dbdc} $now {\1c0} now
230             regsub -all {^((?:..)*?)dbdd} $now {\1db} now
231             puts "netlink-got-packet $location $site $now"
232             netlink-got-packet $location $site $now
233         }
234     }
235 }
236
237 proc netlink-got-packet {location site data} {
238     global initiator
239     if {![hbytes length $data]} return 
240     switch -exact $site!$initiator {
241         inside!inside - outside!outside {
242             switch -glob $data {
243                 45000054ed9d4000fe0166d9ac12e802ac12e80900* {
244                     puts "OK $data"
245                     finish 0
246                 }
247                 * {
248                     error "unexpected $site $data"
249                 }
250             }
251         }
252         default {
253             error "$site rx'd! (initiator $initiator)"
254         }
255     }
256 }
257
258 proc bgerror {message} {
259     global errorInfo errorCode
260     catch {
261         puts stderr "
262 ----------------------------------------
263 $errorInfo
264
265 $errorCode
266 $message
267 ----------------------------------------
268     "
269     }
270     finish 1
271 }
272
273 proc sendpkt {} {
274     global netlinkfh
275     global initiator
276     set p {
277         4500 0054 ed9d 4000 4001 24da ac12 e809
278         ac12 e802 0800 1de4 2d96 0001 f1d4 a05d
279         0000 0000 507f 0b00 0000 0000 1011 1213
280         1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
281         2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
282         3435 3637
283     }
284     puts -nonewline $netlinkfh($initiator.t) \
285         [hbytes h2raw c0[join $p ""]c0]
286 }
287
288 set socktmp $tmp/s
289 exec mkdir -p -m700 $socktmp
290 regsub {^(?!/|\./)} $socktmp {./} socktmp ;# dgram-socket wants ./ or /
291
292 proc prefix_preload {lib} { prefix_some_path LD_PRELOAD $lib }
293
294 set env(UDP_PRELOAD_DIR) $socktmp
295 prefix_preload $builddir/stest/udp-preload.so
296
297 proc finish {estatus} {
298     puts stderr "FINISHING $estatus"
299     signal default SIGCHLD
300     global pidmap
301     foreach pid [array names pidmap] {
302         kill KILL $pid
303     }
304     exit $estatus
305 }
306
307 proc reap {} {
308     global pidmap
309     #puts stderr REAPING
310     foreach pid [array names pidmap] {
311         set got [wait -nohang $pid]
312         if {![llength $got]} continue
313         set info $pidmap($pid)
314         unset pidmap($pid)
315         puts stderr "reaped $info: $got"
316         finish 1
317     }
318 }
319
320 signal -restart trap SIGCHLD { after idle reap }
321
322 proc udp-proxy {} {
323     global socktmp udpsock
324     set u $socktmp/udp
325     file delete $u
326     regsub {^(?!/)} $u {./} u
327     set udpsock [dgram-socket create $u]
328     dgram-socket on-receive $udpsock udp-relay
329 }
330
331 proc udp-relay {data src sock args} {
332     global udpsock socktmp
333     set headerlen [expr {52+1}]
334     set orgsrc $src
335
336     set dst [hbytes range $data 0 $headerlen]
337     regsub {(?:00)*$} $dst {} dst
338     set dst [hbytes h2raw $dst]
339
340     hbytes overwrite data 0 [hbytes zeroes $headerlen]
341     regsub {.*/} $src {} src
342     set srch [hbytes raw2h $src]
343     hbytes append srch 00
344     if {[catch {
345         if {[regexp {[^.,:0-9a-f]} $dst c]} { error "bad dst" }
346         if {[hbytes length $srch] > $headerlen} { error "src addr too long" }
347         hbytes overwrite data 0 $srch
348         dgram-socket transmit $udpsock $data $socktmp/$dst
349     } emsg]} {
350         puts stderr "$orgsrc -> $dst: $emsg"
351     }
352 }
353
354 proc adj-after {timeout args} {
355     upvar #0 env(SECNET_STEST_TIMEOUT_MUL) mul
356     if {[info exists mul]} { set timeout [expr {$timeout * $mul}] }
357     eval after $timeout $args
358 }
359
360 proc test-kex {} {
361     udp-proxy
362     spawn-secnet in inside
363     spawn-secnet out outside
364
365     adj-after 500 sendpkt
366     adj-after 1000 sendpkt
367     adj-after 5000 timed-out
368
369     vwait ok
370 }