How to convert IP range to a single CIDR using Ruby - ruby

Does Ruby have a simple way to convert a range of IP addresses to CIDR?
I know in Python we can do it like this:
cidr = netaddr.iprange_to_cidrs(startip, endip)
I've looked to other questions here at StackOverflow and none of them are about converting a range of IP addresses to a single CIDR, like:
startip = '250.154.64.0'
endip = '250.154.64.255'
output: '250.154.64.0/24'

Found it!
require 'netaddr'
startip = '250.154.64.0'
endip = '250.154.64.255'
ip_net_range = NetAddr.range(startip, endip, :Inclusive => true, :Objectify => true)
cidrs = NetAddr.merge(ip_net_range, :Objectify => true)
puts cidrs
output: 250.154.64.0/24

Related

how to amend a code to get query from external and save result to external

I have a code which looks like this
require 'net/http'
base = 'www.uniprot.org'
tool = 'mapping'
params = {
'from' => 'ACC+ID', 'to' => 'P_ENTREZGENEID', 'format' => 'tab',
'query' => 'A0A0K3AVS5 A0A0K3AVV4 A0A0K3AW32 A0A0K3AWP0'
}
http = Net::HTTP.new base
$stderr.puts "Submitting...\n";
response = http.request_post '/' + tool + '/',
params.keys.map {|key| key + '=' + params[key]}.join('&')
loc = nil
while response.code == '302'
loc = response['Location']
response = http.request_get loc
end
while loc
wait = response['Retry-After'] or break
$stderr.puts "Waiting (#{wait})...\n";
sleep wait.to_i
response = http.request_get loc
end
response.value # raises http error if not 2xx
puts response.body
which gives me what I need. however, I have two questions
1- How to load a query list instead I parse it into the code ? lets say I save a txt file with all the query i want to the desktop of a mac
2- How to export the output ?
If I have
B2D6P1
G5EC52
B2FDA8-2
B2MZB1
B3CJ34
B3CKG1
B3GWA1
what #tadman showed gives me the answer
however, I have the following
B2D6P1
G5EC52;B2D6P4
B2FDA8-2;B2FDA8
B2MZB1;P18834
B3CJ34
B3CKG1
B3GWA1;Q8I7K5
and the answer is like below
B2D6P1 rmd-2
G5EC52 tlf-1
B2D6P4 tlf-1
B2FDA8 smc-3
B2MZB1 col-14
P18834 col-14
B3CJ34 gcn-1
B3CKG1 urm-1
B3GWA1 nono-1
Q8I7K5 nono-1
what I want is that if I have two entries in each row (separated with ;) leading to the similar output , it gives me only one , otherwise give me as many as they have for example in above example , my desire output is
B2D6P1 rmd-2
G5EC52;B2D6P4 tlf-1
B2FDA8-2;B2FDA8 smc-3
B2MZB1;P18834 col-14
B3CJ34 gcn-1
B3CKG1 urm-1
B3GWA1;Q8I7K5 nono-1
is this possible ?
Reading query data:
query = File.readlines('ids.txt').map(&:chomp).join(' ')
That way you can have them on separate lines, easier to edit, and they're space separated when submitted.
That makes your params look like:
params = {
'query' => query,
...
}
Writing data:
File.open('output.txt', 'w') do |f|
f.write(response.body)
end
That's all there is to it. If it's a string, or can be converted to a string, you can write it to a file.

Ruby convert string array to string

I have a ruby string array value and i want to get it as string value. I am using ruby with chef recipe. Running in windows platform. Code-
version_string = Mixlib::ShellOut.new('some.exe -version').run_command
Log.info(version.stdout.to_s)
extract_var = version_string.stdout.to_s.lines.grep(/ver/)
Log.info('version:'+ extract_var.to_s)
output is coming-
version 530
[2016-06-08T07:03:49+00:00] INFO: version ["version 530\r\n"]
I want to extract 530 string only.
long time no see since Rot :)
You can use some Chef helper methods and regular expressions to make this a little easier.
output = shell_out!('saphostexec.exe -version', cwd: 'C:\\Program Files\\hostctrl\\exe').stdout
if output =~ /kernel release\s+(\d+)/
kernel_version = $1
else
raise "unable to parse kernel version"
end
Chef::Log.info(kernel_version)
As you want val = 720 and not val = "720" you can write
val = strvar.first.to_i
#=> 720
You can return the first series of digits found as an integer from the current_kernel string with String#[regexp] :
current_kernel[/\d+/].to_i
#=> 720

Parsing a string field

I have these Syslog messages:
N 4000000 PROD 15307 23:58:12.13 JOB78035 00000000 $HASP395 GGIVJS27 ENDED\r
NI0000000 PROD 15307 23:58:13.41 STC81508 00000200 $A J78036 /* CA-JOBTRAC JOB RELEASE */\r
I would like to parse these messages into various fields in a Hash, e.g.:
event['recordtype'] #=> "N"
event['routingcode'] #=> "4000000"
event['systemname'] #=> "PROD"
event['datetime'] #=> "15307 23:58:12.13"
event['jobid'] #=> "JOB78035"
event['flag'] #=> "00000000"
event['messageid'] #=> "$HASP395"
event['logmessage'] #=> "$HASP395 GGIVJS27 ENDED\r"
This is the code I have currently:
message = event["message"];
if message.to_s != "" then
if message[2] == " " then
array = message.split(%Q[ ]);
event[%q[recordtype]] = array[0];
event[%q[routingcode]] = array[1];
event[%q[systemname]] = array[2];
event[%q[datetime]] = array[3] + " " +array[4];
event[%q[jobid]] = message[38,8];
event[%q[flags]] = message[47,8];
event[%q[messageid]] = message[57,8];
event[%q[logmessage]] = message[56..-1];
else
array = message.split(%Q[ ]);
event[%q[recordtype]] = array[0][0,2];
event[%q[routingcode]] = array[0][2..-1];
event[%q[systemname]] = array[1];
event[%q[datetime]] = array[2] + " "+array[3];
event[%q[jobid]] = message[38,8];
event[%q[flags]] = message[47,8];
event[%q[messageid]] = message[57,8];
event[%q[logmessage]] = message[56..-1];
end
end
I'm looking to improve the above code. I think I could use a regular expression, but I don't know how to approach it.
You can't use split(' ') or a default split to process your fields because you are dealing with columnar data that has fields that have no whitespace between them, resulting in your array being off. Instead, you have to pick apart each record by columns.
There are many ways to do that but the simplest and probably fastest, is indexing into a string and grabbing n characters:
'foo'[0, 1] # => "f"
'foo'[1, 2] # => "oo"
The first means "starting at index 0 in the string, grab one character." The second means "starting at index 1 in the string, grab two characters."
Alternately, you could tell Ruby to extract by ranges:
'foo'[0 .. 0] # => "f"
'foo'[1 .. 2] # => "oo"
These are documented in the String class.
This makes writing code that's easily understood:
record_type = message[ 0 .. 1 ].rstrip
routing_code = message[ 2 .. 8 ]
system_name = message[ 10 .. 17 ]
Once you have your fields captured add them to a hash:
{
'recordtype' => record_type,
'routingcode' => routing_code,
'systemname' => system_name,
'datetime' => date_time,
'jobid' => job_id,
'flags' => flags,
'messageid' => message_id,
'logmessage' => log_message,
}
While you could use a regular expression there's not much gained using one, it's just another way of doing it. If you were picking data out of free-form text it'd be more useful, but in columnar data it tends to result in visual noise that makes maintenance more difficult. I'd recommend simply determining your columns then cutting the data you need based on those from each line.

Using a CSV file to insert values using Ruby

I have some sample code I can execute for our Nexpose server and I need to do some mass asset tagging. Here is an example of the code.
nsc = Nexpose::Connection.new('your_nexpose_instance', 'username', 'password', 3780)
nsc.login
criterion = Nexpose::Tag::Criterion.new('IP_RANGE', 'IN', ['ip1', 'ip2'])
criteria = Nexpose::Tag::Criteria.new(criterion)
tag = Nexpose::Tag.new("tagname", Nexpose::Tag::Type::Generic::CUSTOM)
tag.search_criteria = criteria
tag.save(nsc)
I have a file called with the following data.
ip1,ip2,tagname
192.168.1.1,192.168.1.255,Workstations
How would I go about running a for loop and using the CSV to quickly process the above code? I have no experiance with Ruby and tried to follow some example but I'm confused at this point.
There's a CSV library in Ruby's standard lib collection that you can use.
Basic example based on your code example and data, not tested:
require 'csv'
nsc = Nexpose::Connection.new('your_nexpose_instance', 'username', 'password', 3780)
nsc.login
CSV.foreach("path/to/file.csv", headers: true) do |row|
criterion = Nexpose::Tag::Criterion.new('IP_RANGE', 'IN', [row['ip1'], row['ip2'])
criteria = Nexpose::Tag::Criteria.new(criterion)
tag = Nexpose::Tag.new(row['tagname'], Nexpose::Tag::Type::Generic::CUSTOM)
tag.search_criteria = criteria
tag.save(nsc)
end
I made a directory with input.csv and main.rb
input.csv
ip1,ip2,tagname
192.168.1.1,192.168.1.255,Workstations
main.rb
require "csv"
CSV.foreach("input.csv", headers: true) do |row|
puts "ip1: #{row['ip1']}"
puts "ip2: #{row['ip2']}"
puts "tagname: #{row['tagname']}"
end
the output is
ip1: 192.168.1.1
ip2: 192.168.1.255
tagname: Workstations
I hope this can help. If you have questions I'm here :)
If you just need to loop through each line of the file and fire that chunk of code for each line, you could do something like this:
file = Net::HTTP.get(URI(<whatever_your_file_name_is>))
index = 0
file.each_line do |line|
next if index == 0
index += 1
split_line = line.split(',')
ip1 = split_line[0]
ip2 = split_line[1]
tagname = split_line[2]
nsc = Nexpose::Connection.new('your_nexpose_instance', 'username', 'password', 3780)
nsc.login
criterion = Nexpose::Tag::Criterion.new('IP_RANGE', 'IN', [ip1, ip2])
criteria = Nexpose::Tag::Criteria.new(criterion)
tag = Nexpose::Tag.new(tagname, Nexpose::Tag::Type::Generic::CUSTOM)
tag.search_criteria = criteria
tag.save(nsc)
end
NOTE: This code example is assuming that the CSV file is stored remotely, not locally.
ALSO: In case you're wondering, the next if index == 0 is there to skip your header record.
UPDATE
To use this approach for a local file, you can use File.open() instead of Net::HTTP.get(), like so:
file = File.open(<whatever_your_file_name_is>).read
Two things to note:
Make sure you use the fully-qualified name of the file - i.e. ~/folder/folder/filename.csv instead of just filename.csv.
If the files you're going to be loading are enormous, this might not be an ideal approach because it's actually reading the whole file into memory. But considering your file only has 3 columns, you'd have to have an extreme number of rows in the file for this to be an issue.

unpack base64-encoded 32bit integer representing IP address

I have a base64-encoded, 32-bit integer, that's an IP address: DMmN60
I cannot for the life of me figure out how to both unpack it and turn it into a quad-dotted representation I can actually use.
Unpacking it with unpack('m') actually only gives me three bytes. I don't see how that's right either, but this is far from my expertise.
Hello from the future (two years later) with Ruby 1.9.3. To encode:
require 'base64'
ps = "204.152.222.180"
pa = ps.split('.').map { |_| _.to_i } # => [204, 152, 222, 180]
pbs = pa.pack("C*") # => "\xCC\x98\xDE\xB4"
es = Base64.encode64(s) # => "zJjetA==\n"
To decode:
require 'base64'
es = "zJjetA==\n"
pbs = Base64.decode64(es) # => "\xCC\x98\xDE\xB4"
pa = pbs.unpack("C*") # => [204, 152, 222, 180]
ps = pa.map { |_| _.to_s }.join('.') # => "204.152.222.180"
Name explanation:
ps = plain string
pa = plain array
pbs = plain binary string
es = encoded string
For your example:
Base64.decode64("DMmN60==").unpack("C*").map { |_| _.to_s }.join('.')
# => "12.201.141.235"
Just like #duskwuff said.
Your comment above said that the P10 base64 is non-standard, so I took a look at: http://carlo17.home.xs4all.nl/irc/P10.html which defines:
<base64> = 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
It is the same as http://en.wikipedia.org/wiki/Base64 -- except that the last two characters are + and / in the normal Base64. I don't see how this explains the discrepancy, since your example did not use those characters. I do wonder, however, if it was due to some other factor -- perhaps an endian issue.
Adding padding (DMmN60==) and decoding gives me the bytes:
0C C9 8D EB
Which decodes to 12.201.141.235.

Resources