Merge pull request #122 from rob-patchett/ping-timeout

Allow keep-alive timeout to be configured by the server or client
This commit is contained in:
Davide De Rosa 2019-10-22 10:51:27 +02:00 committed by GitHub
commit eb09493882
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 6 deletions

View File

@ -163,6 +163,8 @@ extension OpenVPNTunnelProvider {
static let keepAlive = "KeepAlive" static let keepAlive = "KeepAlive"
static let keepAliveTimeout = "KeepAliveTimeout"
static let endpointProtocols = "EndpointProtocols" static let endpointProtocols = "EndpointProtocols"
static let renegotiatesAfter = "RenegotiatesAfter" static let renegotiatesAfter = "RenegotiatesAfter"
@ -497,6 +499,9 @@ private extension OpenVPN.Configuration {
if let keepAliveInterval = providerConfiguration[S.keepAlive] as? TimeInterval { if let keepAliveInterval = providerConfiguration[S.keepAlive] as? TimeInterval {
builder.keepAliveInterval = keepAliveInterval builder.keepAliveInterval = keepAliveInterval
} }
if let keepAliveTimeout = providerConfiguration[S.keepAliveTimeout] as? TimeInterval {
builder.keepAliveTimeout = keepAliveTimeout
}
if let renegotiatesAfter = providerConfiguration[S.renegotiatesAfter] as? TimeInterval { if let renegotiatesAfter = providerConfiguration[S.renegotiatesAfter] as? TimeInterval {
builder.renegotiatesAfter = renegotiatesAfter builder.renegotiatesAfter = renegotiatesAfter
} }
@ -571,6 +576,9 @@ private extension OpenVPN.Configuration {
if let keepAliveSeconds = keepAliveInterval { if let keepAliveSeconds = keepAliveInterval {
dict[S.keepAlive] = keepAliveSeconds dict[S.keepAlive] = keepAliveSeconds
} }
if let keepAliveTimeoutSeconds = keepAliveTimeout {
dict[S.keepAliveTimeout] = keepAliveTimeoutSeconds
}
if let renegotiatesAfterSeconds = renegotiatesAfter { if let renegotiatesAfterSeconds = renegotiatesAfter {
dict[S.renegotiatesAfter] = renegotiatesAfterSeconds dict[S.renegotiatesAfter] = renegotiatesAfterSeconds
} }
@ -632,9 +640,14 @@ private extension OpenVPN.Configuration {
log.info("\tTLS security level: default") log.info("\tTLS security level: default")
} }
if let keepAliveSeconds = keepAliveInterval, keepAliveSeconds > 0 { if let keepAliveSeconds = keepAliveInterval, keepAliveSeconds > 0 {
log.info("\tKeep-alive: \(keepAliveSeconds) seconds") log.info("\tKeep-alive interval: \(keepAliveSeconds) seconds")
} else { } else {
log.info("\tKeep-alive: never") log.info("\tKeep-alive interval: never")
}
if let keepAliveTimeoutSeconds = keepAliveTimeout, keepAliveTimeoutSeconds > 0 {
log.info("\tKeep-alive timeout: \(keepAliveTimeoutSeconds) seconds")
} else {
log.info("\tKeep-alive timeout: never")
} }
if let renegotiatesAfterSeconds = renegotiatesAfter, renegotiatesAfterSeconds > 0 { if let renegotiatesAfterSeconds = renegotiatesAfter, renegotiatesAfterSeconds > 0 {
log.info("\tRenegotiation: \(renegotiatesAfterSeconds) seconds") log.info("\tRenegotiation: \(renegotiatesAfterSeconds) seconds")

View File

@ -202,6 +202,9 @@ extension OpenVPN {
/// Sends periodical keep-alive packets if set. /// Sends periodical keep-alive packets if set.
public var keepAliveInterval: TimeInterval? public var keepAliveInterval: TimeInterval?
/// Disconnects after no keep-alive packets are received within timeout interval if set.
public var keepAliveTimeout: TimeInterval?
/// The number of seconds after which a renegotiation should be initiated. If `nil`, the client will never initiate a renegotiation. /// The number of seconds after which a renegotiation should be initiated. If `nil`, the client will never initiate a renegotiation.
public var renegotiatesAfter: TimeInterval? public var renegotiatesAfter: TimeInterval?
@ -277,6 +280,7 @@ extension OpenVPN {
tlsWrap: tlsWrap, tlsWrap: tlsWrap,
tlsSecurityLevel: tlsSecurityLevel, tlsSecurityLevel: tlsSecurityLevel,
keepAliveInterval: keepAliveInterval, keepAliveInterval: keepAliveInterval,
keepAliveTimeout: keepAliveTimeout,
renegotiatesAfter: renegotiatesAfter, renegotiatesAfter: renegotiatesAfter,
hostname: hostname, hostname: hostname,
endpointProtocols: endpointProtocols, endpointProtocols: endpointProtocols,
@ -347,6 +351,9 @@ extension OpenVPN {
/// - Seealso: `ConfigurationBuilder.keepAliveInterval` /// - Seealso: `ConfigurationBuilder.keepAliveInterval`
public let keepAliveInterval: TimeInterval? public let keepAliveInterval: TimeInterval?
/// - Seealso: `ConfigurationBuilder.keepAliveTimeout`
public let keepAliveTimeout: TimeInterval?
/// - Seealso: `ConfigurationBuilder.renegotiatesAfter` /// - Seealso: `ConfigurationBuilder.renegotiatesAfter`
public let renegotiatesAfter: TimeInterval? public let renegotiatesAfter: TimeInterval?
@ -435,6 +442,7 @@ extension OpenVPN.Configuration {
builder.tlsWrap = tlsWrap builder.tlsWrap = tlsWrap
builder.tlsSecurityLevel = tlsSecurityLevel builder.tlsSecurityLevel = tlsSecurityLevel
builder.keepAliveInterval = keepAliveInterval builder.keepAliveInterval = keepAliveInterval
builder.keepAliveTimeout = keepAliveTimeout
builder.renegotiatesAfter = renegotiatesAfter builder.renegotiatesAfter = renegotiatesAfter
builder.hostname = hostname builder.hostname = hostname
builder.endpointProtocols = endpointProtocols builder.endpointProtocols = endpointProtocols

View File

@ -52,6 +52,8 @@ extension OpenVPN {
static let ping = NSRegularExpression("^ping +\\d+") static let ping = NSRegularExpression("^ping +\\d+")
static let pingRestart = NSRegularExpression("^ping-restart +\\d+")
static let renegSec = NSRegularExpression("^reneg-sec +\\d+") static let renegSec = NSRegularExpression("^reneg-sec +\\d+")
static let blockBegin = NSRegularExpression("^<[\\w\\-]+>") static let blockBegin = NSRegularExpression("^<[\\w\\-]+>")
@ -203,6 +205,7 @@ extension OpenVPN {
var optTLSKeyLines: [Substring]? var optTLSKeyLines: [Substring]?
var optTLSStrategy: TLSWrap.Strategy? var optTLSStrategy: TLSWrap.Strategy?
var optKeepAliveSeconds: TimeInterval? var optKeepAliveSeconds: TimeInterval?
var optKeepAliveTimeoutSeconds: TimeInterval?
var optRenegotiateAfterSeconds: TimeInterval? var optRenegotiateAfterSeconds: TimeInterval?
// //
var optHostname: String? var optHostname: String?
@ -398,6 +401,13 @@ extension OpenVPN {
} }
optKeepAliveSeconds = TimeInterval(arg) optKeepAliveSeconds = TimeInterval(arg)
} }
Regex.pingRestart.enumerateArguments(in: line) {
isHandled = true
guard let arg = $0.first else {
return
}
optKeepAliveTimeoutSeconds = TimeInterval(arg)
}
Regex.renegSec.enumerateArguments(in: line) { Regex.renegSec.enumerateArguments(in: line) {
isHandled = true isHandled = true
guard let arg = $0.first else { guard let arg = $0.first else {
@ -599,6 +609,7 @@ extension OpenVPN {
} }
sessionBuilder.keepAliveInterval = optKeepAliveSeconds sessionBuilder.keepAliveInterval = optKeepAliveSeconds
sessionBuilder.keepAliveTimeout = optKeepAliveTimeoutSeconds
sessionBuilder.renegotiatesAfter = optRenegotiateAfterSeconds sessionBuilder.renegotiatesAfter = optRenegotiateAfterSeconds
// MARK: Client // MARK: Client

View File

@ -87,8 +87,8 @@ public class OpenVPNSession: Session {
private var keepAliveInterval: TimeInterval? { private var keepAliveInterval: TimeInterval? {
let interval: TimeInterval? let interval: TimeInterval?
if let negInterval = pushReply?.options.keepAliveInterval, negInterval > 0 { if let negInterval = pushReply?.options.keepAliveInterval, negInterval > 0.0 {
interval = TimeInterval(negInterval) interval = negInterval
} else if let cfgInterval = configuration.keepAliveInterval, cfgInterval > 0.0 { } else if let cfgInterval = configuration.keepAliveInterval, cfgInterval > 0.0 {
interval = cfgInterval interval = cfgInterval
} else { } else {
@ -97,6 +97,16 @@ public class OpenVPNSession: Session {
return interval return interval
} }
private var keepAliveTimeout: TimeInterval {
if let negTimeout = pushReply?.options.keepAliveTimeout, negTimeout > 0.0 {
return negTimeout
} else if let cfgTimeout = configuration.keepAliveTimeout, cfgTimeout > 0.0 {
return cfgTimeout
} else {
return CoreConfiguration.OpenVPN.pingTimeout
}
}
/// An optional `OpenVPNSessionDelegate` for receiving session events. /// An optional `OpenVPNSessionDelegate` for receiving session events.
public weak var delegate: OpenVPNSessionDelegate? public weak var delegate: OpenVPNSessionDelegate?
@ -535,7 +545,7 @@ public class OpenVPNSession: Session {
} }
let now = Date() let now = Date()
guard (now.timeIntervalSince(lastPing.inbound) <= CoreConfiguration.OpenVPN.pingTimeout) else { guard (now.timeIntervalSince(lastPing.inbound) <= keepAliveTimeout) else {
deferStop(.shutdown, OpenVPNError.pingTimeout) deferStop(.shutdown, OpenVPNError.pingTimeout)
return return
} }
@ -1070,7 +1080,10 @@ public class OpenVPNSession: Session {
log.info("\tNegotiated compression algorithm: \(negCompression)") log.info("\tNegotiated compression algorithm: \(negCompression)")
} }
if let negPing = pushReply.options.keepAliveInterval { if let negPing = pushReply.options.keepAliveInterval {
log.info("\tNegotiated keep-alive: \(negPing) seconds") log.info("\tNegotiated keep-alive interval: \(negPing) seconds")
}
if let negPingRestart = pushReply.options.keepAliveTimeout {
log.info("\tNegotiated keep-alive timeout: \(negPingRestart) seconds")
} }
let bridge: OpenVPN.EncryptionBridge let bridge: OpenVPN.EncryptionBridge

View File

@ -156,6 +156,14 @@ class PushTests: XCTestCase {
XCTAssertEqual(reply.options.keepAliveInterval, 10) XCTAssertEqual(reply.options.keepAliveInterval, 10)
} }
func testPingRestart() {
let msg = "PUSH_REPLY,route 192.168.1.0 255.255.255.0,route 10.0.2.0 255.255.255.0,dhcp-option DNS 192.168.1.99,dhcp-option DNS 176.103.130.130,route 10.0.2.1,topology net30,ping 10,ping-restart 60,ifconfig 10.0.2.14 10.0.2.13"
let reply = try! OpenVPN.PushReply(message: msg)!
reply.debug()
XCTAssertEqual(reply.options.keepAliveTimeout, 60)
}
func testProvost() { 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 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? OpenVPN.PushReply(message: msg)! let reply = try? OpenVPN.PushReply(message: msg)!