29

I have searched everywhere but their solution requires some form of IP address. Here are the solutions i have found.

    require 'socket'
#METHOD 1
    ip = IPSocket.getaddress(Socket.gethostname)
    puts ip 

#METHOD 2
    host = Socket.gethostname
    puts host

#METHOD 3(uses Google's address)
    ip = UDPSocket.open {|s| s.connect("64.233.187.99", 1); s.addr.last}
    puts ip

#METHOD 4(uses gateway address)
    def local_ip
      orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true  # turn off reverse DNS resolution temporarily

      UDPSocket.open do |s|
        s.connect '192.168.1.1', 1
        s.addr.last
      end
    ensure
      Socket.do_not_reverse_lookup = orig
    end

    ip=local_ip
    puts ip

All of them require IP address of someone. Is there a solution that does not use someone else's IP address? Preferably, platform independent.

user1535147
  • 1,325
  • 5
  • 14
  • 21
  • 2
    What "IP address of someone" does the first one require? Also, who said that gateways are always at 192.168.1.1 – Matti Virkkunen Jan 01 '13 at 18:17
  • This http://rubygems.org/gems/system-getifaddrs might help. – alk Jan 01 '13 at 18:23
  • Local or global? (eg. 192.168.1.23 or 75.75.75.64)? – Linuxios Jan 01 '13 at 18:35
  • 1
    what wrong with method 1? – Eugene Rourke Jan 01 '13 at 18:50
  • 1
    @EvgeniyRyzhkov: Verbatim from the docs (http://docs.python.org/2/library/socket.html): "*... If you want to know the current machine’s IP address, you may want to use gethostbyname(gethostname()). This operation assumes that there is a valid address-to-host mapping for the host, and the assumption does not always hold.*". Please note the **last seven words**. – alk Jan 01 '13 at 19:01
  • UDPSocket.connect(someone else's IP) doesn't actually connect, UDP being famously connectionless. So the use of someone else's IP, while inelegant, is functionally harmless. Well, elegance has a value, but using 0.0.0.0 or 127.0.0.1, as suggested by some answers at https://superuser.com/questions/698244/ip-address-that-is-the-equivalent-of-dev-null, doesn't work here. – Martin Dorey Apr 06 '17 at 16:54

5 Answers5

49

Isn't the solution you are looking for just:

require 'socket'

addr_infos = Socket.ip_address_list

Since a machine can have multiple interfaces and multiple IP Addresses, this method returns an array of Addrinfo.

You can fetch the exact IP addresses like this:

addr_infos.each do |addr_info|
  puts addr_info.ip_address
end

You can further filter the list by rejecting loopback and private addresses, as they are usually not what you're interested in, like so:

addr_infos.reject( &:ipv4_loopback? )
          .reject( &:ipv6_loopback? )
          .reject( &:ipv4_private? )
Itay Grudev
  • 7,055
  • 4
  • 54
  • 86
31

This is what I've been using in production for years:

require 'socket'
ip = Socket.ip_address_list.detect{|intf| intf.ipv4_private?}
ip.ip_address

Works great; tested on aws and classical hosting

yegor256
  • 102,010
  • 123
  • 446
  • 597
fuzzygroup
  • 1,109
  • 12
  • 12
  • appears it uses getifaddrs under the covers, FWIW. See also http://stackoverflow.com/a/7809076/32453 if you are looking for a public ipv4 – rogerdpack Feb 24 '17 at 18:37
16
require 'socket'
Socket::getaddrinfo(Socket.gethostname,"echo",Socket::AF_INET)[0][3]

quite like method 1, actually

Eugene Rourke
  • 4,934
  • 1
  • 22
  • 24
1

As there is no such thing as a default ip-interface to a host (there does not need to be any ip-interface at all actually) all assumptions regarding nameing are vague, do not necessarily hold.

The value returned by gethostname() can be defined independently to any ip-setup, so it does not need to reflect a valid host in terms of a hostname which could be resolved to any ip-address.

From the POSIX system's API's view the only reliabe function to test for the availablily of (ip-)interfaces is the function getifaddrs(), which returns a list of all interfaces along with their parameters.

As it looks as if Ruby's current Socket lib does not provide an interface to it, this (http://rubygems.org/gems/system-getifaddrs) gem based approach does seem to be the only way to go.

alk
  • 69,737
  • 10
  • 105
  • 255
0

parse the output of the ip command?

from https://gist.github.com/henriquemenezes/a99f13da957515023e78aea30d6c0a48

gw = `ip route show`[/default.*/][/\d+\.\d+\.\d+\.\d+/]

or parse the output of the ipconfig command: https://stackoverflow.com/a/12632929/32453

Community
  • 1
  • 1
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
  • 1
    Won't that give you the ip address of the gateway for the default interface, not the ip address of the default interface? – Thayne Jun 12 '17 at 21:26
  • man, what did you paste? This is the default GW, and if you have multiple default GW you need to check the one with lowest metric – maxadamo Mar 23 '20 at 22:35