Creating a varible with a range - ruby

I have a program that attempts to generate open proxies, I will be using this program as a pentesting tool and have recently come across an error:
proxygen.rb:134:in `<=': comparison of Fixnum with nil failed (ArgumentError)
from proxygen.rb:134:in `check_for_amount_of_proxies'
from proxygen.rb:153:in `<main>'
What is happening is I have a variable #file_size and a variable #amount, the #amount variable is used to determine how many possible IP addresses are created and the #file_size is used to determine if the program has found the required amount of proxies and saved them to a file.
Source:
#!/usr/local/bin/env ruby
require 'colored'
require 'timeout'
require 'net/ping'
require 'proxies-scanner'
require 'etc'
LOGIN = Etc.getlogin
PATH = Dir.pwd
def fatal(input)
t = Time.now
puts "\n[[#{t.hour}:#{t.min}:#{t.sec} FATAL]]#{input}".red.bold
end
def notice(input)
t = Time.now
puts "\n[#{t.hour}:#{t.min}:#{t.sec} NOTICE]#{input}\n".blue.bold
end
def err(input)
t = Time.now
puts "[#{t.hour}:#{t.min}:#{t.sec} ERROR]#{input}".red.bold
end
def info(input)
t = Time.now
puts "[#{t.hour}:#{t.min}:#{t.sec} INFO]#{input}".green.bold
end
def success(input)
t= Time.now
puts "[#{t.hour}:#{t.min}:#{t.sec} [SUCCESS]#{input}".green.bold
end
def warn(input)
t = Time.now
puts "[#{t.hour}:#{t.min}:#{t.sec} WARNING]#{input}".yellow.bold
end
def self.windows?
return File.exist? "c:/WINDOWS" if RUBY_PLATFORM == 'java'
RUBY_PLATFORM =~ /mingw32/ || RUBY_PLATFORM =~ /mswin32/
end
def self.linux?
return File.exist? "/usr" if RUBY_PLATFORM == 'java'
RUBY_PLATFORM =~ /linux/
end
def self.os
return :linux if self.linux?
return :windows if self.windows?
nil
end
def check_os
notice("Hello #{LOGIN}, it appears that #{os.capitalize} is your OS, path has been switched to #{PATH}")
end
def check_file
if File.exist?("proxies.txt")
File.truncate("proxies.txt", 0)
notice("File exists in system, resuming process.")
else
notice("File proxies.txt created successfully.")
File.new("proxies.txt")
end
end
def choose_proxy_amount
print "Enter proxy amount: ".yellow.bold
#amount = gets.chomp.to_i
notice("Amount is measure in KB")
case #amount
when #amount >= 100
#file_size = 0..2154
when #amount <= 101
#file_size = 2166..21618
else
end
end
def create_possibles
notice("Attempting to ping generated IP addresses.")
ports = %w(80 443 1935 2222 3128 3130 7808 8080 8081 8085 8089
8090 8102 8104 8106 8118 8119 8123 8888 8898 9000
9090 9797 9999 10000 10052 10053 10059 10088 12345
18000 18001 18008 37564 40080 55336 59998
)
#amount.times do
#ip = Array.new(4){rand(256)}.join('.')
begin
Timeout::timeout(5) do
if Net::Ping::ICMP.new(#ip).ping?# == true
success("Possible proxies created for IP: #{#ip}")
File.open("proxies.txt", "a+") do |proxy|
ports.each { |port| proxy.puts("#{#ip}:#{port}") }
end
else
err("IP failed to ping: #{#ip}")
end
end
rescue Timeout::Error
warn("IP timed out: #{#ip}")
next
end
end
end
def check_for_amount_of_proxies
if File.size("proxies.txt") <= #file_size
notice("Proxies created, attempting connection")
system("proxies-scanner -f proxies.txt")
warn("Truncating file: proxies.txt")
else
notice("File doesn't contain enough proxies, restarting IP finding proccess.")
create_possibles
end
end
begin
check_file
check_os
choose_proxy_amount
create_possibles
check_for_amount_of_proxies
rescue RuntimeError => e
fatal("This program requires Adminstration access to run, please switch to admin terminal.")
end
So the program is failing when it tries to compare the size of the file to the variable #file_size. My question being is there a way to create this variable into a range?

The way you're assigning ranges is fine. Try assigning a range to a variable in IRB or Pry:
[3] (pry) main: 0> foo = 1..2
1..2
[4] (pry) main: 0> foo.class
Range < Object
You can't use <= #file_size if #file_size is a range:
5 <= 1..6
ArgumentError: bad value for range
or
5 <= (1..6)
ArgumentError: comparison of Fixnum with Range failed
You can use === instead:
(1..6) === 5
true
or:
#file_size === File.size("proxies.txt")
You can't reverse the order of the above. The range MUST be on the left:
5 === (1..6)
false
There's lots of pages explaining why.

Related

What is wrong with my Celluloid actors

I'm playing with celluloid gem. The example works well, but when I press Ctrl-C I get the unexpected message:
^CD, [2015-10-07T09:53:19.784411 #16326] DEBUG -- : Terminating 8 actors...
and after few seconds, I get the error:
E, [2015-10-07T09:53:29.785162 #16326] ERROR -- : Couldn't cleanly terminate all actors in 10 seconds!
/usr/local/rvm/gems/ruby-2.0.0-p353/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in `run_machine': Interrupt
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in `run'
Strange that I create only 4 actors, not 8, and my TERM, INT signals handler isn't be called.
#!/usr/bin/env ruby
require './config/environment'
opts = CommandlineOptions.new.to_h
iface = opts[:iface] || '0.0.0.0'
port = opts[:port] || 3000
App.logger.info('Starting communication server')
connections = Connections.new
local_inbox = LocalQueue.new
auth_server = AuthServer.new(connections, local_inbox)
inbox_service = InboxService.new('inbox', iface, port)
inbox_service.async.process_inbox(local_inbox) # <--------
remote_outbox_name = "outbox_#{iface}:#{port}"
outbox_service = OutboxService.new(connections)
outbox_service.async.subscribe(remote_outbox_name) # <--------
conn_server_opts = { host: iface, port: port }
conn_server_opts.merge!(auth_server.callbacks)
conn_server = ConnServer.new(conn_server_opts)
%W(INT TERM).each do |signal|
trap(signal) do
info("Shutting down...")
conn_server.stop
end
end
conn_server.start
Here InboxService is an actor which creates another actor - there are 2 actors, then OutboxService also creates one actor, so I got created 4 actors.
require 'redis'
require 'celluloid/current'
class InboxServiceActor
include Celluloid
def initialize(remote_inbox_name)
#remote_inbox_name = remote_inbox_name
create_redis_connection
end
def publish(full_msg)
#redis.publish(#remote_inbox_name, full_msg)
end
private
def create_redis_connection
#redis = Redis.new
end
end
require 'json'
require 'redis'
require 'celluloid/current'
class OutboxServiceActor
include Celluloid
include HasLoggerMethods
def initialize
create_redis_connection
end
def subscribe(remote_outbox_name, &block)
#redis.subscribe(remote_outbox_name) do |on|
on.message do |_channel, full_msg|
debug("Outbox message received: '#{full_msg}'")
hash = parse_msg(full_msg)
block.call(hash['signature'], hash['msg']) if message_valid?(hash)
end
end
end
private
def create_redis_connection
#redis = Redis.new
end
def parse_msg(full_msg)
JSON.parse(full_msg)
rescue JSON::ParserError
error('Outbox message JSON parse error')
nil
end
def message_valid?(msg)
msg.is_a?(Hash) && msg.key?('signature') && msg.key?('msg') ||
error('Invalid outbox message. Should '\
'contain "signature" and "msg" keys') && false
end
end

How do I write this ruby class?

I am attempting to write a class to store bans. I want to check if a given IP is banned and return #ip, #time, #reason etc.:
class BannedIP
attr_reader :ip, :time, :reason
def initialize(ip, time, reason)
#ip = ip
#time = time
#reason = reason
end
def banned?(ip)
# What do I use here?
end
end
I need help with the part # What do I use here? so that I can do something like:
if b = BannedIP.banned? '10.10.10.10'
I'm not sure returning ip when you already know ip makes sense but anyhoo...
You could use a custom hash class:
class BannedHash < Hash
def ban(ip, time, reason)
self[ip] = {time: time, reason: reason}
end
def banned?(ip)
if self.include?(ip)
self[ip]
else
"ip: #{ip} not found."
end
end
end
Usage:
def main
b = BannedHash.new
b.ban("10.10.10.10", Time.now, "Some reason")
puts b.banned?("10.10.10.10")
puts b.banned?("11.11.11.11")
end
Output:
{:time=>2015-04-27 21:18:39 +1200, :reason=>"Some reason"}
ip: 11.11.11.11 not found.
Bit of a waste to have a full class for this unless you are planning on putting more in it. If it's just this then track it with an array, it would be easier and cost you less memory.
class BannedIP
attr_accessor :ip, :time, :reason, :status
def initialize(ip)
#ip = ip
#time = Time.new
#reason = reason
#status = status.nil? ? false : true
end
def ban(reason)
#reason = reason
#time = Time.new
#status = true
end
def unban
#reason = ""
#time = Time.new
#status = false
end
def banned?
return #status
end
end
if __FILE__ == $0
puts "ban the bad guy at 10.0.0.1 because he was cheating"
a = BannedIP.new("10.0.0.1")
a.ban "he is a cheater!!"
puts "The status of 10.0.0.1 is " + a.status.to_s
end
$ ruby stack1.rb
ban the bad guy at 10.0.0.1 because he was cheating
The status of 10.0.0.1 is true
Install mysql2 and active record gems
gem install mysql2
gem install active_record
Then execute following code snapshot
require 'active_record'
require 'mysql2'
SOURCE_CREDNTIALS = {
:adapter => "mysql2",
:host => "localhost",
:username => "root",
:password => "password",
:database => "banned_db"
}
class Banned < ActiveRecord::Base
ActiveRecord::Base.establish_connection(SOURCE_CREDNTIALS)
#attr_accessor :id, :ip, :banned_at, :reason
def self.banned?(ip)
where(ip: ip).count > 0
end
end
Now you can use this simple class as
user_foo = Banned.create(ip: '10.10.10.10', banned_at: Time.now, reason: 'violated terms and conditions')
Banned.banned?('10.10.10.10')
BannedIP.banned? method would return true or false depending upon if particular ip is banned or not.

Ruby: Chatterbot can't load bot data

I'm picking up ruby language and get stuck at playing with the chatterbot i have developed. Similar issue has been asked here Click here , I did what they suggested to change the rescue in order to see the full message.But it doesn't seem right, I was running basic_client.rb at rubybot directory and fred.bot is also generated at that directory . Please see the error message below: Your help very be very much appreciated.
Snailwalkers-MacBook-Pro:~ snailwalker$ cd rubybot
Snailwalkers-MacBook-Pro:rubybot snailwalker$ ruby basic_client.rb
/Users/snailwalker/rubybot/bot.rb:12:in `rescue in initialize': Can't load bot data because: No such file or directory - bot_data (RuntimeError)
from /Users/snailwalker/rubybot/bot.rb:9:in `initialize'
from basic_client.rb:3:in `new'
from basic_client.rb:3:in `<main>'
basic_client.rb
require_relative 'bot.rb'
bot = Bot.new(:name => 'Fred', :data_file => 'fred.bot')
puts bot.greeting
while input = gets and input.chomp != 'end'
puts '>> ' + bot.response_to(input)
end
puts bot.farewell
bot.rb:
require 'yaml'
require './wordplay'
class Bot
attr_reader :name
def initialize(options)
#name = options[:name] || "Unnamed Bot"
begin
#data = YAML.load(File.read('bot_data'))
rescue => e
raise "Can't load bot data because: #{e}"
end
end
def greeting
random_response :greeting
end
def farewell
random_response :farewell
end
def response_to(input)
prepared_input = preprocess(input).downcase
sentence = best_sentence(prepared_input)
reversed_sentence = WordPlay.switch_pronouns(sentence)
responses = possible_responses(sentence)
responses[rand(responses.length)]
end
private
def possible_responses(sentence)
responses = []
#data[:responses].keys.each do |pattern|
next unless pattern.is_a?(String)
if sentence.match('\b' + pattern.gsub(/\*/, '') + '\b')
if pattern.include?('*')
responses << #data[:responses][pattern].collect do |phrase|
matching_section = sentence.sub(/^.*#{pattern}\s+/, '')
phrase.sub('*', WordPlay.switch_pronouns(matching_section))
end
else
responses << #data[:responses][pattern]
end
end
end
responses << #data[:responses][:default] if responses.empty?
responses.flatten
end
def preprocess(input)
perform_substitutions input
end
def perform_substitutions(input)
#data[:presubs].each {|s| input.gsub!(s[0], s[1])}
input
end
# select best_sentence by looking at longest sentence
def best_sentence(input)
hot_words = #data[:responses].keys.select do |k|
k.class == String && k =~ /^\w+$/
end
WordPlay.best_sentence(input.sentences, hot_words)
end
def random_response(key)
random_index = rand(#data[:responses][key].length)
#data[:responses][key][random_index].gsub(/\[name\]/, #name)
end
end
I'm assuming that you are trying to load the :data_file passed into Bot.new, but right now you are statically loading a bot_data file everytime. You never mentioned about bot_data in the question. So if I'm right it should be like this :
#data = YAML.load(File.read(options[:data_file]))
Instead of :
#data = YAML.load(File.read('bot_data'))

I must be misunderstanding Celluloid

I currently have a script written in Ruby that scans a range of IP addresses and tries to connect to them. It's extremely slow at the moment. It takes up to 300 seconds to scan 254 hosts on the network, and that's obviously not very practical. What I'm trying to do is give the script some concurrency in hopes of speeding up the script. So far this is what I have:
require 'socket'
require 'celluloid'
$res_arr = []
class Ranger
include Celluloid
def initialize(host)
#host = host
#timeout = 1
end
def ip_range(host)
host =~ /(?:\d{1,3}\.){3}[xX*]{1,3}/
end
def ctrl(host)
begin
if ip_range(host)
strIP = host.gsub(/[xX*]/, '')
(1..254).each do |oct|
$res_arr << strIP+oct.to_s
end
else
puts "Invalid host!"
end
rescue
puts "onnection terminated."
end
end
def connect
addr = Socket.getaddrinfo(#host, nil)
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
rescue Errno::EINPROGRESS
resp = IO.select(nil, [sock], nil, #timeout.to_i)
if resp.nil?
$res_arr << "#{#host} Firewalled!"
end
begin
if sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
$res_arr << "#{#host}Connected!"
end
rescue Errno::ECONNREFUSED
$res_arr << "#{#host} Refused!"
rescue
false
end
end
sock
end
def output(contents)
puts contents.value
end
end # Ranger
main = Ranger.new(ARGV[0])
main.ctrl(ARGV[0])
$res_arr.each do |ip|
scan = Ranger.new(ip)
scnftr = scan.future :connect
scan.output(scnftr)
end
The script works, but it takes just as long as before I included Celluloid at all. Am I misunderstanding how Celluloid works and what it's supposed to do?
Your problem is that each iteration of your loop starts a future, then immediately waits for it to return a value. What you want instead is start all futures, then wait for all futures to finish in two separate steps:
futures = $res_arr.map do |ip|
scan = Ranger.new(ip)
scan.future :connect
end
# now that all futures are running, we can start
# waiting for the first one to finish
futures.each do |future|
puts future.value
end
Here's another example from the celluloid source: https://github.com/celluloid/celluloid/blob/master/examples/simple_pmap.rb

How to tell a connect timeout error from a read timeout error in Ruby's Net::HTTP

My question is related to How to rescue timeout issues (Ruby, Rails).
Here's the common way to rescue from a timeout:
def action
# Post using Net::HTTP
rescue Timeout::Error => e
# Do something
end
I'd like to determine if the exception was raised while trying to connect to the host, or if it was raised while trying to read from the host. Is this possible?
Here's the solution (after Ben's fix):
require "net/http"
http = Net::HTTP.new("example.com")
http.open_timeout = 2
http.read_timeout = 3
begin
http.start
begin
http.request_get("/whatever?") do |res|
res.read_body
end
rescue Timeout::Error
puts "Timeout due to reading"
end
rescue Timeout::Error
puts "Timeout due to connecting"
end
Marc-André Lafortune's solution is still the best if you can't upgrade to ruby 2.x.
Starting from 2.x, a subclass of Timeout::Error will be raised depending on which timeout was triggered:
Net::OpenTimeout
Net::ReadTimeout
However, the read_timeout behavior is strange on 2.x, because it seems to double the value you set. This article explains why.
Here's a test for both timeouts (tested on 1.8.7, 1.9.3, 2.1.2, 2.2.4).
EDIT: The open_timeout test works on Mac, but on Linux, the client gets a "connection refused" error.
require "net/http"
require "socket"
SERVER_HOST = '127.0.0.1'
SERVER_PORT = 9999
def main
puts 'with_nonlistening_server'
with_nonlistening_server do
make_request
end
puts
puts 'with_listening_server'
with_listening_server do
make_request
end
end
def with_listening_server
# This automatically starts listening
serv = TCPServer.new(SERVER_HOST, SERVER_PORT)
begin
yield
ensure
serv.close
end
end
def with_nonlistening_server
raw_serv = Socket.new Socket::AF_INET, Socket::SOCK_STREAM, 0
addr = Socket.pack_sockaddr_in SERVER_PORT, SERVER_HOST
# Bind, but don't listen
raw_serv.bind addr
begin
yield
ensure
raw_serv.close
end
end
def make_request
http = Net::HTTP.new(SERVER_HOST, SERVER_PORT)
http.open_timeout = 1
http.read_timeout = 1 # seems to be doubled on ruby 2.x
start_tm = Time.now
begin
http.start
begin
http.get('/')
rescue Timeout::Error => err
puts "Read timeout: #{err.inspect}"
end
rescue Timeout::Error => err
puts "Open timeout: #{err.inspect}"
end
end_tm = Time.now
puts "Duration (sec): #{end_tm - start_tm}"
end
if __FILE__ == $PROGRAM_NAME
main
end
Example output on 1.9.3:
with_nonlistening_server
Open timeout: #<Timeout::Error: execution expired>
Duration (sec): 1.002477
with_listening_server
Read timeout: #<Timeout::Error: Timeout::Error>
Duration (sec): 1.00599
Example output on 2.1.2:
with_nonlistening_server
Open timeout: #<Net::OpenTimeout: execution expired>
Duration (sec): 1.005923
with_listening_server
Read timeout: #<Net::ReadTimeout: Net::ReadTimeout>
Duration (sec): 2.009582

Resources