Replace NEKit dependency with reduced subset

This commit is contained in:
relikd
2020-03-24 21:12:58 +01:00
parent 2473e77519
commit cbec3981bb
103 changed files with 24996 additions and 264 deletions

View File

@@ -0,0 +1,156 @@
import Foundation
open class AdapterSocket: NSObject, SocketProtocol, RawTCPSocketDelegate {
open var session: ConnectSession!
open var observer: Observer<AdapterSocketEvent>?
open override var description: String {
return "<\(typeName) host:\(session.host) port:\(session.port))>"
}
internal var _cancelled = false
public var isCancelled: Bool {
return _cancelled
}
/**
Connect to remote according to the `ConnectSession`.
- parameter session: The connect session.
*/
open func openSocketWith(session: ConnectSession) {
guard !isCancelled else {
return
}
self.session = session
observer?.signal(.socketOpened(self, withSession: session))
socket?.delegate = self
_status = .connecting
}
deinit {
socket?.delegate = nil
}
// MARK: SocketProtocol Implementation
/// The underlying TCP socket transmitting data.
open var socket: RawTCPSocketProtocol!
/// The delegate instance.
weak open var delegate: SocketDelegate?
var _status: SocketStatus = .invalid
/// The current connection status of the socket.
public var status: SocketStatus {
return _status
}
open var statusDescription: String {
return "\(status)"
}
public init(observe: Bool = true) {
super.init()
if observe {
observer = ObserverFactory.currentFactory?.getObserverForAdapterSocket(self)
}
}
/**
Read data from the socket.
- warning: This should only be called after the last read is finished, i.e., `delegate?.didReadData()` is called.
*/
open func readData() {
guard !isCancelled else {
return
}
socket?.readData()
}
/**
Send data to remote.
- parameter data: Data to send.
- warning: This should only be called after the last write is finished, i.e., `delegate?.didWriteData()` is called.
*/
open func write(data: Data) {
guard !isCancelled else {
return
}
socket?.write(data: data)
}
/**
Disconnect the socket elegantly.
*/
open func disconnect(becauseOf error: Error? = nil) {
_status = .disconnecting
_cancelled = true
session.disconnected(becauseOf: error, by: .adapter)
observer?.signal(.disconnectCalled(self))
socket?.disconnect()
}
/**
Disconnect the socket immediately.
*/
open func forceDisconnect(becauseOf error: Error? = nil) {
_status = .disconnecting
_cancelled = true
session.disconnected(becauseOf: error, by: .adapter)
observer?.signal(.forceDisconnectCalled(self))
socket?.forceDisconnect()
}
// MARK: RawTCPSocketDelegate Protocol Implementation
/**
The socket did disconnect.
- parameter socket: The socket which did disconnect.
*/
open func didDisconnectWith(socket: RawTCPSocketProtocol) {
_status = .closed
observer?.signal(.disconnected(self))
delegate?.didDisconnectWith(socket: self)
}
/**
The socket did read some data.
- parameter data: The data read from the socket.
- parameter from: The socket where the data is read from.
*/
open func didRead(data: Data, from: RawTCPSocketProtocol) {
observer?.signal(.readData(data, on: self))
}
/**
The socket did send some data.
- parameter data: The data which have been sent to remote (acknowledged). Note this may not be available since the data may be released to save memory.
- parameter by: The socket where the data is sent out.
*/
open func didWrite(data: Data?, by: RawTCPSocketProtocol) {
observer?.signal(.wroteData(data, on: self))
}
/**
The socket did connect to remote.
- parameter socket: The connected socket.
*/
open func didConnectWith(socket: RawTCPSocketProtocol) {
_status = .established
observer?.signal(.connected(self))
delegate?.didConnectWith(adapterSocket: self)
}
}

View File

@@ -0,0 +1,48 @@
import Foundation
/// This adapter connects to remote directly.
public class DirectAdapter: AdapterSocket {
/// If this is set to `false`, then the IP address will be resolved by system.
var resolveHost = false
/**
Connect to remote according to the `ConnectSession`.
- parameter session: The connect session.
*/
override public func openSocketWith(session: ConnectSession) {
super.openSocketWith(session: session)
guard !isCancelled else {
return
}
do {
try socket.connectTo(host: session.host, port: Int(session.port), enableTLS: false, tlsSettings: nil)
} catch let error {
observer?.signal(.errorOccured(error, on: self))
disconnect()
}
}
/**
The socket did connect to remote.
- parameter socket: The connected socket.
*/
override public func didConnectWith(socket: RawTCPSocketProtocol) {
super.didConnectWith(socket: socket)
observer?.signal(.readyForForward(self))
delegate?.didBecomeReadyToForwardWith(socket: self)
}
override public func didRead(data: Data, from rawSocket: RawTCPSocketProtocol) {
super.didRead(data: data, from: rawSocket)
delegate?.didRead(data: data, from: self)
}
override public func didWrite(data: Data?, by rawSocket: RawTCPSocketProtocol) {
super.didWrite(data: data, by: rawSocket)
delegate?.didWrite(data: data, by: self)
}
}

View File

@@ -0,0 +1,35 @@
import Foundation
/// The base class of adapter factory.
open class AdapterFactory {
public init() {}
/**
Build an adapter.
- parameter session: The connect session.
- returns: The built adapter.
*/
open func getAdapterFor(session: ConnectSession) -> AdapterSocket {
return getDirectAdapter()
}
/**
Helper method to get a `DirectAdapter`.
- returns: A direct adapter.
*/
public func getDirectAdapter() -> AdapterSocket {
let adapter = DirectAdapter()
adapter.socket = RawSocketFactory.getRawSocket()
return adapter
}
}
/// Factory building direct adapters.
///
/// - note: This is needed since we need to identify direct adapter factory.
public class DirectAdapterFactory: AdapterFactory {
public override init() {}
}

View File

@@ -0,0 +1,27 @@
import Foundation
/// This is a very simple wrapper of a dict of type `[String: AdapterFactory]`.
///
/// Use it as a normal dict.
public class AdapterFactoryManager {
private var factoryDict: [String: AdapterFactory]
public subscript(index: String) -> AdapterFactory? {
get {
if index == "direct" {
return DirectAdapterFactory()
}
return factoryDict[index]
}
set { factoryDict[index] = newValue }
}
/**
Initialize a new factory manager.
- parameter factoryDict: The factory dict.
*/
public init(factoryDict: [String: AdapterFactory]) {
self.factoryDict = factoryDict
}
}

View File

@@ -0,0 +1,11 @@
import Foundation
/// Factory building server adapter which requires authentication.
open class HTTPAuthenticationAdapterFactory: ServerAdapterFactory {
let auth: HTTPAuthentication?
required public init(serverHost: String, serverPort: Int, auth: HTTPAuthentication?) {
self.auth = auth
super.init(serverHost: serverHost, serverPort: serverPort)
}
}

View File

@@ -0,0 +1,21 @@
import Foundation
/// Factory building HTTP adapter.
open class HTTPAdapterFactory: HTTPAuthenticationAdapterFactory {
required public init(serverHost: String, serverPort: Int, auth: HTTPAuthentication?) {
super.init(serverHost: serverHost, serverPort: serverPort, auth: auth)
}
/**
Get a HTTP adapter.
- parameter session: The connect session.
- returns: The built adapter.
*/
override open func getAdapterFor(session: ConnectSession) -> AdapterSocket {
let adapter = HTTPAdapter(serverHost: serverHost, serverPort: serverPort, auth: auth)
adapter.socket = RawSocketFactory.getRawSocket()
return adapter
}
}

View File

@@ -0,0 +1,13 @@
import Foundation
open class RejectAdapterFactory: AdapterFactory {
public let delay: Int
public init(delay: Int = Opt.RejectAdapterDefaultDelay) {
self.delay = delay
}
override open func getAdapterFor(session: ConnectSession) -> AdapterSocket {
return RejectAdapter(delay: delay)
}
}

View File

@@ -0,0 +1,21 @@
import Foundation
/// Factory building SOCKS5 adapter.
open class SOCKS5AdapterFactory: ServerAdapterFactory {
override public init(serverHost: String, serverPort: Int) {
super.init(serverHost: serverHost, serverPort: serverPort)
}
/**
Get a SOCKS5 adapter.
- parameter session: The connect session.
- returns: The built adapter.
*/
override open func getAdapterFor(session: ConnectSession) -> AdapterSocket {
let adapter = SOCKS5Adapter(serverHost: serverHost, serverPort: serverPort)
adapter.socket = RawSocketFactory.getRawSocket()
return adapter
}
}

View File

@@ -0,0 +1,21 @@
import Foundation
/// Factory building secured HTTP (HTTP with SSL) adapter.
open class SecureHTTPAdapterFactory: HTTPAdapterFactory {
required public init(serverHost: String, serverPort: Int, auth: HTTPAuthentication?) {
super.init(serverHost: serverHost, serverPort: serverPort, auth: auth)
}
/**
Get a secured HTTP adapter.
- parameter session: The connect session.
- returns: The built adapter.
*/
override open func getAdapterFor(session: ConnectSession) -> AdapterSocket {
let adapter = SecureHTTPAdapter(serverHost: serverHost, serverPort: serverPort, auth: auth)
adapter.socket = RawSocketFactory.getRawSocket()
return adapter
}
}

View File

@@ -0,0 +1,12 @@
import Foundation
/// Factory building adapter with proxy server host and port.
open class ServerAdapterFactory: AdapterFactory {
let serverHost: String
let serverPort: Int
public init(serverHost: String, serverPort: Int) {
self.serverHost = serverHost
self.serverPort = serverPort
}
}

View File

@@ -0,0 +1,28 @@
//import Foundation
//
///// Factory building Shadowsocks adapter.
//open class ShadowsocksAdapterFactory: ServerAdapterFactory {
// let protocolObfuscaterFactory: ShadowsocksAdapter.ProtocolObfuscater.Factory
// let cryptorFactory: ShadowsocksAdapter.CryptoStreamProcessor.Factory
// let streamObfuscaterFactory: ShadowsocksAdapter.StreamObfuscater.Factory
//
// public init(serverHost: String, serverPort: Int, protocolObfuscaterFactory: ShadowsocksAdapter.ProtocolObfuscater.Factory, cryptorFactory: ShadowsocksAdapter.CryptoStreamProcessor.Factory, streamObfuscaterFactory: ShadowsocksAdapter.StreamObfuscater.Factory) {
// self.protocolObfuscaterFactory = protocolObfuscaterFactory
// self.cryptorFactory = cryptorFactory
// self.streamObfuscaterFactory = streamObfuscaterFactory
// super.init(serverHost: serverHost, serverPort: serverPort)
// }
//
// /**
// Get a Shadowsocks adapter.
//
// - parameter session: The connect session.
//
// - returns: The built adapter.
// */
// override open func getAdapterFor(session: ConnectSession) -> AdapterSocket {
// let adapter = ShadowsocksAdapter(host: serverHost, port: serverPort, protocolObfuscater: protocolObfuscaterFactory.build(), cryptor: cryptorFactory.build(), streamObfuscator: streamObfuscaterFactory.build(for: session))
// adapter.socket = RawSocketFactory.getRawSocket()
// return adapter
// }
//}

View File

@@ -0,0 +1,26 @@
//import Foundation
//
///// Factory building speed adapter.
//open class SpeedAdapterFactory: AdapterFactory {
// open var adapterFactories: [(AdapterFactory, Int)]!
//
// public override init() {}
//
// /**
// Get a speed adapter.
//
// - parameter session: The connect session.
//
// - returns: The built adapter.
// */
// override open func getAdapterFor(session: ConnectSession) -> AdapterSocket {
// let adapters = adapterFactories.map { adapterFactory, delay -> (AdapterSocket, Int) in
// let adapter = adapterFactory.getAdapterFor(session: session)
// adapter.socket = RawSocketFactory.getRawSocket()
// return (adapter, delay)
// }
// let speedAdapter = SpeedAdapter()
// speedAdapter.adapters = adapters
// return speedAdapter
// }
//}

View File

@@ -0,0 +1,110 @@
import Foundation
public enum HTTPAdapterError: Error, CustomStringConvertible {
case invalidURL, serailizationFailure
public var description: String {
switch self {
case .invalidURL:
return "Invalid url when connecting through proxy"
case .serailizationFailure:
return "Failed to serialize HTTP CONNECT header"
}
}
}
/// This adapter connects to remote host through a HTTP proxy.
public class HTTPAdapter: AdapterSocket {
enum HTTPAdapterStatus {
case invalid,
connecting,
readingResponse,
forwarding,
stopped
}
/// The host domain of the HTTP proxy.
let serverHost: String
/// The port of the HTTP proxy.
let serverPort: Int
/// The authentication information for the HTTP proxy.
let auth: HTTPAuthentication?
/// Whether the connection to the proxy should be secured or not.
var secured: Bool
var internalStatus: HTTPAdapterStatus = .invalid
public init(serverHost: String, serverPort: Int, auth: HTTPAuthentication?) {
self.serverHost = serverHost
self.serverPort = serverPort
self.auth = auth
secured = false
super.init()
}
override public func openSocketWith(session: ConnectSession) {
super.openSocketWith(session: session)
guard !isCancelled else {
return
}
do {
internalStatus = .connecting
try socket.connectTo(host: serverHost, port: serverPort, enableTLS: secured, tlsSettings: nil)
} catch {}
}
override public func didConnectWith(socket: RawTCPSocketProtocol) {
super.didConnectWith(socket: socket)
guard let url = URL(string: "\(session.host):\(session.port)") else {
observer?.signal(.errorOccured(HTTPAdapterError.invalidURL, on: self))
disconnect()
return
}
let message = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "CONNECT" as CFString, url as CFURL, kCFHTTPVersion1_1).takeRetainedValue()
if let authData = auth {
CFHTTPMessageSetHeaderFieldValue(message, "Proxy-Authorization" as CFString, authData.authString() as CFString?)
}
CFHTTPMessageSetHeaderFieldValue(message, "Host" as CFString, "\(session.host):\(session.port)" as CFString?)
CFHTTPMessageSetHeaderFieldValue(message, "Content-Length" as CFString, "0" as CFString?)
guard let requestData = CFHTTPMessageCopySerializedMessage(message)?.takeRetainedValue() else {
observer?.signal(.errorOccured(HTTPAdapterError.serailizationFailure, on: self))
disconnect()
return
}
internalStatus = .readingResponse
write(data: requestData as Data)
socket.readDataTo(data: Utils.HTTPData.DoubleCRLF)
}
override public func didRead(data: Data, from socket: RawTCPSocketProtocol) {
super.didRead(data: data, from: socket)
switch internalStatus {
case .readingResponse:
internalStatus = .forwarding
observer?.signal(.readyForForward(self))
delegate?.didBecomeReadyToForwardWith(socket: self)
case .forwarding:
observer?.signal(.readData(data, on: self))
delegate?.didRead(data: data, from: self)
default:
return
}
}
override public func didWrite(data: Data?, by socket: RawTCPSocketProtocol) {
super.didWrite(data: data, by: socket)
if internalStatus == .forwarding {
observer?.signal(.wroteData(data, on: self))
delegate?.didWrite(data: data, by: self)
}
}
}

View File

@@ -0,0 +1,49 @@
import Foundation
public class RejectAdapter: AdapterSocket {
public let delay: Int
public init(delay: Int) {
self.delay = delay
}
override public func openSocketWith(session: ConnectSession) {
super.openSocketWith(session: session)
QueueFactory.getQueue().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(delay)) {
[weak self] in
self?.disconnect()
}
}
/**
Disconnect the socket elegantly.
*/
public override func disconnect(becauseOf error: Error? = nil) {
guard !isCancelled else {
return
}
_cancelled = true
session.disconnected(becauseOf: error, by: .adapter)
observer?.signal(.disconnectCalled(self))
_status = .closed
delegate?.didDisconnectWith(socket: self)
}
/**
Disconnect the socket immediately.
*/
public override func forceDisconnect(becauseOf error: Error? = nil) {
guard !isCancelled else {
return
}
_cancelled = true
session.disconnected(becauseOf: error, by: .adapter)
observer?.signal(.forceDisconnectCalled(self))
_status = .closed
delegate?.didDisconnectWith(socket: self)
}
}

View File

@@ -0,0 +1,112 @@
import Foundation
public class SOCKS5Adapter: AdapterSocket {
enum SOCKS5AdapterStatus {
case invalid,
connecting,
readingMethodResponse,
readingResponseFirstPart,
readingResponseSecondPart,
forwarding
}
public let serverHost: String
public let serverPort: Int
var internalStatus: SOCKS5AdapterStatus = .invalid
let helloData = Data(bytes: UnsafePointer<UInt8>(([0x05, 0x01, 0x00] as [UInt8])), count: 3)
public enum ReadTag: Int {
case methodResponse = -20000, connectResponseFirstPart, connectResponseSecondPart
}
public enum WriteTag: Int {
case open = -21000, connectIPv4, connectIPv6, connectDomainLength, connectPort
}
public init(serverHost: String, serverPort: Int) {
self.serverHost = serverHost
self.serverPort = serverPort
super.init()
}
public override func openSocketWith(session: ConnectSession) {
super.openSocketWith(session: session)
guard !isCancelled else {
return
}
do {
internalStatus = .connecting
try socket.connectTo(host: serverHost, port: serverPort, enableTLS: false, tlsSettings: nil)
} catch {}
}
public override func didConnectWith(socket: RawTCPSocketProtocol) {
super.didConnectWith(socket: socket)
write(data: helloData)
internalStatus = .readingMethodResponse
socket.readDataTo(length: 2)
}
public override func didRead(data: Data, from socket: RawTCPSocketProtocol) {
super.didRead(data: data, from: socket)
switch internalStatus {
case .readingMethodResponse:
var response: [UInt8]
if session.isIPv4() {
response = [0x05, 0x01, 0x00, 0x01]
let address = IPAddress(fromString: session.host)!
response += [UInt8](address.dataInNetworkOrder)
} else if session.isIPv6() {
response = [0x05, 0x01, 0x00, 0x04]
let address = IPAddress(fromString: session.host)!
response += [UInt8](address.dataInNetworkOrder)
} else {
response = [0x05, 0x01, 0x00, 0x03]
response.append(UInt8(session.host.utf8.count))
response += [UInt8](session.host.utf8)
}
let portBytes: [UInt8] = Utils.toByteArray(UInt16(session.port)).reversed()
response.append(contentsOf: portBytes)
write(data: Data(response))
internalStatus = .readingResponseFirstPart
socket.readDataTo(length: 5)
case .readingResponseFirstPart:
var readLength = 0
switch data[3] {
case 1:
readLength = 3 + 2
case 3:
readLength = Int(data[4]) + 2
case 4:
readLength = 15 + 2
default:
break
}
internalStatus = .readingResponseSecondPart
socket.readDataTo(length: readLength)
case .readingResponseSecondPart:
internalStatus = .forwarding
observer?.signal(.readyForForward(self))
delegate?.didBecomeReadyToForwardWith(socket: self)
case .forwarding:
delegate?.didRead(data: data, from: self)
default:
return
}
}
override open func didWrite(data: Data?, by socket: RawTCPSocketProtocol) {
super.didWrite(data: data, by: socket)
if internalStatus == .forwarding {
delegate?.didWrite(data: data, by: self)
}
}
}

View File

@@ -0,0 +1,9 @@
import Foundation
/// This adapter connects to remote host through a HTTP proxy with SSL.
public class SecureHTTPAdapter: HTTPAdapter {
override public init(serverHost: String, serverPort: Int, auth: HTTPAuthentication?) {
super.init(serverHost: serverHost, serverPort: serverPort, auth: auth)
secured = true
}
}

View File

@@ -0,0 +1,133 @@
//import Foundation
//
//extension ShadowsocksAdapter {
// public class CryptoStreamProcessor {
// public class Factory {
// let password: String
// let algorithm: CryptoAlgorithm
// let key: Data
//
// public init(password: String, algorithm: CryptoAlgorithm) {
// self.password = password
// self.algorithm = algorithm
// key = CryptoHelper.getKey(password, methodType: algorithm)
// }
//
// public func build() -> CryptoStreamProcessor {
// return CryptoStreamProcessor(key: key, algorithm: algorithm)
// }
// }
//
// public weak var inputStreamProcessor: StreamObfuscater.StreamObfuscaterBase!
// public weak var outputStreamProcessor: ProtocolObfuscater.ProtocolObfuscaterBase!
//
// var readIV: Data!
// let key: Data
// let algorithm: CryptoAlgorithm
//
// var sendKey = false
//
// var buffer = Buffer(capacity: 0)
//
// lazy var writeIV: Data = {
// [unowned self] in
// CryptoHelper.getIV(self.algorithm)
// }()
// lazy var ivLength: Int = {
// [unowned self] in
// CryptoHelper.getIVLength(self.algorithm)
// }()
// lazy var encryptor: StreamCryptoProtocol = {
// [unowned self] in
// self.getCrypto(.encrypt)
// }()
// lazy var decryptor: StreamCryptoProtocol = {
// [unowned self] in
// self.getCrypto(.decrypt)
// }()
//
// init(key: Data, algorithm: CryptoAlgorithm) {
// self.key = key
// self.algorithm = algorithm
// }
//
// func encrypt(data: inout Data) {
// return encryptor.update(&data)
// }
//
// func decrypt(data: inout Data) {
// return decryptor.update(&data)
// }
//
// public func input(data: Data) throws {
// var data = data
//
// if readIV == nil {
// buffer.append(data: data)
// readIV = buffer.get(length: ivLength)
// guard readIV != nil else {
// try inputStreamProcessor!.input(data: Data())
// return
// }
//
// data = buffer.get() ?? Data()
// buffer.release()
// }
//
// decrypt(data: &data)
// try inputStreamProcessor!.input(data: data)
// }
//
// public func output(data: Data) {
// var data = data
// encrypt(data: &data)
// if sendKey {
// return outputStreamProcessor!.output(data: data)
// } else {
// sendKey = true
// var out = Data(capacity: data.count + writeIV.count)
// out.append(writeIV)
// out.append(data)
//
// return outputStreamProcessor!.output(data: out)
// }
// }
//
// private func getCrypto(_ operation: CryptoOperation) -> StreamCryptoProtocol {
// switch algorithm {
// case .AES128CFB, .AES192CFB, .AES256CFB:
// switch operation {
// case .decrypt:
// return CCCrypto(operation: .decrypt, mode: .cfb, algorithm: .aes, initialVector: readIV, key: key)
// case .encrypt:
// return CCCrypto(operation: .encrypt, mode: .cfb, algorithm: .aes, initialVector: writeIV, key: key)
// }
// case .CHACHA20:
// switch operation {
// case .decrypt:
// return SodiumStreamCrypto(key: key, iv: readIV, algorithm: .chacha20)
// case .encrypt:
// return SodiumStreamCrypto(key: key, iv: writeIV, algorithm: .chacha20)
// }
// case .SALSA20:
// switch operation {
// case .decrypt:
// return SodiumStreamCrypto(key: key, iv: readIV, algorithm: .salsa20)
// case .encrypt:
// return SodiumStreamCrypto(key: key, iv: writeIV, algorithm: .salsa20)
// }
// case .RC4MD5:
// var combinedKey = Data(capacity: key.count + ivLength)
// combinedKey.append(key)
// switch operation {
// case .decrypt:
// combinedKey.append(readIV)
// return CCCrypto(operation: .decrypt, mode: .rc4, algorithm: .rc4, initialVector: nil, key: MD5Hash.final(combinedKey))
// case .encrypt:
// combinedKey.append(writeIV)
// return CCCrypto(operation: .encrypt, mode: .rc4, algorithm: .rc4, initialVector: nil, key: MD5Hash.final(combinedKey))
// }
// }
// }
// }
//}

View File

@@ -0,0 +1,371 @@
//import Foundation
//
//extension ShadowsocksAdapter {
// public struct ProtocolObfuscater {
// public class Factory {
// public init() {}
//
// public func build() -> ProtocolObfuscaterBase {
// return ProtocolObfuscaterBase()
// }
// }
//
// public class ProtocolObfuscaterBase {
// public weak var inputStreamProcessor: CryptoStreamProcessor!
// public weak var outputStreamProcessor: ShadowsocksAdapter!
//
// public func start() {}
// public func input(data: Data) throws {}
// public func output(data: Data) {}
//
// public func didWrite() {}
// }
//
// public class OriginProtocolObfuscater: ProtocolObfuscaterBase {
//
// public class Factory: ProtocolObfuscater.Factory {
// public override init() {}
//
// public override func build() -> ShadowsocksAdapter.ProtocolObfuscater.ProtocolObfuscaterBase {
// return OriginProtocolObfuscater()
// }
// }
//
// public override func start() {
// outputStreamProcessor.becomeReadyToForward()
// }
//
// public override func input(data: Data) throws {
// try inputStreamProcessor.input(data: data)
// }
//
// public override func output(data: Data) {
// outputStreamProcessor.output(data: data)
// }
// }
//
// public class HTTPProtocolObfuscater: ProtocolObfuscaterBase {
//
// public class Factory: ProtocolObfuscater.Factory {
// let method: String
// let hosts: [String]
// let customHeader: String?
//
// public init(method: String = "GET", hosts: [String], customHeader: String?) {
// self.method = method
// self.hosts = hosts
// self.customHeader = customHeader
// }
//
// public override func build() -> ShadowsocksAdapter.ProtocolObfuscater.ProtocolObfuscaterBase {
// return HTTPProtocolObfuscater(method: method, hosts: hosts, customHeader: customHeader)
// }
// }
//
// static let headerLength = 30
// static let userAgent = ["Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0",
// "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/44.0",
// "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
// "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36",
// "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0",
// "Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)",
// "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27",
// "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C)",
// "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
// "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/BuildID) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36",
// "Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
// "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3"]
//
// let method: String
// let hosts: [String]
// let customHeader: String?
//
// var readingFakeHeader = false
// var sendHeader = false
// var remaining = false
//
// var buffer = Buffer(capacity: 8192)
//
// public init(method: String = "GET", hosts: [String], customHeader: String?) {
// self.method = method
// self.hosts = hosts
// self.customHeader = customHeader
// }
//
// private func generateHeader(encapsulating data: Data) -> String {
// let ind = Int(arc4random_uniform(UInt32(hosts.count)))
// let host = outputStreamProcessor.port == 80 ? hosts[ind] : "\(hosts[ind]):\(outputStreamProcessor.port)"
// var header = "\(method) /\(hexlify(data: data)) HTTP/1.1\r\nHost: \(host)\r\n"
// if let customHeader = customHeader {
// header += customHeader
// } else {
// let ind = Int(arc4random_uniform(UInt32(HTTPProtocolObfuscater.userAgent.count)))
// header += "User-Agent: \(HTTPProtocolObfuscater.userAgent[ind])\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Encoding: gzip, deflate\r\nDNT: 1\r\nConnection: keep-alive"
// }
// header += "\r\n\r\n"
// return header
// }
//
// private func hexlify(data: Data) -> String {
// var result = ""
// for i in data {
// result = result.appendingFormat("%%%02x", i)
// }
// return result
// }
//
// public override func start() {
// readingFakeHeader = true
// outputStreamProcessor.becomeReadyToForward()
// }
//
// public override func input(data: Data) throws {
// if readingFakeHeader {
// buffer.append(data: data)
// if buffer.get(to: Utils.HTTPData.DoubleCRLF) != nil {
// readingFakeHeader = false
// if let remainData = buffer.get() {
// try inputStreamProcessor.input(data: remainData)
// return
// }
// }
// try inputStreamProcessor.input(data: Data())
// return
// }
//
// try inputStreamProcessor.input(data: data)
// }
//
// public override func output(data: Data) {
// if sendHeader {
// outputStreamProcessor.output(data: data)
// } else {
// var fakeRequestDataLength = inputStreamProcessor.key.count + HTTPProtocolObfuscater.headerLength
// if data.count - fakeRequestDataLength > 64 {
// fakeRequestDataLength += Int(arc4random_uniform(64))
// } else {
// fakeRequestDataLength = data.count
// }
//
// var outputData = generateHeader(encapsulating: data.subdata(in: 0 ..< fakeRequestDataLength)).data(using: .utf8)!
// outputData.append(data.subdata(in: fakeRequestDataLength ..< data.count))
// sendHeader = true
// outputStreamProcessor.output(data: outputData)
// }
// }
// }
//
// public class TLSProtocolObfuscater: ProtocolObfuscaterBase {
//
// public class Factory: ProtocolObfuscater.Factory {
// let hosts: [String]
//
// public init(hosts: [String]) {
// self.hosts = hosts
// }
//
// public override func build() -> ShadowsocksAdapter.ProtocolObfuscater.ProtocolObfuscaterBase {
// return TLSProtocolObfuscater(hosts: hosts)
// }
// }
//
// let hosts: [String]
// let clientID: Data = {
// var id = Data(count: 32)
// Utils.Random.fill(data: &id)
// return id
// }()
//
// private var status = 0
//
// private var buffer = Buffer(capacity: 1024)
//
// init(hosts: [String]) {
// self.hosts = hosts
// }
//
// public override func start() {
// handleStatus0()
// outputStreamProcessor.socket.readDataTo(length: 129)
// }
//
// public override func input(data: Data) throws {
// switch status {
// case 8:
// try handleInput(data: data)
// case 1:
// outputStreamProcessor.becomeReadyToForward()
// default:
// break
// }
// }
//
// public override func output(data: Data) {
// switch status {
// case 8:
// handleStatus8(data: data)
// return
// case 1:
// handleStatus1(data: data)
// return
// default:
// break
// }
// }
//
// private func authData() -> Data {
// var time = UInt32(Date.init().timeIntervalSince1970).bigEndian
// var output = Data(count: 32)
// var key = inputStreamProcessor.key
// key.append(clientID)
//
// withUnsafeBytes(of: &time) {
// output.replaceSubrange(0 ..< 4, with: $0)
// }
//
// Utils.Random.fill(data: &output, from: 4, length: 18)
// output.withUnsafeBytes {
// output.replaceSubrange(22 ..< 32, with: HMAC.final(value: $0.baseAddress!, length: 22, algorithm: .SHA1, key: key).subdata(in: 0..<10))
// }
// return output
// }
//
// private func pack(data: Data) -> Data {
// var output = Data()
// var left = data.count
// while left > 0 {
// let blockSize = UInt16(min(Int(arc4random_uniform(UInt32(UInt16.max))) % 4096 + 100, left))
// var blockSizeBE = blockSize.bigEndian
// output.append(contentsOf: [0x17, 0x03, 0x03])
// withUnsafeBytes(of: &blockSizeBE) {
// output.append($0.baseAddress!.assumingMemoryBound(to: UInt8.self), count: $0.count)
// }
// output.append(data.subdata(in: data.count - left ..< data.count - left + Int(blockSize)))
// left -= Int(blockSize)
// }
// return output
// }
//
// private func handleStatus8(data: Data) {
// outputStreamProcessor.output(data: pack(data: data))
// }
//
// private func handleStatus0() {
// status = 1
//
// var outData = Data()
// outData.append(contentsOf: [0x03, 0x03])
// outData.append(authData())
// outData.append(0x20)
// outData.append(clientID)
// outData.append(contentsOf: [0x00, 0x1c, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0x0a])
// outData.append("0100".data(using: .utf8)!)
//
// var extData = Data()
// extData.append(contentsOf: [0xff, 0x01, 0x00, 0x01, 0x00])
// let hostData = hosts[Int(arc4random_uniform(UInt32(hosts.count)))].data(using: .utf8)!
//
// var sniData = Data(capacity: hosts.count + 2 + 1 + 2 + 2 + 2)
//
// sniData.append(contentsOf: [0x00, 0x00])
//
// var _lenBE = UInt16(hostData.count + 5).bigEndian
// withUnsafeBytes(of: &_lenBE) {
// sniData.append($0.baseAddress!.assumingMemoryBound(to: UInt8.self), count: $0.count)
// }
//
// _lenBE = UInt16(hostData.count + 3).bigEndian
// withUnsafeBytes(of: &_lenBE) {
// sniData.append($0.baseAddress!.assumingMemoryBound(to: UInt8.self), count: $0.count)
// }
//
// sniData.append(0x00)
//
// _lenBE = UInt16(hostData.count).bigEndian
// withUnsafeBytes(of: &_lenBE) {
// sniData.append($0.baseAddress!.assumingMemoryBound(to: UInt8.self), count: $0.count)
// }
//
// sniData.append(hostData)
//
// extData.append(sniData)
//
// extData.append(contentsOf: [0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0xd0])
//
// var randomData = Data(count: 208)
// Utils.Random.fill(data: &randomData)
// extData.append(randomData)
//
// extData.append(contentsOf: [0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x06, 0x01, 0x06, 0x03, 0x05, 0x01, 0x05, 0x03, 0x04, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x03, 0x02, 0x01, 0x02, 0x03])
// extData.append(contentsOf: [0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00])
// extData.append(contentsOf: [0x00, 0x12, 0x00, 0x00])
// extData.append(contentsOf: [0x75, 0x50, 0x00, 0x00])
// extData.append(contentsOf: [0x00, 0x0b, 0x00, 0x02, 0x01, 0x00])
// extData.append(contentsOf: [0x00, 0x0a, 0x00, 0x06, 0x00, 0x04, 0x00, 0x17, 0x00, 0x18])
//
// _lenBE = UInt16(extData.count).bigEndian
// withUnsafeBytes(of: &_lenBE) {
// outData.append($0.baseAddress!.assumingMemoryBound(to: UInt8.self), count: $0.count)
// }
// outData.append(extData)
//
// var outputData = Data(capacity: outData.count + 9)
// outputData.append(contentsOf: [0x16, 0x03, 0x01])
// _lenBE = UInt16(outData.count + 4).bigEndian
// withUnsafeBytes(of: &_lenBE) {
// outputData.append($0.baseAddress!.assumingMemoryBound(to: UInt8.self), count: $0.count)
// }
// outputData.append(contentsOf: [0x01, 0x00])
// _lenBE = UInt16(outData.count).bigEndian
// withUnsafeBytes(of: &_lenBE) {
// outputData.append($0.baseAddress!.assumingMemoryBound(to: UInt8.self), count: $0.count)
// }
// outputData.append(outData)
// outputStreamProcessor.output(data: outputData)
// }
//
// private func handleStatus1(data: Data) {
// status = 8
//
// var outputData = Data()
// outputData.append(contentsOf: [0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03, 0x03, 0x00, 0x20])
// var random = Data(count: 22)
// Utils.Random.fill(data: &random)
// outputData.append(random)
//
// var key = inputStreamProcessor.key
// key.append(clientID)
// outputData.withUnsafeBytes {
// outputData.append(HMAC.final(value: $0.baseAddress!, length: outputData.count, algorithm: .SHA1, key: key).subdata(in: 0..<10))
// }
//
// outputData.append(pack(data: data))
//
// outputStreamProcessor.output(data: outputData)
// }
//
// private func handleInput(data: Data) throws {
// buffer.append(data: data)
// var unpackedData = Data()
// while buffer.left > 5 {
// buffer.skip(3)
// var length: Int = 0
// buffer.withUnsafeBytes { (ptr: UnsafePointer<UInt16>) in
// length = Int(ptr.pointee.byteSwapped)
// }
// buffer.skip(2)
// if buffer.left >= length {
// unpackedData.append(buffer.get(length: length)!)
// continue
// } else {
// buffer.setBack(length: 5)
// break
// }
// }
// buffer.squeeze()
// try inputStreamProcessor.input(data: unpackedData)
// }
// }
//
// }
//}

View File

@@ -0,0 +1,112 @@
//import Foundation
//import CommonCrypto
//
///// This adapter connects to remote through Shadowsocks proxy.
//public class ShadowsocksAdapter: AdapterSocket {
// enum ShadowsocksAdapterStatus {
// case invalid,
// connecting,
// connected,
// forwarding,
// stopped
// }
//
// enum EncryptMethod: String {
// case AES128CFB = "AES-128-CFB", AES192CFB = "AES-192-CFB", AES256CFB = "AES-256-CFB"
//
// static let allValues: [EncryptMethod] = [.AES128CFB, .AES192CFB, .AES256CFB]
// }
//
// public let host: String
// public let port: Int
//
// var internalStatus: ShadowsocksAdapterStatus = .invalid
//
// private let protocolObfuscater: ProtocolObfuscater.ProtocolObfuscaterBase
// private let cryptor: CryptoStreamProcessor
// private let streamObfuscator: StreamObfuscater.StreamObfuscaterBase
//
// public init(host: String, port: Int, protocolObfuscater: ProtocolObfuscater.ProtocolObfuscaterBase, cryptor: CryptoStreamProcessor, streamObfuscator: StreamObfuscater.StreamObfuscaterBase) {
// self.host = host
// self.port = port
// self.protocolObfuscater = protocolObfuscater
// self.cryptor = cryptor
// self.streamObfuscator = streamObfuscator
//
// super.init()
//
// protocolObfuscater.inputStreamProcessor = cryptor
// protocolObfuscater.outputStreamProcessor = self
//
// cryptor.inputStreamProcessor = streamObfuscator
// cryptor.outputStreamProcessor = protocolObfuscater
//
// streamObfuscator.inputStreamProcessor = self
// streamObfuscator.outputStreamProcessor = cryptor
// }
//
// override public func openSocketWith(session: ConnectSession) {
// super.openSocketWith(session: session)
//
// do {
// internalStatus = .connecting
// try socket.connectTo(host: host, port: port, enableTLS: false, tlsSettings: nil)
// } catch let error {
// observer?.signal(.errorOccured(error, on: self))
// disconnect()
// }
// }
//
// override public func didConnectWith(socket: RawTCPSocketProtocol) {
// super.didConnectWith(socket: socket)
//
// internalStatus = .connected
//
// protocolObfuscater.start()
// }
//
// override public func didRead(data: Data, from socket: RawTCPSocketProtocol) {
// super.didRead(data: data, from: socket)
//
// do {
// try protocolObfuscater.input(data: data)
// } catch {
// disconnect()
// }
// }
//
// public override func write(data: Data) {
// streamObfuscator.output(data: data)
// }
//
// public func write(rawData: Data) {
// super.write(data: rawData)
// }
//
// public func input(data: Data) {
// delegate?.didRead(data: data, from: self)
// }
//
// public func output(data: Data) {
// write(rawData: data)
// }
//
// override public func didWrite(data: Data?, by socket: RawTCPSocketProtocol) {
// super.didWrite(data: data, by: socket)
//
// protocolObfuscater.didWrite()
//
// switch internalStatus {
// case .forwarding:
// delegate?.didWrite(data: data, by: self)
// default:
// return
// }
// }
//
// func becomeReadyToForward() {
// internalStatus = .forwarding
// observer?.signal(.readyForForward(self))
// delegate?.didBecomeReadyToForwardWith(socket: self)
// }
//}

View File

@@ -0,0 +1,167 @@
//import Foundation
//
//extension ShadowsocksAdapter {
// public struct StreamObfuscater {
// public class Factory {
// public init() {}
//
// public func build(for session: ConnectSession) -> StreamObfuscaterBase {
// return StreamObfuscaterBase(for: session)
// }
// }
//
// public class StreamObfuscaterBase {
// public weak var inputStreamProcessor: ShadowsocksAdapter!
// private weak var _outputStreamProcessor: CryptoStreamProcessor!
// public var outputStreamProcessor: CryptoStreamProcessor! {
// get {
// return _outputStreamProcessor
// }
// set {
// _outputStreamProcessor = newValue
// key = _outputStreamProcessor?.key
// writeIV = _outputStreamProcessor?.writeIV
// }
// }
//
// public var key: Data?
// public var writeIV: Data?
//
// let session: ConnectSession
//
// init(for session: ConnectSession) {
// self.session = session
// }
//
// func output(data: Data) {}
// func input(data: Data) throws {}
// }
//
// public class OriginStreamObfuscater: StreamObfuscaterBase {
// public class Factory: StreamObfuscater.Factory {
// public override init() {}
//
// public override func build(for session: ConnectSession) -> ShadowsocksAdapter.StreamObfuscater.StreamObfuscaterBase {
// return OriginStreamObfuscater(for: session)
// }
// }
//
// private var requestSend = false
//
// private func requestData(withData data: Data) -> Data {
// let hostLength = session.host.utf8.count
// let length = 1 + 1 + hostLength + 2 + data.count
// var response = Data(count: length)
// response[0] = 3
// response[1] = UInt8(hostLength)
// response.replaceSubrange(2..<2+hostLength, with: session.host.utf8)
// var beport = UInt16(session.port).bigEndian
// withUnsafeBytes(of: &beport) {
// response.replaceSubrange(2+hostLength..<4+hostLength, with: $0)
// }
// response.replaceSubrange(4+hostLength..<length, with: data)
// return response
// }
//
// public override func input(data: Data) throws {
// inputStreamProcessor!.input(data: data)
// }
//
// public override func output(data: Data) {
// if requestSend {
// return outputStreamProcessor!.output(data: data)
// } else {
// requestSend = true
// return outputStreamProcessor!.output(data: requestData(withData: data))
// }
// }
// }
//
// public class OTAStreamObfuscater: StreamObfuscaterBase {
// public class Factory: StreamObfuscater.Factory {
// public override init() {}
//
// public override func build(for session: ConnectSession) -> ShadowsocksAdapter.StreamObfuscater.StreamObfuscaterBase {
// return OTAStreamObfuscater(for: session)
// }
// }
//
// private var count: UInt32 = 0
//
// private let DATA_BLOCK_SIZE = 0xFFFF - 12
//
// private var requestSend = false
//
// private func requestData() -> Data {
// var response: [UInt8] = [0x13]
// response.append(UInt8(session.host.utf8.count))
// response += [UInt8](session.host.utf8)
// response += [UInt8](Utils.toByteArray(UInt16(session.port)).reversed())
// var responseData = Data(bytes: UnsafePointer<UInt8>(response), count: response.count)
// var keyiv = Data(count: key!.count + writeIV!.count)
//
// keyiv.replaceSubrange(0..<writeIV!.count, with: writeIV!)
// keyiv.replaceSubrange(writeIV!.count..<writeIV!.count + key!.count, with: key!)
// responseData.append(HMAC.final(value: responseData, algorithm: .SHA1, key: keyiv).subdata(in: 0..<10))
// return responseData
// }
//
// public override func input(data: Data) throws {
// inputStreamProcessor!.input(data: data)
// }
//
// public override func output(data: Data) {
// let fullBlockCount = data.count / DATA_BLOCK_SIZE
// var outputSize = fullBlockCount * (DATA_BLOCK_SIZE + 10 + 2)
// if data.count > fullBlockCount * DATA_BLOCK_SIZE {
// outputSize += data.count - fullBlockCount * DATA_BLOCK_SIZE + 10 + 2
// }
//
// let _requestData: Data = requestData()
// if !requestSend {
// outputSize += _requestData.count
// }
//
// var outputData = Data(count: outputSize)
// var outputOffset = 0
// var dataOffset = 0
//
// if !requestSend {
// requestSend = true
// outputData.replaceSubrange(0..<_requestData.count, with: _requestData)
// outputOffset += _requestData.count
// }
//
// while outputOffset != outputSize {
// let blockLength = min(data.count - dataOffset, DATA_BLOCK_SIZE)
// var len = UInt16(blockLength).bigEndian
// withUnsafeBytes(of: &len) {
// outputData.replaceSubrange(outputOffset..<outputOffset+2, with: $0)
// }
//
// var kc = Data(count: writeIV!.count + MemoryLayout.size(ofValue: count))
// kc.replaceSubrange(0..<writeIV!.count, with: writeIV!)
// var c = count.bigEndian
// let ms = MemoryLayout.size(ofValue: c)
// withUnsafeBytes(of: &c) {
// kc.replaceSubrange(writeIV!.count..<writeIV!.count+ms, with: $0)
// }
//
// data.withUnsafeBytes {
// outputData.replaceSubrange(outputOffset+2..<outputOffset+12, with: HMAC.final(value: $0.baseAddress!.advanced(by: dataOffset), length: blockLength, algorithm: .SHA1, key: kc).subdata(in: 0..<10))
// }
//
// data.withUnsafeBytes {
// outputData.replaceSubrange(outputOffset+12..<outputOffset+12+blockLength, with: $0.baseAddress!.advanced(by: dataOffset), count: blockLength)
// }
//
// count += 1
// outputOffset += 12 + blockLength
// dataOffset += blockLength
// }
//
// return outputStreamProcessor!.output(data: outputData)
// }
// }
// }
//}