@maks11060/serve
v0.0.1
Published
Serve - is a wrapper around a tcp listener similar to Deno.serve or Bun.serve
Maintainers
Readme
Serve
Serve - is a wrapper around a tcp listener similar to Deno.serve or Bun.serve
Runtimes
- [x] Deno
- [x] Node
Example
import {serve} from '@maks11060/serve'
import {bidirectionalPipe} from '@maks11060/serve/io'
const port = Number(process.env.PORT) || 1081
const hostname = process.env.HOST || '0.0.0.0'
serve({
port,
hostname,
async connect(request) {
request.connectProtocol // "socks4" | "socks5" | "websocket"
if (request.connectProtocol === 'socks4') {
const socks4 = request.upgradeSocks4()
// ... see example below
}
if (request.connectProtocol === 'socks5') {
const socks5 = request.upgradeSocks5()
// ... see example below
}
if (request.connectProtocol === 'websocket') {
const ws = request.upgradeWebSocketStream()
// ... see example below
}
},
})Socks
const requireAuthorization = false
serve({
port,
hostname,
async connect(request) {
if (request.connectProtocol === 'socks4') {
const socks4 = request.upgradeSocks4()
const clientRequest = socks4.clientRequest()
try {
const targetConn = await Deno.connect(clientRequest)
const clientConn = await socks4.accept()
await bidirectionalPipe(targetConn, clientConn)
} catch (e) {
console.error(e)
await socks4.reject()
}
}
if (request.connectProtocol === 'socks5') {
const socks5 = request.upgradeSocks5() // accept socks5 connect
if (requireAuthorization) {
const cred = await socks5.clientAuthorization('Password') // request password
if (cred.username === 'user' && cred.password === 'pass') {
await socks5.acceptAuthorization()
console.log(
`auth success: ${request.remoteAddress.hostname}:${request.remoteAddress.port} ${cred.username}`,
)
} else {
await socks5.rejectAuthorization()
console.log('auth failed', cred)
}
}
// ClientRequest
const clientRequest = await socks5.clientRequest()
console.log(clientRequest)
try {
if (clientRequest.command === 'connect') {
const targetConn = await Deno.connect(clientRequest)
// Accept connection
const clientConn = await socks5.accept()
await bidirectionalPipe(targetConn, clientConn)
}
} catch (e) {
console.error(e)
await socks5.reject('HostUnreachable')
}
}
},
})WebSocketStream
serve({
port,
hostname,
async connect(request) {
if (request.connectProtocol === 'websocket') {
// https://developer.chrome.com/docs/capabilities/web-apis/websocketstream#use
const ws = request.upgradeWebSocketStream({
protocols: ['echo', 'test'],
maxMessageSize: 10,
fragmentSize: 10,
})
const {readable, writable, protocol} = await ws.opened
console.log({protocol})
const reader = readable.getReader()
const writer = writable.getWriter()
while (true) {
const {value, done} = await reader.read()
if (done) console.log({done})
if (done) break
console.log({value})
await new Promise((r) => setTimeout(r, 500))
if (typeof value === 'string' && value === 'close') {
ws.close({reason: 'user asked to close'})
return
} else if (
value instanceof Uint8Array
&& new TextDecoder().decode(value) === 'close\r\n'
) {
ws.close({reason: 'user asked to close'})
return
}
await writer.write(value) // echo
}
ws.closed.then(console.log)
}
},
})TODO
- [x]
serve()- [ ] add support tls
- [x]
connect(request): Promise<void>- check supported protocol or use raw tcp- [x] socks4
- [x] socks5, socks5h
- [x] websocket - need to test
- [ ] tcp
Testing
Test socks
curl -m 3 -x socks4://127.0.0.1:1080 https://api.myip.com/
curl -m 3 -x socks5://127.0.0.1:1080 https://api.myip.com/
curl -m 3 -x socks5h://127.0.0.1:1080 https://api.myip.com/Test websocket
curl --no-progress-meter -T . -N ws://127.0.0.1:1080