Skip to content

Commit

Permalink
✨ feat: Http Obfuscation add basic parts
Browse files Browse the repository at this point in the history
  • Loading branch information
MoIzadloo committed Apr 17, 2023
1 parent 238d739 commit 5a58b88
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 54 deletions.
73 changes: 52 additions & 21 deletions src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import Address from '../helper/address'
import { AuthMethod } from '../helper/authMethod'
import { COMMANDS } from '../helper/constants'
import Request from '../helper/request'
import ObfsMethod from '../obfs/obfs'
import { None } from '../obfs'
import ObfsMethod, { ObfsBuilder } from '../obfs/obfs'
import { none } from '../obfs'
import Authenticator from './auth/authenticator'

/**
* The Client class is responsible for creating a TCP socket connection,
Expand Down Expand Up @@ -50,13 +51,13 @@ export class Client {
*/
private readonly userId?: string

private obfs: ObfsMethod
private obfs: ObfsBuilder

constructor(
port: number,
host: string,
version: 4 | 5,
obfs: ObfsMethod = new None(),
obfs = none(),
userId?: string
) {
this.host = host
Expand Down Expand Up @@ -109,8 +110,7 @@ export class Client {
connection.request = new Request(ver, cmd, address, 0, id)
connection.resolve = resolve
connection.reject = reject
connection.obfs = this.obfs
connection.obfs.handshake(connection)
connection.obfs = this.obfs(connection)
connection.event.subscribeOnce('error', (err) => {
reject(err.message)
})
Expand All @@ -135,12 +135,20 @@ export class Client {
version,
userId
)
if (connection?.request?.ver === 4) {
if (connection?.request?.addr?.type === 'domain') {
reject('The Address type is not supported')
}
connection.handlers.req.bind(connection)
}
connection.socket.once('connect', () => {
connection.obfs.handshake(() => {
if (connection?.request?.ver === 5) {
const authenticator = new Authenticator(connection)
authenticator.authenticate()
}
if (connection?.request?.ver === 4) {
if (connection?.request?.addr?.type === 'domain') {
reject('The Address type is not supported')
}
connection.handlers.req.bind(connection)
}
})
})
})
}

Expand All @@ -154,7 +162,22 @@ export class Client {
associate(port: number, host: string, version?: 4 | 5) {
return new Promise<HandlerResolve>((resolve, reject) => {
if (version === 5 || (!version && this.version === 5)) {
this.connector(port, host, COMMANDS.associate, resolve, reject, 5)
const connection = this.connector(
port,
host,
COMMANDS.associate,
resolve,
reject,
5
)
connection.socket.once('connect', () => {
connection.obfs.handshake(() => {
if (connection?.request?.ver === 5) {
const authenticator = new Authenticator(connection)
authenticator.authenticate()
}
})
})
} else {
reject("SOCKS V4 doesn't support associate command")
}
Expand All @@ -180,12 +203,20 @@ export class Client {
version,
userId
)
if (connection?.request?.ver === 4) {
if (connection?.request?.addr?.type === 'domain') {
reject('The Address type is not supported')
}
connection.handlers.req.connect(connection)
}
connection.socket.once('connect', () => {
connection.obfs.handshake(() => {
if (connection?.request?.ver === 5) {
const authenticator = new Authenticator(connection)
authenticator.authenticate()
}
if (connection?.request?.ver === 4) {
if (connection?.request?.addr?.type === 'domain') {
reject('The Address type is not supported')
}
connection.handlers.req.connect(connection)
}
})
})
})
}

Expand All @@ -210,7 +241,7 @@ export class Client {
return this
}

public useObfs(method: ObfsMethod): Client {
public useObfs(method: ObfsBuilder): Client {
this.obfs = method
return this
}
Expand All @@ -231,5 +262,5 @@ export const connect = (
version: 4 | 5,
userId?: string
) => {
return new Client(port, host, version, new None(), userId)
return new Client(port, host, version, none(), userId)
}
2 changes: 1 addition & 1 deletion src/client/handlers/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const connect = handler((info, socket, obfs, event, resolve, reject) => {
0,
info.userId
)
socket.write(request.toBuffer())
socket.write(obfs.obfuscate(request.toBuffer()))
socket.on('data', (data) => {
const reply = Reply.from(data)
if (resolve && reject && obfs) {
Expand Down
7 changes: 4 additions & 3 deletions src/helper/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { Handlers } from './handlers'
import { HandlerResolve } from './handler'
import Event from './event'
import Request from './request'
import { none } from '../obfs'
import ObfsMethod from '../obfs/obfs'
import { None } from '../obfs'

export type EventTypes = {
data: (data: Buffer) => void
Expand Down Expand Up @@ -70,7 +70,7 @@ class Connection {
socks4: true,
}

public obfs: ObfsMethod = new None()
public obfs: ObfsMethod

/**
* Clients Request
Expand All @@ -83,6 +83,7 @@ class Connection {
handlers: Handlers,
options?: Options
) {
this.obfs = none()(this)
this.handlers = handlers
this.socket = socket
this.event = event
Expand All @@ -91,7 +92,7 @@ class Connection {
}
socket.on('data', (data) => {
try {
this.readable = new Readable(data)
this.readable = new Readable(this.obfs.deObfuscate(data))
this.parse()
this.reply()
} catch (err) {
Expand Down
1 change: 1 addition & 0 deletions src/helper/readable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* The Readable class turns a Buffer into a readable object,
* so it could be read piece by pieces
*/

class Readable {
/**
* Input Buffer
Expand Down
57 changes: 43 additions & 14 deletions src/obfs/http.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import ObfsMethod from './obfs'
import Connection from '../helper/connection'
import { encryptionMethods } from '../helper/constants'
import { obfsHttpMethods } from '../helper/constants'
import { encryptionMethods, obfsHttpMethods } from '../helper/constants'

export class Http extends ObfsMethod {
class Http extends ObfsMethod {
public path
public name = 'HTTP'
public encryption: string
public method: string
constructor(
path = '',
encryption = encryptionMethods.none,
method = obfsHttpMethods.post
connection: Connection,
type: typeof ObfsMethod.CLIENT | typeof ObfsMethod.SERVER,
path: string,
encryption: string,
method: string
) {
super()
super(connection, type)
this.path = path
this.encryption = encryption
this.method = method
}

handshake() {
console.log('ran')
handshake(callback: () => void): void {
callback()
}

check(message: Buffer) {
Expand All @@ -35,19 +36,47 @@ export class Http extends ObfsMethod {
}

// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(match)
console.log(`Found match, group ${groupIndex}: ${match}`)
})
if (m[1] !== this.method || m[2] !== this.path || m[3] !== '1.1') {
return false
}
}
return true
}

deObfuscate(message: Buffer): Buffer {
const http = message.toString()
if (this.type === ObfsMethod.SERVER) {
const parts = http.split('\r\n')
console.log(parts)
}
return message
}

obfuscate(message: Buffer): Buffer {
return message
let http = ''
if (this.type === ObfsMethod.CLIENT) {
http += `POST ${this.path} HTTP/1.1\r\n`
http += `Host: ${this.connection.socket.remoteAddress}:${this.connection.socket.remotePort}\r\n`
http += `Connection: keep-alive\r\n`
http += `content-length: ${message.length}\r\n`
http += message
http += `\r\n\r\n`
}
return Buffer.from(http)
}
}

export const http =
(
path = '',
encryption = encryptionMethods.none,
method = obfsHttpMethods.post
) =>
(
connection: Connection,
type:
| typeof ObfsMethod.CLIENT
| typeof ObfsMethod.SERVER = ObfsMethod.CLIENT
) => {
return new Http(connection, type, path, encryption, method)
}
21 changes: 14 additions & 7 deletions src/obfs/none.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import ObfsMethod from './obfs'
import Authenticator from '../client/auth/authenticator'
import Connection from '../helper/connection'

export class None extends ObfsMethod {
class None extends ObfsMethod {
name = 'None'

check(message: Buffer): boolean {
Expand All @@ -17,10 +16,18 @@ export class None extends ObfsMethod {
return message
}

handshake(connection: Connection): void {
if (connection?.request?.ver === 5) {
const authenticator = new Authenticator(connection)
authenticator.authenticate()
}
handshake(callback: () => void): void {
callback()
}
}

export const none =
() =>
(
connection: Connection,
type:
| typeof ObfsMethod.CLIENT
| typeof ObfsMethod.SERVER = ObfsMethod.CLIENT
) => {
return new None(connection, type)
}
18 changes: 17 additions & 1 deletion src/obfs/obfs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import Connection from '../helper/connection'

abstract class ObfsMethod {
public static readonly CLIENT = 'CLIENT'
public static readonly SERVER = 'SERVER'
public type: typeof ObfsMethod.CLIENT | typeof ObfsMethod.SERVER
protected connection: Connection
constructor(
connection: Connection,
type: typeof ObfsMethod.CLIENT | typeof ObfsMethod.SERVER
) {
this.connection = connection
this.type = type
}
public abstract name: string
public abstract check(message: Buffer): boolean
public abstract handshake(connection: Connection): void
public abstract handshake(callback: () => void): void
public abstract deObfuscate(message: Buffer): Buffer
public abstract obfuscate(message: Buffer): Buffer
}

export type ObfsBuilder = (
connection: Connection,
type?: typeof ObfsMethod.CLIENT | typeof ObfsMethod.SERVER
) => ObfsMethod

export default ObfsMethod
1 change: 0 additions & 1 deletion src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Handlers } from '../helper/handlers'
import { AuthMethod } from '../helper/authMethod'
import { connect, associate, bind } from './handlers'
import Event from '../helper/event'
import { None } from '../obfs'

type ConnectionListener = ((socket: net.Socket) => void) | undefined

Expand Down
12 changes: 9 additions & 3 deletions src/server/state/socks5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import Request from '../../helper/request'
import * as socks4 from './socks4'
import { State } from '../../helper/state'
import Authenticator from '../auth/authenticator'
import { Http, None } from '../../obfs'
import { http, none } from '../../obfs'
import Readable from '../../helper/readable'
import ObfsMethod from '../../obfs/obfs'

export class ObfsState extends State {
private obfsMethods = [new None(), new Http()]
private obfsMethods = [none(), http()]

parse(): void {
const message = this.context.cat()
for (const method of this.obfsMethods) {
for (const m of this.obfsMethods) {
const method = m(this.context, ObfsMethod.SERVER)
if (method.check(message)) {
this.context.obfs = method
break
Expand All @@ -19,6 +22,9 @@ export class ObfsState extends State {
}

reply(): void {
this.context.readable = new Readable(
this.context.obfs.deObfuscate(this.context.read())
)
this.context.transitionTo(new IdentifierState(this.context))
this.context.parse()
this.context.reply()
Expand Down
Loading

0 comments on commit 5a58b88

Please sign in to comment.