Merge branch 'handle-push-continuation'
This commit is contained in:
commit
537b733130
|
@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Fixed
|
||||
|
||||
- Negotiation times out with SoftEther. [#67](https://github.com/keeshux/tunnelkit/issues/67)
|
||||
- Unable to handle continuated PUSH_REPLY. [#71](https://github.com/keeshux/tunnelkit/issues/71)
|
||||
- TCP requiring multiple PUSH_REQUEST. [#73](https://github.com/keeshux/tunnelkit/issues/73)
|
||||
|
||||
## 1.6.1 (2019-04-07)
|
||||
|
||||
|
|
|
@ -200,9 +200,9 @@ class NETCPLink: LinkInterface {
|
|||
return maxPacketSize
|
||||
}
|
||||
|
||||
let negotiationTimeout: TimeInterval = 10.0
|
||||
let negotiationTimeout: TimeInterval = 60.0
|
||||
|
||||
let hardResetTimeout: TimeInterval = 5.0
|
||||
let hardResetTimeout: TimeInterval = 20.0
|
||||
|
||||
func setReadHandler(queue: DispatchQueue, _ handler: @escaping ([Data]?, Error?) -> Void) {
|
||||
loopReadPackets(queue, Data(), handler)
|
||||
|
|
|
@ -106,6 +106,10 @@ public class ConfigurationParser {
|
|||
static let externalFiles = NSRegularExpression("^(ca|cert|key|tls-auth|tls-crypt) ")
|
||||
|
||||
static let connection = NSRegularExpression("^<connection>")
|
||||
|
||||
// MARK: Continuation
|
||||
|
||||
static let continuation = NSRegularExpression("^push-continuation [12]")
|
||||
}
|
||||
|
||||
private enum Topology: String {
|
||||
|
@ -232,6 +236,16 @@ public class ConfigurationParser {
|
|||
isHandled = true
|
||||
}
|
||||
|
||||
// MARK: Continuation
|
||||
|
||||
var isContinuation = false
|
||||
Regex.continuation.enumerateArguments(in: line) {
|
||||
isContinuation = ($0.first == "2")
|
||||
}
|
||||
guard !isContinuation else {
|
||||
throw SessionError.continuationPushReply
|
||||
}
|
||||
|
||||
// MARK: Inline content
|
||||
|
||||
if unsupportedError == nil {
|
||||
|
|
|
@ -67,6 +67,8 @@ struct CoreConfiguration {
|
|||
|
||||
static let tickInterval = 0.2
|
||||
|
||||
static let pushRequestInterval = 2.0
|
||||
|
||||
static let pingTimeout = 120.0
|
||||
|
||||
static let retransmissionLimit = 0.1
|
||||
|
|
|
@ -59,6 +59,12 @@ public enum SessionError: String, Error {
|
|||
/// The provided credentials failed authentication.
|
||||
case badCredentials
|
||||
|
||||
/// The PUSH_REPLY is multipart.
|
||||
case continuationPushReply
|
||||
|
||||
/// The reply to PUSH_REQUEST is malformed.
|
||||
case malformedPushReply
|
||||
|
||||
/// A write operation failed at the link layer (e.g. network unreachable).
|
||||
case failedLinkWrite
|
||||
|
||||
|
|
|
@ -135,6 +135,8 @@ public class SessionProxy {
|
|||
return link?.isReliable ?? false
|
||||
}
|
||||
|
||||
private var continuatedPushReplyMessage: String?
|
||||
|
||||
private var pushReply: SessionReply?
|
||||
|
||||
private var nextPushRequestDate: Date?
|
||||
|
@ -368,6 +370,7 @@ public class SessionProxy {
|
|||
nextPushRequestDate = nil
|
||||
connectedDate = nil
|
||||
authenticator = nil
|
||||
continuatedPushReplyMessage = nil
|
||||
pushReply = nil
|
||||
link = nil
|
||||
if !(tunnel?.isPersistent ?? false) {
|
||||
|
@ -403,12 +406,10 @@ public class SessionProxy {
|
|||
return
|
||||
}
|
||||
|
||||
if !isReliableLink {
|
||||
pushRequest()
|
||||
flushControlQueue()
|
||||
}
|
||||
pushRequest()
|
||||
flushControlQueue()
|
||||
|
||||
guard (negotiationKey.controlState == .connected) else {
|
||||
guard negotiationKey.controlState == .connected else {
|
||||
queue.asyncAfter(deadline: .now() + CoreConfiguration.tickInterval) { [weak self] in
|
||||
self?.loopNegotiation()
|
||||
}
|
||||
|
@ -607,6 +608,7 @@ public class SessionProxy {
|
|||
log.debug("Send hard reset")
|
||||
|
||||
resetControlChannel(forNewSession: true)
|
||||
continuatedPushReplyMessage = nil
|
||||
pushReply = nil
|
||||
negotiationKeyIdx = 0
|
||||
let newKey = SessionKey(id: UInt8(negotiationKeyIdx))
|
||||
|
@ -696,13 +698,11 @@ public class SessionProxy {
|
|||
|
||||
// Ruby: push_request
|
||||
private func pushRequest() {
|
||||
guard (negotiationKey.controlState == .preIfConfig) else {
|
||||
guard negotiationKey.controlState == .preIfConfig else {
|
||||
return
|
||||
}
|
||||
if !isReliableLink {
|
||||
guard let targetDate = nextPushRequestDate, (Date() > targetDate) else {
|
||||
return
|
||||
}
|
||||
guard let targetDate = nextPushRequestDate, Date() > targetDate else {
|
||||
return
|
||||
}
|
||||
|
||||
log.debug("TLS.ifconfig: Put plaintext (PUSH_REQUEST)")
|
||||
|
@ -727,7 +727,7 @@ public class SessionProxy {
|
|||
if negotiationKey.softReset {
|
||||
completeConnection()
|
||||
}
|
||||
nextPushRequestDate = Date().addingTimeInterval(CoreConfiguration.retransmissionLimit)
|
||||
nextPushRequestDate = Date().addingTimeInterval(CoreConfiguration.pushRequestInterval)
|
||||
}
|
||||
|
||||
private func maybeRenegotiate() {
|
||||
|
@ -854,8 +854,10 @@ public class SessionProxy {
|
|||
}
|
||||
|
||||
do {
|
||||
let controlData = try controlChannel.currentControlData(withTLS: negotiationKey.tls)
|
||||
handleControlData(controlData)
|
||||
while true {
|
||||
let controlData = try controlChannel.currentControlData(withTLS: negotiationKey.tls)
|
||||
handleControlData(controlData)
|
||||
}
|
||||
} catch _ {
|
||||
}
|
||||
}
|
||||
|
@ -915,9 +917,15 @@ public class SessionProxy {
|
|||
log.debug("Received control message: \"\(message)\"")
|
||||
}
|
||||
|
||||
let completeMessage: String
|
||||
if let continuated = continuatedPushReplyMessage {
|
||||
completeMessage = "\(continuated),\(message)"
|
||||
} else {
|
||||
completeMessage = message
|
||||
}
|
||||
let reply: PushReply
|
||||
do {
|
||||
guard let optionalReply = try PushReply(message: message) else {
|
||||
guard let optionalReply = try PushReply(message: completeMessage) else {
|
||||
return
|
||||
}
|
||||
reply = optionalReply
|
||||
|
@ -939,6 +947,10 @@ public class SessionProxy {
|
|||
throw SessionError.serverCompression
|
||||
}
|
||||
}
|
||||
} catch SessionError.continuationPushReply {
|
||||
continuatedPushReplyMessage = completeMessage.replacingOccurrences(of: "push-continuation", with: "")
|
||||
// FIXME: strip "PUSH_REPLY" and "push-continuation 2"
|
||||
return
|
||||
} catch let e {
|
||||
deferStop(.shutdown, e)
|
||||
return
|
||||
|
@ -1143,11 +1155,6 @@ public class SessionProxy {
|
|||
// MARK: Acks
|
||||
|
||||
private func handleAcks() {
|
||||
|
||||
// retry PUSH_REQUEST if ack queue is empty (all sent packets were ack'ed)
|
||||
if isReliableLink && !controlChannel.hasPendingAcks() {
|
||||
pushRequest()
|
||||
}
|
||||
}
|
||||
|
||||
// Ruby: send_ack
|
||||
|
|
|
@ -155,4 +155,10 @@ class PushTests: XCTestCase {
|
|||
|
||||
XCTAssertEqual(reply.options.keepAliveInterval, 10)
|
||||
}
|
||||
|
||||
func testProvost() {
|
||||
let msg = "PUSH_REPLY,route 87.233.192.218,route 87.233.192.219,route 87.233.192.220,route 87.248.186.252,route 92.241.171.245,route 103.246.200.0 255.255.252.0,route 109.239.140.0 255.255.255.0,route 128.199.0.0 255.255.0.0,route 13.125.0.0 255.255.0.0,route 13.230.0.0 255.254.0.0,route 13.56.0.0 255.252.0.0,route 149.154.160.0 255.255.252.0,route 149.154.164.0 255.255.252.0,route 149.154.168.0 255.255.252.0,route 149.154.172.0 255.255.252.0,route 159.122.128.0 255.255.192.0,route 159.203.0.0 255.255.0.0,route 159.65.0.0 255.255.0.0,route 159.89.0.0 255.255.0.0,route 165.227.0.0 255.255.0.0,route 167.99.0.0 255.255.0.0,route 174.138.0.0 255.255.128.0,route 176.67.169.0 255.255.255.0,route 178.239.88.0 255.255.248.0,route 178.63.0.0 255.255.0.0,route 18.130.0.0 255.255.0.0,route 18.144.0.0 255.255.0.0,route 18.184.0.0 255.254.0.0,route 18.194.0.0 255.254.0.0,route 18.196.0.0 255.254.0.0,route 18.204.0.0 255.252.0.0,push-continuation 2"
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue