Skip to content

Instantly share code, notes, and snippets.

@kasuganosora
Created August 25, 2013 03:02
Show Gist options
  • Save kasuganosora/6331728 to your computer and use it in GitHub Desktop.
Save kasuganosora/6331728 to your computer and use it in GitHub Desktop.
local SOCK5 proxy demo
net = require("net")
util = require("util")
AUTHENTICATION =
NOAUTH: 0x00
GSSAOI: 0x01
USERPASS: 0x02
NONE:0xFF
ADDRTYPE =
IP_V4: 0x01
DNS: 0x03
IP_v6: 0x04
REQUEST_CMD =
CONNECT: 0x01
BIND: 0x02
UDP_ASSOCIATE: 0x03
REP_CMD_TYPE =
SUCCEEDED: 0x00
GENERAL_SOCKS_SERVER_FAILURE: 0x01
CONNECTION_NOT_ALLOWED_BY_RULESET: 0x02
NETWORK_UNREACHABLE: 0x03
HOST_UNREACHABLE: 0x04
CONNECTION_REFUSED: 0x05
TTL_EXPIRED: 0x06
COMMAND_NOT_SUPPRTED: 0x07
ADDRESS_TYPE_NOT_SUPPORTED: 0x08
TO_XFF_UNASSIGNED: 0x09
SOCKS_VER = 0x05
inetNtoa = (buf)->
buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]
innetAton = (ipStr)->
parts = ipStr.split(".")
unless parts.length is 4
null
buf = new Buffer(4)
i = 0;
while i < 4
buf[i] = +parts[i]
i++
buf
server = net.createServer (connection)->
stage =0
headerLength = 0
remote = 0
cachedPiess = []
connection.on "data",(data)->
if stage is 5
connection.pause() unless remote.write(data)
if stage is 0
tempBuf = new Buffer(2)
tempBuf.writeUInt8 SOCKS_VER,0
tempBuf.writeUInt8 REP_CMD_TYPE.SUCCEEDED,1
connection.write tempBuf
stage = 1
return
if stage is 1
try
cmd = data[1]
addrType = data[3]
unless cmd is REQUEST_CMD.CONNECT
util.log("unsupported cmd: " + cmd)
reply = new Buffer(4)
reply.writeUInt8 SOCKS_VER,0
reply.writeUInt8 REP_CMD_TYPE.COMMAND_NOT_SUPPRTED ,1
reply.writeUInt8 0x00,2
reply.writeUInt8 0x00,3
reply.writeUInt8 0x01,3
connection.end reply
return
if addrType is ADDRTYPE.DNS
addrLen = data[4]
else unless addrType is ADDRTYPE.IP_v4
util.log("unsupported addrtype: " + addrtype)
connection.end()
return
if addrType is ADDRTYPE.IP_v4
remoteAddr = inetNtoa(data.slice(4,8))
remotePort = data.readUInt16BE(8)
headerLength = 10
else
# DNS
remoteAddr = data.slice(5, 5 + addrLen).toString("binary")
remotePort = data.readUInt16BE(5 + addrLen)
headerLength = 5 + addrLen + 2
buf = new Buffer(10)
# REP_CMD_TYPE.SUCCEEDED
buf.write("\u0005\u0000\u0000\u0001", 0, 4, "binary")
buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary")
buf.writeInt16BE(2222, 8)
connection.write(buf)
remote = net.connect(remotePort,remoteAddr,()->
util.log("connecting " + remoteAddr + ":" + remotePort);
i = 0
while i < cachedPiess.length
piece = cachedPiess[i]
remote.write piece
i++
stage = 5
)
remote.on "data",(data)->
remote.pause unless connection.write(data)
remote.on "end",()->
cachedPiess = null
connection.end()
remote.on "error",(e)->
cachedPiess = null
util.log("remote " + remoteAddr + ":" + remotePort + " error: " + e);
if stage is 4
connection.destroy()
else
connection.end()
remote.on "drain",()->
connection.resume()
remote.setTimeout 3000,()=>
connection.end()
remote.destroy()
if data.length > headerLength
buf = new Buffer( data.length - headerLength)
data.copy(buf,0,headerLength)
cachedPiess.push buf
buf = null
stage = 4
catch e
util.log e
connection.destroy()
remote.destroy() if remote
else
cachedPiess.push(data) if stage is 4
connection.on "end",()->
remote.destroy() if remote
connection.on "error",(e)->
util.log("local error: " + e)
remote.destroy() if remote
connection.on "drain",()->
remote.resume() if remote and stage is 5
connection.setTimeout 3000,()=>
remote.destroy() if remote
connection.destroy()
server.on "error",(e)->
util.log("Address in use, aborting") if e.code is "EADDRINUSE"
process.exit 1
server.listen 1989
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment