myaxes 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/myaxes ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "myaxes"
4
+
5
+ AXES_VER = "0.1.0 alpha"
6
+ AXES_AUTHORS = "InViZz"
7
+
8
+ ################################################################################
9
+ puts "------------------------------------------------------------------------------------ "
10
+ puts " @ @ "
11
+ puts " @@ @@ "
12
+ puts " @@@@ @@@@ "
13
+ puts " @@@@@ @@@@@ "
14
+ puts " @@@@@@ @@@ @@@@@@ "
15
+ puts " @@@@@@@ @@@ @@@@@@@ "
16
+ puts " @@@@@@@@@@@@@@@@@@@@@@@@@@@ "
17
+ puts " @@@@@@@@@@@@@@@@@@@@@@@@@@@ "
18
+ puts " @@@@@@@ @@@ @@@@@@@ "
19
+ puts " @@@@@@ @@@ @@@@@@ "
20
+ puts "@@@@@@@@@@ @@@ @@@ @@@@@ @@@ @@@@@ @@@@@@ @@@ @@@ @@@@@@@@ @@@@@@ "
21
+ puts "@@@@@@@@@@@ @@@ @@@ @@@@ @@@ @@@@ @@@@@@@@ @@@ @@@ @@@@@@@@ @@@@@@@ "
22
+ puts "@@! @@! @@! @@! !@@ @@ @@@ @@ @@! @@@ @@! !@@ @@! !@@ "
23
+ puts "!@! !@! !@! !@! @!! @ @@@ @ !@! @!@ !@! @!! !@! !@! "
24
+ puts "@!! !!@ @!@ !@!@! @@@ @!@!@!@! !@@!@! @!!!:! !!@@!! "
25
+ puts "!@! ! !@! @!!! @@@ !!!@!!!! @!!! !!!!!: !!@!!! "
26
+ puts "!!: !!: !!: @@@ !!: !!! !: :!! !!: !:! "
27
+ puts ":!: :!: :!: @@@ :!: !:! :!: !:! :!: !:! "
28
+ puts "::: :: :: @@@ :: ::: :: ::: :: :::: :::: :: "
29
+ puts " : : : @@@ : : : : :: : :: :: :: : : "
30
+ puts " @@@@@ "
31
+ puts "#{AXES_VER} by #{AXES_AUTHORS} @@@@@ "
32
+ puts " @@@@@ "
33
+ puts "------------------------------------------------------------------------------------"
34
+ ################################################################################
35
+ $DEBUG = false
36
+
37
+ myaxes = MyAxes.new('/etc/myaxes.yml')
38
+ myaxes.start
data/lib/myaxes.rb ADDED
@@ -0,0 +1,145 @@
1
+ require "rubygems"
2
+ require "net/ssh"
3
+ require "net/ssh/gateway"
4
+ require "log4r"
5
+ require 'myaxes/axeconfig'
6
+ require 'myaxes/options'
7
+
8
+ class MyAxes
9
+
10
+ include Log4r
11
+
12
+ def initialize(config='~/.myaxes.yml')
13
+ @logger = Logger.new('MyAxes')
14
+ @logger.outputters = Outputter.stdout
15
+
16
+ @options = Options.new.parse
17
+ @logger.debug "test #{@options}" if $DEBUG
18
+
19
+ @conf = AxeConfig.new(@options)
20
+ @config = @conf.read(config)
21
+ @targets = @conf.targets
22
+ @threads = []
23
+
24
+ @ssh_options ={
25
+ :port => @config['Global']['ssh_port'],
26
+ :verbose => @config['Global']['debug_level'].to_sym,
27
+ :auth_methods => %w(publickey password keyboard-interactive),
28
+ :keys => @config['Global']['ssh_keys'],
29
+ :password => @config['Global']['password']
30
+ }
31
+ @commands_proc = Proc.new { |session, hostname|
32
+ @targets[hostname].each do |query|
33
+ @logger.debug "Query: #{query}" if $DEBUG
34
+ name = hostname.chomp.split(".")[0]
35
+ cmd = "mysql -u #{@config['Targets'][name]['login']} -e '#{query}' -p"
36
+ output = self.exec(session,cmd,name)
37
+ puts "\033[0;32m[*] #{hostname}\033[0m: #{output}"
38
+ end
39
+ }
40
+
41
+ end
42
+
43
+ def start
44
+ @targets.each_key do |hostname|
45
+ if self.use_gw?
46
+ @threads << Thread.new {
47
+ self.via_gw do |jump_server|
48
+ begin
49
+ jump_server.ssh(hostname, @config['Global']['login'], @ssh_options) do |session|
50
+ @commands_proc.call(session,hostname)
51
+ end
52
+ rescue Net::SSH::Disconnect => errmsg
53
+ warn "#{hostname} : #{errmsg}"
54
+ rescue Net::SSH::AuthenticationFailed => errmsg
55
+ warn "#{hostname} : #{errmsg}"
56
+ rescue Errno::ETIMEDOUT => errmsg
57
+ warn "#{hostname} : #{errmsg}"
58
+ rescue Errno::ECONNREFUSED => errmsg
59
+ warn "#{hostname} : #{errmsg}"
60
+ end
61
+ end
62
+ }
63
+ else
64
+ @threads << Thread.new {
65
+ begin
66
+ Net::SSH.start(hostname, @config['Global']['login'], @ssh_options) do |session|
67
+ @commands_proc.call(session,hostname)
68
+ end
69
+ rescue Net::SSH::Disconnect => errmsg
70
+ warn "#{hostname} : #{errmsg}"
71
+ rescue Net::SSH::AuthenticationFailed => errmsg
72
+ warn "#{hostname} : #{errmsg}"
73
+ rescue Errno::ETIMEDOUT => errmsg
74
+ warn "#{hostname} : #{errmsg}"
75
+ rescue Errno::ECONNREFUSED => errmsg
76
+ warn "#{hostname} : #{errmsg}"
77
+ end
78
+ }
79
+ end
80
+ end
81
+
82
+ @threads.each {|thread|
83
+ thread.join
84
+ }
85
+ end
86
+
87
+ def via_gw
88
+ begin
89
+ jump_server = Net::SSH::Gateway.new(@config['Global']['jump_server'], @config['Global']['login'], @ssh_options)
90
+
91
+ @logger.debug "port forwarding ok" if $DEBUG
92
+
93
+ yield jump_server
94
+
95
+ rescue Net::SSH::Disconnect => errmsg
96
+ warn "Gateway : #{errmsg}"
97
+ rescue Net::SSH::AuthenticationFailed => errmsg
98
+ warn "Gateway : #{errmsg}"
99
+ rescue Errno::ETIMEDOUT => errmsg
100
+ warn "Gateway : #{errmsg}"
101
+ rescue Errno::ECONNREFUSED => errmsg
102
+ warn "Gateway : #{errmsg}"
103
+ end
104
+
105
+ end
106
+
107
+ def use_gw?
108
+ @config['Global']['use_jump']
109
+ end
110
+
111
+ def exec(session,cmd,name)
112
+ channel = session.open_channel do |channel|
113
+ channel.request_pty do |ch, success|
114
+ raise "Could not obtain pty (i.e. an interactive ssh session)" if !success
115
+ end
116
+ channel.exec(cmd) do |ch, success|
117
+ die "could not execute command" unless success
118
+ channel.on_data do |ch, data|
119
+ if data == "Enter password: "
120
+ @logger.debug "DEBUG: Password request" if $DEBUG
121
+ channel.send_data "#{@config['Targets'][name]['password']}\n"
122
+ else
123
+ channel[:result] ||= ""
124
+ channel[:result] << data
125
+ end
126
+ end
127
+
128
+ channel.on_extended_data do |ch, type, data|
129
+ raise "SSH command returned on stderr: #{data}"
130
+ end
131
+ end
132
+ end
133
+
134
+ # Nothing has actually happened yet. Everything above will respond to the
135
+ # server after each execution of the ssh loop until it has nothing left
136
+ # to process. For example, if the above recieved a password challenge from
137
+ # the server, ssh's exec loop would execute twice - once for the password,
138
+ # then again after clearing the password (or twice more and exit if the
139
+ # password was bad)
140
+ channel.wait
141
+
142
+ return channel[:result] # it returns with \r\n at the end
143
+ end
144
+
145
+ end
@@ -0,0 +1,40 @@
1
+ require "yaml"
2
+
3
+ class AxeConfig < Hash
4
+
5
+ attr_reader :targets, :config
6
+
7
+ def initialize(options)
8
+ @config = Hash.new
9
+ @options = options
10
+ @targets = Hash.new
11
+ end
12
+
13
+ def read(config)
14
+ user = @options['user']
15
+ ip = @options['ip']
16
+ #password = @options['password']
17
+ group = @options['group']
18
+
19
+ puts "Configfile (#{config}) not found" unless File.readable?(config)
20
+
21
+ begin
22
+ @config = YAML.load_file(config)
23
+ rescue Exception => errmsg
24
+ puts "Configfile format error: #{errmsg}"
25
+ end
26
+
27
+ @config['Targets'].each_key do |target|
28
+ if @config['Targets'][target]['query'].include? group
29
+ @config['Targets'][target]['query'][group].each do |query|
30
+ query.to_s.gsub!('{ip}', ip).gsub!('{user}', user)
31
+ end
32
+ @targets["#{@config['Targets'][target]['hostname']}"] = @config['Targets'][target]['query'][group]
33
+ end
34
+ end
35
+
36
+ self.config
37
+ end
38
+
39
+
40
+ end
@@ -0,0 +1,40 @@
1
+ require "optparse"
2
+
3
+ class Options
4
+
5
+ attr_reader :options
6
+
7
+ def initialize
8
+ @options = Hash.new
9
+
10
+ @options['mode'] = 'log'
11
+ @options['log'] = $stdout
12
+
13
+ end
14
+
15
+ def parse
16
+ OptionParser.new do |opt|
17
+ opt.separator ""
18
+ opt.separator "Usage: myaxes -g <group> -a <ip> -u <username> -p <password>[-H <hostnames>]"
19
+ opt.separator ""
20
+ opt.separator "shell> myaxes -g web -a 192.168.0.101 -u web301 -p qwerty"
21
+ opt.separator ""
22
+ opt.separator ""
23
+ opt.separator "Options:"
24
+ opt.separator "-------------"
25
+ opt.on('-g', '--group GROUPNAME', 'Group from config') { |val| @options['group'] = val }
26
+ opt.on('-a', '--address IP-ADDRESS', 'Ip address') { |val| @options['ip'] = val }
27
+ opt.on('-u', '--user USERNAME', 'Username') { |val| @options['user'] = val }
28
+ opt.on('-p', '--password PASSWORD', 'Password') { |val| @options['password'] = val }
29
+ opt.on('-H', '--hosts HOSTNAME_X,HOSTNAME_Y,HOSTNAME_Z', Array, 'Other Hosts(not from config)') { |val| @options['hosts'] = val }
30
+ opt.separator ""
31
+ opt.on_tail('-h', '--help') { puts opt; exit }
32
+
33
+ opt.parse!
34
+ end
35
+
36
+ self.options
37
+
38
+ end
39
+
40
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: myaxes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - InViZz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-08 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Simple console app for remote execute mysql queries
15
+ email: morion.estariol@gmail.com
16
+ executables:
17
+ - myaxes
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/myaxes.rb
22
+ - lib/myaxes/axeconfig.rb
23
+ - lib/myaxes/options.rb
24
+ - bin/myaxes
25
+ homepage: https://github.com/InViZz/MyAxes
26
+ licenses: []
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 1.8.10
46
+ signing_key:
47
+ specification_version: 3
48
+ summary: MyAxes
49
+ test_files: []