Skip to content

Commit

Permalink
✨ feat: Add associate support
Browse files Browse the repository at this point in the history
  • Loading branch information
MoIzadloo committed Mar 26, 2023
2 parents 3985bd9 + 5196ba6 commit 855a07a
Show file tree
Hide file tree
Showing 31 changed files with 964 additions and 401 deletions.
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
# [v2.0.0](https://github.com/MoIzadloo/tsocks/compare/v1.0.0...v2.0.0) (2023-02-24)

## 💥 Breaking Changes
- [`de8b4c9`](https://github.com/MoIzadloo/tsocks/commit/de8b4c9) feat: Release from version 2
- [`2ba7fc7`](https://github.com/MoIzadloo/tsocks/commit/2ba7fc7) feat: Release from version 2

- [`de8b4c9`](https://github.com/MoIzadloo/tsocks/commit/de8b4c9) feat: Release from version 2
- [`2ba7fc7`](https://github.com/MoIzadloo/tsocks/commit/2ba7fc7) feat: Release from version 2

# v1.0.0 (2023-02-24)

## 💥 Breaking Changes
- [`718b2c2`](https://github.com/MoIzadloo/tsocks/commit/718b2c2) feat: First release

- [`718b2c2`](https://github.com/MoIzadloo/tsocks/commit/718b2c2) feat: First release
250 changes: 178 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# TSocks

TSocks is an implementation of socks protocol.
TSocks is an implementation of SOCKS protocol.
It's designed to be very flexible and adhesive

- **Modular** to be suited to your needs
Expand Down Expand Up @@ -65,7 +65,7 @@ server.listen(port, host)
### Proxy Server With Authentication

There are two different authentication methods independent
of which version of the socks protocol you are working with.
of which version of the SOCKS protocol you are working with.
in case you are using V5, you can use the useAuth hook and use
one of the available methods from the [methods'](src/server/auth/methods)
directory, or if you want to create your own implementations or
Expand Down Expand Up @@ -121,7 +121,7 @@ both useAuth and useIdent together.
server.listen(port, host)
```

3. Server socks4 and socks 5
3. Server socks4 and SOCKS 5

```typescript
import { createServer, serverAuthMethods } from 'tsocks'
Expand Down Expand Up @@ -154,13 +154,42 @@ both useAuth and useIdent together.
server.listen(port, host)
```

### Socks Adaptor
### Associate (UDP Relay)

You may want to use the socks protocol to handle incoming network traffic.
so you can set up a socks server and with the help of
The associate command assists you to send UDP packets to a remote host through the proxy server.
the relay will listen for packets on the same port number as the SOCKS server does, and it doesn't support fragmentation however,
you could replace it with your own implementation with the help of the useReq hook

```typescript
import { createServer } from 'tsocks'

const host = '127.0.0.1'
const port = 1080

const server = createServer({
socks4: true,
socks5: true,
})

server.useReq('associate', (info, socket) => {
const host = info.address.host
const port = info.address.port // Port number
const type = info.address.type // ipv4 | ipv6 | domain
const version = info.version // SOCKS version
// You can implement the rest how ever you want
// Just remember the response should be decided by version
})

server.listen(port, host)
```

### SOCKS Adaptor

You may want to use the SOCKS protocol to handle incoming network traffic.
so you can set up a SOCKS server and with the help of
useReq hook you have access to the socket and request information
which contains information like host address and port, therefore you can send traffic through a tunnel with any other protocol like WS or HTTP
or whatever you want and then send the response back to the client through socks.
or whatever you want and then send the response back to the client through SOCKS.

```typescript
import { createServer } from 'tsocks'
Expand All @@ -177,7 +206,7 @@ server.useReq('connect', (info, socket) => {
const host = info.address.host
const port = info.address.port // Port number
const type = info.address.type // ipv4 | ipv6 | domain
const version = info.version // Socks version
const version = info.version // SOCKS version
// You can implement the rest how ever you want
// Just remember the response should be decided by version
})
Expand All @@ -199,20 +228,24 @@ you can easily implement it in a matter of seconds.
const port = 1080
const httpPort = 80

const socket = await connect(port, host, 5).connect(httpPort, 'google.com')
try {
const info = await connect(port, host, 5).connect(httpPort, 'google.com')

socket.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
info.socket.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
)
)
)

socket.on('data', (data) => {
console.log(data)
})
info.socket.on('data', (data) => {
console.log(data)
})
} catch (err) {
console.log(err)
}
```

2. Multiple connections
Expand All @@ -226,41 +259,49 @@ you can easily implement it in a matter of seconds.

const client = connect(port, host, 5)

const socket1 = await client.connect(httpPort, 'google.com')
try {
const info1 = await client.connect(httpPort, 'google.com')

socket1.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
info1.socket.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
)
)
)

socket1.on('data', (data) => {
console.log(data)
})

const socket2 = await client.connect(httpPort, 'google.com')

socket2.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
info1.socket.on('data', (data) => {
console.log(data)
})
} catch (err) {
console.log(err)
}

try {
const info2 = await client.connect(httpPort, 'google.com')

info2.socket.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
)
)
)

socket2.on('data', (data) => {
console.log(data)
})
info2.socket.on('data', (data) => {
console.log(data)
})
} catch (err) {
console.log(err)
}
```

### Proxy client with authentication

There are two different authentication methods independent
of which version of the socks protocol you are working with.
of which version of the SOCKS protocol you are working with.
in case you are using V5, you can use the useAuth hook and use
one of the available methods from the [methods'](src/client/auth/methods)
directory, or if you want to create your own implementations or
Expand All @@ -280,22 +321,26 @@ as an argument (userId) to the request handler (connect | bind | associate).
const password = 'pass'
const httpPort = 80

const socket = await connect(port, host, 5)
.useAuth(clientAuthMethods.userPass(username, password))
.connect(httpPort, 'google.com')

socket.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
try {
const info = await connect(port, host, 5)
.useAuth(clientAuthMethods.userPass(username, password))
.connect(httpPort, 'google.com')

info.socket.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
)
)
)

socket.on('data', (data) => {
console.log(data)
})
info.socket.on('data', (data) => {
console.log(data)
})
} catch (err) {
console.log(err)
}
```

2. Identification socks4
Expand All @@ -308,25 +353,86 @@ as an argument (userId) to the request handler (connect | bind | associate).
const userId = 'user:pass'
const httpPort = 80

const socket = await connect(port, host, 4, userId).connect(
httpPort,
'142.251.1.101'
)
try {
const info = await connect(port, host, 4, userId).connect(
httpPort,
'142.251.1.101'
)

socket.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
info.socket.write(
Buffer.from(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
)
)
)

socket.on('data', (data) => {
console.log(data)
})
info.socket.on('data', (data) => {
console.log(data)
})
} catch (err) {
console.log(err)
}
```

### Associate (UDP Relay)

The associate command assists you to send UDP packets to a remote host through the proxy server.
after sending an associate request the server will reply with the information about the relays host and port
with that information, you can create a datagram socket and send your UDP packets to the address of the relay to get relayed.
as you can see in the example below you have to wrap your data with the createUdpFrame and also unwrap it with parseUdpFrame as it's part of the protocol

```typescript
import {
createServer,
connect,
createUdpFrame,
parseUdpFrame,
Address,
} from 'tsocks'
import * as dgram from 'dgram'

const host = '127.0.0.1'
const port = 1080

// Create simple socks server
const server = createServer()
server.listen(port, host)

// Creates a simple echo server that returns whatever you send
const echoServerPort = 5467
const echoServer = dgram.createSocket('udp4')
echoServer.on('message', (msg, rinfo) => {
echoServer.send(msg, rinfo.port, rinfo.address)
})
echoServer.bind(echoServerPort)

try {
// Send an associate request
const info = await connect(port, host, 5).associate(0, '0.0.0.0')
const udpSocket = dgram.createSocket('udp4')
udpSocket.send(
createUdpFrame(
new Address(echoServerPort, '127.0.0.1'),
Buffer.from('Hello')
),
info.address.port,
info.address.host
)
udpSocket.once('message', (msg) => {
const parsedMsg = parseUdpFrame(msg)
console.log(parsedMsg.data.toString())
})

info.socket.on('data', (data) => {
console.log(data)
})
} catch (err) {
console.log(err)
}
```

## References

- [RFC - SOCKS Protocol Version 5](https://www.rfc-editor.org/rfc/rfc1928)
Expand Down
5 changes: 4 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@

### In Progress

- [ ] Implementation of server (Bind | Associate)
- [ ] Implementation of server Bind
- [ ] Implementation of client Bind

### Done ✓

- [x] Implementation of server Connect
- [x] Implementation of client Connect
- [x] Implementation of server Associate
- [x] Implementation of client Associate
6 changes: 6 additions & 0 deletions config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ module.exports = {
],
},
resolve: {
fallback: {
net: false,
os: false,
dgram: false,
buffer: false,
},
extensions: ['.ts', '.js', '.tsx', '.jsx'],
},
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@
"url": "https://github.com/MoIzadloo/tsocks/issues"
},
"dependencies": {
"ipaddr.js": "^2.0.1",
"net": "^1.0.2"
"@types/ip": "^1.1.0",
"ip": "^1.1.8"
},
"devDependencies": {
"@commitlint/cli": "^17.4.2",
Expand Down
2 changes: 1 addition & 1 deletion src/client/auth/methods/userPass.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AUTHMODES, SOCKSVERSIONS } from '../../../helper/constants'
import { AUTHMODES } from '../../../helper/constants'
import { AuthMethod } from '../../../helper/authMethod'
import Connection from '../../../helper/connection'
import Writable from '../../../helper/writable'
Expand Down

0 comments on commit 855a07a

Please sign in to comment.