Module 0x3 | Network Kung Fu

IP Address Operation

In network programming, we always perform some operations on IP addresses. Following are some examples.

  • Calculating network prefix of an IP address from IP address and subnet mask.
  • Calculating the host part of an IP address from IP address and subnet mask.
  • Calculating the number of hosts in a subnet.
  • Check whether an IP address belongs to a subnet or not.
  • Converting subnet mask from dot-decimal notation to integer.

Ruby provides class(IPAddr) for basic operations on IP address that can be used to perform all operations mentioned above.

  1. require 'ipaddr'
  2. ip = IPAddr.new("192.34.56.54/24")

Calculating network prefix of an IP address from IP address and subnet mask.

A simple mask method call will give us the network prefix part of IP address. It is simply a bitwise mask of IP address with subnet mask.

  1. require 'ipaddr'
  2. ip = IPAddr.new(ARGV[0])
  3. network_prefix = ip.mask(ARGV[1])
  4. puts network_prefix

Run it

  1. ruby ip_example.rb 192.168.5.130 24
  2. # Returns
  3. 192.168.5.0

Calculating the host part of an IP address from IP address and subnet mask.

calculating the host part is not as trivial as the network part of the IP address. We first calculate the complement of subnet mask.

Subnet(24) : 11111111.11111111.11111111.00000000

neg_subnet(24) : 00000000.00000000.00000000.11111111

we used negation(~) and mask method to calculate complement of subnet mask then simply performed a bitwise AND between the IP and complement of subnet

  1. require 'ipaddr'
  2. ip = IPAddr.new(ARGV[0])
  3. neg_subnet = ~(IPAddr.new("255.255.255.255").mask(ARGV[1]))
  4. host = ip & neg_subnet
  5. puts host

Run it

  1. ruby ip_example.rb 192.168.5.130 24
  2. # Returns
  3. 0.0.0.130

Calculating the number of hosts in a subnet.

We used to_range method to create a range of all the IPs then count method to count the IPs in range. We reduced the number by two to exclude the gateway and broadcast IP address.

  1. require 'ipaddr'
  2. ip=IPAddr.new("0.0.0.0/#{ARGV[0]}")
  3. puts ip.to_range.count-2

Run it

  1. ruby ip_example.rb 24
  2. 254

Check whether an IP address belong to a subnet or not.

=== is an alias of include? which returns true if ip address belongs to the range otherwise it returns false.

  1. require 'ipaddr'
  2. net=IPAddr.new("#{ARG[0]}/#{ARGV[1]}")
  3. puts net === ARGV[2]

Run it

  1. ruby ip_example.rb 192.168.5.128 24 192.168.5.93
  2. true
  1. ruby ip_example.rb 192.168.5.128 24 192.168.6.93
  2. false

Converting subnet mask from dot-decimal notation to integer.

We treated subnet mask as ip address and converted it into an integer by using to_i then used to_s(2) to convert the integer into binary form. Once we had the binary we counted the number of occurrence of digit 1 with count("1").

  1. require 'ipaddr'
  2. subnet_mask = IPAddr.new(ARGV[0])
  3. puts subnet_mask.to_i.to_s(2).count("1").to_s

Run it

  1. ruby ip_example.rb 255.255.255.0
  2. 24

Converting IP to another formats

IP Decimal to Dotted notation

  1. require 'ipaddr'
  2. IPAddr.new(3232236159, Socket::AF_INET).to_s

or

  1. [3232236159].pack('N').unpack('C4').join('.')

IP Dotted notation to Decimal

  1. require 'ipaddr'
  2. IPAddr.new('192.168.2.127').to_i

This part has been pretty quoted from IP address Operations in Ruby topic

IP Geolocation

you may need to know more information about IP location due attack investigation or any other reason.

GeoIP

The special thing about geoip lib is that it’s an API for offline database you download from www.maxmind.com. There are few free databases from MaxMind whoever you can have a subscription database version though.

  • Install geoip gem

    1. gem install geoip
  • Usage

  1. #!/usr/bin/env ruby
  2. ip = ARGV[0]
  3. geoip = GeoIP.new('GeoLiteCity.dat')
  4. geoinfo = geoip.country(ip).to_hash
  5. puts "IP address:\t" + geoinfo[:ip]
  6. puts "Country:\t" + geoinfo[:country_name]
  7. puts "Country code:\t" + geoinfo[:country_code2]
  8. puts "City name:\t" + geoinfo[:city_name]
  9. puts "Latitude:\t" + geoinfo[:latitude]
  10. puts "Longitude:\t" + geoinfo[:longitude]
  11. puts "Time zone:\t" + geoinfo[:timezone]
  1. -> ruby ip2location.rb 108.168.255.243
  2. IP address: 108.168.255.243
  3. Country: United States
  4. Country code: US
  5. City name: Dallas
  6. Latitude: 32.9299
  7. Longitude: -96.8353
  8. Time zone: America/Chicago