myaxes 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.
- data/bin/myaxes +38 -0
- data/lib/myaxes.rb +145 -0
- data/lib/myaxes/axeconfig.rb +40 -0
- data/lib/myaxes/options.rb +40 -0
- metadata +49 -0
    
        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: []
         |