Подтвердить что ты не робот

Как я могу заставить разрешение DNS работать внутри Mac OS X `chroot` на El Capitan?

Я пытаюсь создать chroot для запуска программы, которая нуждается в доступе в Интернет, чтобы создать изолированную, неизменяемую среду разработчика. Пока моя тюрьма работает хорошо: я могу запустить bash внутри нее и запускать простые программы оттуда! Однако разрешение DNS не работает:

bash-3.2$ curl google.ca
curl: (6) Could not resolve host: google.ca

Я почти уверен, что это связано с тем, что внутренний процесс не может подключиться к демонам mDNSResponder, запущенным вне тюрьмы. Вне тюрьмы есть сокет mDNSResponder для всей системы:

host ➜  ls -lA /var/run/mDNSResponder
srw-rw-rw-  1 root  daemon  0 22 Oct 10:41 /var/run/mDNSResponder

Но внутри тюрьмы нет. Итак, я попытался использовать socat для создания прокси-сервера unix изнутри тюрьмы вне его: я запускаю socat (команда ниже), чтобы создать сокет внутри моей тюрьмы, а затем снова внутри curl jail run curl, но curl все равно дает такое же сообщение об ошибке. Я вижу это в syslog после включения подробного ведения журнала mDNSResponder с SIGUSR1:

2015-10-26 5:32:30.835 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 0
2015-10-26 5:32:30.835 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23271](socat)
2015-10-26 5:32:30.836 PM mDNSResponder[95]:  12: read_msg: ERROR failed to get errsd via SCM_RIGHTS
2015-10-26 5:32:30.836 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23271](socat)
2015-10-26 5:32:30.836 PM mDNSResponder[95]:  12: Removing FD
2015-10-26 5:32:31.339 PM curl[23269]: dnssd_clientstub read_all(5) failed 0/4 0 
2015-10-26 5:32:31.339 PM curl[23269]: dnssd_clientstub write_all(4) failed -1/28 32 Broken pipe
2015-10-26 5:32:31.341 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 0
2015-10-26 5:32:31.341 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23272](socat)
2015-10-26 5:32:31.342 PM mDNSResponder[95]:  12: read_msg: ERROR failed to get errsd via SCM_RIGHTS
2015-10-26 5:32:31.342 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23272](socat)
2015-10-26 5:32:31.342 PM mDNSResponder[95]:  12: Removing FD
2015-10-26 5:32:31.844 PM curl[23269]: dnssd_clientstub read_all(5) failed 0/4 0 
2015-10-26 5:32:31.846 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 0
2015-10-26 5:32:31.846 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23274](socat)
2015-10-26 5:32:31.847 PM mDNSResponder[95]:  12: read_msg: ERROR failed to get errsd via SCM_RIGHTS
2015-10-26 5:32:31.847 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23274](socat)
2015-10-26 5:32:31.847 PM mDNSResponder[95]:  12: Removing FD
2015-10-26 5:32:32.349 PM curl[23269]: dnssd_clientstub read_all(5) failed 0/4 0 
2015-10-26 5:32:32.350 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 0
2015-10-26 5:32:32.351 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23275](socat)
2015-10-26 5:32:33.361 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23275](socat)
2015-10-26 5:32:33.361 PM mDNSResponder[95]:  12: Removing FD

который выглядит как curl через dnssd_clientstub, пытается три раза разрешить имя. Здесь журнал socat, в то время как процесс тюрьмы пытался подключиться:

host ~/C/jail (master*) ➜
sudo socat -v -d -d UNIX-LISTEN:/Users/hornairs/Code/jail/jail-test/private/var/run/mDNSResponder,mode=666,fork,user=root,group=daemon UNIX-CLIENT:/private/var/run/mDNSResponder
Password:
2015/10/26 18:16:03 socat[24334] N listening on LEN=67 AF=1 "/Users/hornairs/Code/jail/jail-test/private/var/run/mDNSResponder"
2015/10/26 18:16:07 socat[24334] N accepting connection from LEN=16 AF=1 "" on LEN=67 AF=1 "/Users/hornairs/Code/jail/jail-test/private/var/run/mDNSResponder"
2015/10/26 18:16:07 socat[24334] N forked off child process 24341
2015/10/26 18:16:07 socat[24334] N listening on LEN=67 AF=1 "/Users/hornairs/Code/jail/jail-test/private/var/run/mDNSResponder"
2015/10/26 18:16:07 socat[24341] N opening connection to LEN=32 AF=1 "/private/var/run/mDNSResponder"
2015/10/26 18:16:07 socat[24341] N successfully connected from local address LEN=16 AF=1 ""
2015/10/26 18:16:07 socat[24341] N starting data transfer loop with FDs [6,6] and [5,5]
> 2015/10/26 18:16:07.081847  length=28 from=0 to=27
............................< 2015/10/26 18:16:07.082019  length=4 from=0 to=3
....> 2015/10/26 18:16:07.082167  length=50 from=28 to=77
...............\b...............P.....google.ca....> 2015/10/26 18:16:07.082287  length=1 from=78 to=78
.2015/10/26 18:16:07 socat[24341] N socket 2 (fd 5) is at EOF
2015/10/26 18:16:07 socat[24341] N exiting with status 0
2015/10/26 18:16:07 socat[24334] N childdied(): handling signal 20

Для сравнения, вот какой успешный поиск выглядит, когда я запускаю его с хоста:

2015-10-26 5:31:56.524 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 501
2015-10-26 5:31:56.524 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23190](curl)
2015-10-26 5:31:56.524 PM mDNSResponder[95]:  12: Result code socket 27 created 00000000 00000001
2015-10-26 5:31:56.524 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(15000, 0, google.ca., Addr) START PID[23190]()
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: Result code socket 27 closed  00000000 00000001 (0)
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., Addr) ADD    4 google.ca. Addr 74.216.233.251
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., Addr) ADD    4 google.ca. Addr 74.216.233.249
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., Addr) ADD    4 google.ca. Addr 74.216.233.227
*snip*
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: Result code socket 27 created 00000000 00000002
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(15000, 0, google.ca., AAAA) START PID[23190]()
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: Result code socket 27 closed  00000000 00000002 (0)
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., AAAA) ADD   16 google.ca. AAAA 2607:F8B0:400B:080A:0000:0000:0000:100F
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: Cancel 00000000 00000001
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., Addr) STOP PID[23190]()
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: Cancel 00000000 00000002
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., AAAA) STOP PID[23190]()
2015-10-26 5:31:56.587 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23190](curl)
2015-10-26 5:31:56.587 PM mDNSResponder[95]:  12: Removing FD

Основные различия, которые я замечаю между неудачей и успехом, заключаются в том, что uid равен 0 для запроса внутри тюрьмы и 501 для запроса вне его. Любопытно, но это не похоже на то, где запрос действительно терпит неудачу.

Сообщение об ошибке, появившееся из mDNSResponder, похоже, связано с получением errsd из входящего запроса через сокет. https://github.com/jevinskie/mDNSResponder/blob/2942dde61f920fbbf96ff9a3840567ebbe7cb1b6/mDNSShared/uds_daemon.c#L3660

На данный момент мне кажется, что mDNSResponder ожидает, что его клиенты передадут ему пару fd через сокет, чтобы ответить клиенту, и я не уверен, что это возможно даже изнутри chroot. Я очень плохо программист на С, поэтому я мог ошибаться в этом, но если это правда, возможно ли это сделать, и есть ли лучший способ заставить DNS работать внутри chroot?

Другие лакомые кусочки:

  • Вы можете настроить mDNSResponder для прослушивания более одного сокета в файле запуска plist, но этот файл теперь защищен системой Integrity Protection, которую я не хочу отключать, чтобы заставить это работать. Это janky, и легко выпасть из синхронизации с файловыми системами jail, которые я часто меняю на хостах, что прерывает DNS для каждого процесса, если он не может создать один из сокетов, потому что файл не существует. Запуск прокси-сервера выглядит намного более упругим.

  • ping мгновенно умирает в тюрьме, поэтому я использую curl. Он получает сообщение Killed: 9 на консоли мгновенно.

  • Я получаю некоторые другие файлы в chroot с помощью привязки, но я не могу заставить это работать для сокета mDNSResponder. Я использую http://bindfs.org (поскольку OS X не поддерживает Linux 'mount --bind) для монтирования в /var/run для chroot, но это происходит в журналы при попытке подключения:

    2015-10-26 6:39:40.833 PM curl[25002]: dnssd_clientstub ConnectToServer: connect()-> No of tries: 1
    2015-10-26 6:39:41.837 PM curl[25002]: dnssd_clientstub ConnectToServer: connect()-> No of tries: 2
    2015-10-26 6:39:42.843 PM curl[25002]: dnssd_clientstub ConnectToServer: connect()-> No of tries: 3
    2015-10-26 6:39:43.848 PM curl[25002]: dnssd_clientstub ConnectToServer: connect() failed path:/var/run/mDNSResponder Socket:4 Err:-1 Errno:61 Connection refused
    
4b9b3361

Ответ 1

Проблема здесь в том, что запросы и ответы в сокете /var/run/mDNSResponder используют функцию "вспомогательных данных" sendmsg вызовов recvmsg и sendmsg, а socat не /var/run/mDNSResponder данные в прокси. Мне удалось получить собственный прокси-сервер, который ретранслирует вспомогательные данные для работы и обеспечивает DNS для процессов внутри chroot.

Ответ 2

Вы должны убедиться, что у вас есть копия /etc/resolv.conf в вашем chroot. Без него он не будет знать, с какими DNS-серверами обращаться, поэтому единственным вариантом резервного копирования является использование mDNS. Но даже если mDNS будет работать, вероятно, он сможет разрешить только локальные имена доменов, а не google.ca.