Last active
January 7, 2022 00:17
-
-
Save gangelo/d215f9e7b51a3dc3c9a72191916bd9f4 to your computer and use it in GitHub Desktop.
Hacking
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Examples: | |
# | |
# Hacking::Networking.network_info_for(ip: '192.168.114.32/27') | |
# Hacking::Networking.network_info_for(ip: '192.168.33.12', mask: '255.255.224.0') | |
# => {:ip=>[192, 168, 33, 12], :mask=>[255, 255, 224, 0], :cidr_info=>{:cidr=>19, :network=>"192.168.32.0", :cidr_notation=>"192.168.32.0/19"}, :network=>"192.168.32.0", :host=>"0.0.1.12", :total_hosts=>8192} | |
# Hacking::Networking.network_for(ip: '192.168.33.12', mask: '255.255.224.0') # => "192.168.32.0" | |
# Hacking::Networking.host_for(ip: '192.168.33.12', mask: '255.255.224.0') # => "0.0.1.12" | |
# Hacking::Networking.total_hosts_for(mask: '255.255.224.0') # => 8192 | |
# Hacking::Networking.to_binary('192.168.33.12') # => "11000000.10101000.00100001.00001100" | |
# Hacking::Networking.to_binary('255.255.224.0') # => "11111111.11111111.11100000.00000000" | |
# Hacking::Networking.mask_for(cidr: 23) => "255.255.254.0" | |
module Hacking | |
module Networking | |
CIDR_TOTAL_BITS = 32 | |
module_function | |
def network_info_for(ip:, mask: nil) | |
if mask.nil? | |
puts 'Mask is nil?' | |
ip, cidr = split_cidr(ip: ip) | |
mask = mask_for(cidr: cidr) | |
end | |
ip = octets_for(ip) unless octets?(ip) | |
mask = octets_for(mask) unless octets?(mask) | |
total_hosts = total_hosts_for(mask: mask) | |
cidr_info = cidr_for(ip: ip, mask: mask) | |
{ | |
ip: ip, | |
mask: mask, | |
cidr: cidr_info[:cidr], | |
cidr_notation: cidr_info[:cidr_notation], | |
network: network_for(ip: ip, mask: mask), | |
host: host_for(ip: ip, mask: mask), | |
total_hosts: total_hosts, | |
# Subtract 2 for Network (first address) and Broadcast (last address) | |
total_hosts_actual: total_hosts - 2, | |
binary_representations: | |
{ | |
ip: to_binary(ip), | |
mask: to_binary(mask), | |
mask_inverted: to_binary(invert(mask)), | |
}, | |
} | |
end | |
# Returns the network ip address (as a string) for the given ip address and mask. | |
def network_for(ip:, mask:) | |
ip = octets_for(ip) unless octets?(ip) | |
mask = octets_for(mask) unless octets?(mask) | |
network_part_octets = [] | |
ip.each_with_index do |octet, index| | |
network_part_octets << (octet & mask[index]) | |
end | |
join_octets(network_part_octets) | |
end | |
# Returns the host ip address (as a string) for the given ip address and mask. | |
def host_for(ip:, mask:) | |
ip = octets_for(ip) unless octets?(ip) | |
mask = octets_for(mask) unless octets?(mask) | |
mask = invert(join_octets(mask)) | |
host_octets = [] | |
ip.each_with_index do |octet, index| | |
host_octets << (octet & mask[index]) | |
end | |
join_octets(host_octets) | |
end | |
# Returns the maximum number of host addresses this network can support. | |
def total_hosts_for(mask:) | |
mask = join_octets(mask) if octets?(mask) | |
2 ** bits_on_for(mask: mask) | |
end | |
# Returns the cidr notation given the mask. | |
def cidr_for(ip:, mask:) | |
ip = octets_for(ip) unless octets?(ip) | |
mask = octets_for(mask) unless octets?(mask) | |
cidr = CIDR_TOTAL_BITS - bits_on_for(mask: join_octets(mask)) | |
network = network_for(ip: ip, mask: mask) | |
{ | |
cidr: cidr, | |
network: network, | |
cidr_notation: "#{network}/#{cidr}", | |
} | |
end | |
def mask_for(cidr:) | |
ones_count = cidr | |
zeroes_count = CIDR_TOTAL_BITS - cidr | |
binary_mask = ('1' * ones_count + '0' * zeroes_count).scan(/.{8}/) | |
octets = binary_mask.map { |binary_byte| to_integer(binary: binary_byte) } | |
join_octets(octets) | |
end | |
# Takes an ip address or mask and converts it to binary ip notation. | |
# If invert is true, the result will be inverted. | |
def to_binary(ip) | |
octets = octets_for(ip).each.map { |octet| '%0*b' % [8, octet] } | |
join_octets(octets) | |
end | |
# Takes a binary string and returns the integer equivalent (e.g.) to_integer(binary: '11111110') | |
# # => 254 | |
def to_integer(binary:) | |
Integer("0b#{binary}") | |
end | |
# Takes an ip address or mask string, and returns the octets in an Array. | |
def octets_for(ip) | |
ip = ip.join('.') if octets?(ip) | |
ip.split('.').map do |octet| | |
octet = octet.to_i | |
octet = yield octet if block_given? | |
octet | |
end | |
end | |
# Expects a Fixnum and returns the octet with the bits flipped. | |
def flip_bits(octet) | |
octet ^ 0xff | |
end | |
# Takes an ip address or mask, inverts it, and returns an Array of octets. | |
def invert(ip) | |
octets_for(ip) { |octet| flip_bits(octet) } | |
end | |
# Returns the total number of bits on for this mask; mask is inverted prior to counting tbe | |
# number of bits. No consideration is taken into account for validity of the mask. | |
def bits_on_for(mask:) | |
raise "Argument mask (#{mask}) must respond_to? :split" unless mask.respond_to?(:split) | |
inverted_mask = join_octets(invert(mask)) | |
to_binary(inverted_mask).count('1') | |
end | |
# Returns true if object is an Array, assuming it is an Array of octets (integers). | |
def octets?(object) | |
return false if object.nil? | |
object.is_a?(Array) | |
end | |
# Joins the Array of octets and returns an ip address or mask (e.g. "192.168.1.1"). | |
def join_octets(octets) | |
raise "Argument octets (#{octets}) does not respond_to? :join" unless octets.respond_to?(:join) | |
octets.join('.') | |
end | |
def split_cidr(ip:) | |
ip, cidr =ip.split('/') | |
return ip, cidr.to_i | |
end | |
private_class_method :invert, :bits_on_for, :octets?, :join_octets | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment