
Ejecuta Radmin VPN en Linux mediante Wine: controlador personalizado, puente TAP y cero pérdida de paquetes.
# Radmin VPN para Linux
Ejecuta [Radmin VPN](https://www.radmin-vpn.com/) en Linux mediante Wine. Únete a redes VPN, ve pares, juega — todo sin una máquina virtual de Windows.
> No lo construí porque fuera más fácil que una VM. Lo construí porque pensé que era más fácil que una VM.
**Código asistido por IA.** Construido de forma colaborativa entre un humano y Claude (Anthropic). El driver, los hooks y el puente se escribieron con ingeniería inversa asistida por IA del protocolo de driver no documentado de Radmin VPN usando Ghidra. **Esto funciona, pero no ofrece garantías.** No está afiliado a Famatech. Radmin VPN es propietario — descárgalo tú mismo desde [radmin-vpn.com](https://www.radmin-vpn.com/). Úsalo bajo tu propio riesgo.
## Cómo funciona
El servicio de Windows de Radmin VPN se comunica con un driver miniport NDIS para su adaptador de red virtual. Wine no soporta NDIS, así que reemplazamos el driver con nuestra propia implementación que se conecta a un dispositivo TAP de Linux. Una DLL de hook maneja los problemas de compatibilidad con Wine (nombres de adaptador, permisos de registro). El resultado es un cliente Radmin VPN totalmente funcional ejecutándose de forma nativa bajo Wine.
```
Aplicación Linux ← TAP (radminvpn0) ← tap_bridge ← FIFO ← rvpnnetmp.sys (driver Wine) ← RvControlSvc.exe
```
## Inicio rápido (AppImage, recomendado)
Descarga `RadminVPN-Linux-x86_64.AppImage` desde la [última versión](https://github.com/baptisterajaut/radmin-vpn-linux/releases/latest). No hay nada que instalar — Wine está incluido.
> **Candidatos de versión** (p. ej. `v1.0.0-rc1`) se publican como *pre-releases* de GitHub. El enlace `latest` de arriba siempre apunta a la compilación *estable* más reciente, así que las pre-releases no aparecerán allí — consíguelas desde la [lista completa de versiones](https://github.com/baptisterajaut/radmin-vpn-linux/releases).
```bash
chmod +x RadminVPN-Linux-x86_64.AppImage
./RadminVPN-Linux-x86_64.AppImage
```
En el primer inicio descarga el instalador de Radmin VPN contra el que está validado (o pasa el tuyo propio con `--installer`). Se abre una terminal con el progreso, y se necesita un prompt de contraseña sudo para la configuración de TAP.
El estado persistente (wineprefix, MAC, registros) vive en `~/.local/share/radmin-vpn-linux/`.
> **¿Radmin se cierra solo?** Su propio actualizador está instalando una compilación más nueva dentro del
> prefix en ejecución. Haz la actualización de forma controlada en su lugar — conserva tu prefix y tu ID de Radmin:
> ```bash
> ./RadminVPN-Linux-x86_64.AppImage --update
> ```
> Luego desactiva "Actualizaciones automáticas" en la configuración de Radmin para que deje de intentarlo. Detalles en
> [el actualizador automático de Radmin](#el-actualizador-automático-de-radmin).
## Requisitos previos (compilación desde fuente / no AppImage)
- **Wine** >= 11.0 (probado en Wine 11.5 Arch Linux y en Wine 11.6 Ubuntu 24.04)
- **mingw-w64** compiladores cruzados (`i686-w64-mingw32-gcc`, `x86_64-w64-mingw32-gcc`) — para compilar desde fuente
- **iconv** (glibc) — para el análisis de registros del servicio
- **sudo** — para la creación del dispositivo TAP y el enrutamiento
- **Soporte de kernel TUN/TAP** — normalmente integrado, verifica con `modprobe tun`
- **Instalador de Radmin VPN** — se descarga automáticamente si no está presente. La versión contra la que este proyecto está validado se fija en un solo lugar, `RADMIN_VERSION` en `lib.sh` (actualmente **2.1.4951.1**; 2.0.4899.9 también funciona). Radmin VPN **1.4 no es compatible** — se registra y abre el adaptador pero nunca termina de conectarse bajo el shim de Wine, dejando la GUI atascada en "Conectando...".
### Arch Linux
```bash
sudo pacman -S wine mingw-w64-gcc
```
### Ubuntu/Debian
```bash
sudo apt install wine64 wine32 gcc-mingw-w64
```
## Inicio rápido desde fuente
```bash
git clone https://github.com/baptisterajaut/radmin-vpn-linux.git
cd radmin-vpn-linux
# Opción A: descargar binarios precompilados desde GitHub Releases
mkdir -p build
TAG=$(curl -sI https://github.com/baptisterajaut/radmin-vpn-linux/releases/latest | grep -i location | grep -oP 'v[\d.]+')
curl -sL "https://github.com/baptisterajaut/radmin-vpn-linux/releases/download/${TAG}/radmin-vpn-linux-${TAG}.tar.gz" \
| tar xz -C build/
# Opción B: compilar desde fuente
make
# Descargar el instalador de Radmin VPN desde https://www.radmin-vpn.com/
./run.sh --installer ~/Downloads/Radmin_VPN_*.exe
```
En ejecuciones posteriores, simplemente:
```bash
./run.sh
```
### Banderas de línea de comandos
| Bandera | Descripción |
|------|-------------|
| `--installer <ruta>` | Ruta al instalador `Radmin_VPN_*.exe` (solo primera ejecución). |
| `--no-ui` | Ejecuta el servicio sin lanzar la GUI de Radmin. |
| `--update` | Actualiza Radmin a la versión fijada en su lugar. Conserva el prefix, así que el RID registrado con Famatech sobrevive. |
| `--no-broadcast-routes` | No añade las rutas de broadcast/multicast → TAP. |
| `--filter-ui` | Lanza la UI opcional de filtrado de paquetes GTK4 (desactivada por defecto). |
| `--fix-chat` | Parchea `qwindows.dll` de Qt para corregir el fallo de la ventana de chat bajo Wine (desactivado por defecto). |
### El actualizador automático de Radmin
La GUI de Radmin puede descargar una compilación más nueva y ejecutar su instalador *dentro del prefix en vivo*,
lo que mata la GUI y provoca un fallo en el servicio en ejecución (el registro de la GUI muestra entonces un instalador
bajo `AppData\\Local\\Temp`). Dos defensas: el lanzador incluye la compilación validada actual
para que el actualizador no tenga nada que empujar, y una GUI que muere ya no se lleva el túnel
consigo — se reinicia una vez, y luego la VPN sigue funcionando sin interfaz. Para actualizar
deliberadamente, usa `./run.sh --update`, que detiene todo primero. Desactivar
"Actualizaciones automáticas" en la configuración de la GUI evita la carrera por completo.
Tanto `--filter-ui` como `--fix-chat` son opcionales. La UI de filtrado necesita el binario `rvpn_filter_ui`
(construido por `make`); el arreglo del chat necesita `patch_qwindows_font.py` y un intérprete de Python 3.
## Modos sin interfaz / servidor
Dos lanzadores adicionales ejecutan Radmin VPN sin un escritorio local — para un VPS o un host de centro de datos. Ambos instalan y configuran exactamente como `run.sh` (mismo wineprefix, mismo flujo de primera ejecución con `--installer`, mismo puente TAP); solo difieren en cómo se accede a la GUI.
### `run_datacenter.sh` — GUI a través del navegador
Ejecuta la GUI real de Radmin en una pantalla virtual (Xvfb) y la sirve mediante VNC + noVNC, para que puedas configurar tus redes desde un navegador y luego dejarla en ejecución.
```bash
sudo apt install -y xvfb x11vnc websockify novnc # o: make install-datacenter-deps
./run_datacenter.sh --installer ~/Downloads/Radmin_VPN_*.exe
```
| Bandera | Predeterminado | Descripción |
|------|---------|-------------|
| `--vnc-port <n>` | `5900` | Puerto para el servidor x11vnc. |
| `--web-port <n>` | `6080` | Puerto para el endpoint web noVNC. |
| `--vnc-password <pw>` | *(ninguno)* | Contraseña para la sesión VNC / web. |
| `--web-bind <addr>` | `127.0.0.1` | Dirección en la que noVNC escucha. |
Por defecto noVNC se vincula a `127.0.0.1`, así que solo es accesible a través de un túnel SSH:
```bash
ssh -L 6080:localhost:6080 tu-vps # luego abre http://localhost:6080/vnc.html
```
Para exponerlo públicamente, pasa `--web-bind 0.0.0.0` **junto con** `--vnc-password` — de lo contrario, cualquiera que llegue al puerto web aterriza en un escritorio sin autenticación y con capacidades de root. El script imprime una advertencia contundente si te vinculas públicamente sin contraseña.
### `run_vps.sh` — solo servicio, GUID fijo
Inicia el servicio sin interfaz con un GUID TAP fijo (sin necesidad de WMI de Wine) y sin GUI en absoluto. Si un enumerador de red personalizado (`rv_net_enum.exe`, no incluido en este repositorio) está presente un directorio arriba, se lanza; de lo contrario, el servicio simplemente se ejecuta hasta que presiones Ctrl+C. Solo se acepta `--installer`.
```bash
./run_vps.sh --installer ~/Downloads/Radmin_VPN_*.exe
```
## Compilación desde fuente
Requiere compiladores cruzados `mingw-w64`. Los binarios precompilados están disponibles desde [Releases](https://github.com/baptisterajaut/radmin-vpn-linux/releases) (compilados por CI en cada versión etiquetada) si no quieres instalar mingw.
```bash
make # compila todo a build/
make clean # elimina los artefactos de compilación
```
Produce:
- `build/rvpnnetmp.sys` — driver de kernel de Wine (PE de 64 bits)
- `build/adapter_hook.dll` — DLL de hook (PE de 32 bits)
- `build/rvpn_launcher.exe` — inyector de DLL (PE de 32 bits)
- `build/netsh.exe` — reemplazo de netsh (PE de 32 bits, instalado en SysWOW64)
- `build/netsh64.exe` — reemplazo de netsh (PE de 64 bits, instalado en System32)
- `build/drvinst.exe` — stub sin operación que reemplaza el instalador real del driver NDIS de Radmin (issue #12)
- `build/tap_bridge` — puente TAP nativo de Linux
- `build/rvpn_dnsfix.so` — shim nativo LD_PRELOAD, precargado solo en el servicio
- `build/rvpn_reuseport.so` — shim nativo LD_PRELOAD, precargado en `wineserver`
- `build/rvpn_filter_ui` — UI opcional de filtrado de paquetes GTK4 (`--filter-ui`)
### Compilación del AppImage
```bash
make
./packaging/build-appimage.sh # → packaging/dist/RadminVPN-Linux-x86_64.AppImage
```
Descarga la compilación Kron4ek Wine-Staging `amd64-wow64` (~100 MB) y `appimagetool` en el primer inicio, y las almacena en caché en `packaging/dist/`. Requiere `curl` e ImageMagick (`convert`).
## Qué hace `run.sh`
1. **Primera ejecución**: instala Radmin VPN mediante Wine (`/VERYSILENT`), elimina el driver NDIS real (incompatible con Wine), registra nuestro driver personalizado
2. **Cada ejecución**: crea un dispositivo TAP, inicia el puente TAP-a-FIFO, configura el registro de Wine (GUID del adaptador, servicio del driver), lanza el servicio y la GUI de Radmin VPN
3. **Al salir** (Ctrl+C o cerrar la GUI): mata Wine, elimina el dispositivo TAP, limpia
El wineprefix se almacena en `./wineprefix/` (ejecución desde fuente) o `~/.local/share/radmin-vpn-linux/wineprefix/` (AppImage). Se genera una dirección MAC persistente en la primera ejecución y se guarda en el wineprefix.
## Arquitectura
| Componente | Descripción |
|---|---|
| `rvpnnetmp.sys` | Driver de kernel de Wine. Emula el miniport NDIS de Radmin. Maneja IOCTLs (VERSION, STATUS, SETUP, PEERMAC), codificación/decodificación de tramas TLV, cola de IRP para I/O superpuesto, enrutamiento de tramas basado en MAC para soporte multi-par. |
| `adapter_hook.dll` | DLL complementaria cargada junto con RvControlSvc.exe. Hooks de IAT: renombra el adaptador TAP para que coincida con el nombre esperado por Radmin, anula `RegSetKeySecurity` para sortear un error de SCM de Wine donde los servicios carecen del SID de SYSTEM, y responde las cuatro búsquedas `Perf{Increment,Decrement}ULong{,Long}CounterValue` que `advapi32` de Wine no exporta. Ese último no es cosmético: Radmin 2.1 resuelve siete puntos de entrada de perflib en una cascada de todo-o-nada, y luego pasa el objeto de contador por-par resultante como carga útil del handshake entre pares — así que cuatro exportaciones de telemetría faltantes derriban toda la ruta de datos (issue #24, `docs/wine-perflib.md`). |
| `tap_bridge` | Binario nativo de Linux. Retransmite tramas ethernet entre el dispositivo TAP y las tuberías con nombre (FIFOs) que el driver de Wine lee/escribe. |
| `netsh.exe` / `netsh64.exe` | Reemplaza el stub de netsh de Wine (32 bits en SysWOW64, 64 bits en System32). Traduce los comandos `netsh interface ip` de Windows a comandos `ip addr`/`ip link` de Linux mediante un relé basado en archivos, validando la dirección antes de que llegue al relé raíz. |
| `rvpn_launcher.exe` | Inyecta `adapter_hook.dll` en el proceso del servicio de Radmin mediante `CreateRemoteThread` + `LoadLibrary`. |
| `drvinst.exe` | Stub sin operación que reemplaza el instalador real del driver NDIS de Radmin. Radmin lo ejecuta en tiempo de ejecución para cargar `NetMP60_1_1_64.sys`, que aborta Wine 11.x mediante `NdisInitializeReadWriteLock` (issue #12); dado que nuestro driver ya reemplaza ese adaptador, el real nunca debe cargarse. |
| `rvpn_dnsfix.so` | Shim nativo `LD_PRELOAD`, inyectado solo en el lanzamiento del servicio. Cortocircuita la resolución DNS inversa (`getnameinfo`/`gethostbyaddr`) de IPv4/IPv6 privadas en la capa de glibc. Radmin resuelve PTR de cada dirección candidata local que recopila; en un host cuyo resolvedor bloquea las consultas PTR de RFC1918, eso se detiene durante minutos y el servicio se registra pero nunca queda listo (issue #16). La búsqueda la emite el lado Unix de Wine, fuera del alcance de cualquier hook dentro de `adapter_hook.dll`. |
| `rvpn_reuseport.so` | Shim nativo `LD_PRELOAD`, precargado en `wineserver` (no en el servicio — los sockets Unix pertenecen a wineserver). Establece `SO_REUSEPORT` en cada socket TCP al crearse. Radmin 2.1 hace traversal NAT por reutilización de puerto TCP: vincula un listener a `uplink:PORT`, anuncia ese mapeo, y luego vincula sus sockets de pares salientes al mismo puerto local con `SO_REUSEADDR`, lo que Windows permite. Wine traduce esa solicitud a ninguna opción de nivel Unix para TCP (`server/sock.c`, `SO_REUSEPORT` está compilado solo para `__APPLE__`), así que el kernel rechaza el segundo bind y el cliente ve `WSAEACCES` en cada conexión de par (issue #24). El registro de conflictos propio de wineserver sigue funcionando, así que los binds que Windows rechazaría siguen rechazándose. |
| `rvpn_filter_ui` | UI opcional de GTK4 para inspeccionar y filtrar los paquetes que cruzan el puente. Desactivada por defecto; lánzala con `--filter-ui`. |
## Solución de problemas
**GUI atascada en "Esperando adaptador"**: el driver no está cargando. Verifica que `/tmp/radmin_driver.log` exista y tenga contenido. Si está vacío, el registro del servicio del driver puede faltar — elimina el wineprefix y vuelve a ejecutar.
**Registrado pero nunca "listo"**: el servicio llega a `Registered as #…` y se detiene ahí. Dos causas conocidas, ambas reportadas por el bloque de diagnóstico impreso al agotarse el tiempo. (a) Un proxy transparente o túnel con su propia política de enrutamiento (sing-box, clash/mihomo, v2ray…) interceptando la conexión saliente — tales stacks responden el handshake TCP localmente, así que el socket lee ESTABLISHED mientras nada se retransmite. Excluye `26.0.0.0/8` de sus rutas, y `*.radminte.com` también si puedes alcanzarlos directamente. (b) Un resolvedor que bloquea las búsquedas inversas de direcciones privadas (un `docker0` en `172.17.0.1` es el desencadenante habitual). `rvpn_dnsfix.so` maneja esto, pero es un shim de 64 bits: un Wine de sistema compilado como *old-wow64* lo ignora. Solución alternativa allí — añade una línea para la dirección a `/etc/hosts`, o usa `contrib/run-in-netns.sh` (que lleva el servicio a "listo" pero mantiene la VPN dentro de un namespace: las aplicaciones del host no pueden alcanzar `26.0.0.0/8`, lee la advertencia en su encabezado).
**Tus *otras* aplicaciones de Wine se rompieron después de ejecutar Radmin (`unimplemented function ndis.sys.NdisInitializeReadWriteLock`)**: las versiones hasta 1.0.0 dejaban que `winemenubuilder.exe` de Wine se ejecutara, lo que reescribe las asociaciones de archivos de Windows del host (`.exe`, `.msi`, `.lnk`, `.reg`, `.chm`, …) para abrirlas en *nuestro* prefix. Otros programas de Windows entonces se inician dentro del prefix de Radmin, y si el miniport NDIS real de Radmin (`RvNetMP60`) sigue registrado allí, cada uno de ellos aborta en ese stub de ndis. 1.0.1 desactiva `winemenubuilder` en todas partes, purga las entradas que escribió para un prefix de Radmin, y elimina `RvNetMP60` de `system.reg` sin conexión — solo ejecuta 1.0.1 una vez y ambos quedan reparados. Nota que `echo $WINEPREFIX` no muestra nada en esta situación: el secuestro vive en `~/.local/share/applications/*.desktop`, no en tu entorno. Limpieza manual, si lo prefieres:
```bash
grep -rl 'WINEPREFIX=[^"]*radmin' ~/.local/share/applications --include='*.desktop' | xargs -r rm
rm -rf ~/.local/share/applications/wine/Programs/"Radmin VPN"
update-desktop-database ~/.local/share/applications
```
**En línea y en tus redes, pero ningún par se conecta nunca (`error: 0x700000000`)**: esto es Radmin 2.1 en una compilación anterior a 1.1.0. El registro del servicio se ve saludable hasta las conexiones entre pares, que luego fallan en un bucle con ese código y finalmente se rinden con `node offline`. Dos brechas independientes de Wine, ambas corregidas en 1.1.0 y ambas explicadas arriba en las filas de `rvpn_reuseport.so` y `adapter_hook.dll`: Wine no establece ninguna opción de nivel Unix para un TCP `SO_REUSEADDR`, así que el traversal NAT por reutilización de puerto de 2.1 obtiene `WSAEACCES` en cada conexión de par; y `advapi32` de Wine carece de cuatro exportaciones de perflib, sin las cuales 2.1 envía una carga útil nula como su handshake entre pares. Nota que el código en sí no lleva información — es el abandono genérico al final de la cascada de errores, así que no intentes leer un subsistema de él. El arreglo es actualizar este proyecto a 1.1.0; nada necesita cambiar en el lado de Radmin.
**El servicio muere inmediatamente**: verifica `/tmp/radmin_service.log` para errores de Wine. Causa común: wineprefix antiguo de una versión diferente de Wine. Elimina `./wineprefix/` y vuelve a ejecutar.
**0% de pérdida de paquetes con un par, alta pérdida con muchos**: este era el error original — corregido por el enrutamiento de tramas basado en MAC en el driver. Asegúrate de usar la compilación más reciente.
**El primer ping es lento (~1s)**: la última versión almacena en caché las direcciones MAC para cada paquete IP que ve el driver. Si la IP de destino ha enviado al menos un paquete mientras el driver estaba en ejecución, la MAC ya está en caché y no hay retraso de ARP. Solo los pares completamente silenciosos (los que nunca han enviado un paquete) requieren la resolución ARP inicial, que añade ~1 segundo.
**Los juegos de LAN no ven a otros pares / "auto-descubrimiento" roto**: la mayoría de los juegos de LAN se descubren entre sí con sondas de broadcast (UDP a `255.255.255.255`) o multicast (`224.0.0.0/4`). En Windows, el driver TAP de Radmin se anuncia como la interfaz preferida para esos flujos; en Linux tienes que decírselo explícitamente al kernel. `run.sh` ahora instala dos rutas adicionales cuando la VPN se levanta:
```
ip route append 255.255.255.255/32 dev radminvpn0 metric 0
ip route append 224.0.0.0/4 dev radminvpn0 metric 0
```
Efecto secundario: mDNS / Bonjour / SSDP en tu LAN física (Chromecast, AirPrint, Sonos, smart TVs, ...) irán a través de la VPN mientras esté activa. Si necesitas descubrimiento de LAN local y Radmin en paralelo, ejecuta con `--no-broadcast-routes`:
```bash
./run.sh --no-broadcast-routes
```
Las rutas están limitadas al dispositivo TAP, así que se eliminan automáticamente cuando `run.sh` derriba el dispositivo al salir.
## Limitaciones conocidas
- Solo una instancia puede ejecutarse a la vez (FIFOs compartidos en `/tmp/`)
- La ruta on-link `26.0.0.0/8` afecta a todo el sistema mientras se ejecuta (se limpia al salir)
- Las rutas de broadcast predeterminado (`255.255.255.255/32`) y multicast (`224.0.0.0/4`) se dirigen a la VPN — desactívalas con `--no-broadcast-routes` si necesitas mDNS / SSDP de LAN local en paralelo
- Las versiones antiguas de Wine (< 11.0) pueden tener un comportamiento de I/O superpuesto diferente que rompe el driver
## Notas
**Solución alternativa para un error de Wine.** El hook de `RegSetKeySecurity` sortea una [limitación conocida de Wine](https://forum.winehq.org/viewtopic.php?t=37183) donde los servicios no reciben el SID de SYSTEM (S-1-5-18). Esto puede corregirse upstream en una futura versión de Wine.
## Créditos
Ingeniería inversa y el shim de Wine: [@baptisterajaut](https://github.com/baptisterajaut).
- [@ayozetr](https://github.com/ayozetr) — rastreó el cuelgue de "se registra pero nunca listo" hasta una
búsqueda DNS inversa de una dirección privada bloqueada por el resolvedor del host, lo demostró con un
repro de libc pura después de descartar cuatro teorías erróneas (incluida la mía), y escribió el
original de `src/rvpn_dnsfix.c` y `contrib/run-in-netns.sh`.
- [@gringoestrangeiro](https://github.com/gringoestrangeiro) — trabajo de estabilidad en Linux: filtros de paquetes,
caché ARP, recuperación de fallos, modos sin interfaz y de centro de datos.
- [@yuxiaole-bili](https://github.com/yuxiaole-bili) — descubrió que el SCM de Wine auto-inicia una segunda
instancia del servicio sin hook que pelea con la inyectada por el adaptador.
- [@D1spell-tech](https://github.com/D1spell-tech), [@Milkiway13](https://github.com/Milkiway13) y
todos los que pegaron un bloque de diagnóstico completo — dos hosts independientes es lo que hace que un error sea localizable.
## Licencia
GPL-3.0. Ver [LICENSE](https://github.com/baptisterajaut/radmin-vpn-linux/blob/main/LICENSE).
En espíritu, este código es de dominio público — haz lo que quieras con él. La GPL está aquí como red de seguridad legal: protege explícitamente la ingeniería inversa para interoperabilidad, que es lo que hace este proyecto. Cinturón y tirantes.
Radmin VPN es software propietario de Famatech Corp. Este proyecto proporciona solo herramientas de interoperabilidad — ningún código de Famatech está incluido o distribuido.