PortForwarder forwards incoming tcp/ip data (defined port and ip address) towards an assigned remote ip address and port. Lowlevel security is done by checking on remote ip address (which is not secure but blocks)
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 | #!/usr/local/bin/tclsh
#
# PFW - Portforwarder tcltk use at own risk, Norman Deppenbroek 2001
#
# forwarding raw data from a listening port, towards a standard remote address:port
# block by session limits and accesslist
#
namespace eval pfw {
variable version v0.93
variable copyright "PortForwarder $pfw::version by Nodep"
variable debug False # if true show packet size on stdout
variable localhost 0
variable localport 0
variable remotehost 0
variable remoteport 0
variable maxsession 0
variable allowlist 0
variable denylist 0
proc time {} { return [ clock format [ clock seconds ] -format %D-%T ] }
proc print { syntax } { puts "[ pfw::time ] --> $syntax" }
namespace eval db {
variable cnt 0
proc inc { } {
return [ incr pfw::db::cnt ]
}
proc dec { } {
return [ set pfw::db::cnt [ expr $pfw::db::cnt - 1 ] ]
}
}
}
# PROCEDURES START HERE #
proc sio { fromsock tosock ip port } {
if { [ catch { set data [read $fromsock] } merror ] } {
pfw::print "ERR: #$pfw::db::cnt \t $merror"
pfw::print "CLR: #$pfw::db::cnt \t $pfw::remotehost:$pfw::remoteport <-> $pfw::localhost:$pfw::localport <-> $ip:$port"
catch { close $fromsock }
catch { close $tosock }
pfw::db::dec
return
}
if {[string length $data] == 0} {
catch { close $fromsock }
catch { close $tosock }
pfw::print "CLR: #$pfw::db::cnt \t $pfw::localhost:$pfw::localport <-> $pfw::remotehost:$pfw::remoteport <-> $ip:$port"
pfw::db::dec
return
}
if { $pfw::debug } { pfw::print "TRX: #$pfw::db::cnt \t $pfw::remotehost:$pfw::remoteport <-> $pfw::localhost:$pfw::localport
if { [ catch { puts -nonewline $tosock $data } merror ] } {
pfw::print "ERR: #$pfw::db::cnt \t $merror"
pfw::print "CLR: #$pfw::db::cnt \t $pfw::remotehost:$pfw::remoteport <-> $pfw::localhost:$pfw::localport <-> $ip:$port
catch { close $fromsock }
catch { close $tosock }
pfw::db::dec
}
}
proc connect { serverhost serverport sockclient ip port} {
pfw::db::inc
if { $pfw::db::cnt < $pfw::maxsession } {
if { [ lsearch -exact $pfw::allowlist $ip ] != -1 } {
if { [ catch { set sockserver [ socket $pfw::remotehost $pfw::remoteport ] } merror ] } {
pfw::print "ERR: #$pfw::db::cnt \t $merror"
pfw::print "CLR: #$pfw::db::cnt \t $pfw::localhost:$pfw::localport <-> $ip:$port"
catch { close $sockclient }
catch { close $sockserver }
pfw::db::dec
return
}
pfw::print "NEW: #$pfw::db::cnt \t $pfw::localhost:$pfw::localport <-> $ip:$port"
pfw::print "CON: #$pfw::db::cnt \t $pfw::localhost:$pfw::localport <-> $ip:$port "
fconfigure $sockclient -blocking 0 -buffering none -translation binary
fconfigure $sockserver -blocking 0 -buffering none -translation binary
fileevent $sockclient readable [list sio $sockclient $sockserver $ip $port ]
fileevent $sockserver readable [list sio $sockserver $sockclient $ip $port ]
} else {
pfw::print "INT: #$pfw::db::cnt \t $ip:$port rejected by accesslist!"
catch { close $sockclient }
pfw::db::dec
}
} else {
pfw::print "INT: #$pfw::db::cnt \t $ip:$port rejected, maxsession reached!"
catch { close $sockclient }
pfw::db::dec
}
}
# MAIN STARTS HERE #
if { $argc == 7 } {
set pfw::db::cnt 0
set pfw::localhost [ lindex $argv 0 ]
set pfw::localport [ lindex $argv 1 ]
set pfw::remotehost [ lindex $argv 2 ]
set pfw::remoteport [ lindex $argv 3 ]
set pfw::maxsession [ lindex $argv 4 ]
set pfw::debug [ lindex $argv 5 ]
if { [ catch { set infile [ open [ lindex $argv 6 ]] } merror ] } {
puts "ERROR - $merror"
exit
} else {
set pfw::allowlist [ read $infile ]
if { [ catch { close $infile } merror ] } {
puts "ERROR - $merror"
exit
}
}
pfw::print "---------------------------------------------------------------------------------------"
pfw::print "$pfw::copyright - $pfw::localhost:$pfw::localport <-> $pfw::remotehost:$pfw::remoteport"
pfw::print "Allowing connections from:"
for {set x 0} { $x < [ llength $pfw::allowlist ]} {incr x} {pfw::print [ lindex $pfw::allowlist $x ] }
pfw::print "---------------------------------------------------------------------------------------"
socket -server [list connect $pfw::remotehost $pfw::remoteport ] -myaddr $pfw::localhost $pfw::localport
vwait forever
} else {
puts "\n\n"
puts "------------------------------------"
puts "$pfw::copyright - Usage:"
puts "------------------------------------"
puts "$argv0 localhost localport remotehost remoteport maxsessions false|true xslist.pfw\n\n"
}
# make a file called xslist.pfw and store it in de directory where pfw.tcl
# is listed and executed. XSLIST.PFW contains 1 line of allowed ip addresses:
127.0.0.1 192.168.168.110 212.121.221.121 192.168.168.120 192.168.168.12
|
Forwarding data from one machine to a static ip could be used to passby Firewalls when running the PortForwarder on an outside machine with a granted (by firewall) port (like 80). The example is fully functional, but I would like to have a look using the fcopy command instead and also to see if its possible to do with less catch checks on IO. (could be faster but also have some disadvantages using Fcopy)
Use the code for free and its a great example on how flexible tcl code is when it comes to socket tranfers.
See also sockspy at http://mini.net/tcl/sockspy for a similar port forwarding program but one designed more for the spying upon the data being sent on the socket.
Mini.net is offline. Find the new page for sockspy at wiki.tcl.tk or sourceforge.