Boas xente, hoxe veño a falar dun problema que me teño atopado en varias ocasións. O tema é que configuro o equipo para usar un servidor DNS concreto, incluíndo este no /etc/resolv.conf, e dalí a un anaco me atopo que este se borrou e se volveu ao servidor DNS anterior.
Neste artigo vou ver porque acontece e quen me está tocando o /etc/resolv.conf
e como solucionalo.
Este artigo vai dirixido a entornos onde se usa a consola, xa que cando temos unha interface gráfica, polo xeral nas opcións de rede podemos poñer o DNS que queiramos sen problema ningún.
Imos ao tema.
O ficheiro DNS: /etc/resolv.conf
Como comentaba antes, cambiar o servidor DNS parece sinxelo, xa que en GNU/Linux o ficheiro /etc/resolv.conf indica cales son os servidores DNS en uso.
É sinxelo consultar dito ficheiro para descubrir os nosos servidores DNS:
$ cat /etc/resolv.conf
nameserver 192.168.122.1
E ademais, podemos mudar o servidor DNS a usar escribindo no ficheiro unha
entrada nameserver
:
$ echo "nameserver 192.168.122.135" | sudo tee /etc/resolv.conf
nameserver 192.168.122.135
$ cat /etc/resolv.conf
nameserver 192.168.122.135
Ata aquí todo ben. Agora invítovos a reiniciar a máquina ou agardar uns
minutos. Qué é o mais probable que pase? Que o noso ficheiro
/etc/resolv.conf
volva ao seu estado orixinal, perdendo os nosos cambios. Se
non é o teu caso e o ficheiro se mantén inalterado, noraboa, non tes que tocar
mais nada para cambiar o DNS da máquina, podes deixar de leer.
Porque volve /etc/resolv.conf
ao seu estado anterior? Pois porque en GNU/Linux
xeralmente algún demo (proceso que corre en segundo plano) está modificando o
ficheiro. E cál e dito demo? Depende.
En GNU/Linux existen diferentes programas que se poden encargar da configuración do DNS, polo que temos que descubrir cál é o caso da nosa máquina.
O apaño: Facendo /etc/resolv.conf inmutable
Pero antes, vou mostrar un apaño xenérico que penso funciona contra calquera
demo, inda que pode ter os efectos secundarios non desexados. Para que ningún
demo nos ande a tocar /etc/resolv.conf
podemos optar por modificalo e
logo facelo inmutable, de xeito que ningún proceso, nin sequera os que se
executan como root, o poida alterar (ata que se lle quite a flag de
inmutabilidade).
Para isto podemos usar o comando chattr coma no seguinte exemplo:
$ echo "nameserver 192.168.122.135" | sudo tee /etc/resolv.conf
nameserver 192.168.122.135
$ sudo chattr +i /etc/resolv.conf
Tras executar estes comandos, podemos reiniciar o sistema e verificar que o noso
DNS segue estando configurando como o indicamos. Se o quixeramos volver a
configurar teríamos que quitarlle a inmutabilidade con
sudo chattr -i /etc/resolv.conf
.
Esta pode ser unha boa opción se so queremos configurar un servidor estático, e eu mesmo a teño usado para configurar dnscrypt.
Sen embargo, noutras situacións pode ter as súas desvantaxes se queremos usar tamén o DNS configurado polo demo de rede, por exemplo no caso de que so queramos engadir un DNS para resolver nomes dunha rede interna e usar o outro para resolucións en internet. Neste contexto se cambiasemos de rede, o demo de rede non podería actualizar o DNS (que soe ser a IP do router) e poderíamos perder a conexión a internet. E tampouco estou seguro de se funcionaría ben no caso de que quixéramos usar unha VPN.
Polo tanto, xeralmente o axeitado é cambiar a configuración do noso demo de rede para engadir o DNS que nos queramos.
Demo de demos: Descubrindo quen toca /etc/resolv.conf
O problema cos demos de rede, como comentaba antes, é que cada un é de seu pai e súa nai e ademais non está claro moitas veces cál está usando o noso sistema GNU/Linux. Vou propor varios métodos para descubrir cal é o noso, pero antes, coñezamos aos sospeitosos habituais:
-
NetworkManager: O demo de rede usado polo xeral con GNOME.
-
systemd-resolved: Demo de systemd que se encarga do DNS.
-
etc: Igual hai algún mais, pero neste artigo centrareime nestes tres xa que son os mais comúns.
Sabendo que andamos buscando, imos ver que podemos facer para tentar descubrir
quen anda tocando /etc/resolv.conf
. Temos varias vías de acción.
Pista nº1: O contido de /etc/resolv.conf
O primeiro de todo é leer /etc/resolv.conf
, xa que hai casos que o programa
que modifica o DNS deixa unha mensaxe explicativa, xeralmente dicindo que non o
modifiques porque o vai a sobreescribir.
Por exemplo, este é o /etc/resolv.conf
dunha das miñas máquinas, modificado
por systemd-resolved
:
E este é o contido que me teño atopado no caso de que estea manexado por NetworkManager:
Pero tamén podemos atopar o /etc/resolv.conf
"pelao":
$ cat /etc/resolv.conf
nameserver 192.168.122.1
Neste último caso, ao atoparmo así descrubín que estaba sendo modificado por
dhclient
.
Mais se quedamos en dúbidas podemos probar outras técnicas.
Pista nº2: Monitorizando /etc/resolv.conf
Outra posibilidade é monitorizar que procesos están escribindo
/etc/resolv.conf
. Para isto podemos usar opensnoop, unha utilidade que usa
eBPF para monitorizar cando os procesos abren ficheiros. Mais para poder usala
temos que instalar o paquete bpfcc-tools
e as headers de Linux
(en Debian con sudo apt install linux-headers-$(uname -r)
).
Unha vez instalada, podemos executar o seguinte comando e agardar uns minutos a ver se algún proceso modifica os ficheiros:
O comando anterior indícalle a opensnoop
que queremos que so se mostren os
ficheiros abertos para escritura e filtramos con grep
para amosar aqueles co
nome resolv.conf
. Como podes ver, non so buscamos /etc/resolv.conf
senón
calquera ficheiro que conteña o nome resolv.conf
.
Se queres aprender mais do marabilloso mundo de eBPF podes consultar Learn eBPF Tracing: Tutorial and Examples de Brendan Gregg, que amosa un montón de ferramentas de monitorización basadas en eBPF, incluída tcpconnect, unha das miñas favoritas, que permite ver en tempo real que conexións de rede fai cada proceso.
É interesante non so monitorizar /etc/resolv.conf
, xa que varios programas
usan ficheiros de caché cun nome similar para gardar temporalmente a
configuración. Por exemplo dhclient
escribe en ficheiros de cache como
/etc/resolv.conf.dhclient-new.590
e logo comproba se ten que volcar os cambios
en /etc/resolv.conf
, pero pode que non o faga.
Tamén pode suceder que o que fagan para modificar /etc/resolv.conf
sexa mover
un archivo de caché a este (algo similar a
mv /etc/resolv.conf.HOIHS2 /etc/resolv.conf
, que é o que fai NetworkManager) e
polo tanto /etc/resolv.conf
non aparecerá na lista de ficherios abertos (xa
que non se usa unha syscall open senón rename e opensnoop
non a vai pillar).
Pero bueno, entre o contido de /etc/resolv.conf
e a súa monitorización xa
deberíamos ter unha idea de que demo de rede o está a modificar, mais se inda
non estamos seguros, imos explorar agora todos os demos e ver cales están
activos e como se modifica o DNS en cada un.
Demos de rede
dhclient
Imos ver como engadir un servidor DNS no caso de que sexa dhclient o demo que se encarga diso, pero primeiro temos que estar seguros de que se está executando:
Unha vez o temos confirmado que dhclient
está correndo, para incluir un servidor
DNS temos que indicarllo no ficheiro de configuración /etc/dhcp/dhclient.conf,
no que temos varias opcións relativas ao DNS. En concreto para indicarlle un
servidor DNS podemos engadir algunha destas liñas:
Deste xeito indicamos que engada o noso DNS antes ou despois, respectivamente,
do DNS resolto por DHCP. E falando disto, tamén podemos indicarlle que non
obteña os DNS por DHCP quitando o item domain-name-servers
da cláusula
request
que hai no ficheiro.
dhclient
tamén permite crear configuracións específicas para as diferentes
interfaces de rede e ahí tamén lle podemos indicar un DNS específico para esa
interface, inda que agora non me vou meter niso. Se queres mais información
podes consultar dhclient.conf(5).
Polo tanto, se lle engadimos a /etc/dhcp/dhclient.conf as liñas indicadas previamente e
reiniciamos o servizo ifup
que executa dhclient
deberíamos ver os cambios no
noso /etc/resolv.conf
:
$ sudo systemctl restart ifup@enp1s0.service
$ cat /etc/resolv.conf
nameserver 127.0.0.1
nameserver 192.168.122.1
nameserver 192.168.122.13;
Ten en conta que o servizo ifup
que se encarga de executar dhclient
recibe
como parámetro unha interface de rede, no meu caso enp1s0
, pero pode ser
diferente na túa máquina.
E se reiniciamos a máquina o cambios deberían permanecer.
NetworkManager
Como indicamos antes, polo xeral NetworkManager é o encargado de configurar os
servidores DNS cando nos atopamos un /etc/resolv.conf
similar ao seguinte:
Ademais podemos comprobar se NetworkManager se está a executar verificando que o servicio está correndo:
NetworkManager e mais complicado que outros xestores de rede, xa que ten varias posibilidades para o manexo do DNS, permitindo executar él mesmo esta tarefa ou delegala en terceiros como systemd-resolved ou dhclient. Tes mais información a este respecto na sección dns de NetworkManager.conf(5). Nesta sección imos supoñer que o DNS vaise manexar polo propio NetworkManager, xa que os outros se explican nas súas respectivas seccións.
Para o manexo de NetworkManager podemos usar nmcli. Con esta ferramenta podemos
indicarlle que use un novo servidor DNS na conexión que lle especifiquemos (non
atopei o modo de polo para calqueira conexión). Primeiro, podemos listar as
conexións (interfaces de rede) con nmcli connection show
:
E logo engadir o un servidor DNS con nmcli connection modify
:
Como vemos, os servidores DNS foron modificados tras o noso comando, e se reiniciamos a máquina os cambios deberían persistir. Lémbrate que o nome da túa conexión de rede pode ser diferente da miña e terías que axustar o comando.
Se ademais queres evitar que se use o servidor DNS especificado por DHCP, podes usar o seguinte comando:
sudo nmcli con mod "$network_connection" ipv4.ignore-auto-dns yes
systemd-resolved
Por último, imos ver o caso de systemd-resolved. Podemos confirmar que
systemd-resolved está sendo usado se o /etc/resolv.conf
ten unha pinta similar
a esta:
Se nos fixamos no contido, podemos observar que realmente se configura un
servidor DNS na propia máquina (nameserver 127.0.0.53
), isto xa nos da unha
pista do xeito no que funciona systemd-resolved
.
Por outra banda /etc/resolv.conf
será unha ligazón a
/run/systemd/resolve/stub-resolv.conf
:
$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 39 ago 19 2022 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
E non nos esquezamos de verificar que systemd-resolved
se está executando:
Unha vez temos comprobado que é systemd-resolved
o encargado das resolucións
DNS podemos proceder a engadir un servidor DNS. Para isto podemos engadir
unha entrada DNS
no ficheiro /etc/systemd/resolved.conf
, como a que se
mostra a continuación:
Despois reiniciamos o servizo systemd-resolved
:
sudo systemctl restart systemd-resolved.service
E podemos confirmar con resolvectl
que o noso DNS está configurado:
Tamén o podemos confirmar lendo /run/systemd/resolve/resolv.conf
:
Nesta ocasión hai que apreciar que non confirmarmos os cambios lendo
/etc/resolv.conf
, senon con resolvectl
ou
/run/systemd/resolve/resolv.conf
. Isto débese a que systemd-resolved
realmente non modifica /etc/resolv.conf
, senon que introduce o seu propio
servidor DNS local en 127.0.0.53
e logo redirixe ás peticións DNS ao servidor
que lle indiquemos.
Sexa como sexa, unha vez feito isto a configuración debería manterse tras reiniciar.
Conclusión
Neste artigo repasamos como modificar o noso servidor DNS en diferentes ferramentas despois de descubrir cal delas é o que se encarga de manexalo. Isto é o bonito de GNU/Linux, que existen varias posibilidades para manexar diferentes partes do sistema operativo, inda que de cando en vez nos de dores de cabeza.
Agardo que isto vos servira para solucionar algún problema e aprender un pouco mais sobre o ecosistema GNU/Linux.
Veña xente,
Fe en Tux e ferro a fondo!!