// // SMB2IOCtl.swift // ExtDownloader // // Created by Amir Abbas Mousavian on 4/30/95. // Copyright © 1395 Mousavian. All rights reserved. // import Foundation extension SMB2 { // MARK: SMB2 IOCTL /** * IOCtl usage is usually limited in SMB to pipe requests and duplicating file inside server */ struct IOCtlRequest: SMBRequestBody { static var command: SMB2.Command = .IOCTL let header: Header let requestData: IOCtlRequestProtocol? init(fileId: FileId ,ctlCode: IOCtlCode, requestData: IOCtlRequestProtocol?, flags: IOCtlRequest.Flags = []) { let offset = requestData != nil ? UInt32(MemoryLayout.size + MemoryLayout.size) : 0 self.header = Header(size: 57, reserved: 0, ctlCode: ctlCode, fileId: fileId, inputOffset: offset, inputCount: UInt32((requestData?.data().count ?? 0)), maxInputResponse: 0, outputOffset: offset, outputCount: 0, maxOutputResponse: UInt32(Int32.max), flags: flags, reserved2: 0) self.requestData = requestData } func data() -> Data { var result = Data(value: self.header) if let reqData = requestData?.data() { result.append(reqData) } return result } struct Header { let size: UInt16 fileprivate let reserved: UInt16 let ctlCode: IOCtlCode let fileId: FileId let inputOffset: UInt32 let inputCount: UInt32 let maxInputResponse: UInt32 let outputOffset: UInt32 let outputCount: UInt32 let maxOutputResponse: UInt32 let flags: IOCtlRequest.Flags fileprivate let reserved2: UInt32 } struct Flags: OptionSet { let rawValue: UInt32 init(rawValue: UInt32) { self.rawValue = rawValue } static let IOCTL = Flags(rawValue: 0x00000000) static let FSCTL = Flags(rawValue: 0x00000001) } } struct IOCtlResponse: SMBResponseBody { let header: Header let responseData: IOCtlResponseProtocol? init?(data: Data) { self.header = data.scanValue()! let endRange = Int(self.header.outputOffset - 64) + Int(self.header.outputCount) let response = data.subdata(in: Int(self.header.outputOffset - 64).. Data { var result = Data(value: sourceKey) result.append(Data(value: chunkCount)) let reserved: UInt32 = 0 result.append(Data(value: reserved)) return Data() } struct Chunk { let sourceOffset: UInt64 let targetOffset: UInt64 let length: UInt32 fileprivate let reserved: UInt32 } } struct ReadHash: IOCtlRequestProtocol { static var command: SMB2.Command = .IOCTL let _hashType: IOCtlHashType let _hashVersion: IOCtlHashVersion let _hashRetrievalType: IOCtlHashRetrievalType let length: UInt32 let offset: UInt64 init(offset: UInt64, length: UInt32, hashType: IOCtlHashType = .PEER_DIST, hashVersion: IOCtlHashVersion = .VER_1, hashRetrievalType: IOCtlHashRetrievalType = .FILE_BASED) { self._hashType = hashType self._hashVersion = hashVersion self._hashRetrievalType = hashRetrievalType self.length = length self.offset = offset } } struct ResilencyRequest: IOCtlRequestProtocol { static var command: SMB2.Command = .IOCTL let timeout: UInt32 fileprivate let reserved: UInt32 /// The requested time the server holds the file open after a disconnect before releasing it. This time is in milliseconds. init(timeout: UInt32) { self.timeout = timeout self.reserved = 0 } } struct ValidateNegotiateInfo: IOCtlRequestProtocol { static var command: SMB2.Command = .IOCTL let header: ValidateNegotiateInfo.Header let dialects: [UInt16] init(dialects: [UInt16], guid: uuid_t, capabilities: IOCtlCapabilities, securityMode: UInt16) { self.header = Header(capabilities: capabilities, guid: guid, securityMode: securityMode, dialectCount: UInt16(dialects.count)) self.dialects = dialects } func data() -> Data { var result = Data(value: self.header) dialects.forEach { result.append(Data(value: $0)) } return result } struct Header { let capabilities: IOCtlCapabilities /// Client's GUID let guid: uuid_t let securityMode: UInt16 let dialectCount: UInt16 } } } struct IOCtlResponseData { // SRV_COPYCHUNK, SRV_COPYCHUNK_WRITE struct SrvCopyChunk: IOCtlResponseProtocol { let chunksCount: UInt32 let chunksBytesWritten: UInt32 let totalBytesWriiten: UInt32 } // SRV_ENUMERATE_SNAPSHOTS struct SrvSnapshots: IOCtlResponseProtocol { let count: UInt32 let returnedCount: UInt32 let snapshots: [SMBTime] init?(data: Data) { guard data.count > 8 else { return nil } self.count = data.scanValue()! self.returnedCount = data.scanValue(start: 4)! //let size: UInt32 = decode(data.subdataWithRange(NSRange(location: 8, length: 4))) var snapshots = [SMBTime]() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "'@GMT-'yyyy'.'MM'.'dd'-'HH'.'mm'.'ss" for i in 0...size } self.items = items } struct Item { /// The offset, in bytes, from the beginning of this structure to the beginning of a subsequent 8-byte aligned network interface. let next: UInt32 /// specifies the network interface index. let ifIndex: UInt32 let capability: IOCtlCapabilities fileprivate let reserved: UInt32 /// Speed of the network interface in bits per second let linkSpeed: UInt64 fileprivate let sockaddrStorage: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) var family: sa_family_t { return sockaddrStorage.1 } static let ipv4: sa_family_t = 0x02 static let ipv6: sa_family_t = 0x17 var sockaddr: sockaddr_in { return unsafeBitCast(self.sockaddrStorage, to: sockaddr_in.self) } var sockaddr6: sockaddr_in6 { return unsafeBitCast(self.sockaddrStorage, to: sockaddr_in6.self) } } } struct ValidateNegotiateInfo: IOCtlResponseProtocol { let capabilities: IOCtlCapabilities let guid: uuid_t let securityMode: UInt16 fileprivate let _dialect: UInt16 var dialect: (major: Int, minor: Int) { return (major: Int(_dialect & 0xFF), minor: Int(_dialect >> 8)) } } } struct IOCtlCapabilities: OptionSet { let rawValue: UInt32 init(rawValue: UInt32) { self.rawValue = rawValue } static let RSS_CAPABLE = IOCtlCapabilities(rawValue: 0x00000001) static let RDMA_CAPABLE = IOCtlCapabilities(rawValue: 0x00000002) } struct IOCtlHashType: Option { let rawValue: UInt32 init(rawValue: UInt32) { self.rawValue = rawValue } public static let PEER_DIST = IOCtlHashType(rawValue: 0x00000001) } struct IOCtlHashVersion: Option { let rawValue: UInt32 init(rawValue: UInt32) { self.rawValue = rawValue } public static let VER_1 = IOCtlHashVersion(rawValue: 0x00000001) public static let VER_2 = IOCtlHashVersion(rawValue: 0x00000002) } struct IOCtlHashRetrievalType: Option { let rawValue: UInt32 init(rawValue: UInt32) { self.rawValue = rawValue } public static let HASH_BASED = IOCtlHashRetrievalType(rawValue: 0x00000001) public static let FILE_BASED = IOCtlHashRetrievalType(rawValue: 0x00000002) } }