#!/bin/sh
# restart using wish \
- exec wish8.0 $0 ${1+"$@"}
+exec wish $0 ${1+"$@"}
# sockspy: copyright tom poindexter 1998
+# sockspy: copyright Keith Vetter 2002
# tpoindex@nyx.net
# version 1.0 - december 10, 1998
-# version 2.0 - Keith Vetter keith@ebook.gemstar.com
-# reorganized GUI to be 1 pane with different colors
-# allow changing socket info
-# works both as GUI and command line interface
-#
+# version 2.0 - January, 2002 by Keith Vetter
+# KPV Nov 01, 2002 - added proxy mode
+#
# spy on conversation between a tcp client and server
#
# usage: sockspy clientPort serverHost serverPort
-# clientPort - port to which clients connect
-# serverHost - machine where real server runs
-# serverPort - port on which real server listens
+# -or- sockspy -proxy proxyPort
+# clientPort - port to which clients connect
+# serverHost - machine where real server runs
+# serverPort - port on which real server listens
#
# e.g. to snoop on http connections to a web server:
-# sockspy 8080 webhost 80
+# sockspy 8080 www.some.com 80
# then client web browser should use a url like:
# http://localhost:8080/index.html
# (or set your browser's proxy to use 8080 on the sockspy machine)
+catch {package require uri} ;# Error handled below
+
array set state {
+ version 2.3b
bbar 1
ascii 1
auto 1
playback ""
gui 0
listen ""
+ title "not connected"
+ proxy 0
+ fname ""
}
+array set SP {proxyPort 8080 clntPort 8080 servHost "" servPort 80}
+#set filters(client) {^(GET |POST |HEAD )}
+#set filters(server) {^(HTTP/|Location: )}
##+##########################################################################
#
# createMain
if {"$tcl_platform(platform)" == "windows"} {
doFont -1
}
- wm title . "sockspy"
+ wm title . "SockSpy"
wm resizable . 1 1
wm protocol . WM_DELETE_WINDOW Shutdown ;# So we shut down cleanly
. configure -menu .m
.m add cascade -menu .m.file -label "File" -underline 0
.m add cascade -menu .m.view -label "View" -underline 0
+ .m add cascade -menu .m.help -label "Help" -underline 0
menu .m.file -tearoff 0
.m.file add command -label "Save" -underline 0 -command saveOutput
.m.view add checkbutton -label " Autoscroll" -underline 5 \
-variable state(auto)
+ menu .m.help -tearoff 0
+ .m.help add command -label Help -underline 1 -command Help
+ .m.help add separator
+ .m.help add command -label About -command About
#
# Title and status window
#
pack .cmd -side top -fill x -pady 5 -in .bbar
frame .top
- pack .top -side top -fill x -pady 2 -expand 1
+ pack .top -side top -fill x -pady 2 -expand 0
#button .clear -text Clear -command clearOutput
#pack .clear -in .top -side right -padx 3
- label .title -relief ridge
+ label .title -relief ridge -textvariable state(title)
.title config -font "[.title cget -font] bold"
- .title config -text "localhost:$::clntPort <--> $::servHost:$::servPort"
pack .title -in .top -side left -fill both -expand 1
label .stat -textvariable state(msg) -relief ridge -anchor w
#
text .out -width 80 -height 50 -font $state(fixed) \
-yscrollcommand ".scroll set" -bg white -setgrid 1
- .out tag configure server -background cyan -borderwidth 2 -relief raised
- .out tag configure client -background green -borderwidth 2 -relief raised
+ .out tag configure server -background cyan -borderwidth 2 -relief raised \
+ -lmargin1 5 -lmargin2 5
+ .out tag configure client -background green -borderwidth 2 -relief raised \
+ -lmargin1 5 -lmargin2 5
.out tag configure client2 -font $state(fixedbold)
- .out tag configure meta -background red -borderwidth 2 -relief raised
+ .out tag configure meta -background red -borderwidth 2 -relief raised \
+ -lmargin1 5 -lmargin2 5
+ .out tag configure meta2 -background yellow -borderwidth 2 -relief raised \
+ -lmargin1 5 -lmargin2 5
scrollbar .scroll -orient vertical -command {.out yview}
pack .scroll -side right -fill y
pack .out -side left -fill both -expand 1
-
+ bind .out <Control-l> clearOutput
+ bind all <Alt-c> {console show}
+ focus .out
wm geometry . +10+10
}
##+##########################################################################
# its data source.
#
proc saveOutput {} {
- global state
-
- set but [tk_dialog .what "save" "save which window?" "" 2 \
- server client both cancel]
+ global state but
+
+ set but -1
+ after 1 {set but [tk_dialog .what "SockSpy Save" "Save which window?" \
+ questhead 2 server client both cancel]}
+ after 1 tk_dialogFIX
+ vwait but
+
if {$but == -1 || $but == 3} {
return
}
- set file [tk_getSaveFile -parent .]
- if {"$file" == ""} {
- return
- }
+ set file [tk_getSaveFile -parent . -initialfile $state(fname)]
+ if {$file == ""} return
+
+ set state(fname) $file
if {[catch {open $file w} fd]} {
tk_messageBox -message "file $file cannot be opened" -icon error \
-type ok
}
fconfigure $fd -translation binary
foreach {who data} $state(playback) {
- if {$who == "meta"} continue
+ if {$who == "meta" || $who == "meta2"} continue
if {$but == 2 || ($but == 0 && $who == "server") || \
($but == 1 && $who == "client")} {
puts $fd $data
}
##+##########################################################################
#
+# tk_dialogFIX
+#
+# tk_dialog is SOOO ugly. This is a bit of a hack to at least put
+# some padding around the buttons. This probably will break under
+# future versions hence the catch.
+#
+proc tk_dialogFIX {} {
+ for {set i 0} {$i < 5} {incr i} { ;# Don't do anything...
+ if {[winfo exists .what]} break ;# ...until window is mapped
+ after 200
+ }
+ catch {grid configure .what.button0 -pady 10}
+}
+##+##########################################################################
+#
# printable
#
# Replaces all unprintable characters into dots.
#
proc printable {s {spaces 0}} {
- regsub -all {[^\x20-\x7e]} $s "." n
+ regsub -all {[^\x09\x20-\x7e]} $s "." n
if {$spaces} {
regsub -all { } $n "_" n
}
#
proc insertData {who data} {
global state
- array set prefix {meta = client > server <}
-
+ array set prefix {meta = meta2 = client > server <}
+
+ set data [DoFilter $who $data]
+ if {$data == ""} return
lappend state(playback) $who $data ;# Save for redraw and saving
- if {$state(ascii) || [string equal $who meta]} {
+ if {$state(ascii) || [regexp {^meta2?$} $who] } {
regsub -all \r $data "" data
foreach line [split $data \n] {
set line [printable $line]
# Puts up an informational message both in the output window and
# in the status window.
#
-proc INFO {msg} {
+proc INFO {msg {who meta}} {
global state
set state(msg) $msg
- insertData meta $msg
+ insertData $who $msg
+}
+proc ERROR {emsg} {
+ if {$::state(gui)} {
+ tk_messageBox -title "SockSpy Error" -message $emsg -icon error
+ } else {
+ puts $emsg
+ }
+ exit
}
##+##########################################################################
#
INFO "waiting for new connection..."
return
}
+ if {$toSock == ""} { ;# Not connected yet
+ ProxyConnect $fromSock $data ;# Do proxy forwarding
+ } else {
+ catch { puts -nonewline $toSock $data } ;# Forward if we have a socket
+ }
insertData $who $data
- catch { puts -nonewline $toSock $data } ;# Forward if we have a socket
-
update
}
+proc ProxyConnect {fromSock data} {
+ set line1 [lindex [split $data \r] 0]
+ set bad [regexp -nocase {(http:[^ ]+)} $line1 => uri]
+ if {$bad == 0} {
+ INFO "ERROR: cannot extract URI from '$line1'"
+ close $fromSock
+ insertData meta "----- closed connection -----"
+ insertData meta "waiting for new connection..."
+ }
+ set state(uri) $uri ;# For debugging
+ array set URI [::uri::split $uri]
+ if {$URI(port) == ""} { set URI(port) 80 }
+ set bad [catch {set sockServ [socket $URI(host) $URI(port)]} reason]
+ if {$bad} {
+ set msg "cannot connect to $URI(host):$URI(port) => $reason"
+ INFO $msg
+ close $fromSock
+ insertData meta "----- closed connection -----"
+ insertData meta "waiting for new connection..."
+ tk_messageBox -icon error -type ok -message $msg
+ break
+ }
+ INFO "fowarding to $URI(host):$URI(port)" meta2
+ fileevent $fromSock readable \
+ [list sockReadable $fromSock $sockServ client]
+ fconfigure $sockServ -blocking 0 -buffering none -translation binary
+ fileevent $sockServ readable \
+ [list sockReadable $sockServ $fromSock server]
+ puts -nonewline $sockServ $data
+}
##+##########################################################################
#
# clntConnect
#
# Called when we get a new client connection
#
-proc clntConnect {servHost servPort sockClnt ip port} {
- global state
+proc clntConnect {sockClnt ip port} {
+ global state SP
set state(sockClnt) $sockClnt
+ set state(meta) ""
- INFO "connect from [fconfigure $sockClnt -sockname] $port"
- if {$servHost == {} || $servHost == "none"} {
+ INFO "connect from [fconfigure $sockClnt -sockname] $port" meta2
+ if {$state(proxy) || $SP(servHost) == {} || $SP(servHost) == "none"} {
set sockServ ""
- } elseif {[catch {set sockServ [socket $servHost $servPort]} reason]} {
- INFO "cannot connect: $reason"
- tk_messageBox -icon error -type ok \
- -message "cannot connect to $servHost $servPort: $reason"
- exit
+ } else {
+ set n [catch {set sockServ [socket $SP(servHost) $SP(servPort)]} reason]
+ if {$n} {
+ INFO "cannot connect: $reason"
+ ERROR "cannot connect to $servHost $servPort: $reason"
+ }
+ INFO "connecting to $SP(servHost):$SP(servPort)" meta2
}
;# Configure connection to the client
# it is already open.
#
proc DoListen {} {
- global state clntPort servHost servPort
+ global state SP
catch {close $state(sockClnt)} ;# Only the last open connection
update ;# Need else socket below fails
}
- set n [catch {set state(listen) \
- [socket -server [list clntConnect $servHost $servPort] $clntPort]} \
- emsg]
+ # Listen on clntPort or proxyPort for incoming connections
+ set port $SP(clntPort)
+ if {$state(proxy)} {set port $SP(proxyPort)}
+ set n [catch {set state(listen) [socket -server clntConnect $port]} emsg]
if {$n} {
INFO "socket open error: $emsg"
+ set state(title) "not connected"
+ return 0
} else {
- INFO "localhost:$clntPort <--> $servHost:$servPort"
+ if {$state(proxy)} {
+ set state(title) "proxy localhost:$SP(proxyPort)"
+ } else {
+ set state(title) "localhost:$SP(clntPort) <--> "
+ append state(title) "$SP(servHost):$SP(servPort)"
+ }
+ INFO $state(title)
INFO "waiting for new connection..."
}
+ return 1
}
##+##########################################################################
#
#
# Prompts the user for client port, server host and server port
#
-proc GetSetup {{connect 1}} {
- global state clntPort servHost servPort ok
- set save [list $clntPort $servHost $servPort]
+proc GetSetup {} {
+ global state SP ok
+ array set save [array get SP]
set ok 0 ;# Assume cancelling
;# Put in some default values
- if {![string length $clntPort]} {set clntPort 8080}
- if {![string length $servPort]} {set servPort 80}
+ if {![string length $SP(proxyPort)]} {set SP(proxyPort) 8080}
+ if {![string length $SP(clntPort)]} {set SP(clntPort) 8080}
+ if {![string length $SP(servPort)]} {set SP(servPort) 80}
if {! $state(gui)} {
catch {close $state(listen)}
-
- set clntPort [Prompt "Client port" $clntPort]
- set servHost [Prompt "Server host" $servHost]
- set servPort [Prompt "Server port" $servPort]
- if {$connect} DoListen
+
+ set d "no" ; if {$state(proxy)} { set d yes }
+ set p [Prompt "Proxy mode" $d]
+ if {[regexp -nocase {^y$|^yes$} $p]} {
+ set state(proxy) 1
+ set SP(proxyPort) [Prompt "proxy port" $SP(proxyPort)]
+ } else {
+ set state(proxy) 0
+ set SP(clntPort) [Prompt "Client port" $SP(clntPort)]
+ set SP(servHost) [Prompt "Server host" $SP(servHost)]
+ set SP(servPort) [Prompt "Server port" $SP(servPort)]
+ }
+ DoListen
return
}
- catch {destroy .dlg}
+ catch {destroy .dlg}
toplevel .dlg
- grab set .dlg
wm title .dlg "Sockspy Setup"
wm geom .dlg +176+176
- wm transient .dlg .
-
- frame .dlg.top -bd 2 -relief ridge
- pack .dlg.top -side top -pady 1m -padx .5m
- pack [frame .dlg.top.t] -side top -pady .5m
- pack [frame .dlg.top.b] -side bottom -pady .5m
-
- foreach {n txt var} {1 "Client Port:" clntPort
- 2 "Server Host:" servHost
- 3 "Server Port:" servPort} {
- set f .dlg.f$n
- pack [frame $f] -side top -fill x -expand 1 -in .dlg.top
- pack [frame $f.f] -side right -padx .5m
- label $f.l -text $txt -anchor e
- entry $f.e -textvariable $var
- pack $f.e $f.l -side right
- bind $f.e <Return> [list .dlg.okay invoke]
- }
+ #wm transient .dlg .
+
+ label .dlg.top -bd 2 -relief raised
+ set msg "You can configure SockSpy to either forward data\n"
+ append msg "a fixed server and port or to use the HTTP Proxy\n"
+ append msg "protocol to dynamically determine the server and\n"
+ append msg "port to forward data to."
- button .dlg.okay -text OK -command {
- if {[string length $clntPort] && [string length $servHost] && \
- [string length $servPort]} { set ok 1 ; destroy .dlg }
- }
-
- button .dlg.quit -text Cancel -command { destroy .dlg }
- pack .dlg.okay .dlg.quit -side left -expand 1 -pady 2
- focus .dlg.f1.e
- .dlg.f1.e icursor end
+ #labelframe .dlg.fforward -text "Fixed Server Forwarding"
+ #labelframe .dlg.fproxy -text "HTTP Proxy"
+ frame .dlg.fforward
+ frame .dlg.fproxy
+
+ label .dlg.msg -text $msg -justify left
+ radiobutton .dlg.forward -text "Use fixed server forwarding" \
+ -variable state(proxy) -value 0 -anchor w -command GetSetup2
+ label .dlg.fl1 -text "Client Port:" -anchor e
+ entry .dlg.fe1 -textvariable SP(clntPort)
+
+ label .dlg.fl2 -text "Server Host:" -anchor e
+ entry .dlg.fe2 -textvariable SP(servHost)
+ label .dlg.fl3 -text "Server Port:" -anchor e
+ entry .dlg.fe3 -textvariable SP(servPort)
+
+ radiobutton .dlg.proxy -text "Use HTTP Proxying" \
+ -variable state(proxy) -value 1 -anchor w -command GetSetup2
+ label .dlg.pl1 -text "Proxy Port:" -anchor e
+ entry .dlg.pe1 -textvariable SP(proxyPort)
+ button .dlg.ok -text OK -width 10 -command [list ValidForm 1]
+ button .dlg.cancel -text Cancel -width 10 -command [list destroy .dlg]
+
+ grid .dlg.top -row 0 -column 0 -columnspan 3 -sticky ew -padx 10 -pady 10
+ grid columnconfigure .dlg 0 -weight 1
+ grid x .dlg.ok .dlg.cancel -padx 10
+ grid configure .dlg.ok -padx 0
+ grid rowconfigure .dlg 2 -minsize 8
+ pack .dlg.msg -in .dlg.top -side top -fill x -padx 10 -pady 5
+ pack .dlg.fforward .dlg.fproxy -in .dlg.top -side top -fill x \
+ -padx 10 -pady 10
+
+ grid .dlg.proxy - - -in .dlg.fproxy -sticky w
+ grid x .dlg.pl1 .dlg.pe1 -in .dlg.fproxy -sticky ew
+ grid columnconfigure .dlg.fproxy 0 -minsize .2i
+ grid columnconfigure .dlg.fproxy 2 -weight 1
+ grid columnconfigure .dlg.fproxy 3 -minsize 10
+ grid rowconfigure .dlg.fproxy 2 -minsize 10
+
+ grid .dlg.forward - - -in .dlg.fforward -sticky w
+ grid x .dlg.fl1 .dlg.fe1 -in .dlg.fforward -sticky ew
+ grid x .dlg.fl2 .dlg.fe2 -in .dlg.fforward -sticky ew
+ grid x .dlg.fl3 .dlg.fe3 -in .dlg.fforward -sticky ew
+ grid columnconfigure .dlg.fforward 0 -minsize .2i
+ grid columnconfigure .dlg.fforward 2 -weight 1
+ grid columnconfigure .dlg.fforward 3 -minsize 10
+ grid rowconfigure .dlg.fforward 4 -minsize 10
+ raise .dlg
+
+ bind .dlg.forward <Return> [bind all <Key-Tab>]
+ bind .dlg.proxy <Return> [bind all <Key-Tab>]
+ bind .dlg.fe1 <Return> [bind all <Key-Tab>]
+ bind .dlg.fe2 <Return> [bind all <Key-Tab>]
+ bind .dlg.fe3 <Return> [list .dlg.ok invoke]
+ bind .dlg.pe1 <Return> [list .dlg.ok invoke]
+
+ GetSetup2
+ .dlg.pe1 icursor end
+ .dlg.fe2 icursor end
+ if {$state(proxy)} { focus -force .dlg.pe1 } { focus -force .dlg.fe2 }
+
+ raise .dlg
tkwait window .dlg
+ wm deiconify .
if {$ok} {
- if {$connect} DoListen
+ DoListen
} else {
- foreach {clntPort servHost servPort} $save break
+ array set SP [array get save]
+ }
+}
+proc GetSetup2 {} {
+ global state
+ array set s {1 normal 0 disabled}
+ if {! $state(proxy)} { array set s {0 normal 1 disabled} }
+
+ .dlg.pl1 config -state $s(1)
+ .dlg.pe1 config -state $s(1)
+ foreach w {1 2 3} {
+ .dlg.fl$w config -state $s(0)
+ .dlg.fe$w config -state $s(0)
+ }
+}
+proc ValidForm {kill} {
+ global state SP ok
+ set ok 0
+ if {$state(proxy)} {
+ if {$SP(proxyPort) != ""} {set ok 1}
+ } elseif {$SP(clntPort) !="" && $SP(servHost) !="" && $SP(servPort) !=""} {
+ set ok 1
}
+ if {$ok && $kill} {destroy .dlg}
return $ok
}
##+##########################################################################
.bbar config -height 1 ;# Need this to give remove gap
}
}
-
+proc Help {} {
+ catch {destroy .help}
+ toplevel .help
+ wm title .help "SockSpy Help"
+ wm geom .help "+[expr {[winfo x .] + 50}]+[expr {[winfo y .] + 50}]"
+
+ text .help.t -relief raised -wrap word -width 70 -height 25 \
+ -padx 10 -pady 10 -cursor {} -yscrollcommand {.help.sb set}
+ scrollbar .help.sb -orient vertical -command {.help.t yview}
+ button .help.dismiss -text Dismiss -command {destroy .help}
+ pack .help.dismiss -side bottom -pady 10
+ pack .help.sb -side right -fill y
+ pack .help.t -side top -expand 1 -fill both
+
+ set bold "[font actual [.help.t cget -font]] -weight bold"
+ set fixed "[font actual [.help.t cget -font]] -family courier"
+ .help.t tag config title -justify center -foregr red -font "Times 20 bold"
+ .help.t tag configure title2 -justify center -font "Times 12 bold"
+ .help.t tag configure header -font $bold
+ .help.t tag configure n -lmargin1 15 -lmargin2 15
+ .help.t tag configure fixed -font $fixed -lmargin1 25 -lmargin2 55
+
+ .help.t insert end "SockSpy\n" title
+ .help.t insert end "Authors: Tom Poindexter and Keith Vetter\n\n" title2
+
+ set m "SockSpy lets you watch the conversation of a tcp client and server. "
+ append m "SockSpy acts much like a gateway: it waits for a tcp connection, "
+ append m "then connects to the real server. Data from the client is passed "
+ append m "onto the server, and data from the server is passed onto the "
+ append m "client.\n\n"
+
+ append m "Along the way, the data streams are also displayed in text "
+ append m "widget with data sent from the client displayed in green, data "
+ append m "from the server in blue and connection metadata in red. The data "
+ append m "can be displayed as printable ASCII strings, or as a hex dump "
+ append m "format of both hex and printable characters.\n\n"
+ .help.t insert end "What is SockSpy?\n" header $m n
+
+ set m "Why might you want to use SockSpy? Debugging tcp client/server "
+ append m "programs, examining protocols and diagnosing network problems "
+ append m "are top candidates. Perhaps you just want to figure out how "
+ append m "somethings work. I've used it to bypass firewalls, to rediscover "
+ append m "my lost smtp password, to access a news server on a remote "
+ append m "network, etc.\n\nIt's not a replacement for heavy duty tools "
+ append m "such as 'tcpdump' and other passive packet sniffers. On the "
+ append m "other hand, SockSpy doesn't require any special priviledges to "
+ append m "run (unless of course, you try to listen on a Unix reserved tcp "
+ append m "port less than 1024.)\n\n"
+ .help.t insert end "Why Use SockSpy?\n" header $m n
+
+ set m "Just double click on SockSpy to start it. You will be prompted for "
+ append m "various connection parameters described below.\n\n"
+ append m "Alternatively, you can specify the connection parameters on the "
+ append m "command line. This is also how you can run SockSpy in text mode "
+ append m "without a GUI.\n\n"
+ append m "To start SockSpy from the command line:\n"
+ .help.t insert end "How to Use SockSpy\n" header $m n
+
+ set m "$ sockspy <listen-port> <server-host> <server-port>\n or\n"
+ append m "$ sockspy -proxy <proxy-port>\n\n"
+ .help.t insert end $m fixed
+
+ set m "To start SockSpy in text mode without a GUI:\n"
+ .help.t insert end $m n
+ set m "$ tclsh sockspy <listen-port> <server-host> <server-port>\n or\n"
+ append m "$ tclsh sockspy -proxy <proxy-port>\n\n"
+ .help.t insert end $m fixed
+
+ set m "<listen-port>: the tcp port on which to listen. Clients should "
+ append m "connect to this port.\n"
+ append m "<server-host>: the host where the real server runs.\n"
+ append m "<server-port>: the tcp port on which the real server listens.\n"
+ append m "<proxy-port>: the tcp port on which to listen in proxy-mode.\n\n"
+ .help.t insert end $m n
+
+ set m "In proxy mode SockSpy works like a simple HTTP proxy server. "
+ append m "Instead of forwarding to a fixed server and port, it follows the "
+ append m "HTTP proxy protocol and reads the server information from the "
+ append m "first line of HTTP request.\n\n"
+ append m "You can turn on proxy mode by selecting it in the SockSpy Setup "
+ append m "dialog, or by specifying -proxy on the command line.\n\n"
+ .help.t insert end "Proxy Mode\n" header $m n
+
+ set m "To spy on HTTP connections to a server, type:\n"
+ .help.t insert end "Example\n" header $m n
+ .help.t insert end " sockspy 8080 www.some.com 80\n" fixed
+ .help.t insert end "and point your browser to\n" n
+ .help.t insert end " http://localhost:8080/index.html\n\n" fixed
+ .help.t insert end "Alternatively, you could configure your browser to " n
+ .help.t insert end "use localhost and port 8000 as its proxy, and then " n
+ .help.t insert end "type:\n" n
+ .help.t insert end " sockspy -proxy 8000\n" fixed
+ .help.t insert end "and user your browser normally.\n" n
+
+ .help.t config -state disabled
+}
+
+proc About {} {
+ set m "SockSpy version $::state(version)\n"
+ append m "by Tom Poindexter and Keith Vetter\n"
+ append m "Copyright 1998-[clock format [clock seconds] -format %Y]\n"
+ append m "A program to eavesdrop on a tcp client server conversation."
+ tk_messageBox -icon info -title "About SockSpy" -message $m -parent .
+}
+
+proc DoFilter {who data} {
+ global filters
+
+ if {! [info exists filters($who)]} { return $data }
+ set ndata ""
+ foreach line [split $data \n] {
+ if {[regexp $filters($who) $line]} {
+ lappend ndata $line
+ }
+ }
+ return [join $ndata "\n"]
+}
################################################################
################################################################
################################################################
-# get args and start it up
-
set state(gui) [info exists tk_version]
-set state(listen) ""
-
-set clntPort [lindex $argv 0]
-set servHost [lindex $argv 1]
-set servPort [lindex $argv 2]
-
+if {[catch {package present uri}]} {
+ ERROR "ERROR: SockSpy requires the uri package from tcllib."
+}
+
+if {$state(gui)} { wm withdraw . }
createMain
-if {[llength $argv] < 3} {
- GetSetup 0
+if {[lindex $argv 0] == "-proxy"} {
+ set state(proxy) 1
+ if {$argc == 2} {
+ set SP(proxyPort) [lindex $argv 1]
+ DoListen
+ } else {
+ GetSetup
+ }
+} else {
+ set state(proxy) 0
+ if {$argc >= 1} { set SP(clntPort) [lindex $argv 0] }
+ if {$argc >= 2} { set SP(servHost) [lindex $argv 1] }
+ if {$argc >= 3} { set SP(servPort) [lindex $argv 2] }
+ if {$argc >= 3} {
+ DoListen
+ } else {
+ GetSetup
+ }
}
-DoListen
if {! $state(gui)} {
vwait forever ;# tclsh needs this
+} else {
+ wm deiconify .
}