Obtener el nombre de host o la IP en Ruby on Rails

80

Estoy en el proceso de mantener una aplicación Ruby on Rails y estoy buscando una manera fácil de encontrar el nombre de host o la dirección IP de la caja en la que estoy (ya que es una máquina virtual y las nuevas instancias pueden tener diferentes nombres de host o direcciones IP) . ¿Existe una forma rápida y sencilla de hacer esto en Ruby on Rails?

Editar: la respuesta a continuación es correcta, pero la aclaración que proporcionó Craig es útil (consulte también el enlace proporcionado en la respuesta):

El código [a continuación] NO establece una conexión ni envía ningún paquete (al 64.233.187.99 que es Google). Dado que UDP es un protocolo sin estado, connect () simplemente realiza una llamada al sistema que descubre cómo enrutar los paquetes en función de la dirección y a qué interfaz (y por lo tanto la dirección IP) debe unirse. addr () devuelve una matriz que contiene la familia (AF_INET), el puerto local y la dirección local (que es lo que queremos) del socket.

Chris Bunch
fuente

Respuestas:

50

Desde coderrr.wordpress.com :

require 'socket'

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 '64.233.187.99', 1
    s.addr.last
  end
ensure
  Socket.do_not_reverse_lookup = orig
end

# irb:0> local_ip
# => "192.168.0.127"
titánico
fuente
1
@ user422543 Según la edición de la pregunta anterior, la dirección IP pertenece a Google.
Topher Fangio
137

Nombre de host

Una forma sencilla de obtener el nombre de host en Ruby es:

require 'socket'
hostname = Socket.gethostname

El problema es que esto depende de que el host conozca su propio nombre porque usa la llamada al sistema gethostnameo uname, por lo que no funcionará para el problema original.

Funcionalmente, esto es idéntico a la hostnamerespuesta, sin invocar un programa externo. El nombre de host puede estar completamente calificado o no, según la configuración de la máquina.


Dirección IP

Desde ruby ​​1.9, también puede usar la biblioteca Socket para obtener una lista de direcciones locales. ip_address_listdevuelve una matriz de objetos AddrInfo . La forma en que elija dependerá de lo que quiera hacer y de cuántas interfaces tenga, pero aquí hay un ejemplo que simplemente selecciona la primera dirección IP IPV4 sin bucle invertido como una cadena:

require 'socket'
ip_address = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
Tim Peters
fuente
Socket.gethostname no siempre devuelve el FQDN. Usar 'hostname'.strip puede ser más confiable si se desea el FQDN.
Travis Bear
Enchufe. gethostname aparentemente no siempre es estable, vea los comentarios stackoverflow.com/q/14112955/32453
rogerdpack
Página oficial del documento: ruby-doc.org/stdlib/libdoc/socket/rdoc/…
HarlemSquirrel
24

Prueba esto:

host = `hostname`.strip # Get the hostname from the shell and removing trailing \n
puts host               # Output the hostname
John Topley
fuente
4
Me gusta socket.gethostname por la pureza, pero por una simple búsqueda en un sistema donde se sabe que hostnamese va a trabajar, no se puede superar, por simplicidad
David Smylie
también podrías hacer uname -n.sub (/\..*/, '')
Tilo
13

Un servidor suele tener más de una interfaz, al menos una privada y una pública.

Dado que todas las respuestas aquí tratan con este escenario simple, una forma más limpia es pedirle a Socket la corriente ip_address_list()como en:

require 'socket'

def my_first_private_ipv4
  Socket.ip_address_list.detect{|intf| intf.ipv4_private?}
end

def my_first_public_ipv4
  Socket.ip_address_list.detect{|intf| intf.ipv4? and !intf.ipv4_loopback? and !intf.ipv4_multicast? and !intf.ipv4_private?}
end

Ambos devuelven un objeto Addrinfo, por lo que si necesita una cadena, puede usar el ip_address()método, como en:

ip= my_first_public_ipv4.ip_address unless my_first_public_ipv4.nil?

Puede encontrar fácilmente la solución más adecuada para su caso cambiando los métodos de Addrinfo utilizados para filtrar la dirección de interfaz requerida.

Claudio Floreani
fuente
9

Esta dirección IP utilizada aquí es de Google, pero puede usar cualquier IP accesible.

require "socket"
local_ip = UDPSocket.open {|s| s.connect("64.233.187.99", 1); s.addr.last}
DD-Doug
fuente
8

El más simple está host_with_porten controller.rb

host_port= request.host_with_port
Salil
fuente
2
La desventaja es que tienes que estar en el controlador para acceder a la solicitud ... ¡pero buena idea!
Tilo
Parece que las otras respuestas son solo trucos, mientras que esto lo hace de la manera correcta. ¿Por qué está enterrado debajo de ellos?
tbodt
2

La respuesta aceptada funciona, pero debe crear un conector para cada solicitud y no funciona si el servidor está en una red local y / o no está conectado a Internet. Lo siguiente, creo que siempre funcionará ya que está analizando el encabezado de la solicitud.

request.env["SERVER_ADDR"]
hacintosh
fuente
3
El OP en realidad no dijo que tenían acceso al objeto de solicitud en el punto donde necesita la dirección IP. Las soluciones basadas en Socket son más genéricas
Chris McCauley
2

Ponga la parte resaltada con comillas invertidas:

`dig #{request.host} +short`.strip # dig gives a newline at the end

O simplemente request.hostsi no te importa si es una IP o no.

Sai
fuente
2

Similar a la respuesta usando hostname, usando el unamecomando externo en UNIX / LINUX:

hostname = `uname -n`.chomp.sub(/\..*/,'')  # stripping off "\n" and the network name if present

para las direcciones IP en uso (su máquina podría tener múltiples interfaces de red), podría usar algo como esto:

 # on a Mac:
 ip_addresses = `ifconfig | grep 'inet ' | grep -v 127.0.0.1 | cut -d' ' -f 2`.split
 => ['10.2.21.122','10.8.122.12']

 # on Linux:
 ip_addresses = `ifconfig -a | grep 'inet ' | grep -v 127.0.0.1 | cut -d':' -f 2 | cut -d' ' -f 1`.split
 => ['10.2.21.122','10.8.122.12']
Tilo
fuente
1

Es probable que tenga varias direcciones IP en cada máquina (127.0.0.1, 192.168.0.1, etc.). Si está usando * NIX como su sistema operativo, le sugiero que lo use hostnamey luego ejecute una búsqueda de DNS en eso. Debería poder usar / etc / hosts para definir el nombre de host local para resolverlo en la dirección IP de esa máquina. Hay una funcionalidad similar en Windows, pero no la he usado desde que Windows 95 fue la vanguardia.

La otra opción sería acceder a un servicio de búsqueda como WhatIsMyIp.com . Estos chicos le devolverán su dirección IP del mundo real. Esto también es algo que puede configurar fácilmente con un script Perl en un servidor local si lo prefiere. Creo que unas 3 líneas de código para generar la IP remota desde% ENV deberían cubrirlo.

Jack M.
fuente
WhatIsMyIP.com no funcionará si no hay acceso a Internet externo.
The Tin Man
1
io = IO.popen('hostname')
hostname = io.readlines

io = IO.popen('ifconfig')
ifconfig = io.readlines
ip = ifconfig[11].scan(/\ \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\ /)

El par de respuestas se require 'socket've bien. Los que tienen request.blah_blah_blah asumen que estás usando Rails.

IO debería estar disponible todo el tiempo. El único problema con este script sería que si ifconfigse genera en una mansión diferente en sus sistemas, entonces obtendría resultados diferentes para la IP. La búsqueda de nombre de host debe ser sólida como Sears.

Kevin Krauss
fuente
0

prueba: Request.remote_ip

IP remota()

Determine la dirección IP de origen. REMOTE_ADDR es el estándar, pero fallará si el usuario está detrás de un proxy. HTTP_CLIENT_IP y / o HTTP_X_FORWARDED_FOR son configurados por proxies, así que verifíquelos si REMOTE_ADDR es un proxy. HTTP_X_FORWARDED_FOR puede ser una lista delimitada por comas en el caso de múltiples proxies encadenados; la última dirección que no es de confianza es la IP de origen.

Actualización: Vaya, lo siento, leí mal la documentación.

Craig
fuente
Esto le da la dirección IP de un usuario que envía una solicitud a la aplicación Rails, no la dirección IP de la máquina que ejecuta la aplicación Rails.
tarros