Skip to content

Instantly share code, notes, and snippets.

@scorredoira
Created May 23, 2020 17:56
Show Gist options
  • Save scorredoira/aa38543ffb70d484d0a79c4ddb051512 to your computer and use it in GitHub Desktop.
Save scorredoira/aa38543ffb70d484d0a79c4ddb051512 to your computer and use it in GitHub Desktop.
A simple TCP proxy
/**
* ------------------------------------------------------------------
* A simple TCP proxy.
*
* Configuration example:
*
* {
* "rules": [
* { "local": ":99995", "remote": "127.0.0.18:22" },
* { "local": ":99996", "remote": "127.0.0.19:22" },
* ]
* }
* ------------------------------------------------------------------
*/
import "stdlib/native"
export function main() {
let conf = json.unmarshal(os.fileSystem.readAll("config.json"))
for (let rule of conf.tcproxy) {
startProxy(rule.local, rule.remote)
}
// block
sync.newChannel().receive()
}
function startProxy(local: string, remote: string) {
go(() => new TCPProxy(local, remote).start())
}
class TCPProxy {
localAddr: net.TCPAddr
remoteAddr: net.TCPAddr
constructor(localAddr: string, remoteAddr: string) {
this.localAddr = net.resolveTCPAddr("tcp", localAddr)
this.remoteAddr = net.resolveTCPAddr("tcp", remoteAddr)
}
start() {
let listener = net.listenTCP("tcp", this.localAddr)
while (true) {
try {
let conn = listener.accept()
go(() => this.handleConn(conn))
} catch (error) {
log.write("system", error)
}
}
}
private handleConn(localConn: net.TCPConnection) {
defer(() => localConn.close())
let remoteConn = net.dialTCP("tcp", null, this.remoteAddr)
defer(() => remoteConn.close())
let errChan = sync.newChannel()
go(() => this.copy(localConn, remoteConn, errChan))
go(() => this.copy(remoteConn, localConn, errChan))
errChan.receive()
}
private copy(dst: io.Writer, src: io.Reader, errChan: sync.Channel) {
let err
try {
io.copy(dst, src)
} catch (error) {
err = error
}
errChan.send(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment