¿Puedo crear un archivo de host específico del usuario para complementar / etc / hosts?

193

¿Es posible agregar una lista de hosts que son específicos para un determinado usuario? ¿Quizás un archivo de host específico del usuario?

Este mecanismo también debe complementar las entradas en el /etc/hostsarchivo.

punta roja
fuente
3
bueno, en su lugar, puede ejecutar sus propios servidores de nombres y hacer que el usuario use diferentes servidores de nombres por resolv.conf específico del usuario, excepto que crear resolv.conf específico del usuario parece ser exactamente tan difícil como hacer / etc / hosts específicos del usuario.
SF.
2
Si el servidor es remoto, puede probar el archivo ~ / .ssh / config: esta publicación .
aaiezza

Respuestas:

134

La funcionalidad que busca se implementa en glibc. Puede definir un archivo de hosts personalizado configurando la HOSTALIASESvariable de entorno. Los nombres en este archivo serán recogidos por gethostbyname(ver documentación ).

Ejemplo (probado en Ubuntu 13.10):

$ echo 'g www.google.com' >> ~/.hosts
$ export HOSTALIASES=~/.hosts
$ wget g -O /dev/null

Algunas limitaciones

  • HOSTALIASESsolo funciona para aplicaciones que usan getaddrinfo(3)ogethostbyname(3)
  • Cuando se usa setuid, libc desinfecta el entorno, lo que significa que HOSTALIASESse pierde la configuración. ping es root setuid (porque necesita escuchar paquetes ICMP), por HOSTALIASESlo que no funcionará con ping a menos que ya sea root antes de llamar a ping.
pwuertz
fuente
12
Tenga en cuenta que no funciona si está utilizando nscdy está limitado a nombres de host sin un punto.
Stéphane Chazelas
3
Esto no parece funcionar en CentOS 6
kbolino
3
Tarde a la fiesta, pero esto es lo contrario de lo que se desea, ¿no? Creo que OP está buscando una solución similar para agregar entradas de resolución de host a / etc / hosts, pero que se puede hacer en el país de usuario sin privilegios escalados. (es decir 127.0.0.1 somedomain.com)
Nuri Hodges
No recuerdo entonces, pero estos días ping no es un binario suid en Linux; Utiliza capacidades. Si ejecuta getcap /usr/sbin/pingse puede ver algo como: /usr/bin/ping = cap_net_admin,cap_net_raw+p. Y técnicamente es que necesita abrir un socket sin procesar en lugar de ICMP (pero supongo que podría argumentar que es solo semántica).
Pryftan
1
A pesar de que el hombre dice "primero se buscará el nombre del archivo de alias señalado por HOSTALIAS", la prioridad es aleatoria y si ejecuta este ejemplo de wget una docena de veces, sale mal.
Nakilon
43

Al lado de los LD_PRELOADtrucos. Una alternativa simple que puede funcionar en algunos sistemas sería editar binariamente una copia de la biblioteca del sistema que maneja la resolución del nombre de host para reemplazarla /etc/hostspor una ruta propia.

Por ejemplo, en Linux:

Si no está utilizando nscd, copie libnss_files.soen alguna ubicación propia como:

mkdir -p -- ~/lib &&
cp /lib/x86_64-linux-gnu/libnss_files.so.2 ~/lib

(la biblioteca compartida puede estar ubicada en otro lugar, por ejemplo /lib/libnss_files.so.2)

Ahora, edite binariamente la copia para reemplazarla /etc/hostspor algo de la misma longitud /tmp/hosts.

perl -pi -e 's:/etc/hosts:/tmp/hosts:g' ~/lib/libnss_files.so.2

Editar /tmp/hostspara agregar la entrada que desee. Y use

export LD_LIBRARY_PATH=~/lib

para nss_filesmirar en /tmp/hostslugar de /etc/hosts.

En lugar de /tmp/hosts, también podría hacerlo /dev/fd//3(aquí usando dos barras inclinadas para que la longitud de /dev/fd//3sea ​​la misma que la de /etc/hosts), y haga

exec 3< ~/hosts

Por ejemplo, lo que permitiría que diferentes comandos usen diferentes hostsarchivos.

Si nscdestá instalado y ejecutándose, puede omitirlo haciendo el mismo truco, pero esta vez libc.so.6y reemplazando la ruta al zócalo nscd (algo así como /var/run/nscd/socket) con alguna ruta inexistente.

Stéphane Chazelas
fuente
12
+1 para audacia, -1 para el valor de choque
fche
77
+1 para parches binarios, -1 por implicaciones de seguridad
Parthian Shot
@ParthianShot, ¿qué implicaciones de seguridad?
Stéphane Chazelas
1
@ StéphaneChazelas Cambiar LD_LIBRARY_PATHpara apuntar a un directorio propiedad del usuario significa que cualquier otro proceso ejecutado por el usuario puede usar ese directorio para cooptar cualquier proceso nuevo generado al reemplazar las bibliotecas. Y las actualizaciones a libnss_files.sotravés del administrador de paquetes (incluidas las actualizaciones de seguridad) no se reflejarán en la versión parcheada. En LD_LIBRARY_PATHgeneral, modificar es algo malo por otras razones, pero también es imprudente debido a esos problemas.
Parthian Shot
13
@ParthianShot, su punto sobre las actualizaciones faltantes es un punto justo. Sin embargo, para su otro punto, si se está ejecutando un software malintencionado en su nombre, tener acceso de escritura a un área en $ LD_LIBRARY_PATH sería la menor de sus preocupaciones ya que ya tiene acceso de escritura a áreas mucho peores y más confiables como su .bash *, crontab, .forward y todos los archivos de configuración de todo el software que utiliza (donde, por ejemplo, puede establecer LD_ {PRELOAD, LIBRARY_PATH}, pero normalmente sería mucho peor)
Stéphane Chazelas
25

Los espacios de montaje privados creados con el unsharecomando se pueden usar para proporcionar un archivo privado / etc / hosts a un proceso de shell y cualquier proceso secundario posterior iniciado desde ese shell.

# Start by creating your custom /etc/hosts file
[user] cd ~
[user] cat >my_hosts <<EOF
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
127.0.0.1 news.bbc.co.uk
EOF

[user] sudo unshare --mount
# We're now running as root in a private mountspace. 
# Any filesystem mounts performed in this private mountspace
# are private to this shell process and its children

# Use a bind mount to install our custom hosts file over /etc/hosts
[root] mount my_hosts /etc/hosts --bind

[root] cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
127.0.0.1 news.bbc.co.uk

[root] exec su - appuser

[appuser] # Run your app here that needs a custom /etc/hosts file

[appuser] ping news.bbc.co.uk
PING news.bbc.co.uk (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.026 ms
^C
--- news.bbc.co.uk ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.026/0.044/0.062/0.018 ms
frielp
fuente
3
Espere. Pensé que mount solo montaba sistemas de archivos en directorios (puntos de montaje). No sabía que un archivo podría montarse en otro archivo. ¿Eso realmente funciona? (Lo pido en serio. Eso no es sarcasmo)
Asesino
66
Sí, funciona, puede montar un archivo sobre otro archivo con --bind.
frielp
1
Solo como una nota para los curiosos: esto tiene que ver con espacios de nombres; están los syscalls unshare(2)y clone(2)eso es parte de la magia aquí. Ver también namespaces(7)y user_namespaces(7).
Pryftan
6

Una solución es tener a cada usuario en un sitio separado chroot, para que cada uno pueda tener un sitio separado /etc/hostspara ellos.

Pletiplot
fuente
3
Esto podría ser una respuesta, pero como se indica con poca explicación, es más adecuado como comentario
Anthon,
2
Bueno ... sí, es factible. Aunque el chrooting es una solución bastante resistente para este tipo de cosas. Y trae consigo su propio conjunto de problemas.
Parthian Shot
6

Enfrenté la misma necesidad, así que probé libnss-userhosts, pero falla en aplicaciones multiproceso. Por eso he escrito libnss-homehosts . Es muy nuevo y probado solo por mí. ¡Puedes darle una oportunidad! Admite algunas opciones en /etc/host.conf, múltiples nombres de alias y resolución inversa (dirección a nombre).

bandolera
fuente
1
Esto parece una buena idea para lanzar a los mantenedores de libnss y / o mantenedores de distribución. Pero antes de que eso suceda, los usuarios sin root no podrán usarlo. Aún así, +1
einpoklum
4

Colocar lo siguiente ~/.bashrcestá funcionando para mí en bash. Convierte el nombre de host en el comando en una dirección basada en las entradas en ~/.hosts. Si ~/.hostsno existe o si no se puede encontrar el nombre de host ~/.hosts, el comando se ejecuta normalmente. Esto debería funcionar con los indicadores originales de las funciones relevantes y sin importar dónde se coloque el nombre de host en relación con los indicadores, por ejemplo ping -i 0.5 host1 -c 3, funciona. El ~/.hostsarchivo tiene preferencia sobre cualquier otra ubicación para encontrar nombres de host, por lo que si hay nombres de host duplicados, ~/.hostsse utilizará la dirección .

$ cat ~/.bashrc 
function resolve {
        hostfile=~/.hosts
        if [[ -f "$hostfile" ]]; then
                for arg in $(seq 1 $#); do
                        if [[ "${!arg:0:1}" != "-" ]]; then
                                ip=$(sed -n -e "/^\s*\(\#.*\|\)$/d" -e "/\<${!arg}\>/{s;^\s*\(\S*\)\s*.*$;\1;p;q}" "$hostfile")
                                if [[ -n "$ip" ]]; then
                                        command "${FUNCNAME[1]}" "${@:1:$(($arg-1))}" "$ip" "${@:$(($arg+1)):$#}"
                                        return
                                fi
                        fi
                done
        fi
        command "${FUNCNAME[1]}" "$@"
}

function ping {
        resolve "$@"
}

function traceroute {
        resolve "$@"
}

Un ejemplo de ~/.hostsse da a continuación. Sigue el mismo formato que /etc/hosts. Los comentarios y los espacios en blanco se manejan correctamente.

$ cat ~/.hosts 
# addresses and hostnames
stackexchange.com se

192.168.0.1 host1 # this is host1's address
login-node.inst.ac.uk login
Kyle Fernandes
fuente
¿Puede git o wget usar esta "resolución"? ¿O simplemente su función que utiliza la función "resolver"?
Qinsi
2

No estoy seguro de si esto podría ayudarlo, pero vine aquí buscando una manera de agregar "hosts" guardados en algún lugar que fuera fácilmente accesible solo para mi usuario.

Básicamente, necesitaba poder ingresar a ciertos cuadros en nuestra red de trabajo, que solo tiene un punto de entrada.

Lo que hice fue agregar alias a mi .bashrcarchivo.

Por ejemplo, si agregó:

alias jrfbox='ssh [email protected]' 

en la parte inferior de su ~/.bashrc( ~es su directorio de inicio). Luego, después de cerrar sesión y volver a iniciar sesión, puede escribir jrfbox, presionar Entery se conectará.

Jason
fuente
14
Si está interesado específicamente en el caso de SSH, debería ver man ssh_config.
Nick
1
No tiene que cerrar sesión y volver a iniciarla para volver a cargar ~/.bashrc, simplemente hágalo source ~/.bashrc.
user991710
1
@ user991710 O para el caso. ~/.bashrc
Pryftan