Skip to content

Commit

Permalink
✨ feat: Add server associate implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
MoIzadloo committed Mar 19, 2023
1 parent 758c600 commit 64443ec
Show file tree
Hide file tree
Showing 22 changed files with 362 additions and 91 deletions.
48 changes: 39 additions & 9 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,43 @@ 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 +207,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 Down Expand Up @@ -260,7 +290,7 @@ you can easily implement it in a matter of seconds.
### 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 Down
6 changes: 4 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

### In Progress

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

### Done ✓

- [x] Implementation of server Connect
- [x] Implementation of client (Connect)
- [x] Implementation of client Connect
- [x] Implementation of server Associate
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
"url": "https://github.com/MoIzadloo/tsocks/issues"
},
"dependencies": {
"ipaddr.js": "^2.0.1",
"@types/ip": "^1.1.0",
"ip": "^1.1.8",
"net": "^1.0.2"
},
"devDependencies": {
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
4 changes: 2 additions & 2 deletions src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import { COMMANDS } from '../helper/constants'
*/
export class Client {
/**
* Socks server host
* SOCKS server host
*/
private readonly host: string

/**
* Socks server port
* SOCKS server port
*/
private readonly port: number

Expand Down
5 changes: 2 additions & 3 deletions src/client/handlers/connect.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { handler, Info } from '../../helper/handler'
import { handler } from '../../helper/handler'
import Writable from '../../helper/writable'
import { Readable } from '../../helper/readable'
import Readable from '../../helper/readable'
import { COMMANDS, SOCKS4REPLY, SOCKS5REPLY } from '../../helper/constants'
import net from 'net'

/**
* Handle connect request
Expand Down
28 changes: 7 additions & 21 deletions src/helper/address.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ADDRESSTYPES } from './constants'
import { bufToArray } from './util'
import ipaddr from 'ipaddr.js'
import * as ip from 'ip'

interface BuffIp {
port: Buffer
Expand All @@ -17,18 +16,6 @@ class Address {
public port: number

constructor(port: number, host: string) {
/**
* Regular expression for ipv4
*/
const ipv4Regex =
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'

/**
* Regular expression for ipv6
*/
const ipv6Regex =
'(?!^(?:(?:.*(?:::.*::|:::).*)|::|[0:]+[01]|.*[^:]:|[0-9a-fA-F](?:.*:.*){8}[0-9a-fA-F]|(?:[0-9a-fA-F]:){1,6}[0-9a-fA-F])$)^(?:(::|[0-9a-fA-F]{1,4}:{1,2})([0-9a-fA-F]{1,4}:{1,2}){0,6}([0-9a-fA-F]{1,4}|::)?)$'

/**
* Regular expression for domain
*/
Expand All @@ -47,9 +34,9 @@ class Address {
/**
* Type (ipv4 | ipv6 | domain)
*/
if (this.host.match(ipv4Regex)) {
if (ip.isV4Format(this.host)) {
this.type = 'ipv4'
} else if (this.host.match(ipv6Regex)) {
} else if (ip.isV6Format(this.host)) {
this.type = 'ipv6'
} else if (this.host.match(domainRegex)) {
this.type = 'domain'
Expand All @@ -66,14 +53,13 @@ class Address {
* @returns Address
*/
public static buffToAddrFactory(
host: Buffer,
port: Buffer,
host: Buffer,
type: number
): Address {
let addr
if (type === ADDRESSTYPES.ipv6 || type === ADDRESSTYPES.ipv4) {
addr = ipaddr.fromByteArray(bufToArray(host))
addr = addr.toString()
addr = ip.toString(host)
} else {
addr = host.toString()
}
Expand All @@ -90,11 +76,11 @@ class Address {
switch (this.type) {
case 'ipv4':
type = ADDRESSTYPES.ipv4
addr = Buffer.from(ipaddr.parse(this.host).toByteArray())
addr = ip.toBuffer(this.host)
break
case 'ipv6':
type = ADDRESSTYPES.ipv6
addr = Buffer.from(ipaddr.parse(this.host).toByteArray())
addr = ip.toBuffer(this.host)
break
default:
type = ADDRESSTYPES.domain
Expand Down
5 changes: 2 additions & 3 deletions src/helper/connection.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as net from 'net'
import { State } from './state'
import { Readable } from './readable'
import Readable from './readable'
import { IdentifierState } from '../server/state/socks5'
import Writable from './writable'
import { Handlers } from './handlers'
import { Handler } from './handler'
import Address from './address'
import Event from './event'

Expand Down Expand Up @@ -50,7 +49,7 @@ class Connection {
public readable: Readable = new Readable(Buffer.allocUnsafe(0))

/**
* Socks version
* SOCKS version
*/
public version?: number

Expand Down
16 changes: 12 additions & 4 deletions src/helper/readable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* The Readable class turns a Buffer into a readable object,
* so it could be read piece by pieces
*/
export class Readable {
class Readable {
/**
* Input Buffer
*/
Expand All @@ -13,12 +13,18 @@ export class Readable {
}

/**
* Read n bytes of data
* Read n bytes of data,
* reads all the data if no argument is passed
* @param bytes - Number of bytes to be read from data
* @returns Buffer
*/
public read(bytes: number): Buffer {
const slice = this.data.subarray(0, bytes)
public read(bytes?: number): Buffer {
let slice
if (bytes) {
slice = this.data.subarray(0, bytes)
} else {
slice = this.data.subarray(0, this.data.length)
}
this.data = this.data.subarray(bytes, this.data.length)
return slice
}
Expand All @@ -35,3 +41,5 @@ export class Readable {
return slice
}
}

export default Readable

0 comments on commit 64443ec

Please sign in to comment.