File: common.tcl

package info (click to toggle)
secnet 0.6.8
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 1,956 kB
  • sloc: ansic: 15,234; python: 1,057; perl: 966; sh: 596; tcl: 484; java: 231; asm: 114; yacc: 89; php: 64; makefile: 48; awk: 40
file content (391 lines) | stat: -rw-r--r-- 9,026 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# This file is part of secnet.
# See LICENCE and this file CREDITS for full list of copyright holders.
# SPDX-License-Identifier: GPL-3.0-or-later
# There is NO WARRANTY.

source test-common.tcl

package require Tclx

load chiark_tcl_hbytes-1.so
load chiark_tcl_dgram-1.so

set netlink(inside) {
    local-address "172.18.232.9";
    secnet-address "172.18.232.10";
    remote-networks "172.18.232.0/28";
}
set netlink(outside) {
    local-address "172.18.232.1";
    secnet-address "172.18.232.2";
    remote-networks "172.18.232.0/28";
}

set ports(inside) {16913 16910}
set ports(outside) 16900

set defnet_v4 198.51.100
set defnet_v6 2001:db8:ff00
set defaddr_v4 ${defnet_v4}.1
set defaddr_v6 ${defnet_v6}::1

set extra(inside) {
    local-mobile True;
    mtu-target 1260;
}
set extra(outside) {}

set privkey(inside) test-example/inside.privkeys/
set privkey(outside) test-example/outside.privkeys/

set initiator inside

proc sitesconf_hook {l} { return $l }

proc oldsecnet {site} {
    upvar #0 oldsecnet($site) oldsecnet
    expr {[info exists oldsecnet] && [set oldsecnet]}
}

proc mkconf {location site} {
    global tmp
    global builddir
    global netlink
    global ports
    global extra
    global netlinkfh
    global defaddr_v4 defaddr_v6
    upvar #0 privkey($site) privkey
    set pipefp $tmp/$site.netlink
    foreach tr {t r} {
	file delete $pipefp.$tr
	exec mkfifo -m600 $pipefp.$tr
	set netlinkfh($site.$tr) [set fh [open $pipefp.$tr r+]]
	fconfigure $fh -blocking 0 -buffering none -translation binary
    }
    fileevent $netlinkfh($site.r) readable \
	[list netlink-readable $location $site]
    set fakeuf $tmp/$site.fake-userv
    set fakeuh [open $fakeuf w 0755]
    puts $fakeuh "#!/bin/sh
set -e
exec 3<&0
cat <&3 3<&- >$pipefp.r &
exec 3<>$pipefp.t
exec <$pipefp.t
exec 3<&-
exec cat
"
    close $fakeuh
    set cfg "
	hash sha1;
	netlink userv-ipif {
	    name \"netlink\";
            userv-path \"$fakeuf\";
	$netlink($site)
	    mtu 1400;
	    buffer sysbuffer(2048);
	    interface \"secnet-test-[string range $site 0 0]\";
        };
        comm
"
    set delim {}
    foreach port $ports($site) {
	append cfg "$delim
	    udp {
                port $port;
                address \"$defaddr_v6\", \"$defaddr_v4\";
		buffer sysbuffer(4096);
	    }
	"
        set delim ,
    }
    append cfg ";
	local-name \"test-example/$location/$site\";
"
    switch -glob $privkey {
	*/ {
	    set sitesconf sites.conf
	    append cfg "
	        key-cache priv-cache({
		    privkeys \"$builddir/${privkey}priv.\";
                });
"
	}
	{load-private *} {
	    set sitesconf sites-nonego.conf
	    append cfg "
		local-key load-private(\"[lindex $privkey 1]\",\"$builddir/[lindex $privkey 2]\");
"
	}
	* {
	    set sitesconf sites-nonego.conf
	    append cfg "
		local-key rsa-private(\"$builddir/$privkey\");
"
	}
    }
    set sitesconf $builddir/test-example/$sitesconf
    
    append cfg $extra($site)
    append cfg "
	log logfile {
	    prefix \"$site\";
	    class \"debug\",\"info\",\"notice\",\"warning\",\"error\",\"security\",\"fatal\";
    "
    if {[oldsecnet $site]} { append cfg "
	    filename \"/dev/stderr\";
    " }
    append cfg "
	};
    "
    append cfg {
	system {
	};
	resolver adns {
	};
	log-events "all";
	random randomfile("/dev/urandom",no);
	transform eax-serpent { }, serpent256-cbc { };
    }

    set pubkeys $tmp/$site.pubkeys
    file delete -force $pubkeys
    exec cp -rl $builddir/test-example/pubkeys $pubkeys

    set f [open $sitesconf r]
    while {[gets $f l] >= 0} {
	regsub {\"[^\"]*test-example/pubkeys/} $l "\"$pubkeys/" l
	regsub -all {\"\[127\.0\.0\.1\]\"} $l "\"\[$defaddr_v4\]\"" l
	regsub -all {\"\[::1]\"}           $l "\"\[$defaddr_v6\]\"" l
	set l [sitesconf_hook $l]
	append cfg $l "\n"
    }
    set sites [read $f]
    close $f
    append cfg $sites
    append cfg {
	sites map(site,all-sites);
    }

    return $cfg
}

proc spawn-secnet {location site} {
    global tmp
    global builddir
    global netlinkfh
    global env
    global pidmap
    global readbuf
    upvar #0 pids($site) pid
    set readbuf($site) {}
    set cf $tmp/$site.conf
    set ch [open $cf w]
    puts $ch [mkconf $location $site]
    close $ch
    set secnet $builddir/secnet
    if {[oldsecnet $site]} {
	set secnet $env(OLD_SECNET_DIR)/secnet
    }
    set argl [list $secnet -dvnc $cf]
    set divertk SECNET_STEST_DIVERT_$site
    set spawn_info "spawn:"
    foreach k [array names env] {
	switch -glob $k {
	    SECNET_STEST_DIVERT_* -
	    SECNET_TEST_BUILDDIR - OLD_SECNET_DIR { }
	    *SECNET* -
	    *PRELOAD* { append spawn_info " $k=$env($k)" }
	}
    }
    if {[info exists env($divertk)]} {
	set divert $env($divertk)
    } else {
	set divert {}
    }
    switch -glob $divert {
	i - {i *} {
	    regsub {^i} $divert {} divert_prefix
	    puts "$spawn_info $divert_prefix $argl"
	    puts -nonewline "run ^ command, hit return "
	    flush stdout
	    gets stdin
	    set argl {}
	}
	0 - "" {
	    puts "$spawn_info $argl"
	}
	/* - ./* {
	    puts "$spawn_info $argl"
	    set argl [split $divert]
	    puts "... $argl"
	}
	* {
	    error "$divertk not understood"
	}
    }
    if {[llength $argl]} { 
	set pid [fork]
	set pidmap($pid) "secnet $location/$site"
	if {!$pid} {
	    execl [lindex $argl 0] [lrange $argl 1 end]
	}
    }
    puts -nonewline $netlinkfh($site.t) [hbytes h2raw c0]
}

proc netlink-readable {location site} {
    global ok
    upvar #0 readbuf($site) buf
    upvar #0 netlinkfh($site.r) fh
    while 1 {
	set x [read $fh]
	set h [hbytes raw2h $x]
	if {![hbytes length $h]} return
	append buf $h
	#puts "READABLE $site buf=$buf"
	while {[regexp {^((?:..)*?)c0(.*)$} $buf dummy now buf]} {
	    #puts "READABLE $site now=$now (buf=$buf)"
	    regsub -all {^((?:..)*?)dbdc} $now {\1c0} now
	    regsub -all {^((?:..)*?)dbdd} $now {\1db} now
	    puts "netlink-got-packet $location $site $now"
	    netlink-got-packet $location $site $now
	}
    }
}

proc netlink-got-packet {location site data} {
    global initiator
    if {![hbytes length $data]} return 
    switch -exact $site!$initiator {
	inside!inside - outside!outside {
	    switch -glob $data {
		45000054ed9d4000fe0166d9ac12e802ac12e80900* {
		    puts "OK $data"
		    finish 0
		}
		* {
		    error "unexpected $site $data"
		}
	    }
	}
	default {
	    error "$site rx'd! (initiator $initiator)"
	}
    }
}

proc bgerror {message} {
    global errorInfo errorCode
    catch {
	puts stderr "
----------------------------------------
$errorInfo

$errorCode
$message
----------------------------------------
    "
    }
    finish 1
}

proc sendpkt {} {
    global netlinkfh
    global initiator
    set p {
        4500 0054 ed9d 4000 4001 24da ac12 e809
        ac12 e802 0800 1de4 2d96 0001 f1d4 a05d
        0000 0000 507f 0b00 0000 0000 1011 1213
        1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
        2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
        3435 3637
    }
    puts -nonewline $netlinkfh($initiator.t) \
	[hbytes h2raw c0[join $p ""]c0]
}

set socktmp $tmp/s
exec mkdir -p -m700 $socktmp
regsub {^(?!/|\./)} $socktmp {./} socktmp ;# dgram-socket wants ./ or /

proc prefix_preload {lib} { prefix_some_path LD_PRELOAD $lib }

set env(UDP_PRELOAD_DIR) $socktmp
prefix_preload $builddir/stest/udp-preload.so

proc finish {estatus} {
    puts stderr "FINISHING $estatus"
    signal default SIGCHLD
    global pidmap
    foreach pid [array names pidmap] {
	kill KILL $pid
    }
    exit $estatus
}

proc reap {} {
    global pidmap
    #puts stderr REAPING
    foreach pid [array names pidmap] {
	set got [wait -nohang $pid]
	if {![llength $got]} continue
	set info $pidmap($pid)
	unset pidmap($pid)
	puts stderr "reaped $info: $got"
	finish 1
    }
}

signal -restart trap SIGCHLD { after idle reap }

proc udp-proxy {} {
    global socktmp udpsock
    set u $socktmp/udp
    file delete $u
    regsub {^(?!/)} $u {./} u
    set udpsock [dgram-socket create $u]
    dgram-socket on-receive $udpsock udp-relay
}

proc udp-relay {data src sock args} {
    global udpsock socktmp
    set headerlen [expr {52+1}]
    set orgsrc $src

    set dst [hbytes range $data 0 $headerlen]
    regsub {(?:00)*$} $dst {} dst
    set dst [hbytes h2raw $dst]

    hbytes overwrite data 0 [hbytes zeroes $headerlen]
    regsub {.*/} $src {} src
    set srch [hbytes raw2h $src]
    hbytes append srch 00
    if {[catch {
	if {[regexp {[^.,:0-9a-f]} $dst c]} { error "bad dst" }
	if {[hbytes length $srch] > $headerlen} { error "src addr too long" }
	hbytes overwrite data 0 $srch
	dgram-socket transmit $udpsock $data $socktmp/$dst
    } emsg]} {
	puts stderr "$orgsrc -> $dst: $emsg"
    }
}

proc adj-after {timeout args} {
    upvar #0 env(SECNET_STEST_TIMEOUT_MUL) mul
    if {[info exists mul]} { set timeout [expr {$timeout * $mul}] }
    eval after $timeout $args
}

proc test-kex {} {
    udp-proxy
    spawn-secnet in inside
    spawn-secnet out outside

    adj-after 500 sendpkt
    adj-after 1000 sendpkt
    adj-after 5000 timed-out

    vwait ok
}