Revista Tecnología

¿Cómo cerrar un puerto TCP ocupado por una aplicación en GNU/Linux?

Publicado el 04 julio 2017 por Gaspar Fernández Moreno @gaspar_fm

¿Cómo cerrar puerto ocupado aplicación GNU/Linux?¿Cómo cerrar un puerto TCP ocupado por una aplicación en GNU/Linux?

Cuando vamos a establecer una comunicación entre dos máquinas a través de una red TCP/IP, vamos lo que estamos haciendo a diario miles de veces con nuestro ordenador mientras navegamos por Internet, lo hacemos a través de un puerto. Imaginemos que tenemos un sistema de comunicación rudimentario entre 10 amigos, con 5 cables y, cada cable, nos permite hablar con uno de nuestros amigos, pero claro, como sólo tenemos 5 cables, sólo podemos hablar con 5 amigos al mismo tiempo, así que en algún punto del recorrido deberá haber alguien con la capacidad de enchufar y desenchufar esos cables. El caso es que esos cables serían los canales, o puertos de nuestro sistema, alguien deberá enchufar y desenchufar cables para asegurarse de que nos conectemos con quien queremos.
Por lo tanto, yo tengo 5 cables que corresponden con las 5 conexiones que puedo tener simultáneas, ahora, por seguir un orden, si quiero conectarme con Alberto, éste se conectará con mi canal 1, aunque nadie me dice a mí que yo también esté en su canal 1. Ahora bien, conecto con Bruno por el canal 2 y cierro a Alberto, para conectar con Carla, que podemos enchufarla en el 1, ya que está libre... ahora Bruno y Alberto contactarán entre ellos, cada uno por alguno de los canales que tenga libre. Bueno, ¿se capta la idea?

Hablando de TCP/IP tenemos algunos más de 5 puertos (podríamos tener 65535 puertos) y serían las conexiones que podemos tener abiertas al mismo tiempo desde una máquina, o al menos desde una misma dirección IP. Y, hablando de nuestro ordenador, cada programa que tenemos en ejecución y que hace conexiones de red puede estar utilizando determinados puertos para establecer las comunicaciones. Por ejemplo, nuestro navegador, programas de chat, correo, música online, sincronización de información y demás tendrán ciertos puertos abiertos para utilizar dichos servicios. Algunos puertos estarán abiertos en modo escucha (para que otros se conecten con nosotros) y otros puertos serán las conexiones establecidas (nos hemos conectado a un puerto en modo escucha, en nuestro equipo, o en un equipo de la red).

Entonces, las aplicaciones que corren en nuestro sistema pueden tener determinados puertos abiertos para realizar su trabajo.

Nos gusta el cacharreo

Ahora bien, puede que si estamos desarrollando un programa que haga uso de la red, nuestro programa deje un puerto abierto y se haya quedado bloqueado. O también puede ser que estemos intentando poner a prueba la gestión de errores de un software, o estemos haciendo algo de ingeniería inversa. En cualquier modo, lo que queremos es cerrar sin piedad un puerto en nuestro ordenador.
Tenemos que tener cuidado porque, si lo hacemos sin control, puede que algún programa haga cosas muy raras. Además, necesitaremos permisos de root para algunas cosas, por lo que serán acciones privilegiadas.
En mi caso, casi siempre que hago esto es para experimentar. Por ejemplo, ¿cómo se comportaría mi programa si cierro la conexión de repente? Sin que ninguna de las dos partes se lo espere. Como también está bien utilizar iptables para restringir las futuras comunicaciones de mi aplicación (sería algo así como tirar del cable). El objetivo es que nuestro software sea más rubusto y sepa qué hacer en este tipo de casos.

Ver qué programa utiliza qué puerto

Lo primero que debemos hacer es averiguar qué proceso está utilizando el puerto que queremos. Con netstat.


Sólo he puesto una pequeña muestra. Con los argumentos tanp conseguimos:

  • -t: Sólo muestra conexiones TCP.
  • -a: Muestra también los puertos que estamos escuchando
  • -n: No resuelve las direcciones. (Es mucho más rápido, pero veremos sólo IPs y no nombres)
  • -p: Muestra los procesos que originan dichas conexiones. (pid y nombre, si es posible)

Vemos que muchos programas no aparecen y eso puede ser debido a los privilegios con los que hemos ejecutado el programa, por lo que si utilizamos sudo deberíamos ver todos o casi todos. Por supuesto, la salida de netstat la podemos pasar por grep, para realizar un filtrado de lo que nos interesa:

netstat -tanp | grep 40008

Si queremos más información sobre las conexiones abiertas y su asociación con procesos, en lugar de netstat podremos utilizar lsof. Aunque con lsof veremos muchísima información, ya que no sólo se centra en conexiones de red, sino que veremos cada descriptor de archivo abierto en el sistema. Y como las conexiones de red suelen tener un descriptor de archivo asociado, las veremos también . Por lo que, con lsof, podremos visualizar todos los descriptores abiertos por todos los procesos. Por ejemplo:


Con lo que veremos las conexiones TCP que ha establecido mi aplicación Emacs.

También podemos conocer con fuser, el proceso que origina la conexión. Conociendo el puerto (por ejemplo 35381):

35381/tcp: 7359

Matando procesos

Si queremos ser rápidos, lo más fácil para cerrar la conexión de manera abrupta, y una buena forma para probar nuestros programas es matarlos. Como muchos sabréis podemos hacerlo con kill.


O con killall, pero tenemos que tener cuidado si hay varios procesos con el mismo nombre.

Aunque tanto kill como killall, por defecto intentan cerrar la aplicación educadamente, y la aplicación puede elegir cerrarse o no. Incluso puede estar bloqueada, por lo que si queremos podemos utilizar el argumento -9 o -SIGKILL , con lo que el programa no tendrá más remedio que terminar, es más, no tiene elección, ya que es el sistema operativo el que lo mata.

De todas formas, una forma algo más segura es matar al proceso que tiene un determinado puerto. Igual que antes veíamos la información con fuser. Este comando también mata aplicaciones, directamente enviando SIGKILL, es decir, matando, sin pedir permiso, las aplicaciones (a no ser que lo especifiquemos en los argumentos):

8080/tcp: 23003

Método artesano que sólo cierra conexiones

Me encanta este método. Con él hacemos que el proceso entre en depuración y lo matamos. Una cosa importante a tener en cuenta, como dije antes, son los descriptores. Cada conexión, o fichero abierto tiene un descriptor único para la aplicación en la que se encuentra. Y suelen ser números pequeños y secuenciales. Así como la salida estándar por pantalla suele ser el 1, la salida de error el 2, y la entrada por teclado el 0, cuando abrimos el primer fichero, se le asignará el 3 y cuando creamos una conexión después el 4, y así sucesivamente. Entonces, veamos cómo al ejecutar lsof, vemos en mi cuarta columna, generalmente unos números. Para hacer el ejemplo más legible, he ejecutado netcat para abrir un puerto, así:


Luego, para averiguar el ID de proceso, lo podemos hacer con fuser, por ejemplo, aunque podemos utilizar cualquier comando de los explicados anteriormente:

54321/tcp: 23101


Ya que tenemos nuestro PID, 23101, vemos los descriptores abiertos por ese proceso:

Al final, veremos 0u, 1u, 2u, 3u (la u indica que es de lectura/escritura; r, sería lectura y w, escritura. Aunque algunas veces tenemos descriptores de lectura/escritura que no son necesariamente así... pero eso es otra historia). Lo que nos interesa es que el descriptor 3 es el que corresponde con la conexión que queremos cerrar. Ahora, podemos utilizar gdb para depurar el programa e introducir un comando close() a dicho descriptor, para cerrarlo (salen muchas letras, pero es sencillo):

Adjuntando a process 23101

hecho.

hecho.

hecho.

Eso sí, puede que el programa que estamos corriendo dependa de la conexión, o ese sea su único propósito, por ejemplo netcat o telnet, por lo que una vez cerrada la conexión se cierran. Aunque otros programas utilizan las conexiones de red realizan otras tareas como por ejemplo mantener un entorno gráfico, monitorizar el sistema, actualizar un fichero, etc; deberían poder gestionar correctamente ese cierre de conexión sin sufrir ningún desastre.

killcx, o cerrar conexiones educadamente

Ésta es una de esas herramientas (escrita en Perl) que deben estar en nuestra caja de herramientas de sysadmin. Y sirve para matar conexiones, aunque lo hace de un modo seguro. Es más, es capaz de cerrar una conexión que se ha quedado bloqueada en el sistema. Para utilizarla debemos hacer:

sudo ./killcx 127.0.0.1:54321 lo

La IP y puerto variarán según nuestras necesidades, y lo es el dispositivo, que podrá ser eth0, wlan0, etc.
La herramienta podemos descargarla desde aquí.

Foto principal: Alex Lehner

También podría interesarte...


Volver a la Portada de Logo Paperblog