vpn_routing_mac 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e9ecb73a4d58f0057830bf9e6f67249908bd9d7f3651f562304b84c65a5782e1
4
+ data.tar.gz: 21cbf564773aa16289eeea22ceaf772748d47f3f3848fef2497c1e353398ba27
5
+ SHA512:
6
+ metadata.gz: c99b84e0e3764f87a34dcbcdc1fffdf50956d07893b29bbb13dbb980b9688439cb651904dc7aa52e9d3087e9c6d2dbb7bc300f2df90818bae0aec46c0ad2fe23
7
+ data.tar.gz: fd5ff97f2d0ddd639e08657e525d91ca8b738bdbade9c833bf3393b881d343d2f108ed5b1424aa5f09cc2a2e9fb1601d995f6116857c4dab9822c0065803140a
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /vendor/bundle
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ system
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.1
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in vpn_routing_mac.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vpn_routing_mac (0.1.0)
5
+ thor (~> 1.1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.5.0)
11
+ rake (12.3.3)
12
+ rspec (3.10.0)
13
+ rspec-core (~> 3.10.0)
14
+ rspec-expectations (~> 3.10.0)
15
+ rspec-mocks (~> 3.10.0)
16
+ rspec-core (3.10.1)
17
+ rspec-support (~> 3.10.0)
18
+ rspec-expectations (3.10.1)
19
+ diff-lcs (>= 1.2.0, < 2.0)
20
+ rspec-support (~> 3.10.0)
21
+ rspec-mocks (3.10.2)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.10.0)
24
+ rspec-support (3.10.3)
25
+ thor (1.1.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+ universal-darwin-19
30
+
31
+ DEPENDENCIES
32
+ rake (~> 12.0)
33
+ rspec (~> 3.0)
34
+ vpn_routing_mac!
35
+
36
+ BUNDLED WITH
37
+ 2.3.3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Yuji Kuroko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # VpnRoutingMac
2
+
3
+ ## License
4
+
5
+ MIT
6
+
7
+ ## Requirement
8
+
9
+ macOS catalina or later
10
+
11
+ ## Description
12
+
13
+ VpnRoutingMac is vpn routing tool for macOS.
14
+ When using a VPN, we will connect via the VPN all packet.
15
+ VpnRoutingMac can routing part of endpoint using /etc/ppp/ip-up.
16
+
17
+ VpnRoutingMacはmacOS向けのVPNルーティングツールです。
18
+ 通常、VPNを繋ぐとすべてのパケットがVPNを通過するようになります。
19
+ VpnRoutingMacを使うと、/etc/ppp/ip-upの機能を利用して一部の通信のみVPNを通すことができます。
20
+ 必要な通信のみVPNを通し、Google MeetやZoomはVPNを介さないようにすることで、
21
+ 快適なネット環境およびVPNへの負荷軽減を行うことができます。
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ sudo /usr/bin/gem install bundler -v 2.3.3
27
+ sudo /usr/bin/gem install vpn_routing_mac
28
+ sudo vpn-routing install
29
+ ```
30
+
31
+ ## Uninstall
32
+
33
+ ```bash
34
+ sudo vpn-routing uninstall
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### new VPN config
40
+
41
+ 1. you connect VPN.
42
+ 2. see `sudo cat ~/.vpn-routing/recent.log` in the IP address.
43
+ 3. `sudo vpn-routing create-config --dir #{CONFIG_NAME} --gateway-ip=#{IP_ADDRESS}
44
+ verbose option is show executed command.
45
+ ### routing config
46
+
47
+ ```
48
+ # If you have only one VPN config, you can omit the dir option.
49
+ # verbose option is show executed command.
50
+
51
+ # add routing ip with save the config.
52
+ sudo vpn-routing add-ip 192.168.1.1/32 --permanent --dir=#{CONFIG_NAME} --verbose
53
+
54
+ # delete routing ip. (without save the config)
55
+ sudo vpn-routing delete-ip 192.168.1.1/32 --dir=#{CONFIG_NAME} --verbose
56
+
57
+ # add routing domain with save the config.
58
+ sudo vpn-routing add-domain example.test --permanent --dir=#{CONFIG_NAME} --verbose
59
+
60
+ # delete routing ip. (without save the config)
61
+ sudo vpn-routing delete-domain example.test --dir=#{CONFIG_NAME} --verbose
62
+
63
+ # open config directory using Finder
64
+ vpn-routing edit
65
+
66
+ # reload config. (Isn't delete routing)
67
+ vpn-routing reload
68
+ ```
69
+
70
+ ### config directory
71
+
72
+ ```
73
+ .vpn-routing/
74
+ ├── config
75
+ │ └── CONFIG_DIR_NAME
76
+ │ ├── config.yml
77
+ │ ├── domains
78
+ │ │ └── cli.txt
79
+ │ └── ip_addresses
80
+ │ └── cli.txt
81
+ └── recent.log
82
+ ```
83
+
84
+ ## Contributing
85
+
86
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Yuji-Kuroko/vpn_routing_mac.
87
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "vpn_routing_mac"
5
+ require "vpn_routing_mac/application"
6
+
7
+ VpnRoutingMac::Application.setup
8
+
9
+ # You can add fixtures and/or initialization code here to make experimenting
10
+ # with your gem easier. You can also use a different console, if you like.
11
+
12
+ # (If you use this, don't forget to add pry to your Gemfile!)
13
+ # require "pry"
14
+ # Pry.start
15
+
16
+ require "irb"
17
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ # gem install bundler -v 2.3.3
7
+ bundle _2.3.3_ install
8
+
9
+ # Do any other automated setup that you need to do here
data/config/ip-up ADDED
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ #
3
+ # @see http://www.ytsuboi.org/wp/archives/2178
4
+ #
5
+ # $1 interface-name
6
+ # $2 tty-device
7
+ # $3 speed
8
+ # $4 local-IP-address
9
+ # $5 remote-IP-address
10
+ # $6 ipparam
11
+
12
+ cd $(dirname $(realpath $0))/..
13
+
14
+ exe/vpn-routing ip-up\
15
+ --interface-name="$1"\
16
+ --tty-device="$2"\
17
+ --speed="$3"\
18
+ --local-ip="$4"\
19
+ --remote-ip="$5"\
20
+ --ipparam="$6" >/tmp/ppp.log 2>&1\
21
+ --verbose
data/exe/vpn-routing ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/vpn_routing_mac/application"
4
+ VpnRoutingMac::Application.setup
5
+ require "thor"
6
+
7
+ class VpnRoutingCLI < Thor
8
+ class RequireSudoError < StandardError; end
9
+ class DoNotRequireSudoError < StandardError; end
10
+
11
+ desc "ip-up", "called by ip-up"
12
+ option :interface_name, required: true
13
+ option :remote_ip, required: true
14
+ option :tty_device
15
+ option :speed
16
+ option :local_ip
17
+ option :ipparam
18
+ option :verbose, type: :boolean, default: false
19
+ def ip_up
20
+ require_sudo!
21
+ dup_options = options.dup
22
+ CommandExecutor.instance.verbose = dup_options.delete("verbose")
23
+ VpnRoutingMac::Application.cmd_ip_up(**dup_options.transform_keys(&:to_sym))
24
+ end
25
+
26
+ desc "reload", "reload configs"
27
+ option :verbose, type: :boolean, default: false
28
+ def reload
29
+ require_sudo!
30
+ dup_options = options.dup
31
+ CommandExecutor.instance.verbose = dup_options.delete("verbose")
32
+ VpnRoutingMac::Application.cmd_reload
33
+ end
34
+
35
+ desc "add_domain", "add domain of routing"
36
+ option :permanent, type: :boolean, default: false
37
+ option :comment, type: :string, default: ""
38
+ option :dir, type: :string, default: nil
39
+ option :verbose, type: :boolean, default: false
40
+ def add_domain(domain)
41
+ require_sudo!
42
+ dup_options = options.dup
43
+ CommandExecutor.instance.verbose = dup_options.delete("verbose")
44
+ VpnRoutingMac::Application.cmd_add_domain(domain, **dup_options.transform_keys(&:to_sym))
45
+ end
46
+
47
+ desc "delete_domain", "delete domain of routing (temporary)"
48
+ option :dir, type: :string, default: nil
49
+ option :verbose, type: :boolean, default: false
50
+ def delete_domain(domain)
51
+ require_sudo!
52
+ dup_options = options.dup
53
+ CommandExecutor.instance.verbose = dup_options.delete("verbose")
54
+ VpnRoutingMac::Application.cmd_delete_domain(domain, **dup_options.transform_keys(&:to_sym))
55
+ end
56
+
57
+ desc "add_ip", "add ip of routing"
58
+ option :permanent, type: :boolean, default: false
59
+ option :comment, type: :string, default: ""
60
+ option :dir, type: :string, default: nil
61
+ option :verbose, type: :boolean, default: false
62
+ def add_ip(ip)
63
+ require_sudo!
64
+ dup_options = options.dup
65
+ CommandExecutor.instance.verbose = dup_options.delete("verbose")
66
+ VpnRoutingMac::Application.cmd_add_ip(ip, **dup_options.transform_keys(&:to_sym))
67
+ end
68
+
69
+ desc "delete_ip", "delete ip of routing (temporary)"
70
+ option :dir, type: :string, default: nil
71
+ option :verbose, type: :boolean, default: false
72
+ def delete_ip(domain)
73
+ require_sudo!
74
+ dup_options = options.dup
75
+ CommandExecutor.instance.verbose = dup_options.delete("verbose")
76
+ VpnRoutingMac::Application.cmd_delete_ip(domain, **dup_options.transform_keys(&:to_sym))
77
+ end
78
+
79
+ desc "edit", "open config directory in Finder"
80
+ def edit
81
+ do_not_require_sudo!
82
+ `open -a "Finder" "#{VpnRoutingMac::Config.config_dir}"`
83
+ end
84
+
85
+ desc "install", "setup /etc/ppp/ip-up"
86
+ def install
87
+ require_sudo!
88
+ VpnRoutingMac::Application.cmd_install
89
+ end
90
+
91
+ desc "uninstall", "delete /etc/ppp/ip-up"
92
+ def uninstall
93
+ require_sudo!
94
+ VpnRoutingMac::Application.cmd_uninstall
95
+ end
96
+
97
+ desc "create_config", "create new vpn config"
98
+ option :dir, type: :string, required: true
99
+ option :gateway_ip, type: :string, required: true
100
+ def create_config
101
+ do_not_require_sudo!
102
+ VpnRoutingMac::Application.cmd_create_config(**options.transform_keys(&:to_sym))
103
+ end
104
+
105
+ no_tasks do
106
+ def require_sudo!
107
+ raise RequireSudoError.new("Error: require sudo") if `/usr/bin/whoami`.strip != "root"
108
+ end
109
+
110
+ def do_not_require_sudo!
111
+ raise DoNotRequireSudoError.new("Error: Do not require sudo") if `/usr/bin/whoami`.strip == "root"
112
+ end
113
+ end
114
+ end
115
+
116
+ VpnRoutingCLI.start(ARGV)
@@ -0,0 +1,42 @@
1
+ module VpnRoutingMac
2
+ class Installer
3
+ # required: sudo
4
+ def install
5
+ if ip_up_path.exist?
6
+ backup_ip_up! if ip_up_path.exist?
7
+ ip_up_path.delete
8
+ end
9
+
10
+ FileUtils.ln_s(project_ip_up_path, ip_up_path)
11
+
12
+ VpnRoutingMac::Config.etc_config_dir.unlink if VpnRoutingMac::Config.etc_config_dir.exist?
13
+ FileUtils.ln_s(VpnRoutingMac::Config.home_config_dir, VpnRoutingMac::Config.etc_config_dir)
14
+ end
15
+
16
+ # required: sudo
17
+ def uninstall
18
+ if ip_up_path.exist?
19
+ backup_ip_up!
20
+ ip_up_path.delete
21
+ end
22
+ end
23
+
24
+ def project_ip_up_path
25
+ VpnRoutingMac::Application.project_root.join("config/ip-up")
26
+ end
27
+
28
+ def ip_up_dir_path
29
+ Pathname.new("/etc/ppp")
30
+ end
31
+
32
+ def ip_up_path
33
+ ip_up_dir_path.join("ip-up")
34
+ end
35
+
36
+ def backup_ip_up!
37
+ backup_dir_path = ip_up_dir_path.join(Time.now.strftime("backup.%Y%m%d%H%M%S"))
38
+ backup_dir_path.mkdir
39
+ FileUtils.cp(ip_up_path, backup_dir_path)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,119 @@
1
+ module VpnRoutingMac
2
+ class Application
3
+ class DefaultGatewayNotFound; end
4
+
5
+ class << self
6
+ # load
7
+ def setup
8
+ require "bundler/setup"
9
+ require "yaml"
10
+ project_root.glob("lib/**/*.rb").each do |path|
11
+ require path
12
+ end
13
+ end
14
+
15
+ def project_root
16
+ Pathname.new("#{__dir__}/../..")
17
+ end
18
+
19
+ def set_default_gateway!
20
+ cmd_active_interface_name = <<~CMD
21
+ /sbin/ifconfig | /usr/bin/grep -o '^en[0-9]*' | /usr/bin/xargs -n1 -I{} /bin/zsh -c "/sbin/ifconfig {} | /usr/bin/grep 'inet ' > /dev/null && echo {}"
22
+ CMD
23
+ active_interface_name = CommandExecutor.instance.execute!(cmd_active_interface_name, exception: false).strip
24
+ raise DefaultGatewayNotFound if active_interface_name == ""
25
+
26
+ cmd = "/sbin/route change default -interface #{active_interface_name}"
27
+ CommandExecutor.instance.execute!(cmd)
28
+ end
29
+
30
+ def recent_vpn_log_path
31
+ VpnRoutingMac::Config.etc_config_dir.join("recent.log")
32
+ end
33
+
34
+ def cmd_ip_up(remote_ip:, interface_name:, local_ip:, tty_device:, speed:, ipparam:)
35
+ # logging vpn info
36
+ recent_vpn_log_path.open("a") do |f|
37
+ f.puts("#{Time.now}:#{interface_name}:#{remote_ip}")
38
+ end
39
+
40
+ config = VpnRoutingMac::Config.load_with_ip(remote_ip)
41
+ config.interface = interface_name
42
+ config.route_all!
43
+
44
+ set_default_gateway!
45
+ end
46
+
47
+ def cmd_reload
48
+ VpnRoutingMac::Config.active_configs.each do |config|
49
+ config.route_all!
50
+ end
51
+ end
52
+
53
+ def cmd_add_domain(domain, permanent:, comment:, dir: nil)
54
+ config = config_with_dir(dir)
55
+ ip_addresses = VpnRoutingMac::Config.search_ip_with_domain(domain)
56
+ ip_addresses.each do |ip|
57
+ config.route!(ip)
58
+ puts "added: #{ip}"
59
+ end
60
+
61
+ if permanent
62
+ config.save_domain!(domain, comment)
63
+ end
64
+ end
65
+
66
+ def cmd_delete_domain(domain, dir: nil)
67
+ config = config_with_dir(dir)
68
+ ip_addresses = VpnRoutingMac::Config.search_ip_with_domain(domain)
69
+ ip_addresses.each do |ip|
70
+ config.delete_route!(ip)
71
+ puts "deleted: #{ip}"
72
+ end
73
+ end
74
+
75
+ def cmd_add_ip(ip, permanent:, comment:, dir: nil)
76
+ config = config_with_dir(dir)
77
+ config.route!(ip)
78
+ puts "added: #{ip}"
79
+
80
+ if permanent
81
+ config.save_ip_address!(ip, comment)
82
+ end
83
+ end
84
+
85
+ def cmd_delete_ip(ip, dir: nil)
86
+ config = config_with_dir(dir)
87
+ config.delete_route!(ip)
88
+ puts "deleted: #{ip}"
89
+ end
90
+
91
+ def config_with_dir(dir)
92
+ config = if dir
93
+ VpnRoutingMac::Config.find_with_directory_name(dir)
94
+ else
95
+ all_configs = VpnRoutingMac::Config.all_configs
96
+ raise "required: --dir option" if all_configs.count >= 2
97
+
98
+ # 1 directory only
99
+ all_configs.first
100
+ end
101
+ end
102
+
103
+ def cmd_create_config(dir:, gateway_ip:)
104
+ new_dir_path = VpnRoutingMac::Config.create_config_directory(dir: dir, gateway_ip: gateway_ip)
105
+ puts "created: #{new_dir_path.to_s}"
106
+ end
107
+
108
+ # setup /etc/ppp/ip-up
109
+ def cmd_install
110
+ VpnRoutingMac::Installer.new.install
111
+ end
112
+
113
+ # delete /etc/ppp/ip-up
114
+ def cmd_uninstall
115
+ VpnRoutingMac::Installer.new.uninstall
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,26 @@
1
+ require "singleton"
2
+
3
+ class CommandExecutor
4
+ include Singleton
5
+ attr_accessor :verbose
6
+
7
+ class CommandFailed < StandardError; end
8
+
9
+ def instance
10
+ @verbose = false
11
+ end
12
+
13
+ # execute command
14
+ #
15
+ # @param [String] command execute command
16
+ # @param [Boolean] verbose log for the command
17
+ # @param [Boolean] exception raise exception if the command failed
18
+ def execute!(command, verbose: @verbose, exception: true)
19
+ puts "cmd: #{command}" if verbose
20
+ ret, err, status = Open3.capture3(command)
21
+
22
+ raise CommandFailed.new(err) if exception && !status.success?
23
+
24
+ ret
25
+ end
26
+ end
@@ -0,0 +1,191 @@
1
+ require "open3"
2
+
3
+ module VpnRoutingMac
4
+ class Config
5
+ class InterfaceNotFoundError < StandardError; end
6
+ class DirectoryNameNotFoundError < StandardError; end
7
+
8
+ attr_reader :gateway_ip
9
+ attr_reader :dir_path
10
+ attr_accessor :interface
11
+
12
+ # @return [VpnRoutingMac::Config, nil]
13
+ def self.load_with_ip(ip_address)
14
+ all_configs.find { |a| a.gateway_ip == ip_address }
15
+ end
16
+
17
+ # @return [VpnRoutingMac::Config]
18
+ def self.find_with_directory_name(dirname)
19
+ config = all_configs.find { |a| a.directory_name == dirname }
20
+ raise DirectoryNameNotFoundError.new(dirname) if config.nil?
21
+
22
+ config
23
+ end
24
+
25
+
26
+ # configs in active connection
27
+ # @return [Array<VpnRoutingMac::Config>]
28
+ def self.active_configs
29
+ all_configs.select(&:active_connection?)
30
+ end
31
+
32
+ # @return [Array<VpnRoutingMac::Config>]
33
+ def self.all_configs
34
+ config_files = config_dir.glob("config/*/config.yml")
35
+
36
+ return [] if config_files.count == 0
37
+
38
+ config_files.map { |config_file|
39
+ params = YAML.load_file(config_file)
40
+ self.new(params, dir_path: config_file.dirname)
41
+ }
42
+ end
43
+
44
+ def self.config_dir
45
+ if ENV.include?("HOME")
46
+ home_config_dir
47
+ else
48
+ etc_config_dir
49
+ end
50
+ end
51
+
52
+ def self.home_config_dir
53
+ Pathname.new("#{ENV.fetch("HOME")}/.vpn-routing")
54
+ end
55
+
56
+ def self.etc_config_dir
57
+ Pathname.new("/etc/ppp/config")
58
+ end
59
+
60
+ # @return [Pathname] created dir path
61
+ def self.create_config_directory(dir:, gateway_ip:)
62
+ new_config_dir = home_config_dir.join("config/#{dir}")
63
+ new_config_dir.mkpath
64
+ new_config_dir.join("config.yml").write({
65
+ gateway_ip: gateway_ip
66
+ })
67
+ new_config_dir.join("ip_addresses").mkdir
68
+ new_config_dir.join("domains").mkdir
69
+
70
+ new_config_dir
71
+ end
72
+
73
+ # @return [Array<String>]
74
+ def self.search_ip_with_domain(domain)
75
+ CommandExecutor.instance.execute!("/usr/bin/dig +short #{domain}").lines.map(&:strip).select { |a|
76
+ /\A\d+\.\d+\.\d+\.\d+\z/.match?(a)
77
+ }.map { |ip| "#{ip}/32" }
78
+ end
79
+
80
+ # ---
81
+
82
+ def initialize(params, dir_path: nil, interface: nil)
83
+ @gateway_ip = params["gateway_ip"]
84
+ @interface = interface
85
+ @dir_path = dir_path
86
+ end
87
+
88
+ def directory_name
89
+ @dir_path.basename.to_s
90
+ end
91
+
92
+ # @return [Array<String>] ["example.test"]
93
+ def domains
94
+ file_paths = dir_path.glob("domains/*")
95
+ return [] if file_paths.count == 0
96
+
97
+ # e.g.
98
+ # example.test # The example domain
99
+ file_paths.map { |f| f.read.lines.map { |a| a.strip.split("#").first } }.flatten
100
+ end
101
+
102
+ # @return [Array<String>] ["192.168.1.1/32"]
103
+ def ip_addresses
104
+ file_paths = dir_path.glob("ip_addresses/*")
105
+ return [] if file_paths.count == 0
106
+
107
+ # e.g.
108
+ # 192.168.1.1/32 # local ip
109
+ file_paths.map { |f| f.read.lines.map { |a| a.strip.split("#").first } }.flatten
110
+ end
111
+
112
+ # #domains + #ip_addresses
113
+ #
114
+ # @return [Array<String>] ["192.168.1.1/32"]
115
+ def all_ip_addresses
116
+ (domains.map { |domain|
117
+ self.class.search_ip_with_domain(domain)
118
+ }.flatten + ip_addresses).uniq
119
+ end
120
+
121
+ # set routing
122
+ # require: MacOS catalina or later.
123
+ #
124
+ # @param [String] ip_address "192.168.191.0/32"
125
+ def route!(ip_address, interface: nil)
126
+ interface ||= self.interface
127
+
128
+ raise InterfaceNotFoundError.new(interface) unless interface_exist?(interface)
129
+
130
+ CommandExecutor.instance.execute!("/sbin/route add -net #{ip_address} -interface #{interface}")
131
+ end
132
+
133
+ def route_all!
134
+ all_ip_addresses.map(&:to_s).map(&:strip).select { |a| %r;\A\d+\.\d+\.\d+\.\d+(/\d+)?\z;.match?(a) }.each do |ip_address|
135
+ route!(ip_address)
136
+ end
137
+ end
138
+
139
+ def delete_route!(ip_address, interface: nil)
140
+ interface ||= self.interface
141
+
142
+ raise InterfaceNotFoundError.new(interface) unless interface_exist?(interface)
143
+
144
+ CommandExecutor.instance.execute!("/sbin/route delete -net #{ip_address} -interface #{interface}")
145
+ end
146
+
147
+ def interface(gateway_ip = @gateway_ip)
148
+ @interface ||= fetch_interface(gateway_ip)
149
+ end
150
+
151
+ # @param [String] gateway_ip 192.168.1.1
152
+ def fetch_interface(gateway_ip)
153
+ all_interfaces.find { |a|
154
+ CommandExecutor.instance.execute!("/sbin/ifconfig #{a} | grep #{gateway_ip}") rescue false
155
+ }
156
+ end
157
+
158
+ def active_connection?(gateway_ip = @gateway_ip)
159
+ fetch_interface(gateway_ip)
160
+ end
161
+
162
+ def all_interfaces
163
+ @all_interfaces ||= CommandExecutor.instance.execute!("/sbin/ifconfig -l").strip.split(" ")
164
+ end
165
+
166
+ def interface_exist?(interface)
167
+ all_interfaces.include?(interface)
168
+ end
169
+
170
+ def save_ip_address!(ip_address, comment)
171
+ cli_config_path = @dir_path.join("ip_addresses/cli.txt")
172
+ cli_config_path.open("a") do |f|
173
+ f.puts "#{ip_address} # #{comment}"
174
+ end
175
+
176
+ user = ENV.fetch("USER")
177
+
178
+ CommandExecutor.instance.execute!("chown #{user} #{cli_config_path.to_s}")
179
+ end
180
+
181
+ def save_domain!(domain, comment)
182
+ cli_config_path = @dir_path.join("domains/cli.txt")
183
+ cli_config_path.open("a") do |f|
184
+ f.puts "#{domain} # #{comment}"
185
+ end
186
+
187
+ user = ENV.fetch("USER")
188
+ CommandExecutor.instance.execute!("chown #{user} #{cli_config_path.to_s}")
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,3 @@
1
+ module VpnRoutingMac
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ require "vpn_routing_mac/version"
2
+
3
+ module VpnRoutingMac
4
+ end
@@ -0,0 +1,28 @@
1
+ require_relative 'lib/vpn_routing_mac/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "vpn_routing_mac"
5
+ spec.version = VpnRoutingMac::VERSION
6
+ spec.authors = ["Yuji Kuroko"]
7
+ spec.email = ["patye.roifure+gem@gmail.com"]
8
+
9
+ spec.summary = %q{Mac VPN routing setting tool.}
10
+ spec.description = %q{Mac VPN routing setting tool.}
11
+ spec.homepage = "https://github.com/Yuji-Kuroko/vpn_routing_mac"
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
13
+
14
+ spec.metadata["homepage_uri"] = spec.homepage
15
+ spec.metadata["source_code_uri"] = "https://github.com/Yuji-Kuroko/vpn_routing_mac"
16
+ spec.metadata["changelog_uri"] = "https://github.com/Yuji-Kuroko/vpn_routing_mac"
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_dependency "thor", "~>1.1.0"
28
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vpn_routing_mac
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yuji Kuroko
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-12-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.1.0
27
+ description: Mac VPN routing setting tool.
28
+ email:
29
+ - patye.roifure+gem@gmail.com
30
+ executables:
31
+ - vpn-routing
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".gitignore"
36
+ - ".rspec"
37
+ - ".ruby-version"
38
+ - ".travis.yml"
39
+ - Gemfile
40
+ - Gemfile.lock
41
+ - LICENSE
42
+ - README.md
43
+ - Rakefile
44
+ - bin/console
45
+ - bin/setup
46
+ - config/ip-up
47
+ - exe/vpn-routing
48
+ - lib/vpn_routing_mac.rb
49
+ - lib/vpn_routing_mac/Installer.rb
50
+ - lib/vpn_routing_mac/application.rb
51
+ - lib/vpn_routing_mac/command_executor.rb
52
+ - lib/vpn_routing_mac/config.rb
53
+ - lib/vpn_routing_mac/version.rb
54
+ - vpn_routing_mac.gemspec
55
+ homepage: https://github.com/Yuji-Kuroko/vpn_routing_mac
56
+ licenses: []
57
+ metadata:
58
+ homepage_uri: https://github.com/Yuji-Kuroko/vpn_routing_mac
59
+ source_code_uri: https://github.com/Yuji-Kuroko/vpn_routing_mac
60
+ changelog_uri: https://github.com/Yuji-Kuroko/vpn_routing_mac
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 2.3.0
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubygems_version: 3.0.3
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Mac VPN routing setting tool.
80
+ test_files: []