From c6ab3b57db7312df74b6da011d0de1ec232d42ff Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Wed, 20 Mar 2019 17:18:08 +0100 Subject: [PATCH 1/3] Fix a few return in wrong scope --- TunnelKit/Sources/Core/SessionProxy.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TunnelKit/Sources/Core/SessionProxy.swift b/TunnelKit/Sources/Core/SessionProxy.swift index 366daa0..58a75b6 100644 --- a/TunnelKit/Sources/Core/SessionProxy.swift +++ b/TunnelKit/Sources/Core/SessionProxy.swift @@ -992,8 +992,8 @@ public class SessionProxy { self?.queue.sync { log.error("Failed LINK write during control flush: \(error)") self?.deferStop(.shutdown, SessionError.failedLinkWrite) - return } + return } } } @@ -1115,8 +1115,8 @@ public class SessionProxy { self?.queue.sync { log.error("Data: Failed LINK write during send data: \(error)") self?.deferStop(.shutdown, SessionError.failedLinkWrite) - return } + return } // log.verbose("Data: \(encryptedPackets.count) packets successfully written to LINK") } @@ -1161,8 +1161,8 @@ public class SessionProxy { self?.queue.sync { log.error("Failed LINK write during send ack for packetId \(controlPacket.packetId): \(error)") self?.deferStop(.shutdown, SessionError.failedLinkWrite) - return } + return } log.debug("Ack successfully written to LINK for packetId \(controlPacket.packetId)") } From c93461b15336f5dbb26e64b97908ba8f5ffa2287 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Wed, 20 Mar 2019 17:40:13 +0100 Subject: [PATCH 2/3] Send explicit exit notification if UDP Implement --explicit-exit-notify by default. Fixes #29 --- CHANGELOG.md | 6 ++++++ TunnelKit/Sources/Core/Packet.swift | 16 ++++++++++++++++ TunnelKit/Sources/Core/SessionProxy.swift | 5 +++++ 3 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c1e89e..9f64bb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- Send explicit exit notification if UDP. [#29](https://github.com/keeshux/tunnelkit/issues/29) + ## 1.5.0 (2019-03-20) ### Added diff --git a/TunnelKit/Sources/Core/Packet.swift b/TunnelKit/Sources/Core/Packet.swift index 036f5fb..b934f61 100644 --- a/TunnelKit/Sources/Core/Packet.swift +++ b/TunnelKit/Sources/Core/Packet.swift @@ -128,6 +128,22 @@ class DataPacket { static let pingString = Data(hex: "2a187bf3641eb4cb07ed2d0a981fc748") } +enum OCCPacket: UInt8 { + case exit = 0x06 + + private static let magicString = Data(hex: "287f346bd4ef7a812d56b8d3afc5459c") + + func serialized(_ info: Any? = nil) -> Data { + var data = OCCPacket.magicString + data.append(rawValue) + switch self { + case .exit: + break // nothing more + } + return data + } +} + /// :nodoc: extension PacketCode: CustomStringConvertible { public var description: String { diff --git a/TunnelKit/Sources/Core/SessionProxy.swift b/TunnelKit/Sources/Core/SessionProxy.swift index 58a75b6..ad4dc29 100644 --- a/TunnelKit/Sources/Core/SessionProxy.swift +++ b/TunnelKit/Sources/Core/SessionProxy.swift @@ -1176,6 +1176,11 @@ public class SessionProxy { private func deferStop(_ method: StopMethod, _ error: Error?) { isStopping = true + + // send exit notification if socket is unreliable (normally UDP) + if let link = link, !link.isReliable { + sendDataPackets([OCCPacket.exit.serialized()]) + } switch method { case .shutdown: From a5b890791839a23e6b7c345c2537d0381b89fe67 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Wed, 20 Mar 2019 17:54:59 +0100 Subject: [PATCH 3/3] Postpone shutdown until notification is written Otherwise socket might be force-closed while sending the packet. --- TunnelKit/Sources/Core/SessionProxy.swift | 34 ++++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/TunnelKit/Sources/Core/SessionProxy.swift b/TunnelKit/Sources/Core/SessionProxy.swift index ad4dc29..da820b6 100644 --- a/TunnelKit/Sources/Core/SessionProxy.swift +++ b/TunnelKit/Sources/Core/SessionProxy.swift @@ -1177,17 +1177,31 @@ public class SessionProxy { private func deferStop(_ method: StopMethod, _ error: Error?) { isStopping = true - // send exit notification if socket is unreliable (normally UDP) - if let link = link, !link.isReliable { - sendDataPackets([OCCPacket.exit.serialized()]) + let completion = { [weak self] in + switch method { + case .shutdown: + self?.doShutdown(error: error) + + case .reconnect: + self?.doReconnect(error: error) + } } - - switch method { - case .shutdown: - doShutdown(error: error) - - case .reconnect: - doReconnect(error: error) + + // shut down after sending exit notification if socket is unreliable (normally UDP) + if let link = link, !link.isReliable { + do { + guard let packets = try currentKey?.encrypt(packets: [OCCPacket.exit.serialized()]) else { + completion() + return + } + link.writePackets(packets) { (error) in + completion() + } + } catch { + completion() + } + } else { + completion() } }