Posso criar um arquivo de hosts específicos do usuário para complementar o / etc / hosts?

193

É possível adicionar uma lista de hosts que são específicos apenas para um determinado usuário? Talvez um arquivo de hosts específicos do usuário?

Esse mecanismo também deve complementar as entradas no /etc/hostsarquivo.

redspike
fonte
3
bem, você pode executar servidores de nomes próprios e fazer com que o usuário use servidores de nomes diferentes por resolv.conf específico do usuário - exceto a criação de resolv.conf específico do usuário parece ser tão difícil quanto tornar / etc / hosts específicos do usuário.
SF.
2
Se o servidor for remoto, você pode tentar o arquivo ~ / .ssh / config: nesta postagem .
aaiezza

Respostas:

134

A funcionalidade que você está procurando é implementada na glibc. Você pode definir um arquivo de hosts customizados configurando a HOSTALIASESvariável de ambiente. Os nomes neste arquivo serão selecionados por gethostbyname(consulte a documentação ).

Exemplo (testado no Ubuntu 13.10):

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

Algumas limitações:

  • HOSTALIASESsó funciona para aplicativos que usam getaddrinfo(3)ougethostbyname(3)
  • Quando setuid é usado, o libc limpa o ambiente, o que significa que a HOSTALIASESconfiguração é perdida. ping é root setuid (porque precisa escutar pacotes ICMP), portanto HOSTALIASES, não funcionará com ping, a menos que você já seja root antes de chamá-lo.
pwuertz
fonte
12
Observe que não funciona se você estiver usando nscde está limitado a nomes de host sem um ponto.
Stéphane Chazelas
3
Isso parece não funcionar no CentOS 6
kbolino
3
Tarde para a festa, mas esse é o inverso do que é desejado, não é? Acho que o OP está procurando uma solução semelhante à adição de entradas de resolução de host ao / etc / hosts, mas que pode ser feita na área de usuário sem privilégios escalados. (ie 127.0.0.1 somedomain.com)
Nuri Hodges
Não me lembro, mas hoje em dia o ping não é um binário inteligente no Linux; Ele usa recursos. Se você executar o getcap /usr/sbin/pingque você pode ver algo como: /usr/bin/ping = cap_net_admin,cap_net_raw+p. E tecnicamente é que ele precisa abrir um soquete bruto em vez do ICMP (mas suponho que você possa argumentar que isso é apenas semântica).
Pryftan
1
Apesar de o homem dizer que "o arquivo de alias apontado por HOSTALIASES será primeiro pesquisado por nome", a prioridade é aleatória e, se executar este exemplo do wget, uma dúzia de vezes, ocorrerá um erro.
Nakilon 14/01
43

Ao lado dos LD_PRELOADtruques. Uma alternativa simples que pode funcionar em alguns sistemas seria a edição binária de uma cópia da biblioteca do sistema que lida com a resolução do nome do host para substituir /etc/hostspor um caminho próprio.

Por exemplo, no Linux:

Se você não estiver usando nscd, copie libnss_files.sopara algum local como:

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

(a biblioteca compartilhada pode estar localizada em outro lugar, por exemplo /lib/libnss_files.so.2)

Agora, edite a cópia binária para substituir /etc/hostsnela com algo do mesmo tamanho /tmp/hosts.

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

Edite /tmp/hostspara adicionar a entrada desejada. E use

export LD_LIBRARY_PATH=~/lib

para nss_filesprocurar em /tmp/hostsvez de /etc/hosts.

Em vez de /tmp/hosts, você também pode fazê-lo /dev/fd//3(aqui usando duas barras para que o comprimento de /dev/fd//3seja o mesmo de /etc/hosts) e

exec 3< ~/hosts

Por exemplo, o que permitiria que comandos diferentes usassem hostsarquivos diferentes .

Se nscdestiver instalado e em execução, você pode ignorá-lo fazendo o mesmo truque, mas desta vez libc.so.6e substituindo o caminho para o soquete nscd (algo como /var/run/nscd/socket) por algum caminho inexistente.

Stéphane Chazelas
fonte
12
+1 para audácia, -1 para o valor do choque
fche 27/09/2013
7
+1 para binário patching, -1 para implicações de segurança
tiro Parthian
@ParthianShot, que implicações de segurança?
Stéphane Chazelas
1
@ StéphaneChazelas Alterar LD_LIBRARY_PATHpara apontar para um diretório de propriedade do usuário significa que qualquer outro processo executado pelo usuário pode usar esse diretório para cooptar quaisquer novos processos gerados pela substituição de bibliotecas. E as atualizações libnss_files.soatravés do gerenciador de pacotes (incluindo atualizações de segurança) não serão refletidas na versão corrigida. Modificar LD_LIBRARY_PATHgeralmente é uma coisa ruim a ser recomendada por outros motivos, mas também é imprudente por causa desses problemas.
Tiro parta
13
@ParthianShot, seu ponto sobre a falta de atualizações é um ponto justo. No entanto, para seu outro ponto, se um software não autorizado estiver sendo executado em seu nome, ter acesso de gravação a uma área em $ LD_LIBRARY_PATH seria a menor das suas preocupações, pois ele já tem acesso de gravação a áreas muito piores e mais confiáveis, como o seu .bash *, crontab, .forward, e todos os arquivos de configuração de todo o software que você usa (onde ele pode, por exemplo, definir LD_ {PRELOAD, LIBRARY_}, mas normalmente faria muito pior)
Stéphane Chazelas
25

Espaços de montagem privados criados com o unsharecomando podem ser usados ​​para fornecer um arquivo / etc / hosts privado a um processo de shell e quaisquer processos filhos subsequentes iniciados a partir desse 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
fonte
3
Esperar. Eu pensei que montar apenas sistemas de arquivos montados em diretórios (pontos de montagem). Eu não sabia que um arquivo poderia ser montado em outro arquivo. Isso realmente funciona? (Eu estou pedindo isso a sério Isso não é sarcasmo..)
killermist
6
Sim, funciona, você pode montar um arquivo sobre outro arquivo com --bind.
Frielp
1
Apenas como uma observação para os curiosos: isso tem a ver com espaços para nome; existem os syscalls unshare(2)e clone(2)isso faz parte da mágica aqui. Veja também namespaces(7)e user_namespaces(7).
Pryftan
6

Uma solução é ter cada usuário em separado chroot, para que cada um possa ter um separado /etc/hostspara si.

Pletiplot
fonte
3
Esta poderia ser uma resposta, mas como dito com poucas explicações é mais adequado como um comentário
Anthon
2
Bem ... sim, é factível. Embora o chrooting seja uma solução bastante pesada para esse tipo de coisa. E traz consigo seu próprio conjunto de questões.
Tiro parta
6

Eu enfrentei a mesma necessidade, então tentei o libnss-userhosts, mas ele falha em aplicativos multithread. Portanto, eu escrevi libnss-homehosts . É muito novo e testado apenas por mim. Você pode dar uma chance para isso! Ele suporta algumas opções no /etc/host.conf, vários nomes de alias e resolução reversa (endereço para nome).

bandie
fonte
1
Parece uma boa ideia abordar os mantenedores da libnss e / ou os mantenedores da distribuição. Porém, antes que isso aconteça, os usuários sem raiz não poderão usá-lo. Ainda assim, +1
einpoklum 14/08
4

Colocar o seguinte em ~/.bashrcestá funcionando para mim no bash. Ele converte o nome do host no comando em um endereço com base nas entradas em ~/.hosts. Se ~/.hostsnão existir ou se o nome do host não puder ser encontrado ~/.hosts, o comando será executado normalmente. Isso deve funcionar com os sinalizadores originais das funções relevantes e independentemente de onde o nome do host é colocado em relação aos sinalizadores, por exemplo ping -i 0.5 host1 -c 3, funciona. O ~/.hostsarquivo tem preferência sobre qualquer outro local para localizar nomes de host; portanto, se houver nomes de host duplos, o endereço ~/.hostsserá usado.

$ 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 "$@"
}

Um exemplo de ~/.hostsé dado abaixo. Segue o mesmo formato que /etc/hosts. Comentários e espaço em branco são tratados corretamente.

$ 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
fonte
O git ou wget pode usar esta "resolução"? Ou apenas a sua função que usa a função "resolver"?
Qinsi 02/07
2

Não tenho certeza se isso iria ajudá-lo, mas eu vim aqui procurando uma maneira de adicionar "hosts" salvos em algum lugar que fosse facilmente acessível apenas ao meu usuário.

Basicamente, eu precisava ser capaz de ssh em determinadas caixas em nossa rede de trabalho, que possui apenas um ponto de entrada.

O que fiz foi adicionar aliases ao meu .bashrcarquivo.

Por exemplo, se você adicionou:

alias jrfbox='ssh [email protected]' 

na parte inferior do seu ~/.bashrc( ~é o seu diretório inicial). Depois de sair e fazer login novamente, você pode digitar jrfbox, clicar Entere ele se conectará.

Jason
fonte
14
Se você é interessante especificamente no caso SSH, você deve ver man ssh_config.
Nick
1
Você não precisa sair e entrar novamente para recarregar ~/.bashrc, basta fazer source ~/.bashrc.
user991710
1
@ user991710 Ou para que o assunto. ~/.bashrc
Pryftan