Improve some things about OpenVPN.Configuration

- Treat empty passphrase as no passphrase
- Parse authentication requirement from --auth-user-pass
- Overload ConfigurationParser with String parameter
- Move OpenVPN fallbacks inline with builder

Give a withFallbacks: option to initialize basic fields rather
than leaving them nil.
This commit is contained in:
Davide De Rosa 2022-02-12 08:37:51 +01:00
parent 88544e4877
commit c019cecbe0
3 changed files with 84 additions and 30 deletions

View File

@ -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
### Added
- Parse OpenVPN authentication requirement from `--auth-user-pass`.
## 4.1.0 (2022-02-09)
### Added

View File

@ -242,6 +242,9 @@ extension OpenVPN {
/// The tunnel MTU.
public var mtu: Int?
/// Requires username authentication.
public var authUserPass: Bool?
// MARK: Server
/// The auth-token returned by the server.
@ -300,7 +303,18 @@ extension OpenVPN {
/// Policies for redirecting traffic through the VPN gateway.
public var routingPolicies: [RoutingPolicy]?
public init() {
/**
Creates a `ConfigurationBuilder`.
- Parameter withFallbacks: If `true`, initializes builder with fallback values rather than nil.
*/
public init(withFallbacks: Bool = false) {
if withFallbacks {
cipher = Fallback.cipher
digest = Fallback.digest
compressionFraming = Fallback.compressionFraming
compressionAlgorithm = Fallback.compressionAlgorithm
}
}
/**
@ -332,6 +346,7 @@ extension OpenVPN {
randomizeEndpoint: randomizeEndpoint,
usesPIAPatches: usesPIAPatches,
mtu: mtu,
authUserPass: authUserPass,
authToken: authToken,
peerId: peerId,
ipv4: ipv4,
@ -348,24 +363,6 @@ extension OpenVPN {
routingPolicies: routingPolicies
)
}
// MARK: Shortcuts
public var fallbackCipher: Cipher {
return cipher ?? Fallback.cipher
}
public var fallbackDigest: Digest {
return digest ?? Fallback.digest
}
public var fallbackCompressionFraming: CompressionFraming {
return compressionFraming ?? Fallback.compressionFraming
}
public var fallbackCompressionAlgorithm: CompressionAlgorithm {
return compressionAlgorithm ?? Fallback.compressionAlgorithm
}
}
/// The immutable configuration for `OpenVPNSession`.
@ -437,6 +434,9 @@ extension OpenVPN {
/// - Seealso: `ConfigurationBuilder.mtu`
public let mtu: Int?
/// - Seealso: `ConfigurationBuilder.authUserPass`
public let authUserPass: Bool?
/// - Seealso: `ConfigurationBuilder.authToken`
public let authToken: String?
@ -502,15 +502,16 @@ extension OpenVPN.Configuration {
/**
Returns a `ConfigurationBuilder` to use this configuration as a starting point for a new one.
- Parameter withFallbacks: If `true`, initializes builder with fallback values rather than nil.
- Returns: An editable `ConfigurationBuilder` initialized with this configuration.
*/
public func builder() -> OpenVPN.ConfigurationBuilder {
public func builder(withFallbacks: Bool = false) -> OpenVPN.ConfigurationBuilder {
var builder = OpenVPN.ConfigurationBuilder()
builder.cipher = cipher
builder.cipher = cipher ?? (withFallbacks ? OpenVPN.Fallback.cipher : nil)
builder.dataCiphers = dataCiphers
builder.digest = digest
builder.compressionFraming = compressionFraming
builder.compressionAlgorithm = compressionAlgorithm
builder.digest = digest ?? (withFallbacks ? OpenVPN.Fallback.digest : nil)
builder.compressionFraming = compressionFraming ?? (withFallbacks ? OpenVPN.Fallback.compressionFraming : nil)
builder.compressionAlgorithm = compressionAlgorithm ?? (withFallbacks ? OpenVPN.Fallback.compressionAlgorithm : nil)
builder.ca = ca
builder.clientCertificate = clientCertificate
builder.clientKey = clientKey
@ -527,6 +528,7 @@ extension OpenVPN.Configuration {
builder.randomizeEndpoint = randomizeEndpoint
builder.usesPIAPatches = usesPIAPatches
builder.mtu = mtu
builder.authUserPass = authUserPass
builder.authToken = authToken
builder.peerId = peerId
builder.ipv4 = ipv4
@ -549,7 +551,6 @@ extension OpenVPN.Configuration {
// MARK: Encoding
extension OpenVPN.Configuration {
public func print() {
guard let endpointProtocols = endpointProtocols else {
fatalError("No sessionConfiguration.endpointProtocols set")
@ -558,6 +559,7 @@ extension OpenVPN.Configuration {
log.info("\tCipher: \(fallbackCipher)")
log.info("\tDigest: \(fallbackDigest)")
log.info("\tCompression framing: \(fallbackCompressionFraming)")
log.info("\tUsername authentication: \(authUserPass ?? false)")
if let compressionAlgorithm = compressionAlgorithm, compressionAlgorithm != .disabled {
log.info("\tCompression algorithm: \(compressionAlgorithm)")
} else {

View File

@ -78,6 +78,8 @@ extension OpenVPN {
static let remote = NSRegularExpression("^remote +[^ ]+( +\\d+)?( +(udp[46]?|tcp[46]?))?")
static let authUserPass = NSRegularExpression("^auth-user-pass")
static let eku = NSRegularExpression("^remote-cert-tls +server")
static let remoteRandom = NSRegularExpression("^remote-random")
@ -178,7 +180,7 @@ extension OpenVPN {
}
/**
Parses an .ovpn file from an URL.
Parses a configuration from a .ovpn file.
- Parameter url: The URL of the configuration file.
- Parameter passphrase: The optional passphrase for encrypted data.
@ -187,8 +189,39 @@ extension OpenVPN {
- Throws: `ConfigurationError` if the configuration file is wrong or incomplete.
*/
public static func parsed(fromURL url: URL, passphrase: String? = nil, returnsStripped: Bool = false) throws -> Result {
let lines = try String(contentsOf: url).trimmedLines()
return try parsed(fromLines: lines, isClient: true, passphrase: passphrase, originalURL: url, returnsStripped: returnsStripped)
let contents = try String(contentsOf: url)
return try parsed(
fromContents: contents,
passphrase: passphrase,
originalURL: url,
returnsStripped: returnsStripped
)
}
/**
Parses a configuration from a string.
- Parameter contents: The contents of the configuration file.
- Parameter passphrase: The optional passphrase for encrypted data.
- Parameter originalURL: The optional original URL of the configuration file.
- Parameter returnsStripped: When `true`, stores the stripped file into `Result.strippedLines`. Defaults to `false`.
- Returns: The `Result` outcome of the parsing.
- Throws: `ConfigurationError` if the configuration file is wrong or incomplete.
*/
public static func parsed(
fromContents contents: String,
passphrase: String? = nil,
originalURL: URL? = nil,
returnsStripped: Bool = false
) throws -> Result {
let lines = contents.trimmedLines()
return try parsed(
fromLines: lines,
isClient: true,
passphrase: passphrase,
originalURL: originalURL,
returnsStripped: returnsStripped
)
}
/**
@ -202,7 +235,13 @@ extension OpenVPN {
- Returns: The `Result` outcome of the parsing.
- Throws: `ConfigurationError` if the configuration file is wrong or incomplete.
*/
public static func parsed(fromLines lines: [String], isClient: Bool = false, passphrase: String? = nil, originalURL: URL? = nil, returnsStripped: Bool = false) throws -> Result {
public static func parsed(
fromLines lines: [String],
isClient: Bool = false,
passphrase: String? = nil,
originalURL: URL? = nil,
returnsStripped: Bool = false
) throws -> Result {
var optStrippedLines: [String]? = returnsStripped ? [] : nil
var optWarning: ConfigurationError?
var unsupportedError: ConfigurationError?
@ -229,6 +268,7 @@ extension OpenVPN {
var optDefaultProto: SocketType?
var optDefaultPort: UInt16?
var optRemotes: [(String, UInt16?, SocketType?)] = [] // address, port, socket
var authUserPass = false
var optChecksEKU: Bool?
var optRandomizeEndpoint: Bool?
var optMTU: Int?
@ -537,6 +577,10 @@ extension OpenVPN {
}
optMTU = Int(str)
}
Regex.authUserPass.enumerateComponents(in: line) { _ in
isHandled = true
authUserPass = true
}
// MARK: Server
@ -687,10 +731,11 @@ extension OpenVPN {
sessionBuilder.compressionAlgorithm = optCompressionAlgorithm
sessionBuilder.ca = optCA
sessionBuilder.clientCertificate = optClientCertificate
sessionBuilder.authUserPass = authUserPass
if let clientKey = optClientKey, clientKey.isEncrypted {
// FIXME: remove dependency on TLSBox
guard let passphrase = passphrase else {
guard let passphrase = passphrase, !passphrase.isEmpty else {
throw ConfigurationError.encryptionPassphrase
}
do {
@ -746,6 +791,7 @@ extension OpenVPN {
sessionBuilder.hostname = nil
}
sessionBuilder.authUserPass = authUserPass
sessionBuilder.checksEKU = optChecksEKU
sessionBuilder.randomizeEndpoint = optRandomizeEndpoint
sessionBuilder.mtu = optMTU