#!/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