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