Если кратко, то записи о nameserver'ах в /etc/resolv.conf прописываются в неверном порядке если для подключения к сетям использовать NetworkManager. Если подробнее, то NetworkManager неправильно взаимодействует с resolvconf и передает неверное с точки зрения resolvconf имя интерфейса (точнее сказать не передает совсем). Resolvconf требует указывать название интерфейса и название программы, которая обновляет информацию о резолверах (например /sbin/resolvconf -a ppp0.pppd). При этом добавление записи в /etc/resolv.conf выполняется согласно порядку интерфейса в /etc/resolvconf/interface-order.
Например вы подключились через 3G модем к сотовому оператору и название вашего интерфейса ppp0. Сотовый оператор выдает два nameserver'а (x.x.x.1 и x.x.x.2). Далее вы подключаетесь к корпоративной сети VPN и вам выдает еще два nameserver'a (y.y.y.1 и y.y.y.2). Чтобы все работало правильно нужно чтобы /etc/resolv.conf выглядел так:
nameserver y.y.y.1 nameserver y.y.y.2 nameserver x.x.x.1 nameserver x.x.x.2
Но вместо этого в /etc/resolv.conf записи выглядят так:
nameserver x.x.x.1 nameserver x.x.x.2 nameserver y.y.y.1 nameserver y.y.y.2
Поскольку корпоративные nameserver'а оказались в конце списка, то внутренние ресурсы оказываются недоступными.
В процессе изучения проблемы оказалось, что NetworkManager использует вызов /sbin/resolvconf -a NetworkManager (указывает все nameserver'а без указания принадлежности к интерфейсу). Один из вариантов - изменить файл /etc/resolvconf/interface-order, чтобы явно задать приоритет NetworkManager, но поскольку это NM не следует соглашению, то я решил поправить его код.
Нужный мне участок кода быстро нашелся в файле NetworkManager/src/dns-manager/nm-dns-manager.c. Для добавления и удаления записей через resolvconf используется функция dispatch_resolvconf()
#ifdef RESOLVCONF_PATH static gboolean dispatch_resolvconf (const char *domain, char **searches, char **nameservers, const char *iface, GError **error) { char *cmd; FILE *f; gboolean retval = FALSE; if (! g_file_test (RESOLVCONF_PATH, G_FILE_TEST_IS_EXECUTABLE)) return FALSE; if (domain || searches || nameservers) { cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL); nm_log_info (LOGD_DNS, "(%s): writing resolv.conf to %s", iface, RESOLVCONF_PATH); if ((f = popen (cmd, "w")) == NULL) g_set_error (error, NM_DNS_MANAGER_ERROR, NM_DNS_MANAGER_ERROR_SYSTEM, "Could not write to %s: %s\n", RESOLVCONF_PATH, g_strerror (errno)); else { retval = write_resolv_conf (f, domain, searches, nameservers, error); retval &= (pclose (f) == 0); } } else { cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL); nm_log_info (LOGD_DNS, "(%s): removing resolv.conf from %s", iface, RESOLVCONF_PATH); if (nm_spawn_process (cmd) == 0) retval = TRUE; } g_free (cmd); return retval; } #endif
В выделенных строках видно какую команду выполняет NetworkManager. Чтобы исправить ситуацию достаточно добавить название интерфейса, который получает функция. Патч получился тривиальный
--- NetworkManager/src/dns-manager/nm-dns-manager.c.orig 2014-01-16 12:10:52.265616559 +0300 +++ NetworkManager/src/dns-manager/nm-dns-manager.c 2014-01-16 12:15:09.069611996 +0300 @@ -416,7 +416,7 @@ dispatch_resolvconf (const char *domain, return FALSE; if (domain || searches || nameservers) { - cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL); + cmd = g_strconcat (RESOLVCONF_PATH, " -a ", iface, ".NetworkManager", NULL); nm_log_info (LOGD_DNS, "(%s): writing resolv.conf to %s", iface, RESOLVCONF_PATH); if ((f = popen (cmd, "w")) == NULL) g_set_error (error, @@ -430,7 +430,7 @@ dispatch_resolvconf (const char *domain, retval &= (pclose (f) == 0); } } else { - cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL); + cmd = g_strconcat (RESOLVCONF_PATH, " -d ", iface, ".NetworkManager", NULL); nm_log_info (LOGD_DNS, "(%s): removing resolv.conf from %s", iface, RESOLVCONF_PATH); if (nm_spawn_process (cmd) == 0) retval = TRUE;
После пересборки пакетов и обновления системы приоритет nameserver'ов правильный.
P.S. К сожалению этот патч не будет работать на последней версии NetworkManager, поскольку там изменился прототип функции dispatch_resolvconf() и имя интерфейса более не передается. Позже попробую закинуть им баг на эту тему.
Комментариев нет:
Отправить комментарий