Skip to content

Instantly share code, notes, and snippets.

@gangelo
Last active January 7, 2022 00:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gangelo/d215f9e7b51a3dc3c9a72191916bd9f4 to your computer and use it in GitHub Desktop.
Save gangelo/d215f9e7b51a3dc3c9a72191916bd9f4 to your computer and use it in GitHub Desktop.
Hacking
# 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