OpenVPN se detiene con una queja errno 2 sobre /dev/net/tun mientras que lsmod enumera sin problemas el módulo tun. Ambos hechos son ciertos a la vez. El módulo proporciona un controlador, y la ruta que abre el cliente es un nodo de dispositivo que algo más tiene que crear. Tratarlos como un solo objeto es la razón por la que la reparación obvia de recargar el módulo no cambia absolutamente nada.

Dos objetos, dos propietarios distintos

Un módulo del núcleo y un nodo de dispositivo son objetos independientes con ciclos de vida independientes. Cargar el módulo registra un controlador, y en un sistema con devtmpfs el núcleo pide que se cree el nodo correspondiente. En un sistema sin devtmpfs nada crea nada, y el controlador se queda ahí sin ninguna ruta que apunte a él. El módulo puede estar cargado, sano y completamente inalcanzable a través del sistema de archivos en el mismo momento.

Por eso el texto del error y la lista de módulos no se contradicen. El cliente abre una ruta, la ruta no existe, y el núcleo devuelve ENOENT antes de que el controlador tun sea consultado siquiera. Recargar el módulo no puede reparar una ruta ausente, y crear la ruta no puede reparar un controlador ausente.

lsmod | grep -w tun
stat -c "%F %t:%T" /dev/net/tun
grep " /dev " /proc/mounts

devtmpfs frente a un mknod explícito

Normalmente dos mecanismos crean ese nodo, y saber cuál se supone que es el responsable le dice qué reparar. devtmpfs hace que el núcleo cree nodos de dispositivo en una instancia montada, y udev aplica propiedad y permisos encima de ellos. Un mknod explícito es la ruta manual para imágenes y espacios de nombres donde ninguno de los dos se ejecuta al arrancar.

Compare resultados en lugar de intenciones. Si devtmpfs está montado en /dev y el nodo sigue ausente, el controlador no es el que usted supone, o algo eliminó el nodo después del arranque. Si /dev es un directorio normal dentro de un rootfs desempaquetado, no existe ningún mecanismo automático y quien construye la imagen tiene que crear el nodo.

stat -c "%F major=%t minor=%T" /dev/net/tun
# expect: character special file major=a minor=c8

Donde no se ejecuta ninguno de los dos mecanismos, el nodo tiene que hacerse a mano, y el orden importa. Cree primero el directorio padre, porque mknod no puede inventarlo, luego el dispositivo de caracteres, luego un modo que lo deje escribible solo para root. Recargue el módulo antes de crear el nodo, y elimine una ruta existente solo después de que ls haya mostrado que es un directorio y no un dispositivo.

sudo modprobe tun
sudo mkdir -p /dev/net
sudo mknod /dev/net/tun c 10 200
sudo chmod 600 /dev/net/tun
ls -l /dev/net/tun

El tipo que informa stat es el discriminante más rápido, y un directorio en esa ruta es la sorpresa más habitual en imágenes mínimas. Un mkdir bienintencionado en un Dockerfile deja exactamente eso, y ninguna cantidad de carga de módulos sustituye un directorio por un dispositivo de caracteres. Major 10 con minor 200 es el par registrado para tun, expresado en hexadecimal como a y c8.

Cuatro rastros, cuatro causas

Cuatro causas explican casi todos los casos, y cada una deja un rastro distinto en los registros. Empiece por el entorno de arranque. Las imágenes sin disco, las placas integradas y las etapas de initramfs a menudo no montan ni devtmpfs ni un /devgestionado por udev, así que ningún proceso escribe nunca el nodo. Después lea las opciones de montaje de lo que aloje /dev, porque nodev permite que la ruta exista mientras se niega a abrirla, y un montaje bind tomado de un anfitrión endurecido lleva la bandera sin anunciarse. Un montaje de solo lectura falla antes y más alto: mknod devuelve allí EROFS, mientras que EPERM significa que al proceso le falta la capacidad y no que el sistema de archivos se proteja. Por último, un runtime de contenedores con su propio /dev tmpfs necesita que el nodo se inyecte en su propio espacio de nombres, y su cgroup de dispositivos debe permitir el par major y minor.

Compruebe la capa de política antes de volver a cambiar permisos. SELinux y AppArmor pueden denegar una apertura que todos los atributos del archivo permiten, y esa denegación aparece en el registro de auditoría y no en la salida del cliente. Un cambio de permisos que nunca aparece en una denegación es tiempo gastado en la capa completamente equivocada.

sudo journalctl -k -n 20 --no-pager
sudo ausearch -m AVC -ts recent | tail -5

Demuéstrelo con una interfaz, no con un listado

Un listado correcto demuestra que una ruta existe y nada más. Abra un nodo tun sano para lectura y la llamada vuelve con un error, porque el dispositivo no tiene semántica de lectura y no es un archivo normal. Ese error es aquí la señal de éxito, y reconocerlo le evita perseguirlo como si fuera una avería.

head -c 1 /dev/net/tun
head: error reading '/dev/net/tun': File descriptor in bad state

La prueba decisiva crea una interfaz, porque ejercita el controlador, el nodo y sus privilegios en un solo paso. Si la adición tiene éxito y el enlace aparece, los tres funcionan. Cuando falla, el errno separa las causas: ENOENT significa que no hay ningún nodo utilizable, EPERM apunta a la capacidad, las banderas de montaje o la política, y EBUSY significa que otro proceso ya posee la interfaz.

sudo ip tuntap add dev tun7 mode tun
ip -brief link show tun7
sudo ip tuntap del dev tun7 mode tun

Ejecute esa prueba en el contexto que realmente falla, porque una unidad de servicio, un contenedor o una tarea programada pueden llevar un conjunto de capacidades distinto del de su intérprete de órdenes de inicio de sesión. Una prueba que pasa en el contexto equivocado no demuestra nada sobre la que falla.

Cuando el dispositivo no es el problema

Si la prueba de interfaz tiene éxito y el cliente sigue fallando, el problema restante es el perfil, el contexto del servicio o la ruta, y el dispositivo está bien. Ese es el momento de dejar de editar nodos de dispositivo, porque más cambios solo añaden distancia respecto a un sistema que funciona.

Ejecute las mismas cinco comprobaciones cada vez en lugar de inventar una nueva: ¿está el módulo cargado sin un módulo rival, es la ruta un dispositivo de caracteres con el major y el minor correctos, están limpias las opciones de montaje, lleva el contexto del proceso la capacidad, y hay una denegación de política en la marca de tiempo del fallo. Una avería que sobrevive a las cinco no es un problema de dispositivo, diga lo que diga el mensaje.

Artículos relacionados