1#!/usr/bin/wish
2
3proc check_callback {} {
4	global debug
5	if {$debug} {
6		puts stderr "."
7	}
8	check_closed
9	after 1000 check_callback
10}
11
12proc getout {} {
13	global client_fh server_fh
14
15	set delay 50
16	catch {flush $client_fh}
17	after $delay
18	catch {close $client_fh}
19	set client_fh ""
20	after $delay
21	catch {flush $server_fh}
22	after $delay
23	catch {close $server_fh}
24	set server_fh ""
25	after $delay
26
27	global bmesg_cnt
28	if [info exists bmesg_cnt] {
29		catch {tkwait window .bmesg$bmesg_cnt}
30	}
31	destroy .
32	exit
33}
34
35proc check_closed {} {
36	global got_connection debug
37	global client_fh server_fh
38
39	if {! $got_connection} {
40		return
41	}
42	if {$client_fh != ""} {
43		set ef ""
44		catch {set ef [eof $client_fh]}
45		if {$ef == 1} {
46			if {$debug} {
47				puts stderr "client_fh EOF"
48			}
49			getout
50		}
51	}
52	if {$server_fh != ""} {
53		set ef ""
54		catch {set ef [eof $server_fh]}
55		if {$ef == 1} {
56			if {$debug} {
57				puts stderr "server_fh EOF"
58			}
59			getout
60		}
61	}
62}
63
64proc xfer_in_to_out {} {
65	global client_fh server_fh debug do_bridge
66	if {$client_fh != "" && ![eof $client_fh]} {
67		set ef ""
68		catch {set ef [eof $client_fh]}
69		if {$ef == 0} {
70			set str ""
71			catch {set str [read $client_fh 4096]}
72			if {$debug} {
73				#puts stderr "xfer_in_to_out: $str"
74				puts stderr "xfer_in_to_out: [string length $str]"
75			}
76			if {$server_fh != "" && $str != ""} {
77				catch {puts -nonewline $server_fh $str}
78				catch {flush $server_fh}
79			}
80		}
81	}
82	check_closed
83}
84
85proc xfer_out_to_in {} {
86	global client_fh server_fh debug do_bridge
87	if {$server_fh != ""} {
88		set ef ""
89		catch {set ef [eof $server_fh]}
90		if {$ef == 0} {
91			set str ""
92			catch {set str [read $server_fh 4096]}
93			if {$debug} {
94				#puts stderr "xfer_out_to_in: $str"
95				puts stderr "xfer_out_to_in: [string length $str]"
96			}
97			if {$client_fh != "" && $str != ""} {
98				catch {puts -nonewline $client_fh $str}
99				catch {flush $client_fh}
100			}
101		}
102	}
103	check_closed
104}
105
106proc bmesg {msg} {
107	global env
108	if {! [info exists env(BMESG)]} {
109		return
110	}
111	if {$env(BMESG) == 0} {
112		return
113	}
114
115	global bmesg_cnt
116	if {! [info exists bmesg_cnt]} {
117		set bmesg_cnt 0
118	}
119	incr bmesg_cnt
120	set w .bmesg$bmesg_cnt
121	catch {destroy $w}
122	toplevel $w
123	label $w.l -width 70 -text "$msg"
124	pack $w.l
125	update
126	if {$env(BMESG) > 1} {
127		for {set i 0} {$i < $env(BMESG)} {incr i} {
128			after 1000
129			update
130		}
131	}
132}
133
134proc do_connect_http {sock hostport which} {
135	global debug cur_proxy
136	set con ""
137	append con "CONNECT $hostport HTTP/1.1\r\n"
138	append con "Host: $hostport\r\n"
139	append con "Connection: close\r\n\r\n"
140
141	puts stderr "pxy=$which CONNECT $hostport HTTP/1.1 via $cur_proxy"
142	bmesg "H: $which CONNECT $hostport HTTP/1.1 $cur_proxy";
143
144	puts -nonewline $sock $con
145	flush $sock
146
147	set r ""
148	set cnt 0
149	while {1} {
150		incr cnt
151		set c [read $sock 1]
152		if {$c == ""} {
153			check_closed
154			after 20
155		}
156		append r $c
157		if {[regexp "\r\n\r\n" $r] || [regexp "a--no--\n\n" $r]} {
158			break
159		}
160		if {$cnt > 30000} {
161			break
162		}
163	}
164	if {! [regexp {HTTP/.* 200} $r]} {
165		puts stderr "did not find HTTP 200 #1"
166		destroy .
167		exit 1
168	}
169}
170
171proc do_connect_socks4 {sock hostport which} {
172	global debug cur_proxy
173
174	set host ""
175	set port ""
176	if [regexp {^(.*):([0-9][0-9]*)$} $hostport mvar host port] {
177		;
178	} else {
179		puts stderr "could not parse host:port $hostport"
180		destroy .
181		exit 1
182	}
183
184	set i1 ""
185	set i2 ""
186	set i3 ""
187	set i4 ""
188
189	set socks4a 0
190
191	if {$host == "localhost" || $host == "127.0.0.1"} {
192		set i1 127
193		set i2 0
194		set i3 0
195		set i4 1
196
197	} elseif [regexp {^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$} $host] {
198		set n [split $host "."]
199		set i1 [lindex $n 0]
200		set i2 [lindex $n 1]
201		set i3 [lindex $n 2]
202		set i4 [lindex $n 3]
203	} else {
204		set i1 0
205		set i2 0
206		set i3 0
207		set i4 3
208
209		set socks4a 1
210	}
211
212	if {$socks4a} {
213		puts stderr "pxy=$which socks4a connection to $host:$port via $cur_proxy"
214	} else {
215		puts stderr "pxy=$which socks4  connection to $host:$port via $cur_proxy"
216	}
217
218	set p1 [binary format ccScccc 4 1 $port $i1 $i2 $i3 $i4]
219	set p2 "nobody"
220	set p3 [binary format c 0]
221
222	puts -nonewline $sock $p1
223	puts -nonewline $sock $p2
224	puts -nonewline $sock $p3
225	if {$socks4a} {
226		puts -nonewline $sock $host
227		puts -nonewline $sock $p3
228	}
229	flush $sock
230
231	set r ""; set s ""; set i 0; set cnt 0
232	set ok 1
233	while {$cnt < 30000 && $i < 8} {
234		incr cnt
235		set c [read $sock 1]
236		if {$c == ""} {
237			check_closed
238			after 20
239			continue
240		}
241
242		binary scan $c c s
243		if {$i == 0 && $s != 0} {
244			puts stderr "socks4: $i - $s"
245			set ok 0
246		}
247		if {$i == 1 && $s != 90} {
248			puts stderr "socks4: $i - $s"
249			set ok 0
250		}
251		set r "$r,$s"
252		incr i
253	}
254	if {! $ok} {
255		puts stderr "socks4 failure: $r"
256		destroy .
257		exit 1
258	}
259}
260
261proc do_connect_socks5 {sock hostport which} {
262	global debug cur_proxy
263
264	set host ""
265	set port ""
266	if [regexp {^(.*):([0-9][0-9]*)$} $hostport mvar host port] {
267		;
268	} else {
269		puts stderr "could not parse host:port $hostport"
270		destroy .
271		exit 1
272	}
273
274	set p1 [binary format ccc 5 1 0]
275	puts -nonewline $sock $p1
276	flush $sock
277
278	set r ""; set s ""; set i 0; set cnt 0
279	set ok 1
280	while {$cnt < 30000 && $i < 2} {
281		incr cnt
282		set c [read $sock 1]
283		if {$c == ""} {
284			check_closed
285			after 20
286			continue
287		}
288
289		binary scan $c c s
290		if {$i == 0 && $s != 5} {
291			puts stderr "$i - $s"
292			set ok 0
293		}
294		if {$i == 1 && $s != 0} {
295			puts stderr "$i - $s"
296			set ok 0
297		}
298		set r "$r,$s"
299		incr i
300	}
301	if {! $ok} {
302		puts stderr "socks5 failure: $r"
303		destroy .
304		exit 1
305	}
306
307	set len [string length $host]
308	set p1 [binary format ccccc 5 1 0 3 $len]
309	set p2 $host
310
311	set n1 [expr int($port/256)]
312	set n2 [expr "$port - $n1 * 256"]
313	set p3 [binary format cc $n1 $n2]
314
315	puts stderr "pxy=$which socks5  connection to $host:$port via $cur_proxy"
316
317	puts -nonewline $sock $p1
318	puts -nonewline $sock $p2
319	puts -nonewline $sock $p3
320	flush $sock
321
322	set i1 ""; set i2 ""; set i3 ""; set i4 ""
323	set r ""; set s ""; set i 0; set cnt 0
324	set ok 1
325	while {$cnt < 30000 && $i < 4} {
326		incr cnt
327		set c [read $sock 1]
328		if {$c == ""} {
329			check_closed
330			after 20
331			continue
332		}
333
334		binary scan $c c s
335		if {$i == 0} {
336			set i1 $s
337		} elseif {$i == 1} {
338			set i2 $s
339		} elseif {$i == 2} {
340			set i3 $s
341		} elseif {$i == 3} {
342			set i4 $s
343		}
344		incr i
345	}
346	set r "i1=$i1,i2=$i2,i3=$i3,i4=$i4"
347
348	if {$i4 == 1} {
349		set n 6
350	} elseif {$i4 == 3} {
351		set c ""
352		for {set i 0} {$i < 1000} {incr i} {
353			set c [read $sock 1]
354			if {$c == ""} {
355				check_closed
356				after 20
357				continue
358			}
359			break;
360		}
361		if {$c == ""} {
362			puts stderr "socks5 failure c: $r"
363			destroy .
364			exit 1
365		}
366		binary scan $c c s
367		set n [expr $s + 2]
368	} elseif {$i4 == 4} {
369		set n 18
370	} else {
371		puts stderr "socks5 failure x: $r"
372		destroy .
373		exit 1
374	}
375	#puts "n=$n --- $r"
376
377	set i 0; set cnt 0
378	while {$cnt < 30000 && $i < $n} {
379		incr cnt
380		set c [read $sock 1]
381		if {$c == ""} {
382			check_closed
383			after 20
384			continue
385		}
386		incr i
387	}
388	if {$i1 != 5 || $i2 != 0 || $i3 != 0} {
389		puts stderr "socks failure $r"
390		destroy .
391		exit 1
392	}
393}
394
395proc do_connect_repeater {sock hostport which repeater} {
396	global debug cur_proxy
397
398	# 250 is UltraVNC buffer size.
399	set con [binary format a250 $repeater]
400
401	puts stderr "pxy=$which REPEATER $repeater via $cur_proxy"
402	bmesg "R: $which CONNECT $hostport | $repeater $cur_proxy";
403
404	puts -nonewline $sock $con
405	flush $sock
406
407	set r ""
408	set cnt 0
409	while {1} {
410		incr cnt
411		set c [read $sock 1]
412		if {$c == ""} {
413			check_closed
414			after 20
415		}
416		append r $c
417		if {[string length $r] >= 12} {
418			puts stderr "do_connect_repeater: $r"
419			break
420		}
421		if {$cnt > 30000} {
422			break
423		}
424	}
425}
426
427proc vread {n sock} {
428	set str ""
429	set max 3000
430	set dt 10
431	set i 0
432	set cnt 0
433	while {$cnt < $max && $i < $n} {
434		incr cnt
435		set c [read $sock 1]
436		if {$c == ""} {
437			check_closed
438			after $dt
439			continue
440		}
441		incr i
442		append str $c
443	}
444	if {$i != $n} {
445		puts stderr "vread failure $n  $i"
446		destroy .; exit 1
447	}
448	return $str
449}
450
451proc append_handshake {str} {
452	global env
453	if [info exists env(SSVNC_PREDIGESTED_HANDSHAKE)] {
454		set file $env(SSVNC_PREDIGESTED_HANDSHAKE)
455		set fh ""
456		catch {set fh [open $file a]}
457		if {$fh != ""} {
458			puts $fh $str
459			catch {close $fh}
460		}
461	}
462}
463
464proc vencrypt_bridge_connection {fh host port} {
465	puts stderr "vencrypt_bridge_connection: got connection $fh $host $port"
466	bmesg       "vencrypt_bridge_connection: got connection $fh $host $port"
467	global viewer_sock
468	set viewer_sock $fh
469}
470
471proc center_win {w} {
472	update
473	set W [winfo screenwidth  $w]
474	set W [expr $W + 1]
475	wm geometry $w +$W+0
476	update
477	set x [expr [winfo screenwidth  $w]/2 - [winfo width  $w]/2]
478	set y [expr [winfo screenheight $w]/2 - [winfo height $w]/2]
479
480	wm geometry $w +$x+$y
481	wm deiconify $w
482	update
483}
484
485
486proc get_user_pass {} {
487	global env
488	set up ""
489	if [info exists env(SSVNC_UNIXPW)] {
490		set rm 0
491		set up $env(SSVNC_UNIXPW)
492		if [regexp {^rm:} $up]  {
493			set rm 1
494			regsub {^rm:} $up "" up
495		}
496		if [file exists $up] {
497			set fh ""
498			set f $up
499			catch {set fh [open $up r]}
500			if {$fh != ""} {
501				gets $fh u
502				gets $fh p
503				catch {close $fh}
504				set up "$u@$p"
505			}
506			if {$rm} {
507				catch {file delete $f}
508			}
509		}
510	} elseif [info exists env(SSVNC_VENCRYPT_USERPASS)] {
511		set up $env(SSVNC_VENCRYPT_USERPASS)
512	}
513	if {$up != ""} {
514		return $up
515	}
516
517	toplevel .t
518	wm title .t {VeNCrypt Viewer Bridge User/Pass}
519
520	global user pass
521	set user ""
522	set pass ""
523	label .t.l -text {SSVNC VeNCrypt Viewer Bridge}
524
525	frame .t.f0
526	frame .t.f0.fL
527	label .t.f0.fL.la -text {Username: }
528	label .t.f0.fL.lb -text {Password: }
529
530	pack .t.f0.fL.la .t.f0.fL.lb -side top
531
532	frame .t.f0.fR
533	entry .t.f0.fR.ea -width 24 -textvariable user
534	entry .t.f0.fR.eb -width 24 -textvariable pass -show *
535
536	pack .t.f0.fR.ea .t.f0.fR.eb -side top -fill x
537
538	pack .t.f0.fL -side left
539	pack .t.f0.fR -side right -expand 1 -fill x
540
541	button .t.no -text Cancel -command {set user ""; set pass ""; destroy .t}
542	button .t.ok -text Done   -command {destroy .t}
543
544	center_win .t
545	pack .t.l .t.f0 .t.no .t.ok -side top -fill x
546	update
547	wm deiconify .t
548
549	bind .t.f0.fR.ea <Return> {focus .t.f0.fR.eb}
550	bind .t.f0.fR.eb <Return> {destroy .t}
551	focus .t.f0.fR.ea
552
553	wm resizable .t 1 0
554	wm minsize .t [winfo reqwidth .t] [winfo reqheight .t]
555
556	tkwait window .t
557	if {$user == "" || $pass == ""} {
558		return ""
559	} else {
560		return "$user@$pass"
561	}
562}
563
564proc do_vencrypt_viewer_bridge {listen connect} {
565	global env
566
567	#set env(BMESG) 1
568
569	vencrypt_constants
570
571	set backwards 0
572
573	if {! [info exists env(SSVNC_PREDIGESTED_HANDSHAKE)]} {
574		puts stderr "no SSVNC_PREDIGESTED_HANDSHAKE filename in environment."
575		destroy .; exit 1
576	}
577	set handshake $env(SSVNC_PREDIGESTED_HANDSHAKE)
578	bmesg $handshake
579
580	if {$listen < 0} {
581		set backwards 1
582		set listen [expr -$listen]
583	}
584
585	# listen on $listen
586	global viewer_sock
587	set viewer_sock ""
588	set lsock ""
589	set rc [catch {set lsock [socket -myaddr 127.0.0.1 -server vencrypt_bridge_connection $listen]}]
590	if {$rc != 0} {
591		puts stderr "error listening on 127.0.0.1:$listen"
592		destroy .; exit 1
593	}
594	bmesg "listen on $listen OK"
595
596	# accept
597	vwait viewer_sock
598	catch {close $lsock}
599	fconfigure $viewer_sock -translation binary -blocking 0
600
601	global got_connection
602	set got_connection 1
603
604	# connect to $connect
605	set server_sock ""
606	set rc [catch {set server_sock [socket 127.0.0.1 $connect]}]
607	if {$rc != 0} {
608		puts stderr "error connecting to 127.0.0.1:$connect"
609		destroy .; exit 1
610	}
611	bmesg "made connection to $connect"
612	fconfigure $server_sock -translation binary -blocking 0
613
614	if {$backwards} {
615		puts stderr "reversing roles of viewer and server"
616		set t $viewer_sock
617		set viewer_sock $server_sock
618		set server_sock $t
619	}
620
621	# wait for SSVNC_PREDIGESTED_HANDSHAKE "done", put in hash.
622	set dt 200
623	set slept 0
624	set maxwait 20000
625	set hs(mode) init
626	while {$slept < $maxwait} {
627		after $dt
628		set slept [expr $slept + $dt]
629		set done 0
630		set fh ""
631		catch {set fh [open $handshake r]}
632		set str ""
633		if {$fh != ""} {
634			array unset hs
635			while {[gets $fh line] > -1} {
636				set line [string trim $line]
637				set str "$str$line\n";
638				if {$line == "done"} {
639					set done 1
640				} elseif [regexp {=} $line] {
641					set s [split $line "="]
642					set key [lindex $s 0]
643					set val [lindex $s 1]
644					set hs($key) $val
645				}
646			}
647			catch {close $fh}
648		}
649		if {$done} {
650			puts stderr $str
651			bmesg "$str"
652			break
653		}
654	}
655
656	catch [file delete $handshake]
657
658	if {! [info exists hs(sectype)]} {
659		puts stderr "no hs(sectype) found"
660		destroy .; exit 1
661	}
662
663	# read viewer RFB
664	if {! [info exists hs(server)]} {
665		set hs(server) "RFB 003.008"
666	}
667	puts -nonewline $viewer_sock "$hs(server)\n"
668	flush $viewer_sock
669	puts stderr "sent $hs(server) to viewer sock."
670
671	set viewer_rfb [vread 12 $viewer_sock]
672	puts stderr "read viewer_rfb $viewer_rfb"
673
674	set viewer_major 3
675	set viewer_minor 8
676	if [regexp {^RFB 003\.0*([0-9][0-9]*)} $viewer_rfb m v] {
677		set viewer_minor $v
678	}
679
680	if {$hs(sectype) == $rfbSecTypeAnonTls} {
681		puts stderr "handling rfbSecTypeAnonTls"
682		if {$viewer_major > 3 || $viewer_minor >= 7} {
683			puts stderr "viewer >= 3.7, nothing to set up."
684		} else {
685			puts stderr "viewer <= 3.3, faking things up."
686			set t [vread 1 $server_sock]
687			binary scan $t c nsectypes
688			puts stderr "nsectypes=$nsectypes"
689			for {set i 0} {$i < $nsectypes} {incr i} {
690				set t [vread 1 $server_sock]
691				binary scan $t c st
692				puts stderr "   $i: $st"
693				set types($st) $i
694			}
695			set use 1
696			if [info exists types(1)] {
697				set use 1
698			} elseif [info exists types(2)] {
699				set use 2
700			} else {
701				puts stderr "no valid sectypes"
702				destroy .; exit 1
703			}
704			# this should be MSB:
705			vsend_uchar $viewer_sock 0
706			vsend_uchar $viewer_sock 0
707			vsend_uchar $viewer_sock 0
708			vsend_uchar $viewer_sock $use
709
710			vsend_uchar $server_sock $use
711			if {$use == 1} {
712				set t [vread 4 $server_sock]
713			}
714		}
715	} elseif {$hs(sectype) == $rfbSecTypeVencrypt} {
716		puts stderr "handling rfbSecTypeVencrypt"
717		if {! [info exists hs(subtype)]} {
718			puts stderr "no subtype"
719			destroy .; exit 1
720		}
721		set fake_type "None"
722		set plain 0
723
724		set sub_type $hs(subtype)
725
726
727		if {$sub_type == $rfbVencryptTlsNone} {
728			set fake_type "None"
729		} elseif {$sub_type == $rfbVencryptTlsVnc} {
730			set fake_type "VncAuth"
731		} elseif {$sub_type == $rfbVencryptTlsPlain} {
732			set fake_type "None"
733			set plain 1
734		} elseif {$sub_type == $rfbVencryptX509None} {
735			set fake_type "None"
736		} elseif {$sub_type == $rfbVencryptX509Vnc} {
737			set fake_type "VncAuth"
738		} elseif {$sub_type == $rfbVencryptX509Plain} {
739			set fake_type "None"
740			set plain 1
741		}
742
743		if {$plain} {
744			set up [get_user_pass]
745			if [regexp {@} $up] {
746				set user $up
747				set pass $up
748				regsub {@.*$}  $user "" user
749				regsub {^[^@]*@} $pass "" pass
750				vsend_uchar $server_sock 0
751				vsend_uchar $server_sock 0
752				vsend_uchar $server_sock 0
753				vsend_uchar $server_sock [string length $user]
754				vsend_uchar $server_sock 0
755				vsend_uchar $server_sock 0
756				vsend_uchar $server_sock 0
757				vsend_uchar $server_sock [string length $pass]
758				puts stderr "sending VencryptPlain user and pass."
759				puts -nonewline $server_sock $user
760				puts -nonewline $server_sock $pass
761				flush $server_sock
762			}
763		}
764		set ft 0
765		if {$fake_type == "None"} {
766			set ft 1
767		} elseif {$fake_type == "VncAuth"} {
768			set ft 2
769		} else {
770			puts stderr "no valid fake_type"
771			destroy .; exit 1
772		}
773
774		if {$viewer_major > 3 || $viewer_minor >= 7} {
775			vsend_uchar $viewer_sock 1
776			vsend_uchar $viewer_sock $ft
777			set t [vread 1 $viewer_sock]
778			binary scan $t c cr
779			if {$cr != $ft} {
780				puts stderr "client selected wront type $cr $ft"
781				destroy .; exit 1
782			}
783		} else {
784			puts stderr "viewer <= 3.3, faking things up."
785			# this should be MSB:
786			vsend_uchar $viewer_sock 0
787			vsend_uchar $viewer_sock 0
788			vsend_uchar $viewer_sock 0
789			vsend_uchar $viewer_sock $ft
790
791			if {$ft == 1} {
792				set t [vread 4 $server_sock]
793			}
794		}
795	}
796
797	global client_fh server_fh
798	set client_fh $viewer_sock
799	set server_fh $server_sock
800
801	fileevent $client_fh readable xfer_in_to_out
802	fileevent $server_fh readable xfer_out_to_in
803}
804
805proc vsend_uchar {sock n} {
806	set s [binary format c $n]
807	puts -nonewline $sock $s
808	flush $sock
809}
810
811proc vencrypt_constants {} {
812	uplevel {
813		set rfbSecTypeAnonTls  18
814		set rfbSecTypeVencrypt 19
815
816		set rfbVencryptPlain        256
817		set rfbVencryptTlsNone      257
818		set rfbVencryptTlsVnc       258
819		set rfbVencryptTlsPlain     259
820		set rfbVencryptX509None     260
821		set rfbVencryptX509Vnc      261
822		set rfbVencryptX509Plain    262
823	}
824}
825
826proc do_vencrypt {sock which} {
827
828	vencrypt_constants
829
830	set t [vread 1 $sock]
831	binary scan $t c vs_major
832	set t [vread 1 $sock]
833	binary scan $t c vs_minor
834
835	if {$vs_minor == "" || $vs_major == "" || $vs_major != 0 || $vs_minor < 2} {
836		puts stderr "vencrypt failure bad vs version major=$major minor=$minor"
837		destroy .; exit 1
838	}
839	puts stderr "server vencrypt version $vs_major.$vs_minor"
840	bmesg "server vencrypt version $vs_major.$vs_minor"
841
842	append_handshake "subversion=0.2"
843	vsend_uchar $sock 0
844	vsend_uchar $sock 2
845
846	set t [vread 1 $sock]
847	binary scan $t c result
848	if {$result != 0} {
849		puts stderr "vencrypt failed result: $result"
850		bmesg "vencrypt failed result: $result"
851		destroy .; exit 1
852	}
853
854	set t [vread 1 $sock]
855	binary scan $t c nsubtypes
856	puts stderr "nsubtypes: $nsubtypes"
857	bmesg "nsubtypes: $nsubtypes"
858
859	for {set i 0} {$i < $nsubtypes} {incr i} {
860		set t [vread 4 $sock]
861		binary scan $t I stype
862		puts stderr "subtypes: $i: $stype"
863		append_handshake "sst$i=$stype"
864		set subtypes($stype) $i
865	}
866
867	set subtype 0
868	if [info exists subtypes($rfbVencryptX509None)] {
869		set subtype $rfbVencryptX509None
870		puts stderr "selected rfbVencryptX509None"
871	} elseif [info exists subtypes($rfbVencryptX509Vnc)] {
872		set subtype $rfbVencryptX509Vnc
873		puts stderr "selected rfbVencryptX509Vnc"
874	} elseif [info exists subtypes($rfbVencryptX509Plain)] {
875		set subtype $rfbVencryptX509Plain
876		puts stderr "selected rfbVencryptX509Plain"
877	} elseif [info exists subtypes($rfbVencryptTlsNone)] {
878		set subtype $rfbVencryptTlsNone
879		puts stderr "selected rfbVencryptTlsNone"
880	} elseif [info exists subtypes($rfbVencryptTlsVnc)] {
881		set subtype $rfbVencryptTlsVnc
882		puts stderr "selected rfbVencryptTlsVnc"
883	} elseif [info exists subtypes($rfbVencryptTlsPlain)] {
884		set subtype $rfbVencryptTlsPlain
885		puts stderr "selected rfbVencryptTlsPlain"
886	}
887	append_handshake "subtype=$subtype"
888	set st [binary format I $subtype]
889	puts -nonewline $sock $st
890	flush $sock
891
892	if {$subtype == 0} {
893		puts stderr "vencrypt could not find an acceptable subtype: $subtype"
894		destroy .; exit 1
895	}
896
897	set t [vread 1 $sock]
898	binary scan $t c result
899	puts stderr "result=$result"
900
901	append_handshake "done"
902
903	if {$result == 0} {
904		puts stderr "vencrypt failure result: $result"
905		destroy .; exit 1
906	}
907
908}
909
910proc do_connect_vencrypt {sock hostport which} {
911	global debug cur_proxy
912
913	vencrypt_constants
914
915	puts stderr "pxy=$which vencrypt $hostport via $cur_proxy"
916	bmesg "V: $which vencrypt $hostport via $cur_proxy"
917
918	append_handshake "mode=connect"
919
920	set srfb [vread 12 $sock]
921	puts stderr "srfb: $srfb"
922	bmesg "srfb: $srfb"
923	set srfb [string trim $srfb]
924	append_handshake "server=$srfb"
925
926	set minor ""
927	if [regexp {^RFB 00[456]\.} $srfb] {
928		set minor 8
929	} elseif [regexp {^RFB 003\.0*([0-9][0-9]*)} $srfb mvar minor] {
930		;
931	}
932	if {$minor == "" || $minor < 7} {
933		puts stderr "vencrypt failure bad minor=$minor"
934		destroy .; exit 1
935	}
936
937	set vrfb "RFB 003.008\n"
938	if {$minor == 7} {
939		set vrfb "RFB 003.007\n"
940	}
941	puts -nonewline $sock $vrfb
942	flush $sock
943
944	set vrfb [string trim $vrfb]
945	append_handshake "viewer=$vrfb"
946	append_handshake "latency=0.10"
947
948	set str [vread 1 $sock]
949	binary scan $str c nsec
950	puts stderr "nsec: $nsec"
951	bmesg "nsec: $nsec"
952	for {set i 0} {$i < $nsec} {incr i} {
953		set str [vread 1 $sock]
954		binary scan $str c sec
955		puts stderr "sec: $sec"
956		bmesg "sec: $sec"
957		set sectypes($i) $sec
958	}
959	for {set i 0} {$i < $nsec} {incr i} {
960		if {$sectypes($i) == $rfbSecTypeVencrypt} {
961			append_handshake "sectype=$rfbSecTypeVencrypt"
962			vsend_uchar $sock $rfbSecTypeVencrypt
963			after 500
964			bmesg "do_vencrypt $sock $which"
965			do_vencrypt $sock $which
966			return
967		}
968	}
969	for {set i 0} {$i < $nsec} {incr i} {
970		if {$sectypes($i) == $rfbSecTypeAnonTls} {
971			append_handshake "sectype=$rfbSecTypeAnonTls"
972			vsend_uchar $sock $rfbSecTypeAnonTls
973			bmesg "rfbSecTypeAnonTls"
974			after 500
975			append_handshake "done"
976			return
977		}
978	}
979}
980
981proc do_connect {sock type hostport which} {
982	if {$type == "http"} 	{
983		do_connect_http $sock $hostport $which
984	} elseif {$type == "socks"} {
985		do_connect_socks4 $sock $hostport $which
986	} elseif {$type == "socks5"} {
987		do_connect_socks5 $sock $hostport $which
988	} elseif [regexp -nocase {^repeater:} $type] {
989		regsub -nocase {^repeater:} $type "" repeater
990		do_connect_repeater $sock $hostport $which $repeater
991	} elseif {$type == "vencrypt"} {
992		do_connect_vencrypt $sock $hostport $which
993	}
994}
995
996proc handle_connection {fh host port} {
997	global proxy1_host proxy1_port proxy1_type
998	global proxy2_host proxy2_port proxy2_type
999	global proxy3_host proxy3_port proxy3_type
1000	global proxy1 proxy2 proxy3 dest
1001	global debug cur_proxy
1002	global got_connection
1003
1004	if {$got_connection} {
1005		catch {close $fh}
1006		return
1007	}
1008	set got_connection 1
1009
1010	if {$debug} {
1011		puts stderr "connection from: $host $port"
1012		puts stderr "socket $proxy1_host $proxy1_port"
1013	}
1014
1015	set rc [catch {set sock [socket $proxy1_host $proxy1_port]}]
1016	if {$rc != 0} {
1017		puts stderr "error connecting"
1018		catch {close $sock}
1019		destroy .
1020		exit
1021	}
1022
1023	if {$debug} {
1024		puts stderr "got sock: $sock"
1025	}
1026
1027	global client_fh server_fh
1028	set client_fh $fh
1029	set server_fh $sock
1030
1031	fconfigure $fh   -translation binary -blocking 0
1032	fconfigure $sock -translation binary -blocking 0
1033
1034	set cur_proxy $proxy1
1035	if {$proxy2 != ""} {
1036		do_connect $sock $proxy1_type "$proxy2_host:$proxy2_port" 1
1037
1038		set cur_proxy $proxy2
1039		if {$proxy3 != ""} {
1040			do_connect $sock $proxy2_type "$proxy3_host:$proxy3_port" 2
1041
1042			set cur_proxy $proxy3
1043			do_connect $sock $proxy3_type $dest 3
1044
1045		} else {
1046			do_connect $sock $proxy2_type $dest 2
1047		}
1048	} else {
1049		do_connect $sock $proxy1_type $dest 1
1050	}
1051
1052	fileevent $fh   readable xfer_in_to_out
1053	fileevent $sock readable xfer_out_to_in
1054}
1055
1056proc proxy_type {proxy} {
1057	if [regexp -nocase {^socks://} $proxy] {
1058		return "socks"
1059	} elseif [regexp -nocase {^socks4://} $proxy] {
1060		return "socks"
1061	} elseif [regexp -nocase {^socks4a://} $proxy] {
1062		return "socks"
1063	} elseif [regexp -nocase {^socks5://} $proxy] {
1064		return "socks5"
1065	} elseif [regexp -nocase {^http://} $proxy] {
1066		return "http"
1067	} elseif [regexp -nocase {^https://} $proxy] {
1068		return "http"
1069	} elseif [regexp -nocase {^repeater://.*\+(.*)$} $proxy mat idstr] {
1070		return "repeater:$idstr"
1071	} elseif [regexp -nocase {^vencrypt://} $proxy] {
1072		return "vencrypt"
1073	} else {
1074		return "http"
1075	}
1076}
1077
1078proc proxy_hostport {proxy} {
1079	regsub -nocase {^[a-z][a-z0-9]*://} $proxy "" hp
1080	regsub {\+.*$} $hp "" hp
1081	if {! [regexp {:[0-9]} $hp] && [regexp {^repeater:} $proxy]} {
1082		set hp "$hp:5900"
1083	}
1084	return $hp
1085}
1086
1087proc setb {} {
1088	wm withdraw .
1089	catch {destroy .b}
1090	button .b -text "CONNECT_BR" -command {destroy .}
1091	pack .b
1092	after 1000 check_callback
1093}
1094
1095proc connect_br_sleep {} {
1096	global env
1097	if [info exists env(CONNECT_BR_SLEEP)] {
1098		if [regexp {^[0-9][0-9]*$} $env(CONNECT_BR_SLEEP)] {
1099			setb
1100			for {set i 0} {$i < $env(CONNECT_BR_SLEEP)} {incr i} {
1101				bmesg "$i sleep"
1102				after 1000
1103			}
1104		}
1105	}
1106}
1107
1108global env
1109
1110set got_connection 0
1111set proxy1 ""
1112set proxy2 ""
1113set proxy3 ""
1114set client_fh ""
1115set server_fh ""
1116set do_bridge 0
1117set debug 0
1118
1119if [info exists env(CONNECT_BR_DEBUG)] {
1120	set debug 1
1121}
1122
1123if [info exists env(SSVNC_VENCRYPT_VIEWER_BRIDGE)] {
1124	set s [split $env(SSVNC_VENCRYPT_VIEWER_BRIDGE) ","]
1125	set listen  [lindex $s 0]
1126	set connect [lindex $s 1]
1127
1128	setb
1129
1130	do_vencrypt_viewer_bridge $listen $connect
1131	set do_bridge 1
1132}
1133
1134if {$do_bridge} {
1135	;
1136} else {
1137	if {$debug && 0} {
1138		if {! [info exists env(SSVNC_DEST)]} {
1139			set env(SSVNC_DEST) "haystack:2037"
1140		}
1141		if {! [info exists env(SSVNC_PROXY)]} {
1142			set env(SSVNC_PROXY) "haystack:2037"
1143		}
1144		if {! [info exists env(SSVNC_LISTEN)]} {
1145			set env(SSVNC_LISTEN) "6789"
1146		}
1147	} else {
1148		if {! [info exists env(SSVNC_DEST)]} {
1149			destroy .; exit;
1150		}
1151		if {! [info exists env(SSVNC_PROXY)]} {
1152			destroy .; exit;
1153		}
1154		if {! [info exists env(SSVNC_LISTEN)] && ! [info exists env(SSVNC_REVERSE)]} {
1155			destroy .; exit;
1156		}
1157	}
1158
1159	#set env(BMESG) 1
1160
1161	set dest $env(SSVNC_DEST)
1162
1163	if [regexp {,} $env(SSVNC_PROXY)] {
1164		set s [split $env(SSVNC_PROXY) ","]
1165		set proxy1 [lindex $s 0]
1166		set proxy2 [lindex $s 1]
1167		set proxy3 [lindex $s 2]
1168	} else {
1169		set proxy1 $env(SSVNC_PROXY)
1170	}
1171
1172	set proxy1_type [proxy_type     $proxy1]
1173	set proxy1_hp   [proxy_hostport $proxy1]
1174
1175	set proxy1_host ""
1176	set proxy1_port ""
1177	if [regexp {^(.*):([0-9][0-9]*)$} $proxy1_hp mvar proxy1_host proxy1_port] {
1178		;
1179	} else {
1180		puts stderr "could not parse hp1 host:port $proxy1_hp"
1181		destroy .
1182		exit 1
1183	}
1184
1185	set proxy2_type ""
1186	set proxy2_host ""
1187	set proxy2_port ""
1188
1189	if {$proxy2 != ""} {
1190		set proxy2_type [proxy_type     $proxy2]
1191		set proxy2_hp   [proxy_hostport $proxy2]
1192
1193		set proxy2_host ""
1194		set proxy2_port ""
1195		if [regexp {^(.*):([0-9][0-9]*)$} $proxy2_hp mvar proxy2_host proxy2_port] {
1196			;
1197		} else {
1198			puts stderr "could not parse hp2 host:port $proxy2_hp"
1199			destroy .
1200			exit 1
1201		}
1202	}
1203
1204	set proxy3_type ""
1205	set proxy3_host ""
1206	set proxy3_port ""
1207
1208	if {$proxy3 != ""} {
1209		set proxy3_type [proxy_type     $proxy3]
1210		set proxy3_hp   [proxy_hostport $proxy3]
1211
1212		set proxy3_host ""
1213		set proxy3_port ""
1214		if [regexp {^(.*):([0-9][0-9]*)$} $proxy3_hp mvar proxy3_host proxy3_port] {
1215			;
1216		} else {
1217			puts stderr "could not parse hp3 host:port $proxy3_hp"
1218			destroy .
1219			exit 1
1220		}
1221	}
1222
1223	bmesg "1: '$proxy1_host' '$proxy1_port' '$proxy1_type'";
1224	bmesg "2: '$proxy2_host' '$proxy2_port' '$proxy2_type'";
1225	bmesg "3: '$proxy3_host' '$proxy3_port' '$proxy3_type'";
1226
1227	if [info exists env(SSVNC_REVERSE)] {
1228		set rhost ""
1229		set rport ""
1230		if [regexp {^(.*):([0-9][0-9]*)$} $env(SSVNC_REVERSE) mvar rhost rport] {
1231			;
1232		} else {
1233			puts stderr "could not parse SSVNC_REVERSE host:port $env(SSVNC_REVERSE)"
1234			destroy .
1235			exit 1
1236		}
1237		setb
1238		set rc [catch {set lsock [socket $rhost $rport]}]
1239		if {$rc != 0} {
1240			puts stderr "error reversing"
1241			bmesg "1 error reversing"
1242			after 2000
1243			set rc [catch {set lsock [socket $rhost $rport]}]
1244		}
1245		if {$rc != 0} {
1246			puts stderr "error reversing"
1247			bmesg "2 error reversing"
1248			after 2000
1249			set rc [catch {set lsock [socket $rhost $rport]}]
1250		}
1251		if {$rc != 0} {
1252			puts stderr "error reversing"
1253			bmesg "3 error reversing"
1254			destroy .; exit 1
1255		}
1256		puts stderr "SSVNC_REVERSE to $rhost $rport OK";
1257		bmesg "SSVNC_REVERSE to $rhost $rport OK";
1258		connect_br_sleep
1259		handle_connection $lsock $rhost $rport
1260	} else {
1261		set lport $env(SSVNC_LISTEN)
1262		connect_br_sleep
1263		set rc [catch {set lsock [socket -myaddr 127.0.0.1 -server handle_connection $lport]}]
1264		if {$rc != 0} {
1265			puts stderr "error listening"
1266			destroy .; exit 1
1267		}
1268		puts stderr "SSVNC_LISTEN on $lport OK";
1269		setb
1270	}
1271}
1272