ovpnmcgen.rb 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/ChangeLog +11 -0
- data/README.md +63 -4
- data/bin/ovpnmcgen.rb +34 -27
- data/lib/ovpnmcgen.rb +18 -17
- data/lib/ovpnmcgen/ovpnconfig.rb +51 -0
- data/lib/ovpnmcgen/version.rb +2 -2
- data/ovpnmcgen.rb.gemspec +1 -1
- metadata +8 -6
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 367d863a65d76ef7131544d0cfeabe155b43ada8
|
4
|
+
data.tar.gz: 638bd7fb996c3f265005992d0d452d41fceb1ab3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11d4d579cb0a28ed0536afb99ba0c98c88c97923c0c1deaa7acc4dedd01dc8ef24f315a0bcc2fa2164511216c65164b39bdcdd7c97b6506ef7078e715aace314
|
7
|
+
data.tar.gz: f981db017988637593dc2b883531014040fefbe4b0846187a330519960a2e310690c757bd0e1a9020253a16dd139f4f0aa6cdbff8491ced055da851b1c27cd46
|
data/.gitignore
CHANGED
data/ChangeLog
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
= 0.1.0 / 2014-03-27
|
2
|
+
* Added support for `--ovpnconfigfile`, `--port`, `--proto`.
|
3
|
+
* Shorter switches for `--[un]trusted-ssids`.
|
4
|
+
* Improved Documentation.
|
5
|
+
|
6
|
+
= 0.0.2 / 2014-03-26
|
7
|
+
* Require ruby >= 1.9.3.
|
8
|
+
* Improved Documentation.
|
9
|
+
|
10
|
+
= 0.0.1 / 2014-03-26
|
11
|
+
* Initial Release.
|
data/README.md
CHANGED
@@ -2,16 +2,56 @@
|
|
2
2
|
|
3
3
|
OpenVPN iOS Configuration Profile Utility
|
4
4
|
|
5
|
-
|
5
|
+
Generates iOS configuration profiles (.mobileconfig) that configures OpenVPN for use with VPN-on-Demand that are not accessible through the Apple Configurator or the iPhone Configuration Utility.
|
6
|
+
|
7
|
+
Although there are many possible VPN-on-Demand (VoD) triggers, this utility currently only implements `SSIDMatch` and `InterfaceTypeMatch`. The following algorithm is executed upon network changes, in order:
|
8
|
+
|
9
|
+
- If wireless SSID matches any specified with `--trusted-ssids`, tear down the VPN connection and do not reconnect on demand.
|
10
|
+
- Else if wireless SSID matches any specified with `--untrusted-ssids`, unconditionally bring up the VPN connection on the next network attempt.
|
11
|
+
- Else if the primary network interface becomes Wifi (any SSID except those above), bring up the VPN connection.
|
12
|
+
- Else if the primary network interface becomes Cellular, leave any existing VPN connection up, but do not reconnect on demand.
|
13
|
+
- Else, unconditionally bring up the VPN connection on the next network attempt.
|
14
|
+
|
15
|
+
Note: The other match triggers, such as `DNSDomainMatch`, `DNSServerAddressMatch`, `URLStringProbe`, and per-connection domain inspection (`ActionParameters`), are not implemented. I reckon some kind of DSL will need to be built to support them; pull-requests are welcome.
|
6
16
|
|
7
17
|
## Installation
|
8
18
|
|
9
|
-
Install
|
19
|
+
Install the production version from Rubygems.org:
|
10
20
|
|
11
21
|
$ gem install ovpnmcgen.rb
|
12
22
|
|
23
|
+
### Local Development
|
24
|
+
|
25
|
+
Clone the source:
|
26
|
+
|
27
|
+
$ git clone https://github.com/iphoting/ovpnmcgen.rb
|
28
|
+
|
29
|
+
Build and install the gem:
|
30
|
+
|
31
|
+
$ cd ovpnmcgen.rb/
|
32
|
+
$ bundle install # install dependencies
|
33
|
+
# Hack away...
|
34
|
+
$ rake install # build and install gem
|
35
|
+
|
13
36
|
## Usage
|
14
37
|
|
38
|
+
```
|
39
|
+
Usage: ovpnmcgen.rb generate [options] <user> <device>
|
40
|
+
|
41
|
+
Options:
|
42
|
+
--cafile FILE Path to OpenVPN CA file. (Required)
|
43
|
+
--tafile FILE Path to TLS Key file. (Required)
|
44
|
+
--host HOSTNAME Hostname of OpenVPN server. (Required)
|
45
|
+
--p12file FILE Path to user PKCS#12 file. (Required)
|
46
|
+
--p12pass PASSWORD Password to unlock PKCS#12 file.
|
47
|
+
--[no-]vod Enable or Disable VPN-On-Demand. [Default: Enabled]
|
48
|
+
--trusted-ssids SSIDS List of comma-separated trusted SSIDs.
|
49
|
+
--untrusted-ssids SSIDS List of comma-separated untrusted SSIDs.
|
50
|
+
-o, --output FILE Output to file. [Default: stdout]
|
51
|
+
```
|
52
|
+
|
53
|
+
## Examples
|
54
|
+
|
15
55
|
### Typical Usage
|
16
56
|
$ ovpnmcgen.rb gen --trusted-ssids home --host vpn.example.com \
|
17
57
|
--cafile path/to/ca.pem --tafile path/to/ta.key \
|
@@ -225,10 +265,29 @@ Output similar to above:
|
|
225
265
|
</plist>
|
226
266
|
```
|
227
267
|
|
228
|
-
### Using OpenSSL to
|
268
|
+
### Using OpenSSL to convert files into PKCS#12 (.p12)
|
229
269
|
openssl pkcs12 -export -out path/to/john-ipad.p12 \
|
230
270
|
-inkey path/to/john-ipad.key -in path/to/john-ipad.crt \
|
231
|
-
-passout pass:p12passphrase
|
271
|
+
-passout pass:p12passphrase -name john-ipad@vpn.example.com
|
272
|
+
|
273
|
+
## TODO
|
274
|
+
|
275
|
+
- Config file to specify global options, such as `--cafile`, `--tafile`, `--host`, `--[un]trusted-ssids`.
|
276
|
+
- Batch-operation mode, with CSV-file as input, and a CSV UUID-index file to track generated profiles as output.
|
277
|
+
|
278
|
+
The same UUID should be used for profile updates, so that iOS knows which profile to replace, especially in MDM environments.
|
279
|
+
|
280
|
+
- Adopt OpenVPN parameters from an OpenVPN-compatible client.conf input file.
|
281
|
+
|
282
|
+
Implemented, but lacks support for inline `<ca|tls-auth>` data enclosures.
|
283
|
+
|
284
|
+
- Sign/Encrypt .mobileconfig.
|
285
|
+
|
286
|
+
Current workaround is to use a trusted MDM solution to securely push these unsigned, unencrypted profiles to iOS devices, through the encrypted MDM connected.
|
287
|
+
|
288
|
+
## References
|
289
|
+
|
290
|
+
- Apple, at <https://developer.apple.com/library/ios/featuredarticles/iPhoneConfigurationProfileRef/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010206-CH1-SW27>.
|
232
291
|
|
233
292
|
## Contributing
|
234
293
|
|
data/bin/ovpnmcgen.rb
CHANGED
@@ -13,44 +13,51 @@ never_trace!
|
|
13
13
|
|
14
14
|
command :generate do |c|
|
15
15
|
c.syntax = 'ovpnmcgen.rb generate [options] <user> <device>'
|
16
|
-
c.summary = 'Generates iOS Configuration Profiles'
|
17
|
-
c.description = 'Generates
|
16
|
+
c.summary = 'Generates iOS Configuration Profiles (.mobileconfig)'
|
17
|
+
c.description = 'Generates iOS configuration profiles (.mobileconfig) that configures OpenVPN for use with VPN-on-Demand that are not accessible through the Apple Configurator or the iPhone Configuration Utility.'
|
18
18
|
c.example 'Typical Usage', 'ovpnmcgen.rb gen --trusted-ssids home --host vpn.example.com --cafile path/to/ca.pem --tafile path/to/ta.key --p12file path/to/john-ipad.p12 --p12pass p12passphrase john ipad'
|
19
19
|
c.example 'Extended Usage', 'ovpnmcgen.rb gen --trusted-ssids home,school --untrusted-ssids virusnet --host vpn.example.com --cafile path/to/ca.pem --tafile path/to/ta.key --p12file path/to/john-ipad.p12 --p12pass p12passphrase john ipad'
|
20
|
-
c.example '
|
20
|
+
c.example 'Using OpenSSL to convert files into PKCS#12 (.p12)', 'openssl pkcs12 -export -out path/to/john-ipad.p12 -inkey path/to/john-ipad.key -in path/to/john-ipad.crt -passout pass:p12passphrase -name john-ipad@vpn.example.com'
|
21
21
|
c.option '--cafile FILE', 'Path to OpenVPN CA file. (Required)'
|
22
22
|
c.option '--tafile FILE', 'Path to TLS Key file. (Required)'
|
23
23
|
c.option '--host HOSTNAME', 'Hostname of OpenVPN server. (Required)'
|
24
|
+
c.option '--proto PROTO', 'OpenVPN server protocol. [Default: udp]'
|
25
|
+
c.option '-p', '--port PORT', 'OpenVPN server port. [Default: 1194]'
|
24
26
|
c.option '--p12file FILE', 'Path to user PKCS#12 file. (Required)'
|
25
27
|
c.option '--p12pass PASSWORD', 'Password to unlock PKCS#12 file.'
|
26
28
|
c.option '--[no-]vod', 'Enable or Disable VPN-On-Demand. [Default: Enabled]'
|
27
|
-
c.option '--trusted-ssids SSIDS', Array, 'List of comma-separated trusted SSIDs.'
|
28
|
-
c.option '--untrusted-ssids SSIDS', Array, 'List of comma-separated untrusted SSIDs.'
|
29
|
+
c.option '-t', '--trusted-ssids SSIDS', Array, 'List of comma-separated trusted SSIDs.'
|
30
|
+
c.option '-u', '--untrusted-ssids SSIDS', Array, 'List of comma-separated untrusted SSIDs.'
|
31
|
+
c.option '--ovpnconfigfile FILE', 'Path to OpenVPN client config file.'
|
29
32
|
c.option '-o', '--output FILE', 'Output to file. [Default: stdout]'
|
30
33
|
c.action do |args, options|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
raise ArgumentError.new "PKCS#12 file is required
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
34
|
+
raise ArgumentError.new "Invalid arguments. Run '#{File.basename(__FILE__)} help generate' for guidance" if args.nil? or args.length < 2
|
35
|
+
raise ArgumentError.new "Host is required" unless options.host
|
36
|
+
raise ArgumentError.new "cafile is required" unless options.cafile
|
37
|
+
raise ArgumentError.new "tafile is required" unless options.tafile
|
38
|
+
raise ArgumentError.new "PKCS#12 file is required" unless options.p12file
|
39
|
+
options.default :vod => true, :proto => 'udp', :port => 1194
|
40
|
+
user, device, p12file, p12pass = args
|
41
|
+
inputs = {
|
42
|
+
:user => user,
|
43
|
+
:device => device,
|
44
|
+
:p12file => options.p12file,
|
45
|
+
:p12pass => options.p12pass,
|
46
|
+
:cafile => options.cafile,
|
47
|
+
:tafile => options.tafile,
|
48
|
+
:host => options.host,
|
49
|
+
:proto => options.proto,
|
50
|
+
:port => options.port,
|
51
|
+
:enableVOD => options.vod,
|
52
|
+
:trusted_ssids => options.trusted_ssids,
|
53
|
+
:untrusted_ssids => options.untrusted_ssids
|
54
|
+
}
|
55
|
+
inputs[:ovpnconfigfile] = options.ovpnconfigfile if options.ovpnconfigfile
|
56
|
+
|
57
|
+
unless options.output
|
58
|
+
puts Ovpnmcgen.generate(inputs)
|
52
59
|
else
|
53
|
-
|
60
|
+
# write to file
|
54
61
|
begin
|
55
62
|
File.write(options.output, Ovpnmcgen.generate(inputs))
|
56
63
|
rescue Errno::ENOENT
|
data/lib/ovpnmcgen.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "ovpnmcgen/version"
|
2
|
+
require "ovpnmcgen/ovpnconfig"
|
2
3
|
require 'plist'
|
3
4
|
require 'base64'
|
4
5
|
|
@@ -13,8 +14,7 @@ module Ovpnmcgen
|
|
13
14
|
identifier = inputs[:identifier] || inputs[:host].split('.').reverse!.join('.')
|
14
15
|
port = inputs[:port] || 1194
|
15
16
|
certUUID = inputs[:certUUID] || `uuidgen`.chomp.upcase
|
16
|
-
user, device, domain, host = inputs[:user], inputs[:device], inputs[:host], inputs[:host]
|
17
|
-
enableVOD = inputs[:enableVOD]
|
17
|
+
user, device, domain, host, proto, enableVOD = inputs[:user], inputs[:device], inputs[:host], inputs[:host], inputs[:proto], inputs[:enableVOD]
|
18
18
|
p12pass = inputs[:p12pass] || ''
|
19
19
|
trusted_ssids = inputs[:trusted_ssids] || false
|
20
20
|
untrusted_ssids = inputs[:untrusted_ssids] || false
|
@@ -40,6 +40,21 @@ module Ovpnmcgen
|
|
40
40
|
exit
|
41
41
|
end
|
42
42
|
|
43
|
+
unless inputs[:ovpnconfigfile].nil?
|
44
|
+
ovpnconfighash = Ovpnmcgen.getOVPNVendorConfigHash(inputs[:ovpnconfigfile])
|
45
|
+
else # Bare minimum configuration
|
46
|
+
ovpnconfighash = {
|
47
|
+
'client' => 'NOARGS',
|
48
|
+
'comp-lzo' => 'NOARGS',
|
49
|
+
'dev' => 'tun',
|
50
|
+
'key-direction' => '1',
|
51
|
+
'remote-cert-tls' => 'server'
|
52
|
+
}
|
53
|
+
end
|
54
|
+
ovpnconfighash['remote'] = "#{host} #{port} #{proto}"
|
55
|
+
ovpnconfighash['ca'] = ca_cert
|
56
|
+
ovpnconfighash['tls-auth'] = tls_auth
|
57
|
+
|
43
58
|
vpnOnDemandRules = Array.new
|
44
59
|
vodTrusted = { # Trust only Wifi SSID
|
45
60
|
'SSIDMatch' => trusted_ssids,
|
@@ -93,21 +108,7 @@ module Ovpnmcgen
|
|
93
108
|
},
|
94
109
|
'VPNSubType' => 'net.openvpn.OpenVPN-Connect.vpnplugin',
|
95
110
|
'VPNType' => 'VPN',
|
96
|
-
'VendorConfig' =>
|
97
|
-
'ca' => ca_cert,
|
98
|
-
'client' => 'NOARGS',
|
99
|
-
'comp-lzo' => 'NOARGS',
|
100
|
-
'dev' => 'tun',
|
101
|
-
'key-direction' => '1',
|
102
|
-
'persist-key' => 'NOARGS',
|
103
|
-
'persist-tun' => 'NOARGS',
|
104
|
-
'proto' => 'udp',
|
105
|
-
'remote' => "#{host} #{port} udp",
|
106
|
-
'remote-cert-tls' => 'server',
|
107
|
-
'resolv-retry' => 'infinite',
|
108
|
-
'tls-auth' => tls_auth,
|
109
|
-
'verb' => '3'
|
110
|
-
}
|
111
|
+
'VendorConfig' => ovpnconfighash
|
111
112
|
}
|
112
113
|
|
113
114
|
plistPayloadContent = [vpn, cert] # to encrypt this array
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
module Ovpnmcgen
|
3
|
+
def getOVPNVendorConfigHash(ovpnfilepath)
|
4
|
+
ovpnfile = ""
|
5
|
+
begin
|
6
|
+
# get rid of comments in the file.
|
7
|
+
ovpnfile = File.readlines(ovpnfilepath).delete_if { |l| ; l.start_with?('#') or l.start_with?(';') or l.chomp.empty? }
|
8
|
+
|
9
|
+
# TODO: [Warning] Get rid of/handle <ca>...</ca>, <cert>...</cert>, <key>...</key>, <tls-auth>...</tls-auth> inline cert/key enclosures.
|
10
|
+
# Bail when inline cert/key enclosures are detected.
|
11
|
+
ovpnfile.each do |l|
|
12
|
+
r = l.chomp.match(/<.*>/)
|
13
|
+
raise ArgumentError.new "OpenVPN client config file contains inline data enclosures: #{r.to_a.join(', ')}!\nSuch files are not yet supported. Remove them and try again" unless r.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO: Handle multiple remote lines.
|
17
|
+
# Currently, the last remote line will be used.
|
18
|
+
|
19
|
+
# map to key => value pairs for plist purposes. Singular verbs will be: 'verb' => 'NOARGS'.
|
20
|
+
ovpnhash = Hash[ovpnfile.map do |l|
|
21
|
+
a = l.split
|
22
|
+
if a.length == 1
|
23
|
+
a << "NOARGS"
|
24
|
+
elsif a.length > 2
|
25
|
+
b = a.take(1)
|
26
|
+
c = a.drop(1).join ' '
|
27
|
+
a.replace(b << c)
|
28
|
+
end
|
29
|
+
a
|
30
|
+
end]
|
31
|
+
|
32
|
+
# delete obviously unsupported keys.
|
33
|
+
ovpnhash.delete_if do |key, value|
|
34
|
+
case key
|
35
|
+
when 'fragment', 'mssfix', 'secret', 'socks-proxy', 'persist-key', 'persist-tun', 'resolv-retry', 'nobind', 'verb', 'user', 'group', 'pull', 'mute'
|
36
|
+
true
|
37
|
+
when 'remote', 'ca', 'pkcs12', 'tls-auth', 'cert', 'key', 'proto' # specified with switches.
|
38
|
+
true
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
rescue Errno::ENOENT
|
44
|
+
puts "OpenVPN config file not found: #{ovpnfilepath}!"
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
return ovpnhash
|
48
|
+
end
|
49
|
+
|
50
|
+
module_function :getOVPNVendorConfigHash
|
51
|
+
end
|
data/lib/ovpnmcgen/version.rb
CHANGED
data/ovpnmcgen.rb.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Ronald Ip"]
|
10
10
|
spec.email = ["myself@iphoting.com"]
|
11
11
|
spec.summary = Ovpnmcgen::SUMMARY
|
12
|
-
spec.description = "
|
12
|
+
spec.description = "Generates iOS configuration profiles (.mobileconfig) that configures OpenVPN for use with VPN-on-Demand that are not accessible through the Apple Configurator or the iPhone Configuration Utility."
|
13
13
|
spec.homepage = ""
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ovpnmcgen.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ronald Ip
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,7 +66,9 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '4.1'
|
69
|
-
description:
|
69
|
+
description: Generates iOS configuration profiles (.mobileconfig) that configures
|
70
|
+
OpenVPN for use with VPN-on-Demand that are not accessible through the Apple Configurator
|
71
|
+
or the iPhone Configuration Utility.
|
70
72
|
email:
|
71
73
|
- myself@iphoting.com
|
72
74
|
executables:
|
@@ -75,14 +77,14 @@ extensions: []
|
|
75
77
|
extra_rdoc_files: []
|
76
78
|
files:
|
77
79
|
- ".gitignore"
|
78
|
-
-
|
79
|
-
- ".ruby-version"
|
80
|
+
- ChangeLog
|
80
81
|
- Gemfile
|
81
82
|
- LICENSE.txt
|
82
83
|
- README.md
|
83
84
|
- Rakefile
|
84
85
|
- bin/ovpnmcgen.rb
|
85
86
|
- lib/ovpnmcgen.rb
|
87
|
+
- lib/ovpnmcgen/ovpnconfig.rb
|
86
88
|
- lib/ovpnmcgen/version.rb
|
87
89
|
- ovpnmcgen.rb.gemspec
|
88
90
|
homepage: ''
|
@@ -108,5 +110,5 @@ rubyforge_project:
|
|
108
110
|
rubygems_version: 2.2.2
|
109
111
|
signing_key:
|
110
112
|
specification_version: 4
|
111
|
-
summary: An OpenVPN iOS Configuration Profile Utility
|
113
|
+
summary: An OpenVPN iOS Configuration Profile (.mobileconfig) Utility
|
112
114
|
test_files: []
|
data/.ruby-gemset
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ovpnmcgen
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ruby-2.1.1
|