No New Messages
author avatar
Syed Reza
1463252921483 | NOTE

Fetch Default Internal IP Address

Suppose for example that you want the internal IP address of your default interface. There are many ways to go about this, here is one that I currently use and find to be useful. Note, it may be useful to write a series of wrappers for unix commands which strictly outputs things in json or any other machine-friendly format.

Parsing Output from ifconfig

The output from ifconfig is not in a particularly machine-friendly format, like json or yaml. Let's take a look at what output from ifconfig might look like.

Output From ifconfig:

eno1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether xx:xx:xx:xx:xx:xx  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1  (Local Loopback)
        RX packets 18212  bytes 22941391 (21.8 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 18212  bytes 22941391 (21.8 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlo1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.4  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx  prefixlen 64  scopeid 0x0<global>
        inet6 xxxx::xxx:xxxx:xxxx:xxxx  prefixlen 64  scopeid 0x20<link>
        ether xx:xx:xx:xx:xx:xx  txqueuelen 1000  (Ethernet)
        RX packets 119400  bytes 67832986 (64.6 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 89166  bytes 24200211 (23.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Not very machine friendly, but easily parsed. So let's parse it. We will only look at the blocks that have inet address.

#!/usr/bin/env ruby
ifconfig = `ifconfig |grep -B1 'inet '`.split("\n--\n").inject({}) do |s, e| 
  f=e.split("\n");s[f[0][/^\w+/]] = f[1][/\d+\.\d+\.\d+\.\d+/];s
end

This is a bit verbose, and yes we could possibly avoid the pipe to grep, but let's keep going. What we have now is a hash that looks like this:

{"lo"=>"127.0.0.1", "wlo1"=>"192.168.0.4"}

Now all we have to do is get our default interface. This can be accomplished by parsing the output of route as follows:

Ruby Script Continued:

cols = [:destination, :gateway, :genmask, :flags, :metric, :ref, :use, :iface];
route = `route`.split("\n").drop(2).inject({}) do |s, e| 
  e.strip; f=e.split(/\s+/);
  s[f[0]] = f.each_with_index.inject({}) {|s, (e,i)| s[cols[i]]=e;s}
  s;
end

What this gives us is another hash, which looks like this:

{"default"=>
  {:destination=>"default",
   :gateway=>"gateway",
   :genmask=>"0.0.0.0",
   :flags=>"UG",
   :metric=>"303",
   :ref=>"0",
   :use=>"0",
   :iface=>"wlo1"},
 "192.168.0.0"=>
  {:destination=>"192.168.0.0",
   :gateway=>"*",
   :genmask=>"255.255.255.0",
   :flags=>"U",
   :metric=>"303",
   :ref=>"0",
   :use=>"0",
   :iface=>"wlo1"}}

At this point we have everything required to output the internal IP of the default interface:

puts ifconfig[route["default"][:iface]]

All Together Now

#!/usr/bin/env ruby

ifconfig = `ifconfig |grep -B1 'inet '`.split("\n--\n").inject({}) do |s, e| 
  f=e.split("\n");s[f[0][/^\w+/]] = f[1][/\d+\.\d+\.\d+\.\d+/];s
end

cols = [:destination, :gateway, :genmask, :flags, :metric, :ref, :use, :iface];
route = `route`.split("\n").drop(2).inject({}) do |s, e| 
  e.strip; f=e.split(/\s+/);
  s[f[0]] = f.each_with_index.inject({}) {|s, (e,i)| s[cols[i]]=e;s}
  s;
end

puts ifconfig[route["default"][:iface]]

Caveat

This likely not a good way to do this. Here are a bunch of shorter alternatives as answered on unix.stackexchange.com