Un recorrido paso a paso: desde dos ordenadores unidos por un cable hasta una red con Internet, DHCP, DNS, web, VPN, Tor y detección de ataques. Todo con ip netns, sin programas complicados.
Este laboratorio monta redes de ordenadores dentro de tu propio PC, sin máquinas virtuales. Para ello usamos tres piezas del kernel de Linux:
ip netns add.Cada fase es un script. Las fases 01 a 05 son independientes (cada una monta su red desde cero). A partir de la 06 se construye una sola red que va creciendo, así que esas se ejecutan en orden:
sh 01_pc_pc.sh # fases 01-05: pruébalas sueltas
sh 06_internet.sh # base de las siguientes
sh 07_dhcp.sh
sh 08_dns.sh
sh 09_web.sh
sh 10_vpn.sh
sh 11_iptables.sh
sh 12_tor.sh # tarda ~2 min (espera a que Tor arranque)
sh 13_deteccion_ataques.sh
Todos los comandos llevan sudo porque crear redes requiere permisos de administrador. La limpieza total está comentada al final de las fases 12 y 13.
Conectar dos ordenadores directamente con un cable.
[pc1] 10.0.0.1 ══════════════════ 10.0.0.2 [pc2]
ip netns add pc1 y pc2.ip link add veth_pc1_pc2 type veth peer name veth_pc2_pc1.ip link set veth_pc1_pc2 netns pc1.lo.10.0.0.0/24.ip netns exec pc1 ping -c3 10.0.0.2 y ip neigh para ver la MAC de pc2 aprendida por ARP.En vez de un cable directo, usar un switch para poder enchufar muchos PCs.
[pc1] 192.168.1.10 ──┐ ┌── 192.168.1.20 [pc2]
└─[ sw1 ]──┘
(bridge)
ip link add sw1 type bridge.ip link set veth_sw1_pc1 master sw1.ping entre los PCs y bridge fdb show br sw1 para ver la tabla de MACs que ha aprendido el switch.Comunicar dos redes distintas a través de un router.
RED A 192.168.1.0/24 RED B 192.168.2.0/24 [pc1]─[sw1]─[ r1 ]─[sw2]─[pc2] .1.10 .1.1 .2.1 .2.10
sysctl -w net.ipv4.ip_forward=1.ip route add default via 192.168.1.1.El router no necesita rutas: conoce las dos redes porque está conectado a ambas.
ping de pc1 a pc2 y tracepath -n 192.168.2.10 para ver que el paquete pasa por r1.Varios routers en fila. Ahora cada uno NO conoce todas las redes: hay que enseñarle el camino con rutas estáticas.
[pc1]─[sw1]─[r1]──[r2]──[r3]──[r4]─[sw2]─[pc2]
10.0.12.0/30 10.0.23.0/30 10.0.34.0/30
/30 (solo 2 IPs útiles).ip netns exec r1 ip route add 192.168.2.0/24 via 10.0.12.2
ip netns exec r2 ip route add 192.168.2.0/24 via 10.0.23.2
...
tracepath de pc1 a pc2 debe mostrar los 4 routers.Los routers forman una malla con varios caminos. Si un enlace se cae, el tráfico va por otro lado.
┌──[ r2 ]──┐
[pc1]─[sw1]─[r1] [r4]─[sw2]─[pc2]
└──[ r3 ]──┘
Principal: r1→r2→r4 Respaldo: r1→r3→r4
ip route add ... metric 100 / metric 200.Con ignore_routes_with_linkdown=1, si un cable queda muerto el kernel deja de usar sus rutas y entra la de reserva.
Conectar la red a un "ISP" y, a través de él, a un Internet simulado y al Internet real del PC.
[srv1] 203.0.113.10 ─[inet]─[ isp ]═ HOST ═▶ Internet real
│
[pc1]─[sw1]─[ r1 ]═ red de routers ═[ r4 ]─[sw2]─[pc2]
(NAT) 198.51.100.2 = IP pública
| IP privada | 192.168.x.x, 10.x.x.x — solo valen dentro de casa. |
|---|---|
| IP pública | Única en Internet (usamos los rangos de documentación 198.51.100.0/24 y 203.0.113.0/24). |
| NAT (MASQUERADE) | r1 cambia la IP privada de origen por su IP pública al salir. iptables -t nat -A POSTROUTING -o veth_r1_isp -j MASQUERADE |
| Ruta por defecto | "Lo que no sé dónde está, mándalo hacia Internet". |
8.8.8.8 (Internet real). Desde Internet, srv1 no puede ver las IPs privadas: es lo que esperamos.Que los PCs nuevos reciban IP, gateway y DNS automáticamente, en vez de ponerlo a mano.
dnsmasq en r1 (red A) y r4 (red B), repartiendo el rango .100–.150.dhcpcd en pc3 y pc4. Nacen sin IP a propósito.dnsmasq --interface=veth_r1_sw1 \
--dhcp-range=192.168.1.100,192.168.1.150,255.255.255.0,12h \
--dhcp-option=option:router,192.168.1.1
ip addr en pc3 muestra la IP que recibió, y el archivo .leases registra a quién se la dio.Poder escribir srv1.melvin.lab en lugar de recordar la IP.
dnsmasq) en Internet, en 203.0.113.53.*.melvin.lab apuntados en un archivo tipo /etc/hosts.8.8.8.8./etc/netns/<pc>/resolv.conf.dig +short srv1.melvin.lab devuelve la IP. Usamos dig porque respeta el resolv.conf del namespace.Montar una web pública en Internet y una intranet privada.
203.0.113.80 (web.melvin.lab).192.168.1.10), accesible solo desde dentro.python3 -m http.server 80. Registramos los nombres en el DNS y avisamos a dnsmasq con una señal HUP.curl http://203.0.113.80 funciona desde todas partes; la intranet se ve desde la red interna pero no desde Internet.Un usuario que está en Internet (su "casa") entra a las redes privadas como si estuviera dentro, por un túnel cifrado.
[casa] 203.0.113.100 ══ TÚNEL CIFRADO (UDP 51820) ══ [ r1 ] 198.51.100.2 wg0: 10.10.0.2 wg0: 10.10.0.1
wg0 cifra lo que sale y descifra lo que entra.allowed-ips indica qué IPs van por el túnel: la del túnel (10.10.0.0/24) y las redes privadas (192.168.0.0/16).
wg show muestra el último handshake.Proteger la red: hasta ahora todo estaba permitido. Ponemos cortafuegos en r1 y en el servidor web.
| INPUT | Tráfico dirigido al propio equipo. |
|---|---|
| FORWARD | Tráfico que el router reenvía. |
| Política DROP | "Todo prohibido salvo lo permitido": iptables -P FORWARD DROP. |
| ESTABLISHED,RELATED | Dejar pasar las respuestas de conexiones ya permitidas. |
| DNAT | Publicar un servicio interno: quien entra a 198.51.100.2:8080 llega a la intranet de pc1. |
Montar nuestra propia red Tor (no la real) y navegar de forma anónima desde pc1.
[ da ] autoridad + entrada [ mid ] intermedio circuito de 3 saltos cifrado [ exit ] salida ─▶ [ web ] pc1 = cliente Tor (SOCKS 127.0.0.1:9050)
TestingTorNetwork 1 para que arranque rápido y permita IPs privadas.Montar un servidor "víctima" y una máquina "atacante" en un segmento aislado, lanzar ataques clásicos contra nuestro propio servidor y aprender a verlos y bloquearlos.
[atacante] 10.13.13.20 ─[ sw13 ]─ 10.13.13.10 [victima]
web: /login /buscar
.pcap que se abre con Wireshark.Una web mal hecha construye la consulta pegando lo que escribe el usuario:
SELECT * FROM productos WHERE nombre = '<lo que escribe el usuario>'
Si el atacante escribe ' OR '1'='1 la condición siempre es verdadera; con UNION SELECT intentaría sacar otras tablas. Lo detectamos buscando esas palabras en el paquete:
iptables -A INPUT -p tcp --dport 80 \
-m string --algo bm --icase --string "union select" \
-j LOG --log-prefix "ALERTA-SQLI "
El atacante prueba muchas contraseñas seguidas. Lo detectamos contando conexiones nuevas por IP:
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW \
-m recent --update --seconds 60 --hitcount 4 --name BF -j DROP
/etc/passwd). Por eso, en vez de una base de datos real, simulamos el login y la BD con un pequeño servidor en Python; se ve igual de bien y es más sencillo.dmesg), los contadores de reglas, las IPs en la lista recent, el log del servidor y el resumen del .pcap. Primero se ve el ataque sin defensas y luego con ellas, para comparar.⚠️ Todos los ataques se lanzan contra el servidor del propio laboratorio, en un segmento aislado y con fines educativos.