spior 0.1.6 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,58 +1,61 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Spior
2
4
  module Iptables
5
+ # Make Local Redirection Through Tor.
3
6
  class Tor < Iptables::Root
4
7
  def initialize
5
8
  super
6
- @tor = Spior::Tor::Info.new
7
- @non_tor = ["#{@lo_addr}/8", "192.168.0.0/16", "172.16.0.0/12", "10.0.0.0/8"]
8
- @tables = ["nat", "filter"]
9
+ @non_tor = %W[#{@lo_addr}/8 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8]
10
+ @tables = %w[nat filter]
9
11
  end
10
12
 
11
13
  private
12
14
 
13
15
  def redirect
14
- @tables.each { |table|
15
- target = "ACCEPT"
16
- target = "RETURN" if table == "nat"
16
+ Msg.p 'Redirecting local traffic though Tor...'
17
+ @tables.map do |table|
18
+ target = 'ACCEPT'
19
+ target = 'RETURN' if table == 'nat'
17
20
 
18
21
  ipt "-t #{table} -F OUTPUT"
19
22
  ipt "-t #{table} -A OUTPUT -m state --state ESTABLISHED -j #{target}"
20
- ipt "-t #{table} -A OUTPUT -m owner --uid #{@tor.uid} -j #{target}"
23
+ ipt "-t #{table} -A OUTPUT -m owner --uid #{CONFIG.uid} -j #{target}"
21
24
 
22
- match_dns_port = @tor.dns
23
- if table == "nat"
24
- target = "REDIRECT --to-ports #{@tor.dns}"
25
- match_dns_port = "53"
25
+ match_dns_port = CONFIG.dns_port
26
+ if table == 'nat'
27
+ target = "REDIRECT --to-ports #{CONFIG.dns_port}"
28
+ match_dns_port = '53'
26
29
  end
27
30
 
28
31
  ipt "-t #{table} -A OUTPUT -p udp --dport #{match_dns_port} -j #{target}"
29
32
  ipt "-t #{table} -A OUTPUT -p tcp --dport #{match_dns_port} -j #{target}"
30
33
 
31
- target = "REDIRECT --to-ports #{@tor.trans_port}" if table == "nat"
32
- ipt "-t #{table} -A OUTPUT -d #{@tor.virt_addr} -p tcp -j #{target}"
34
+ target = "REDIRECT --to-ports #{CONFIG.trans_port}" if table == 'nat'
35
+ ipt "-t #{table} -A OUTPUT -d #{CONFIG.virt_addr} -p tcp -j #{target}"
33
36
 
34
- target = "RETURN" if table == "nat"
37
+ target = 'RETURN' if table == 'nat'
35
38
  @non_tor.each { |ip|
36
39
  ipt "-t #{table} -A OUTPUT -d #{ip} -j #{target}"
37
40
  }
38
41
 
39
- target = "REDIRECT --to-ports #{@tor.trans_port}" if table == "nat"
42
+ target = "REDIRECT --to-ports #{CONFIG.trans_port}" if table == 'nat'
40
43
  ipt "-t #{table} -A OUTPUT -p tcp -j #{target}"
41
- }
44
+ end
42
45
  end
43
46
 
44
47
  def input
45
48
  # SSH
46
- ipt "-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT"
49
+ ipt '-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT'
47
50
  # Allow loopback
48
51
  ipt "-A INPUT -i #{@lo} -j ACCEPT"
49
52
  # Accept related
50
- ipt "-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT"
53
+ ipt '-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT'
51
54
  end
52
55
 
53
56
  def all
54
- ipt "-t filter -A OUTPUT -p udp -j REJECT"
55
- ipt "-t filter -A OUTPUT -p icmp -j REJECT"
57
+ ipt '-t filter -A OUTPUT -p udp -j REJECT'
58
+ ipt '-t filter -A OUTPUT -p icmp -j REJECT'
56
59
  end
57
60
  end
58
61
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Spior
2
4
  module Iptables
3
5
  end
@@ -6,3 +8,4 @@ end
6
8
  require_relative 'iptables/root'
7
9
  require_relative 'iptables/tor'
8
10
  require_relative 'iptables/default'
11
+ require_relative 'iptables/rules'
data/lib/spior/menu.rb CHANGED
@@ -1,43 +1,36 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Spior
2
4
  module Menu
3
- extend self
4
-
5
- def run
6
- banner
5
+ def self.run
7
6
  loop do
8
7
  Msg.head
9
- puts %q{Please select an option:
8
+ puts 'Please select an option:
10
9
 
11
- 1. Redirect traffic through tor
12
- 2. Reload tor and change your ip
13
- 3. Clear and restore your files
14
- 4. Check info on your current ip
15
- 5. Quit}
10
+ 1. Redirect traffic through Tor
11
+ 2. Reload Spior and change your IP
12
+ 3. Stop Tor and use a clearnet navigation
13
+ 4. Check info on your current IP
14
+ 5. Install all the dependencies
15
+ 6. Quit'
16
16
 
17
17
  puts
18
- print ">> "
18
+ print '>> '
19
19
  case gets.chomp
20
20
  when '1'
21
- Spior::Iptables::Tor.new.run!
21
+ Spior::Service.start
22
22
  when '2'
23
- Spior::Serice.restart
23
+ Spior::Service.restart
24
24
  when '3'
25
- Spior::Clear.all
25
+ Spior::Service.stop
26
26
  when '4'
27
27
  Spior::Status.info
28
28
  when '5'
29
+ Spior::Dep.looking
30
+ else
29
31
  exit
30
32
  end
31
33
  end
32
34
  end
33
-
34
- private
35
-
36
- def banner
37
- puts "┏━┓┏━┓╻┏━┓┏━┓"
38
- puts "┗━┓┣━┛┃┃ ┃┣┳┛"
39
- puts "┗━┛╹ ╹┗━┛╹┗╸"
40
- # generated with toilet -F crop -f future spior
41
- end
42
35
  end
43
36
  end
data/lib/spior/msg.rb CHANGED
@@ -1,28 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rainbow'
2
4
 
3
5
  module Msg
4
- extend self
6
+ module_function
7
+
8
+ def banner
9
+ puts
10
+ puts '┏━┓┏━┓╻┏━┓┏━┓'
11
+ puts '┗━┓┣━┛┃┃ ┃┣┳┛'
12
+ puts '┗━┛╹ ╹┗━┛╹┗╸'
13
+ puts
14
+ # generated with toilet -F crop -f future spior
15
+ end
5
16
 
6
17
  def head
7
- puts Rainbow("------------------------------------------------").cyan
18
+ puts Rainbow('------------------------------------------------').cyan
8
19
  end
9
20
 
10
21
  def p(text)
11
- puts Rainbow("[").cyan + Rainbow("+").white + Rainbow("]").cyan + " " + text
22
+ puts Rainbow('[').cyan + Rainbow('+').white + Rainbow(']').cyan + ' ' + text
12
23
  end
13
24
 
14
25
  def err(text)
15
- puts Rainbow("[").red + Rainbow("-").white + Rainbow("]").red + " " + text
26
+ puts Rainbow('[').red + Rainbow('-').white + Rainbow(']').red + ' ' + text
16
27
  end
17
28
 
18
29
  def info(text)
19
- puts Rainbow("-").blue + Rainbow("-").white + Rainbow("-").blue + " " + text + " " + Rainbow("-").blue + Rainbow("-").white + Rainbow("-").blue
30
+ print Rainbow('-').blue + Rainbow('-').white + Rainbow('-').blue
31
+ print " #{text} "
32
+ print Rainbow('-').blue + Rainbow('-').white + Rainbow('-').blue + "\n"
20
33
  end
21
34
 
22
35
  def report(text)
23
- puts ""
36
+ puts
24
37
  info text
25
- puts "Please, report this issue at https://github.com/szorfein/spior/issues"
26
- puts ""
38
+ puts 'Please, report this issue at https://github.com/szorfein/spior/issues'
39
+ puts
40
+ exit 1
27
41
  end
28
42
  end
data/lib/spior/options.rb CHANGED
@@ -1,13 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
4
 
3
5
  module Spior
4
6
  class Options
5
- attr_reader :install , :tor , :persist
6
-
7
7
  def initialize(argv)
8
- @install = false
9
- @tor = false
10
- @persist = false
11
8
  parse(argv)
12
9
  end
13
10
 
@@ -15,46 +12,46 @@ module Spior
15
12
 
16
13
  def parse(argv)
17
14
  OptionParser.new do |opts|
18
- opts.on("-i", "--install", "Install the dependencies") do
19
- @install = true
15
+ opts.on('-i', '--install', 'Install the dependencies.') do
16
+ Spior::Dep.looking
20
17
  end
21
18
 
22
- opts.on("-t", "--tor", "Redirect traffic through TOR") do
23
- @tor = true
19
+ opts.on('-t', '--tor', 'Redirect traffic through TOR.') do
20
+ Spior::Service.start
24
21
  end
25
22
 
26
- opts.on("-r", "--reload", "Reload TOR to change your ip") do
23
+ opts.on('-r', '--reload', 'Reload TOR to change your IP.') do
27
24
  Spior::Service.restart
28
25
  exit
29
26
  end
30
27
 
31
- opts.on("-c", "--clearnet", "Reset iptables and return to clearnet navigation") do
32
- Spior::Clear.all
28
+ opts.on('-c', '--clearnet', 'Reset iptables and return to clearnet navigation.') do
29
+ Spior::Service.stop
33
30
  end
34
31
 
35
- opts.on("-s", "--status", "Look infos about your current ip") do
32
+ opts.on('-s', '--status', 'Look infos about your current IP.') do
36
33
  Spior::Status.info
37
34
  exit
38
35
  end
39
36
 
40
- opts.on("-p", "--persist", "Active Spior at every boot.") do
41
- @persist = true
37
+ opts.on('-p', '--persist', 'Active Spior at every boot.') do
38
+ Spior::Service.enable
42
39
  end
43
40
 
44
- opts.on("-m", "--menu", "Display an interactive menu") do
41
+ opts.on('-m', '--menu', 'Display an interactive menu.') do
45
42
  Spior::Menu.run
46
43
  end
47
44
 
48
- opts.on("-h", "--help", "Show this message") do
45
+ opts.on('-h', '--help', 'Show this message.') do
49
46
  puts opts
50
47
  exit
51
48
  end
52
49
 
53
50
  begin
54
- argv = ["-m"] if argv.empty?
51
+ argv = ['-m'] if argv.empty?
55
52
  opts.parse!(argv)
56
53
  rescue OptionParser::ParseError => e
57
- STDERR.puts e.message, "\n", opts
54
+ warn e.message, "\n", opts
58
55
  exit(-1)
59
56
  end
60
57
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nomansland'
4
+
5
+ module Spior
6
+ module Service
7
+ extend self
8
+
9
+ # enable the Tor redirection when you boot your system
10
+ #
11
+ # It should use and enable the services:
12
+ # + tor
13
+ # + iptables
14
+ def enable
15
+ case Nomansland.distro?
16
+ when :gentoo
17
+ for_gentoo
18
+ when :archlinux
19
+ Iptables::Rules.new.backup
20
+ Tor::Config.new(Tempfile.new('torrc')).backup
21
+ Helpers::Exec.new('systemctl').run('enable iptables tor')
22
+ Msg.p 'Services enabled for Archlinux...'
23
+ else
24
+ Msg.report 'Your distro is not yet supported.'
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def for_gentoo
31
+ case Nomansland.init?
32
+ when :systemd
33
+ systemd_start('iptables-store')
34
+ systemd_enable('iptables-restore')
35
+ systemd_enable('tor')
36
+ when :openrc
37
+ system('sudo /etc/init.d/iptables save')
38
+ rc_upd = Helpers::Exec.new('rc-update')
39
+ rc_upd.run('rc-update add iptables boot')
40
+ rc_upd.run('rc-update add tor')
41
+ rc_upd.run('rc-update add tor default')
42
+ else
43
+ Msg.report 'Init no yet supported for start Iptables at boot'
44
+ end
45
+ end
46
+
47
+ def systemd_enable(service)
48
+ systemctl = Helpers::Exec.new('systemctl')
49
+ Msg.p "Search for service #{service}..."
50
+ unless system("systemctl is-enabled #{service}")
51
+ systemctl.run("enable #{service}")
52
+ end
53
+ end
54
+
55
+ def systemd_start(service)
56
+ systemctl = Helpers::Exec.new('systemctl')
57
+ Msg.p "Search for service #{service}..."
58
+ unless system("systemctl is-active #{service}")
59
+ systemctl.run("start #{service}")
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,21 +1,13 @@
1
- require 'tty-which'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Spior
4
4
  module Service
5
5
  module_function
6
6
 
7
7
  def restart
8
- if TTY::Which.exist?('systemctl')
9
- Helpers::Exec.new("systemctl").run("restart tor")
10
- Msg.p "ip changed."
11
- elsif TTY::Which.exist? 'sv'
12
- Helpers::Exec.new('sv').run('restart tor')
13
- Msg.p 'ip changed.'
14
- elsif File.exist? '/etc/init.d/tor'
15
- Helpers::Exec.new('/etc/init.d/tor').run('restart')
16
- else
17
- Msg.report "Don't known yet how to restart Tor for your system."
18
- end
8
+ Service.stop
9
+ Service.start
10
+ Msg.p 'ip changed.'
19
11
  end
20
12
  end
21
13
  end
@@ -1,26 +1,14 @@
1
- require 'tty-which'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Spior
4
4
  module Service
5
5
  module_function
6
6
 
7
+ # Service.start should start Tor if not alrealy running
8
+ # And start to redirect the local traffic with Iptables
7
9
  def start
8
- if TTY::Which.exist?('systemctl')
9
- state = `systemctl is-active tor`.chomp
10
- unless state == 'active'
11
- Helpers::Exec.new("systemctl").run("start tor")
12
- Msg.p "TOR started."
13
- end
14
- elsif TTY::Which.exist? 'sv'
15
- unless File.exist? '/var/service/tor'
16
- Helpers::Exec.new('ln').run('-s /etc/sv/tor /var/service/tor')
17
- Msg.p "TOR started."
18
- end
19
- elsif File.exist? '/etc/init.d/tor'
20
- Helpers::Exec.new('/etc/init.d/tor').run('start')
21
- else
22
- Msg.report "Don't known yet how to start Tor for your system."
23
- end
10
+ Tor.start
11
+ Iptables::Tor.new.run!
24
12
  end
25
13
  end
26
14
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spior
4
+ module Service
5
+ module_function
6
+
7
+ def stop
8
+ Tor.stop
9
+ Iptables::Rules.new.restore
10
+ end
11
+ end
12
+ end
data/lib/spior/service.rb CHANGED
@@ -1,7 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Spior
4
+ # Service should start/stop/restart Tor and Iptable.
2
5
  module Service
3
6
  end
4
7
  end
5
8
 
6
9
  require_relative 'service/start'
10
+ require_relative 'service/stop'
7
11
  require_relative 'service/restart'
12
+ require_relative 'service/enable'
data/lib/spior/status.rb CHANGED
@@ -1,38 +1,46 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'open-uri'
2
4
  require 'json'
3
5
 
4
6
  module Spior
7
+ # Status display information on your current IP addresse
8
+ #
9
+ # If you use an IPV6 address, it should fail to display a Tor IP...
5
10
  module Status
11
+ # Check on https://check.torproject.org/api/ip if Tor is enable or not
12
+ # and display the result.
6
13
  def self.enable
7
- begin
8
- status = "Disable"
9
- api_check = "https://check.torproject.org/api/ip"
10
- URI.open(api_check) do |l|
11
- hash = JSON.parse l.read
12
- status = "Enable" if hash["IsTor"] == true
13
- end
14
- status
15
- rescue OpenURI::HTTPError => error
16
- res = error.io
17
- puts "Fail to join server #{res.status}"
14
+ status = 'Disable'
15
+ URI.open('https://check.torproject.org/api/ip') do |l|
16
+ hash = JSON.parse l.read
17
+ status = 'Enable' if hash['IsTor'] == true
18
18
  end
19
+ status
20
+ rescue OpenURI::HTTPError => error
21
+ res = error.io
22
+ puts "Fail to join server #{res.status}"
19
23
  end
20
24
 
25
+ # info check and display information from https://ipleak.net/json
26
+ #
27
+ # Check for:
28
+ # * +ip+
29
+ # * +continent_name+
30
+ # * +time_zone+
31
+ #
32
+ # We can add later info on City/Region or other things.
21
33
  def self.info
22
- begin
23
- api_check = "https://ipleak.net/json"
24
- URI.open(api_check) do |l|
25
- hash = JSON.parse l.read
26
- puts
27
- puts " Current ip ===> #{hash["ip"]}"
28
- puts " Continent ===> #{hash["continent_name"]}"
29
- puts " Timezone ===> #{hash["time_zone"]}"
30
- end
31
- puts " Status ===> #{enable}"
32
- rescue OpenURI::HTTPError => error
33
- res = error.io
34
- puts "Fail to join server #{res.status}"
34
+ URI.open('https://ipleak.net/json') do |l|
35
+ hash = JSON.parse l.read
36
+ puts " Current ip ===> #{hash['ip']}"
37
+ puts " Continent ===> #{hash['continent_name']}"
38
+ puts " Timezone ===> #{hash['time_zone']}"
35
39
  end
40
+ puts " Status ===> #{enable}"
41
+ rescue OpenURI::HTTPError => error
42
+ res = error.io
43
+ puts "Fail to join server #{res.status}"
36
44
  end
37
45
  end
38
46
  end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Spior
6
+ module Tor
7
+ # Generate a config file (torrc) for Spior
8
+ class Config
9
+ # ==== Attributes
10
+ #
11
+ # * +filename+ - A reference to a tempfile like filename=Tempfile.new('foo')
12
+ #
13
+ def initialize(filename)
14
+ @filename = filename
15
+ @content = ['# Generated by Spior, don\'t edit.', 'RunAsDaemon 1',
16
+ 'ClientOnly 1', 'SocksPort 0']
17
+ @content_torrc = []
18
+ end
19
+
20
+ # Generate a `torrc` compatible file for Spior
21
+ # Use value from Spior::CONFIG
22
+ def generate
23
+ generate_content(@content)
24
+ return if @content.length == 4
25
+
26
+ File.write @filename.path, @content.join("\n") + "\n"
27
+ Msg.p 'Generating Tor config...'
28
+ end
29
+
30
+ # Save current Tor options (Spior::CONFIG) in /etc/tor/torrc
31
+ # Only if theses options are not alrealy present
32
+ def backup
33
+ generate_content(@content_torrc)
34
+ outfile = File.open(@filename.path, 'w')
35
+ outfile.puts(File.read('/etc/tor/torrc'))
36
+ outfile.puts(@content_torrc.join("\n")) if @content_torrc != []
37
+ outfile.chmod(0644)
38
+ outfile.close
39
+
40
+ Msg.p 'Saving Tor options...'
41
+ move(@filename.path, '/etc/tor/torrc')
42
+ end
43
+
44
+ protected
45
+
46
+ def generate_content(content)
47
+ adding content, 'AutomapHostsOnResolve 1'
48
+ adding content, "DNSPort #{CONFIG.dns_port}"
49
+ adding content, "VirtualAddrNetworkIpv4 #{CONFIG.virt_addr}"
50
+ adding content, "TransPort #{CONFIG.trans_port} IsolateClientAddr
51
+ IsolateClientProtocol IsolateDestAddr IsolateDestPort"
52
+ end
53
+
54
+ private
55
+
56
+ def search(option_name)
57
+ File.open('/etc/tor/torrc') do |f|
58
+ f.each do |line|
59
+ return Regexp.last_match(1) if line.match(/#{option_name} ([a-z0-9]*)/i)
60
+ end
61
+ end
62
+ false
63
+ end
64
+
65
+ def adding(content, option)
66
+ o = option.split(' ')
67
+ all = o[1..o.length].join(' ')
68
+ unless search(o[0])
69
+ content << "#{o[0]} #{all}"
70
+ end
71
+ end
72
+
73
+ def digest_match?(src, dest)
74
+ md5_src = Digest::MD5.file src
75
+ md5_dest = Digest::MD5.file dest
76
+ md5_src == md5_dest
77
+ end
78
+
79
+ # Permission for Archlinux on a torrc are chmod 644, chown root:root
80
+ def fix_perm(file)
81
+ if Process::Sys.getuid == '0'
82
+ file.chown(0, 0)
83
+ else
84
+ Helpers::Exec.new('chown').run("root:root #{file}")
85
+ end
86
+ end
87
+
88
+ def move(src, dest)
89
+ return if digest_match? src, dest
90
+
91
+ fix_perm(@filename.path)
92
+ if Process::Sys.getuid == '0'
93
+ FileUtils.mv(src, dest)
94
+ else
95
+ Helpers::Exec.new('mv').run("#{src} #{dest}")
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nomansland'
4
+
5
+ module Spior
6
+ module Tor
7
+ ##
8
+ # Data
9
+ # Fill Spior::CONFIG with data found on `/etc/tor/torrc` or set default.
10
+ #
11
+ # ==== Attributes
12
+ #
13
+ # * +user+ - Username used by Tor on your distro, e.g 'tor' on Archlinux
14
+ # * +dns_port+ - Open this port to listen for UDP DNS requests, and resolve them anonymously
15
+ # * +uid+ - The uid value from the user attribute.
16
+ # * +trans_port+ - Port to open to listen for transparent proxy connections.
17
+ # * +virt_addr+ - Default use '10.192.0.0/10'.
18
+ #
19
+ class Data
20
+ attr_accessor :user, :dns_port, :trans_port, :virt_addr, :uid
21
+
22
+ def initialize
23
+ @user = search('User') || 'tor'
24
+ @dns_port = search('DNSPort') || '9061'
25
+ @trans_port = search('TransPort') || '9040'
26
+ @virt_addr = search('VirtualAddrNetworkIPv4') || '10.192.0.0/10'
27
+ @uid = search_uid || 0
28
+ end
29
+
30
+ private
31
+
32
+ # Search value of option_name in the /etc/tor/torrc
33
+ # Return false by default
34
+ def search(option_name)
35
+ File.open('/etc/tor/torrc') do |f|
36
+ f.each do |line|
37
+ return Regexp.last_match(1) if line.match(/#{option_name} ([a-z0-9.\/]*)/i)
38
+ end
39
+ end
40
+ false
41
+ end
42
+
43
+ def search_uid
44
+ case Nomansland.distro?
45
+ when :debian || :ubuntu
46
+ `id -u debian-tor`.chomp
47
+ else
48
+ `id -u #{@user}`.chomp
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end