chiark / gitweb /
stest: Require SECNET_STEST_DIVERT_* paths to start / or ./
[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                 puts "... $argl"
205             }
206             * {
207                 error "$divertk not understood"
208             }
209         }
210     }
211     if {[llength $argl]} { 
212         set pid [fork]
213         set pidmap($pid) "secnet $location/$site"
214         if {!$pid} {
215             execl [lindex $argl 0] [lrange $argl 1 end]
216         }
217     }
218     puts -nonewline $netlinkfh($site.t) [hbytes h2raw c0]
219 }
220
221 proc netlink-readable {location site} {
222     global ok
223     upvar #0 readbuf($site) buf
224     upvar #0 netlinkfh($site.r) fh
225     while 1 {
226         set x [read $fh]
227         set h [hbytes raw2h $x]
228         if {![hbytes length $h]} return
229         append buf $h
230         #puts "READABLE $site buf=$buf"
231         while {[regexp {^((?:..)*?)c0(.*)$} $buf dummy now buf]} {
232             #puts "READABLE $site now=$now (buf=$buf)"
233             regsub -all {^((?:..)*?)dbdc} $now {\1c0} now
234             regsub -all {^((?:..)*?)dbdd} $now {\1db} now
235             puts "netlink-got-packet $location $site $now"
236             netlink-got-packet $location $site $now
237         }
238     }
239 }
240
241 proc netlink-got-packet {location site data} {
242     global initiator
243     if {![hbytes length $data]} return 
244     switch -exact $site!$initiator {
245         inside!inside - outside!outside {
246             switch -glob $data {
247                 45000054ed9d4000fe0166d9ac12e802ac12e80900* {
248                     puts "OK $data"
249                     finish 0
250                 }
251                 * {
252                     error "unexpected $site $data"
253                 }
254             }
255         }
256         default {
257             error "$site rx'd! (initiator $initiator)"
258         }
259     }
260 }
261
262 proc bgerror {message} {
263     global errorInfo errorCode
264     catch {
265         puts stderr "
266 ----------------------------------------
267 $errorInfo
268
269 $errorCode
270 $message
271 ----------------------------------------
272     "
273     }
274     finish 1
275 }
276
277 proc sendpkt {} {
278     global netlinkfh
279     global initiator
280     set p {
281         4500 0054 ed9d 4000 4001 24da ac12 e809
282         ac12 e802 0800 1de4 2d96 0001 f1d4 a05d
283         0000 0000 507f 0b00 0000 0000 1011 1213
284         1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
285         2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
286         3435 3637
287     }
288     puts -nonewline $netlinkfh($initiator.t) \
289         [hbytes h2raw c0[join $p ""]c0]
290 }
291
292 set socktmp $tmp/s
293 exec mkdir -p -m700 $socktmp
294 regsub {^(?!/|\./)} $socktmp {./} socktmp ;# dgram-socket wants ./ or /
295
296 proc prefix_preload {lib} { prefix_some_path LD_PRELOAD $lib }
297
298 set env(UDP_PRELOAD_DIR) $socktmp
299 prefix_preload $builddir/stest/udp-preload.so
300
301 proc finish {estatus} {
302     puts stderr "FINISHING $estatus"
303     signal default SIGCHLD
304     global pidmap
305     foreach pid [array names pidmap] {
306         kill KILL $pid
307     }
308     exit $estatus
309 }
310
311 proc reap {} {
312     global pidmap
313     #puts stderr REAPING
314     foreach pid [array names pidmap] {
315         set got [wait -nohang $pid]
316         if {![llength $got]} continue
317         set info $pidmap($pid)
318         unset pidmap($pid)
319         puts stderr "reaped $info: $got"
320         finish 1
321     }
322 }
323
324 signal -restart trap SIGCHLD { after idle reap }
325
326 proc udp-proxy {} {
327     global socktmp udpsock
328     set u $socktmp/udp
329     file delete $u
330     regsub {^(?!/)} $u {./} u
331     set udpsock [dgram-socket create $u]
332     dgram-socket on-receive $udpsock udp-relay
333 }
334
335 proc udp-relay {data src sock args} {
336     global udpsock socktmp
337     set headerlen [expr {52+1}]
338     set orgsrc $src
339
340     set dst [hbytes range $data 0 $headerlen]
341     regsub {(?:00)*$} $dst {} dst
342     set dst [hbytes h2raw $dst]
343
344     hbytes overwrite data 0 [hbytes zeroes $headerlen]
345     regsub {.*/} $src {} src
346     set srch [hbytes raw2h $src]
347     hbytes append srch 00
348     if {[catch {
349         if {[regexp {[^.,:0-9a-f]} $dst c]} { error "bad dst" }
350         if {[hbytes length $srch] > $headerlen} { error "src addr too long" }
351         hbytes overwrite data 0 $srch
352         dgram-socket transmit $udpsock $data $socktmp/$dst
353     } emsg]} {
354         puts stderr "$orgsrc -> $dst: $emsg"
355     }
356 }
357
358 proc adj-after {timeout args} {
359     upvar #0 env(SECNET_STEST_TIMEOUT_MUL) mul
360     if {[info exists mul]} { set timeout [expr {$timeout * $mul}] }
361     eval after $timeout $args
362 }
363
364 proc test-kex {} {
365     udp-proxy
366     spawn-secnet in inside
367     spawn-secnet out outside
368
369     adj-after 500 sendpkt
370     adj-after 1000 sendpkt
371     adj-after 5000 timed-out
372
373     vwait ok
374 }