Attachment "socks5.diff" to
ticket [3501392fff]
added by
dongola7
2012-03-11 06:19:29.
diff --git a/examples/socks5/test_client.tcl b/examples/socks5/test_client.tcl
new file mode 100755
index 0000000..040f494
--- /dev/null
+++ b/examples/socks5/test_client.tcl
@@ -0,0 +1,67 @@
+#!/bin/sh
+# This line continues for Tcl, but is a single line for 'sh' \
+exec tclsh "$0" ${1+"$@"}
+
+# test_client.tcl --
+#
+# Implements a simple TCP client program utilizing the SOCKS 5 library
+#
+# Copyright (c) 2011 Blair Kitchen
+#
+# See the file "license.terms" for information on usage and
+# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+
+set proxyIP "localhost"
+set proxyPort "1080"
+set serverHost "localhost"
+set serverIP "127.0.0.1"
+set serverPort "30000"
+
+set root [file join [file dirname [info script]] ..]
+source [file join $root socks5.tcl]
+
+set data ""
+proc handleConnect {result arg} {
+ if {$result != "ok"} {
+ puts "SOCKS error accepting incoming connection: $arg"
+ return
+ }
+
+ set ::data $arg
+}
+
+::socks5::configure -proxy $proxyIP -proxyport $proxyPort -username foo -password bar
+
+foreach server [list $serverHost $serverIP] {
+ puts "Attempting CNTRL connection to $server:$serverPort using proxy $proxyIP:$proxyPort"
+ set cntrl [::socks5::connect $server $serverPort]
+ puts "CNTRL connection established"
+
+ puts "Attempting to create SOCKS5 binding for DATA connection"
+ set bindInfo [::socks5::bind $server $serverPort handleConnect]
+ lassign $bindInfo host port
+ puts "SOCKS server listening for DATA connection on $host:$port"
+
+ puts "Sending details via CNTRL connection"
+ puts $cntrl $host
+ puts $cntrl $port
+ flush $cntrl
+
+ puts "Waiting for DATA connection"
+ vwait data
+ puts "DATA connection established"
+
+ puts $cntrl "Hello World (via CNTRL)"
+ flush $cntrl
+ puts [gets $data]
+
+ puts $data "Hello World (via DATA)"
+ flush $data
+ puts [gets $cntrl]
+
+ close $data
+ close $cntrl
+
+ puts "---------------"
+}
diff --git a/examples/socks5/test_server.tcl b/examples/socks5/test_server.tcl
new file mode 100755
index 0000000..ac31249
--- /dev/null
+++ b/examples/socks5/test_server.tcl
@@ -0,0 +1,53 @@
+#!/bin/sh
+# This line continues for Tcl, but is a single line for 'sh' \
+exec tclsh "$0" ${1+"$@"}
+
+# socks5.tcl --
+#
+# Implements a simple TCP server for use with test_client.tcl
+#
+# Copyright (c) 2011 Blair Kitchen
+#
+# See the file "license.terms" for information on usage and
+# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+
+set listenPort "30000"
+
+set root [file join [file dirname [info script]] ..]
+source [file join $root socks5.tcl]
+
+set cntrl ""
+
+proc handleConnect {cntrl addr port} {
+ puts "CNTRL connection from $addr:$port"
+ set host [gets $cntrl]
+ set port [gets $cntrl]
+
+ puts "Attempting DATA connection to $host:$port"
+ set data [socket $host $port]
+ puts "DATA connection established"
+
+ fconfigure $cntrl -blocking 0 -translation binary -encoding binary
+ fconfigure $data -blocking 0 -translation binary -encoding binary
+ fileevent $cntrl readable [list handleRead $cntrl $data]
+ fileevent $data readable [list handleRead $data $cntrl]
+}
+
+proc handleRead {src dst} {
+ if {[eof $src]} {
+ close $src
+ close $dst
+ puts "Client disconnected"
+ return
+ }
+
+ puts "Echoing data"
+ set data [read $src]
+ puts -nonewline $dst $data
+ flush $dst
+}
+
+set server_sock [socket -server handleConnect $listenPort]
+puts "Listening for CNTRL connections on port $listenPort"
+vwait forever
diff --git a/examples/socks5/test_tor.tcl b/examples/socks5/test_tor.tcl
new file mode 100755
index 0000000..27a5505
--- /dev/null
+++ b/examples/socks5/test_tor.tcl
@@ -0,0 +1,35 @@
+#!/bin/sh
+# This line continues for Tcl, but is a single line for 'sh' \
+exec tclsh "$0" ${1+"$@"}
+
+# test_tor.tcl --
+#
+# Implements a simple script that connects to the Internet through a
+# Tor proxy. Assumes you have a tor proxy running on localhost:9050.
+#
+# Copyright (c) 2012 Blair Kitchen
+#
+# See the file "license.terms" for information on usage and
+# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+
+package require Tcl 8.5
+package require tls 1.6
+package require http 2.7
+
+set root [file join [file dirname [info script]] ..]
+source [file join $root socks5.tcl]
+
+proc httpsConnect {host port} {
+ set sock [::socks5::connect $host $port]
+ ::tls::import $sock
+ return $sock
+}
+
+::http::register http 80 ::socks5::connect
+::http::register https 443 ::httpsConnect
+
+::socks5::configure -proxy localhost -proxyport 9050
+
+set token [::http::geturl "https://check.torproject.org" -channel stdout]
+::http::cleanup $token
diff --git a/modules/socks5/pkgIndex.tcl b/modules/socks5/pkgIndex.tcl
new file mode 100644
index 0000000..3ece077
--- /dev/null
+++ b/modules/socks5/pkgIndex.tcl
@@ -0,0 +1,11 @@
+# Tcl package index file, version 1.1
+# This file is generated by the "pkg_mkIndex" command
+# and sourced either when an application starts up or
+# by a "package unknown" script. It invokes the
+# "package ifneeded" command to set up package-related
+# information so that packages will be loaded automatically
+# in response to "package require" commands. When this
+# script is sourced, the variable $dir must contain the
+# full path name of this file's directory.
+
+package ifneeded socks5 1.0 [list source [file join $dir socks5.tcl]]
diff --git a/modules/socks5/socks5.man b/modules/socks5/socks5.man
new file mode 100644
index 0000000..e44b002
--- /dev/null
+++ b/modules/socks5/socks5.man
@@ -0,0 +1,170 @@
+[manpage_begin socks5 n 1.0]
+[copyright {2012 Blair Kitchen <[email protected]>}]
+[moddesc {Networking}]
+[moddesc {Implements client support for SOCKS 5 proxies}]
+[require Tcl 8.5]
+[require socks5 [opt 1.0]]
+[description]
+[para]
+
+This package provides routines for connecting to remote servers via a SOCKS 5
+proxy server. Support for both CONNECT and BIND methods is included.
+
+[section COMMANDS]
+
+[list_begin definitions]
+
+[call [cmd ::socks5::configure] [opt [arg options]]]
+
+Configure the library for use by specifying information such as the proxy
+server, port number, etc.
+
+[list_begin definitions]
+[def "[cmd -proxy] [arg hostname]"]
+ [term Hostname] specifies the domain-style name or numerical IP address
+ of the proxy server.
+[def "[cmd -proxyport] [arg port]"]
+ [term Port] specifies an integer port number on which the proxy server
+ will respond to incoming requests.
+[def "[cmd -bindtimeout] [arg timeout]"]
+ [term Timeout] specifies a timeout (in milliseconds) when waiting for
+ an incoming connection via [cmd ::socks5::bind]
+[def "[cmd -username] [arg username]"]
+ [term Username] specifies the username to be used when the proxy
+ server requires username/password authentication. Providing an empty
+ value for this option disables the use of authentication.
+[def "[cmd -password] [arg password]"]
+ [term Password] specifies the password to be used when the proxy
+ server requires username/password authentication. Providing an empty
+ value for this option disables the use of authentication.
+[list_end]
+
+[para]
+The following example illustrates use of the [cmd ::socks5::configure] command.
+
+[example {::socks5::configure -proxy localhost -proxyport 1080 -bindtimeout 2000}]
+
+[para]
+[call [cmd ::socks5::connect] [opt [arg options]] [arg hostname] [arg port]]
+
+Establishes a connection with a remote host through the configured proxy
+
+[list_begin definitions]
+[def "[cmd -myaddr] [arg addr]"]
+ [term Addr] gives the domain-style name or numerical IP address of the
+ client-side network interface to use for the connection. This option
+ may be useful if the client machine has multiple network interfaces.
+ If the option is omitted then the client-side interface will be chosen
+ by the system software.
+[def "[cmd -myport] [arg port]"]
+ [term Port] specifies an integer port number (or service name, where
+ supported and understood by the host operating system) to use for the
+ client's side of the connection. If this option is omitted, the client's
+ port number will be chosen at random by the system software.
+[list_end]
+
+[para]
+The following example illustrates use of the [cmd ::socks5::connect] command.
+
+[example {::socks5::connect www.google.com 80}]
+
+[para]
+[call [cmd ::socks5::bind] [opt [arg options]] [arg hostname] [arg port] [arg command]]
+
+Requests the proxy open a TCP port for listening and wait for an incoming
+connection from the specified host and port. [term Hostname] gives the
+anticipated domain-style name or numerical IP address of the incoming
+connection. [term Port] specifies the integer port number of the incoming
+connection.
+
+[para]
+The [term command] parameter will be evaluated at the global scope when the
+incoming connection is established. Two parameters will be appended. The
+first indicates the type of response from the proxy, while the second depends
+on the response.
+
+[list_begin definitions]
+[def "[cmd -myaddr] [arg addr]"]
+ [term Addr] gives the domain-style name or numerical IP address of the
+ client-side network interface to use for the connection. This option
+ may be useful if the client machine has multiple network interfaces.
+ If the option is omitted then the client-side interface will be chosen
+ by the system software.
+[def "[cmd -myport] [arg port]"]
+ [term Port] specifies an integer port number (or service name, where
+ supported and understood by the host operating system) to use for the
+ client's side of the connection. If this option is omitted, the client's
+ port number will be chosen at random by the system software.
+[list_end]
+
+[para]
+The following example illustrates use of the [cmd ::socks5::bind] command.
+
+[example {
+proc handle_connect {result arg} {
+ if {$result eq "ok"} {
+ puts "connection established via channel $arg"
+ } elseif {$result eq "timeout"} {
+ puts "timeout expired while waiting for connection"
+ } elseif {$result eq "error"} {
+ puts "error from proxy while waiting for connection: $arg"
+ }
+}
+
+::socks5::bind ftp.cdrom.com 21 handle_connect
+}]
+
+[list_end]
+
+[section EXAMPLES]
+The [term socks5] package can be used to SOCKS enable the [term http] package.
+This is useful for passing all HTTP requests through the Tor network, for
+example. Assuming you have Tor running on your local system and listening for
+connections on port 9050, the following sample code demonstrates how to enable
+http use of Tor.
+
+[example {
+package require Tcl 8.5
+package require tls 1.6
+package require http 2.7
+package require socks5
+
+proc httpsConnect {host port} {
+ # Establish connection with SOCKS 5
+ set sock [::socks5::connect $host $port]
+ # Enable SSL on open socket
+ ::tls::import $sock
+ return $sock
+}
+
+::http::register http 80 ::socks5::connect
+::http::register https 443 ::httpsConnect
+
+::socks5::configure -proxy localhost -port 9050
+
+# Retrieve https://check.torproject.org to confirm we are using Tor
+set token [::http::geturl "https://check.torproject.org" -channel stdout]
+::http::cleanup $token
+}]
+
+[section "KNOWN LIMITATIONS"]
+The following known limitations exist:
+
+[list_begin bullet]
+[bullet] No support for IPv6
+[bullet] Support for username/password authentication only
+[bullet] No support for the UDP ASSOCIATE command
+[list_end]
+
+[section {BUGS, IDEAS, FEEDBACK}]
+
+This document, and the package it describes, will undoubtedly contain
+bugs and other problems.
+
+Please report such in the category [emph socks5] of the
+[uri {http://sourceforge.net/tracker/?group_id=12883} {Tcllib SF Trackers}].
+
+Please also report any ideas for enhancements you may have for either
+package and/or documentation.
+
+[manpage_end]
diff --git a/modules/socks5/socks5.tcl b/modules/socks5/socks5.tcl
new file mode 100644
index 0000000..6f2a9ad
--- /dev/null
+++ b/modules/socks5/socks5.tcl
@@ -0,0 +1,427 @@
+# socks5.tcl --
+#
+# Tcl implementation of a SOCKS 5 client
+#
+# Copyright (c) 2011 Blair Kitchen
+#
+# See the file "license.terms" for information on usage and
+# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+
+package require Tcl 8.5
+package require cmdline 1.3
+
+package provide socks5 1.0
+
+namespace eval ::socks5 {
+ namespace export configure bind connect
+
+ array set Config {
+ proxy {}
+ proxyport 1080
+ bindtimeout 2000
+ username {}
+ password {}
+ }
+
+ array set ResponseCodes {
+ 0 "succeeded"
+ 1 "general SOCKS server failure"
+ 2 "connection not allowed by ruleset"
+ 3 "network unreachable"
+ 4 "host unreachable"
+ 5 "connection refused"
+ 6 "TTL expired"
+ 7 "command not supported"
+ 8 "address type not supported"
+ }
+
+ array set MethodCodes {
+ 0 "no authentication required"
+ 1 "gssapi"
+ 2 "username/password"
+ 255 "no acceptable methods"
+ }
+}
+
+# ::socks5::configure
+#
+# Configures the SOCKS 5 client library
+#
+# Arguments:
+# args List of parameters to configure (see ::socks5::Config for list)
+#
+# Results:
+# None
+#
+proc ::socks5::configure {args} {
+ variable Config
+
+ set options [list proxy.arg \
+ proxyport.arg \
+ bindtimeout.arg \
+ username.arg \
+ password.arg]
+
+ while {[::cmdline::getopt args $options option value] == 1} {
+ switch -- $option {
+ proxyport {
+ if {($value <= 0) || ($value >= 65565)} {
+ return -code error "proxyport requires a value between 1 and 65565"
+ }
+ }
+ bindtimeout {
+ if {($value < 0)} {
+ return -code error "bindtimeout requires a value greater than 1"
+ }
+ }
+ }
+
+ set Config($option) $value
+ }
+
+ if {[llength $args] > 0} {
+ return -code error "unknown option '[lindex $args 0]'"
+ }
+}
+
+# ::socks5::bind
+#
+# Requests the SOCKS 5 server open a port for listening and await a
+# connection from the specified host and port.
+#
+# Arguments:
+# options List of options to pass to the socket call
+# ?-myaddr addr? ?-myport port?
+# host The hostname or IP from which a connection will be established
+# port The port number from which a connection will be established
+# command Command that will be executed when the connection is established
+#
+# Results:
+# List consisting of IP and port on the proxy server opened and listening
+# for an incoming connection
+#
+# command is executed when the connection is established and two arguments
+# appended. The first is the success indication and is one of: ok, timeout,
+# or error. The second is an argument related to the success indicator. For
+# ok, it is the channel handle on which communication may take place. For
+# error and timeout, it is an error message.
+#
+proc ::socks5::bind {args} {
+ variable Config
+
+ set errorCode [catch {ProxyConnect args} sock]
+ if {$errorCode == -1} {
+ return -code error $sock
+ } elseif {$errorCode != 0} {
+ return -code $errorCode -errorinfo $::errorInfo $sock
+ }
+
+ if {[llength $args] != 3} {
+ return -code "wrong # args: should be \"bind ?-myaddr addr? ?-myport myport? host port command"
+ }
+
+ lassign $args host port command
+
+ set cmd [binary format ccc 5 2 0]
+ append cmd [FormatAddress $host $port]
+
+ puts -nonewline $sock $cmd
+ flush $sock
+
+ set errorCode [catch {ReadResponse $sock} result]
+ if {$errorCode != 0} {
+ chan close $sock
+ if {$errorCode == -1} {
+ return -code error $result
+ } else {
+ return -code $errorCode -errorinfo $::errorInfo $result
+ }
+ }
+
+ set timeout_id [after $Config(bindtimeout) \
+ [list ::socks5::BindCallback timeout {} $sock $command]]
+ chan event $sock readable \
+ [list ::socks5::BindCallback readable $timeout_id $sock $command]
+
+ return $result
+}
+
+# ::socks5::connect
+#
+# Requests the SOCKS 5 server establish an outgoing connection to
+# the named host on the named port.
+#
+# Arguments:
+# options List of options to pass to the socket call
+# ?-myaddr addr? ?-myport port?
+# host The hostname or IP to which a connection should be established
+# port The port number to which a connection should be established
+#
+# Results:
+# Returns a channel handle to the socket used for communication.
+# The channel is ready for normal use when returned.
+#
+proc ::socks5::connect {args} {
+ set errorCode [catch {ProxyConnect args} sock]
+ if {$errorCode == -1} {
+ return -code error $sock
+ } elseif {$errorCode != 0} {
+ return -code $errorCode -errorinfo $::errorInfo $sock
+ }
+
+ if {[llength $args] != 2} {
+ return -code "wrong # args: should be \"connect ?-myaddr addr? ?-myport myport? host port command"
+ }
+
+ lassign $args host port
+
+ set cmd [binary format ccc 5 1 0]
+ append cmd [FormatAddress $host $port]
+
+ puts -nonewline $sock $cmd
+ flush $sock
+
+
+ set errorCode [catch {ReadResponse $sock} msg]
+ if {$errorCode != 0} {
+ chan close $sock
+ if {$errorCode == -1} {
+ return -code error $msg
+ } else {
+ return -code $errorCode -errorinfo $::errorInfo
+ }
+ }
+
+ return $sock
+}
+
+# ::sock5::BindCallback
+#
+# Callback procedure registered by ::socks5::bind on the
+# SOCKS 5 client socket for the readable event.
+#
+# Arguments:
+# reason The reason the callback is firing (timeout or else)
+# timeout_id after callback identifier for cancelling the timeout event
+# sock Channel handle to the open socket
+# command User command for callback (passed to ::socks5::bind)
+#
+# Results:
+# Calls "command" in the global namespace to provide information
+# to the user logic.
+#
+proc ::socks5::BindCallback {reason timeout_id sock command} {
+ after cancel $timeout_id
+
+ if {$reason eq "timeout"} {
+ chan close $sock
+ uplevel #0 [list $command timeout "timeout occurred while waiting for connection"]
+ } else {
+ if {[catch {ReadResponse $sock} result]} {
+ chan close $sock
+ uplevel #0 [list $command error $result]
+ } else {
+ uplevel #0 [list $command ok $sock]
+ }
+ }
+}
+
+# ::socks5::FormatAddress
+#
+# Formats a hostname and port into the format defined by the SOCKS 5
+# specification.
+#
+# Arguments:
+# host The hostname or IP address
+# port The port number
+#
+# Results:
+# Returns the hostname/IP and port number formatted as a binary message
+# for transmission to the SOCKS 5 server.
+#
+proc ::socks5::FormatAddress {host port} {
+ if {[regexp -- {^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$} $host]} {
+ set parts [split $host .]
+ set result [binary format cccccS 1 {*}$parts $port]
+ } else {
+ if {[string length $host] > 255} {
+ return -code -1 "host must be 255 characters or less"
+ }
+
+ set result [binary format cca*S 3 [string length $host] $host $port]
+ }
+
+ return $result
+}
+
+# ::socks5::ReadResponse
+#
+# Reads a SOCKS 5 server response message from the given channel handle.
+#
+# Arguments:
+# sock The channel handle from which to read
+#
+# Results:
+# Returns an error if there is a problem reading the response. Otherwise
+# returns a two element list consisting of the hostname/IP and port number
+# from the response.
+#
+proc ::socks5::ReadResponse {sock} {
+ variable ResponseCodes
+
+ set rsp [read $sock 3]
+ if {[string length $rsp] != 3} {
+ return -code -1 "unable to read response from proxy"
+ }
+
+ binary scan $rsp ccx version reply
+ if {$reply != 0} {
+ if {[info exists ResponseCodes($reply)]} {
+ return -code -1 "error from proxy: $ResponseCodes($reply) ($reply)"
+ }
+
+ return -code -1 "error from proxy: $reply"
+ }
+
+ set rsp [read $sock 1]
+ binary scan $rsp c addr_type
+
+ if {$addr_type == 1} {
+ set rsp [read $sock 6]
+ binary scan $rsp "cucucucuSu" ip1 ip2 ip3 ip4 port
+ set result [list "$ip1.$ip2.$ip3.$ip4" $port]
+ } elseif {$addr_type == 3} {
+ set len [read $sock 1]
+ set len [binary scan $len c]
+
+ set host [read $sock $len]
+ set port [binary scan S [read $sock 2]]
+ set result [list $host $port]
+ } else {
+ return -code -1 "invalid address type from proxy: $addr_type"
+ }
+
+ return $result
+}
+
+#
+# ::socks5::ProxyConnect
+#
+# Helper procedure to connect and perform handshaking with a SOCKS 5 proxy
+# server. The proxy server address and port are taken from the global
+# configuration and may be specified via a call to ::socks5::configure.
+#
+# Arguments:
+# args List of arguments to pass to the socket call
+# ?-myaddr addr? ?-myport port?
+#
+# Results:
+# Returns a channel handle to the open connection on success. Returns an
+# error otherwise. The channel is authenticated and ready for use in SOCKS 5
+# client requests on return.
+#
+proc ::socks5::ProxyConnect { argsVar } {
+ variable Config
+ variable MethodCodes
+
+ if {$Config(proxy) eq {} || $Config(proxyport) eq {}} {
+ return -code -1 "no proxy or proxy port specified"
+ }
+
+ # Parse the command line options for socket related options. Leave the
+ # remaining arguments for the parent
+ upvar $argsVar args
+ set socketOptions [list]
+ while {[set result [cmdline::getopt args {myaddr.arg myport.arg} option value]] == 1} {
+ lappend socketOptions "-$option" $value
+ }
+
+ if {$result == -1} {
+ return -code -1 "unknown option '[lindex $args 0]'"
+ }
+
+ set errorCode [catch {socket {*}$socketOptions $Config(proxy) $Config(proxyport)} sock]
+ if {$errorCode != 0} {
+ return -code -1 "unable to connect to proxy: $sock"
+ }
+ fconfigure $sock -translation binary -encoding binary -blocking 1
+
+ set numMethods 1
+ set methods [list 0]
+
+ if {$Config(username) != {} || $Config(password) != {}} {
+ incr numMethods
+ lappend methods 5
+ }
+
+ puts -nonewline $sock [binary format ccc* 5 $numMethods $methods]
+ flush $sock
+
+ set rsp [read $sock 2]
+ if {[string length $rsp] != 2} {
+ chan close $sock
+ return -code -1 "unable to read handshake response from proxy"
+ }
+
+ binary scan $rsp cc version method
+ if {$version != 5} {
+ chan close $sock
+ return -code -1 "unsupported version: $version"
+ } elseif {$method == 255} {
+ chan close $sock
+ return -code -1 "unsupported method from proxy: $MethodCodes($method) ($method)"
+ } elseif {$method == 5} {
+ PerformUserPassAuth $sock
+ }
+
+ return $sock
+}
+
+# ::socks5::PerformUserPassAuth
+#
+# Performs username/password authentication on the given channel. The
+# username and password are taken from the global configuration and may
+# be specified via a call to ::socks5::configure.
+#
+# Arguments:
+# sock The socket on which to perform authentication
+#
+# Results:
+# Returns an error on authentication failure.
+#
+proc ::socks5::PerformUserPassAuth {sock} {
+ variable Config
+
+ if {[string length $Config(username)] > 255]} {
+ chan close $sock
+ return -code -1 "username must be 255 characters or less"
+ }
+
+ if {[string length $Config(password)] > 255]} {
+ chan close $sock
+ return -code -1 "password must be 255 characters or less"
+ }
+
+ puts -nonewline $sock [binary scan cca*ca* 1 \
+ [string length $Config(username)] $Config(username) \
+ [string length $Config(password)] $Config(password)]
+ flush $sock
+
+ set rsp [read $sock 2]
+ if {[string length $rsp] != 2} {
+ chan close $sock
+ return -code -1 "unable to read auth response from proxy"
+ }
+
+ binary scan cc $rsp version reply
+ if {$version != 1} {
+ chan close $sock
+ return -code -1 "unsupported username/password auth version ($version)"
+ } elseif {$reply != 0} {
+ chan close $sock
+ return -code -1 "proxy denied presented auth tokens"
+ }
+
+ return
+}
diff --git a/support/installation/modules.tcl b/support/installation/modules.tcl
index 7ed5b68..a07db19 100755
--- a/support/installation/modules.tcl
+++ b/support/installation/modules.tcl
@@ -118,6 +118,7 @@ Module sha1 _tcl _man _null
Module simulation _tcl _man _null
Module smtpd _tcl _man _exa
Module snit _tcl _man _null
+Module socks5 _tcl _man _exa
Module soundex _tcl _man _null
Module stooop _tcl _man _null
Module stringprep _tcl _man _null