Могу ли я создать специальный файл hosts для дополнения / etc / hosts?

193

Можно ли добавить список хостов, которые относятся только к определенному пользователю? Возможно, пользовательский файл hosts?

Этот механизм также должен дополнять записи в /etc/hostsфайле.

redspike
источник
3
что ж, вы могли бы вместо этого запускать собственные серверы имен и предлагать пользователю использовать разные серверы имен для каждого конкретного пользователя resolv.conf, за исключением того, что создание конкретного пользовательского resolv.conf кажется таким же трудным, как создание конкретного пользователя / etc / hosts.
SF.
2
Если сервер удаленный, вы можете попробовать файл ~ / .ssh / config: этот пост .
Aaiezza

Ответы:

134

Функциональность, которую вы ищете, реализована в glibc. Вы можете определить собственный файл hosts, установив HOSTALIASESпеременную окружения. Имена в этом файле будут подобраны gethostbyname(см. Документацию ).

Пример (проверено на Ubuntu 13.10):

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

Некоторые ограничения:

  • HOSTALIASESработает только для приложений, использующих getaddrinfo(3)илиgethostbyname(3)
  • Когда используется setuid, libc очищает среду, что означает, что HOSTALIASESнастройка потеряна. ping - это setuid root (потому что он должен прослушивать ICMP-пакеты), поэтому HOSTALIASESон не будет работать с ping, если вы уже не являетесь пользователем root, прежде чем вызывать ping.
pwuertz
источник
12
Обратите внимание, что он не работает, если вы используете, nscdи ограничен именами хостов без точки.
Стефан Шазелас
3
Похоже, это не работает на CentOS 6
kbolino
3
Опоздал на вечеринку, но это не то, что нужно, не так ли? Я думаю, что OP ищет аналогичное решение для добавления разрешающих хост записей в / etc / hosts, но такое, которое может быть сделано в пользовательской среде без повышенных привилегий. (т.е. 127.0.0.1 somedomain.com)
Нури Ходжес
Я не помню тогда, но в наши дни ping не является suid-файлом в Linux; он использует возможности. При запуске getcap /usr/sbin/pingвы можете увидеть что - то вроде: /usr/bin/ping = cap_net_admin,cap_net_raw+p. И технически это то, что ему нужно открывать необработанный сокет, а не ICMP (но я полагаю, вы могли бы поспорить, что это просто семантика).
Прифтан
1
Несмотря на то, что человек говорит, что «файл псевдонимов, на который указывает HOSTALIASES, сначала будет искать имя», приоритет является случайным, и, если запустить этот пример wget, дюжину раз, он пойдет не так.
Накилон
43

Помимо LD_PRELOADтрюков. Простая альтернатива, которая может работать в нескольких системах, заключается в двоичном редактировании копии системной библиотеки, которая обрабатывает разрешение имени хоста, чтобы заменить ее /etc/hostsсобственным путем.

Например, в Linux:

Если вы не используете nscd, скопируйте libnss_files.soв какое-либо место, например:

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

(общая библиотека может быть расположена в другом месте, например /lib/libnss_files.so.2)

Теперь бинарно отредактируйте копию, чтобы заменить ее /etc/hostsна что-то похожее по длине /tmp/hosts.

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

Изменить, /tmp/hostsчтобы добавить запись, которую вы хотите. И использовать

export LD_LIBRARY_PATH=~/lib

для nss_filesсмотреть в /tmp/hostsа /etc/hosts.

Вместо этого /tmp/hostsвы также можете сделать это /dev/fd//3(здесь использовать две косые черты, чтобы длина была /dev/fd//3такой же, как у /etc/hosts), и сделать

exec 3< ~/hosts

Например, который позволил бы различным командам использовать разные hostsфайлы.

Если nscdон установлен и работает, вы можете обойти его, выполнив тот же трюк, но на этот раз libc.so.6и заменив путь к сокету nscd (что-то вроде /var/run/nscd/socket) каким-то несуществующим путем.

Стефан Шазелас
источник
12
+1 для дерзости, -1 для значения шока
fche
7
+1 для бинарного исправления, -1 для последствий для безопасности
Парфянский выстрел
@ParthianShot, какие последствия для безопасности?
Стефан Шазелас
1
@ StéphaneChazelas Изменение LD_LIBRARY_PATHуказателя на каталог, принадлежащий пользователю, означает, что любой другой процесс, запускаемый пользователем, может использовать этот каталог для кооперации любых новых процессов, порожденных путем замены библиотек. А обновления libnss_files.soчерез менеджер пакетов (включая обновления безопасности) не будут отражены в исправленной версии. Модификация, LD_LIBRARY_PATHкак правило, плохая вещь, которую можно рекомендовать по другим причинам, но она также неразумна из-за этих проблем.
Парфянский выстрел
13
@ParthianShot, ваша точка зрения о пропущенных обновлениях - это справедливо. Однако, с другой стороны, если на ваше имя работает мошенническое программное обеспечение, то наличие доступа к записи в области в $ LD_LIBRARY_PATH будет наименьшим из ваших беспокойств, поскольку у него уже есть доступ для записи в гораздо худшие и более надежные области, такие как ваша. .bash *, crontab, .forward и все файлы конфигурации всеми используемыми вами программами (где он может, например, установить LD_ {PRELOAD, LIBRARY_PATH}, но обычно это будет намного хуже)
Стефан Шазелас
25

Личные монтируемые пространства, созданные с помощью unshareкоманды, могут использоваться для предоставления частного файла / etc / hosts для процесса оболочки, а также любые последующие дочерние процессы, запускаемые из этой оболочки.

# 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
источник
3
Подождите. Я думал смонтировать только что смонтированные файловые системы на каталоги (точки монтирования). Я не знал, что файл может быть подключен к другому файлу. Это действительно работает? (Я спрашиваю об этом серьезно. Это не сарказм.)
убийца
6
Да, это работает, вы можете смонтировать файл поверх другого файла с помощью --bind.
frielp
1
Как примечание для любопытных: это связано с пространствами имен; Есть системные вызовы, unshare(2)и clone(2)это часть магии здесь. Смотрите также namespaces(7)и user_namespaces(7).
Прифтан
6

Одно из решений состоит в том, чтобы каждый пользователь был отдельным chroot, чтобы каждый мог иметь отдельного /etc/hostsдля себя.

Pletiplot
источник
3
Это может быть ответом, но, как указано с небольшим объяснением, он больше подходит в качестве комментария
Anthon
2
Ну ... да, это выполнимо. Хотя chroot - довольно мощное решение для такого рода вещей. И приносит с собой свой собственный набор вопросов.
Парфянский выстрел
6

Я столкнулся с такой же потребностью, поэтому я попробовал libnss-userhosts, но это не помогло многопоточным приложениям. Поэтому я написал libnss-homehosts . Это очень новое и проверено только мной. Вы можете дать шанс для этого! Он поддерживает некоторые параметры в /etc/host.conf, несколько псевдонимов и обратное разрешение (адрес к имени).

bandie
источник
1
Похоже, это хорошая идея передать сопровождающим libnss и / или сторонним распространителям. Но до того, как это произойдет, пользователи без рута сами не смогут его использовать. Тем не менее, +1
einpoklum
4

Размещение следующего в ~/.bashrcработает для меня в Bash. Он преобразует имя хоста в команде в адрес на основе записей в ~/.hosts. Если ~/.hostsне существует или если имя хоста не может быть найдено ~/.hosts, команда выполняется как обычно. Это должно работать с исходными флагами соответствующих функций и независимо от того, где размещено имя хоста относительно флагов, например ping -i 0.5 host1 -c 3, работает. ~/.hostsФайл отдается предпочтение перед любым другим местом для нахождения хостов, так что если есть какие - dupicate имен хостов, адрес в ~/.hostsбудет использоваться.

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

Пример ~/.hostsприведен ниже. Это следует в том же формате, что и /etc/hosts. Комментарии и пробелы обрабатываются правильно.

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

192.168.0.1 host1 # this is host1's address
login-node.inst.ac.uk login
Кайл Фернандес
источник
Могут ли git или wget использовать это «разрешение»? Или просто ваша функция, которая использует функцию «разрешить»?
Цинси
2

Не уверен, поможет ли это вам, но я пришел сюда в поисках способа добавления сохраненных «хостов» в такое место, которое было бы легко доступно только моему пользователю.

Мне в основном нужно было иметь возможность подключаться к определенным блокам в нашей рабочей сети, которая имеет только одну точку входа.

Я добавил псевдонимы в мой .bashrcфайл.

Например, если вы добавили:

alias jrfbox='ssh jason@192.168.6.6' 

внизу вашего ~/.bashrc( ~это ваш домашний каталог). Затем, после того как вы выйдете из системы и войдите снова, вы можете напечатать jrfbox, нажать Enter, и она подключится.

Джейсон
источник
14
Если вам интересно именно SSH, вы должны это увидеть man ssh_config.
Ник
1
Вам не нужно выходить из системы и снова входить в нее ~/.bashrc, чтобы перезагрузить компьютер , просто сделайте это source ~/.bashrc.
user991710
1
@ user991710 Или в этом отношении. ~/.bashrc
Pryftan