Comprensión de sockets

Introducción

Los sockets son una forma de habilitar la comunicación entre procesos entre programas que se ejecutan en un servidor, o entre programas que se ejecutan en servidores separados. La comunicación entre servidores se basa en sockets de red, que utilizan el Protocolo de Internet (IP) para encapsular y manejar el envío y recepción de datos.

Los sockets de red tanto en clientes como en servidores se denominan por su dirección de socket. Una dirección es una combinación única de un protocolo de transporte como el Protocolo de Control de Transmisión (TCP) o el Protocolo de Datagramas de Usuario (UDP), una dirección IP y un número de puerto.

En este tutorial aprenderás sobre los siguientes tipos diferentes de sockets que se utilizan para la comunicación entre procesos:

  • Sockets de flujo, que utilizan TCP como su protocolo de transporte subyacente
  • Sockets de datagrama, que utilizan UDP como su protocolo de transporte subyacente
  • Sockets de dominio de Unix, que utilizan archivos locales para enviar y recibir datos en lugar de interfaces de red y paquetes IP.

En cada sección de este tutorial también aprenderás cómo enumerar los tipos de sockets respectivos en un sistema Linux. Examinarás cada tipo de socket utilizando una variedad de herramientas de línea de comandos.

Prerrequisitos

Los ejemplos en este tutorial fueron validados en un servidor Ubuntu 20.04. Puedes seguir este tutorial usando la mayoría de las distribuciones de Linux modernas en una computadora local o un servidor remoto, siempre y cuando tengas la versión equivalente de cada una de las herramientas requeridas instaladas para tu distribución.

Para comenzar a usar Ubuntu 20.04, necesitarás un servidor que haya sido configurado siguiendo nuestra guía Configuración Inicial del Servidor para Ubuntu 20.04.

También necesitarás algunos paquetes adicionales para examinar los sockets en tu sistema. Asegúrate de que la caché de paquetes de tu sistema esté actualizada usando el comando apt update:

  1. sudo apt update

Luego, instala los paquetes requeridos usando este comando:

  1. sudo apt install iproute2 netcat-openbsd socat

El paquete iproute2 contiene la utilidad ss, que es lo que usaremos para inspeccionar los sockets. Usaremos el paquete netcat-openbsd para instalar netcat. Ten en cuenta que netcat se abrevia como nc cuando se invoca en la línea de comandos. Finalmente, usaremos el paquete socat para crear ejemplos de sockets.

¿Qué es un Socket de Flujo?

Los sockets de flujo son orientados a la conexión, lo que significa que los paquetes enviados y recibidos desde un socket de red son entregados por el sistema operativo host para ser procesados por una aplicación. Los sockets de flujo basados en red típicamente utilizan el Protocolo de Control de Transmisión (TCP) para encapsular y transmitir datos a través de una interfaz de red.

TCP está diseñado para ser un protocolo de red confiable que se basa en una conexión con estado. Los datos enviados por un programa utilizando un socket de flujo basado en TCP serán recibidos exitosamente por un sistema remoto (asumiendo que no hay problemas de enrutamiento, firewall u otras conectividades). Los paquetes TCP pueden llegar a una interfaz de red física en cualquier orden. En el caso de que los paquetes lleguen desordenados, el adaptador de red y el sistema operativo host se asegurarán de que sean reensamblados en la secuencia correcta para ser procesados por una aplicación.

A typical use for a TCP-based stream socket would be for a web server like Apache or Nginx handling HTTP requests on port 80, or HTTPS on port 443. For HTTP, a socket address would be similar to 203.0.113.1:80, and for HTTPS it would be something like 203.0.113.1:443.

Creación de Sockets de Flujo Basados en TCP

En el siguiente ejemplo, utilizarás el comando socat (abreviatura de SOcket CAT) para emular un servidor web escuchando peticiones HTTP en el puerto 8080 (el puerto HTTP alternativo). Luego examinarás el socket usando los comandos ss y nc.

Primero, ejecuta los siguientes comandos socat para crear dos sockets basados en TCP que están escuchando conexiones en el puerto 8080, utilizando interfaces IPv4 e IPv6:

  1. socat TCP4-LISTEN:8080,fork /dev/null&
  2. socat TCP6-LISTEN:8080,ipv6only=1,fork /dev/null&
  • Los argumentos TCP4-LISTEN:8080 y TCP6-LISTEN:8080 son el tipo de protocolo y el número de puerto a utilizar. Le indican a socat que cree sockets TCP en el puerto 8080 en todas las interfaces IPv4 e IPv6, y que escuche cada socket en busca de conexiones entrantes. socat puede escuchar en cualquier puerto disponible en un sistema, por lo que cualquier puerto de 0 a 65535 es un parámetro válido para la opción de socket.
  • La opción fork se utiliza para asegurar que socat continúe ejecutándose después de manejar una conexión, de lo contrario, saldría automáticamente.
  • La ruta /dev/null se utiliza en lugar de una dirección de socket remoto. En este caso, le indica a socat que imprima cualquier entrada entrante en el archivo /dev/null, que la descarta silenciosamente.
  • La bandera ipv6only=1 se utiliza para el socket IPv6 para decirle al sistema operativo que el socket no está configurado para enviar paquetes a direcciones IPv6 mapeadas a IPv4. Sin esta bandera, socat se enlazará a direcciones IPv4 e IPv6.
  • El carácter & indica al shell que ejecute el comando en segundo plano. Esta bandera asegurará que socat continúe ejecutándose mientras invoca otros comandos para examinar el socket.

Recibirás una salida como la siguiente, que indica los dos ID de proceso socat que se están ejecutando en segundo plano de tu sesión de shell. Tus IDs de proceso serán diferentes a los destacados aquí:

Output
[1] 434223 [2] 434224

Ahora que tienes dos procesos socat escuchando en el puerto TCP 8080 en segundo plano, puedes examinar los sockets utilizando las utilidades ss y nc.

Examinando Sockets de Flujo Basados en TCP

Para examinar los sockets TCP en un sistema Linux moderno utilizando el comando ss, ejecútalo con las siguientes banderas para restringir la salida:

  • Las banderas -4 y -6 indican a ss que examine solo los sockets IPv4 o IPv6 respectivamente. Omitir esta opción mostrará ambos conjuntos de sockets.

  • La bandera t limita la salida a sockets TCP. Por defecto, la herramienta ss mostrará todos los tipos de sockets en uso en un sistema Linux.

  • La bandera l limita la salida a sockets en escucha. Sin esta bandera, se mostrarían todas las conexiones TCP, lo que incluiría cosas como SSH, clientes que pueden estar conectados a un servidor web o conexiones que su sistema pueda tener con otros servidores.

  • La bandera n asegura que se muestren los números de puerto en lugar de los nombres de servicio.

Primero ejecuta el comando ss -4 -tln para examinar los sockets TCP IPv4 que están escuchando conexiones en tu sistema:

  1. ss -4 -tln

Recibirás una salida como la siguiente:

Output
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process . . . LISTEN 0 1 0.0.0.0:8080 0.0.0.0:* . . .

Puede haber otras líneas con otros puertos en su salida, dependiendo de qué servicios se estén ejecutando en su sistema. La parte resaltada 0.0.0.0:8080 de la salida indica que el socket TCP IPv4 está escuchando en todas las interfaces IPv4 disponibles en el puerto 8080. Un servicio que solo esté escuchando en una dirección IPv4 específica mostrará solo esa IP en el campo resaltado, por ejemplo 203.0.113.1:8080.

Ahora ejecute el mismo comando ss nuevamente, pero con la bandera -6:

  1. ss -6 -tln

Recibirá una salida como la siguiente:

Output
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process . . . LISTEN 0 5 [::]:8080 [::]:* . . .

Puede haber otras líneas con otros puertos en su salida, dependiendo de qué servicios se estén ejecutando en su sistema. La parte resaltada [::]:8080 de la salida indica que el socket TCP IPv6 está escuchando en todas las interfaces IPv6 disponibles en el puerto 8080 (como indican los caracteres ::, que son la notación IPv6 para una dirección compuesta por todos ceros). Un servicio que solo esté escuchando en una dirección IPv6 específica mostrará solo esa IP en el campo resaltado, por ejemplo [2604:a880:400:d1::3d3:6001]:8080.

Conexión a sockets de flujo basados en TCP

Hasta ahora has aprendido cómo crear y enumerar sockets TCP en interfaces IPv4 e IPv6. Ahora que tienes dos sockets escuchando conexiones, puedes experimentar conectándote a los sockets utilizando la utilidad netcat.

El uso de netcat para probar conexiones TCP a sockets locales y remotos es una técnica de resolución de problemas muy útil que puede ayudar a aislar problemas de conectividad y firewall entre sistemas.

Para conectarse al socket IPv4 sobre la dirección de bucle local utilizando netcat, ejecute el siguiente comando:

  1. nc -4 -vz 127.0.0.1 8080
  • La bandera -4 indica a netcat que use IPv4.
  • La bandera -v se utiliza para imprimir una salida detallada en su terminal.
  • La opción -z asegura que netcat solo se conecte a un socket, sin enviar ningún dato.
  • Se utiliza la dirección IP de bucle local 127.0.0.1 ya que su sistema tendrá su propia dirección IP única. Si conoce la IP de su sistema, también puede probar usando esa. Por ejemplo, si la dirección IP pública o privada de su sistema es 203.0.113.1, podría usarla en lugar de la IP de bucle local.

Recibirá una salida como la siguiente:

Output
Connection to 127.0.0.1 (127.0.0.1) 8080 port [tcp/http-alt] succeeded!

La línea resaltada es la salida de netcat. Indica que netcat se conectó al socket TCP escuchando en la dirección IPv4 de bucle local 127.0.0.1 en el puerto 8080. Puede ignorar la segunda línea, proviene del proceso socat en ejecución en segundo plano en su terminal.

Ahora puede repetir la misma prueba de conexión pero utilizando IPv6. Ejecute el siguiente comando de netcat:

  1. nc -6 -vz ::1 8080

Debería recibir una salida como la siguiente:

Output
Connection to ::1 8080 port [tcp/http] succeeded!

La línea resaltada es la salida de netcat. Indica que netcat se conectó al socket TCP escuchando en la dirección IPv6 de bucle local ::1 en el puerto 8080. Nuevamente, puede ignorar la segunda línea de salida.

Para limpiar tus sockets, deberás ejecutar el comando fg (foreground) para cada proceso socat que hayas creado. Luego utilizarás CTRL+C para cerrar cada socat. fg llevará los procesos al primer plano de tu terminal en el orden inverso en que los ejecutaste, así que cuando lo ejecutes, la segunda instancia de socat será la que interactúes primero.

Ejecuta fg para llevar la segunda instancia de socat IPv6 al primer plano de tu terminal. Luego ejecuta CTRL+C para cerrarla.

  1. fg

Recibirás una salida como la siguiente:

Output
socat TCP6-LISTEN:8080,ipv6only=1,fork /dev/null

Pulsa CTRL+C para detener el proceso.

Ahora ejecuta fg nuevamente para limpiar el primer socket IPv4. Deberías obtener una salida como la siguiente:

Output
socat TCP4-LISTEN:8080,fork /dev/null

Pulsa CTRL+C para detener el proceso.

Ahora has creado, examinado y conectado a sockets IPv4 e IPv6 en tu sistema. Estas técnicas y herramientas funcionarán en sistemas de desarrollo locales o servidores de producción remotos, así que prueba experimentar con cada herramienta para familiarizarte más con cómo pueden utilizarse para probar y solucionar problemas con los sockets TCP.

¿Qué es un Socket de Datagramas?

Los sockets de datagramas son sin conexión, lo que significa que los paquetes enviados y recibidos desde un socket son procesados individualmente por las aplicaciones. Los sockets de datagramas basados en red típicamente utilizan el Protocolo de Datagramas del Usuario (UDP) para encapsular y transmitir datos.

UDP no codifica información de secuencia en los encabezados de paquetes, y no hay corrección de errores incorporada en el protocolo. Los programas que utilizan sockets de red basados en datagramas deben incluir su propia lógica de manejo de errores y ordenación de datos para garantizar una transmisión exitosa de datos.

Los sockets UDP son comúnmente utilizados por servidores de Sistema de Nombres de Dominio (DNS). Por defecto, los servidores DNS utilizan el puerto 53 para enviar y recibir consultas de nombres de dominio. Un ejemplo de dirección de socket UDP para un servidor DNS sería similar a 203.0.113.1:53.

Nota: Aunque el protocolo no está incluido en la versión legible por humanos de la dirección del socket, los sistemas operativos diferencian las direcciones de socket incluyendo los protocolos TCP y UDP como parte de la dirección. Por lo tanto, una dirección de socket legible por humanos como 203.0.113.1:53 podría estar utilizando cualquiera de los protocolos. Herramientas como ss, y la antigua utilidad netstat, se utilizan para determinar qué tipo de socket se está utilizando.

El Protocolo de Tiempo de Red (NTP) utiliza un socket UDP en el puerto 123 para sincronizar los relojes entre computadoras. Un ejemplo de socket UDP para el protocolo NTP sería 203.0.113.1:123.

Creación de Sockets de Datagrama

Como en el ejemplo anterior de socket TCP, en esta sección volverás a utilizar socat para emular un servidor NTP escuchando peticiones en el puerto UDP 123. Luego examinarás los sockets que creas utilizando los comandos ss y nc.

Primero, ejecuta los siguientes comandos socat para crear dos sockets UDP que estén escuchando conexiones en el puerto 123, utilizando interfaces IPv4 e IPv6:

  1. sudo socat UDP4-LISTEN:123,fork /dev/null&
  2. sudo socat UDP6-LISTEN:123,ipv6only=1,fork /dev/null&

Recibirás una salida similar a la siguiente, que indica los dos IDs de proceso de socat que se están ejecutando en segundo plano en tu sesión de terminal. Tus IDs de proceso serán diferentes a los resaltados aquí:

Output
[1] 465486 [2] 465487
  • Cada comando está precedido por sudo, porque los puertos 0 al 1024 están reservados en la mayoría de los sistemas. sudo ejecuta un comando con permisos de administrador, lo que permite a socat enlazarse a cualquier puerto en el rango reservado.
  • Los argumentos UDP4-LISTEN:123 y UDP6-LISTEN:123 son el tipo de protocolo y el puerto a usar. Le indican a socat que cree sockets UDP en el puerto 123 en las interfaces IPv4 e IPv6, y que esté a la espera de datos entrantes. Una vez más, cualquier puerto en todo el rango de 0 a 65535 es un parámetro válido para los sockets UDP.
  • Los argumentos fork, ipv6only=1 y /dev/null se utilizan de la misma manera que se describe en el ejemplo anterior de TCP.

Ahora que tienes dos procesos socat escuchando en el puerto UDP 123, puedes examinar los sockets utilizando las utilidades ss y nc.

Examinando Sockets de Datagrama

Para examinar los sockets UDP en un sistema Linux moderno usando el comando ss, ejecútalo con las siguientes banderas -4, -6 y -uln para restringir la salida:

La bandera u limita la salida a los sockets UDP.
Las otras banderas son las mismas que las utilizadas en el ejemplo anterior de TCP.

Primero ejecuta el comando ss -4 -uln para examinar los sockets UDP IPv4 que están escuchando conexiones en tu sistema:

  1. ss -4 -uln

Recibirás una salida similar a la siguiente:

Output
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process . . . UNCONN 0 0 0.0.0.0:123 0.0.0.0:* . . .

Puede haber otras líneas con otros puertos en tu salida dependiendo de qué servicios se estén ejecutando en tu sistema. La porción resaltada 0.0.0.0:123 de la salida indica que el socket UDP IPv4 está disponible en todas las interfaces IPv4 en el puerto 123. Un servicio que solo está disponible en una dirección IPv4 específica mostrará solo esa IP en el campo resaltado, por ejemplo 203.0.113.1:123.

Ahora ejecuta el mismo comando ss nuevamente pero con la bandera -6:

  1. ss -6 -uln

Recibirás una salida similar a la siguiente:

Output
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process . . . UNCONN 0 0 [::]:123 [::]:* . . .

Puede haber otras líneas con otros puertos en tu salida dependiendo de qué servicios estén en ejecución en tu sistema. La parte resaltada [::]:123 de la salida indica que el socket TCP IPv6 está disponible en todas las interfaces IPv6 en el puerto 123 (como lo indican los caracteres ::). Un servicio que solo está disponible en una dirección IPv6 específica mostrará solo esa IP en el campo resaltado, por ejemplo [2604:a880:400:d1::3d3:6001]:123.

Prueba de sockets de datagrama

Ahora que estás familiarizado con cómo crear y enumerar sockets UDP en interfaces tanto IPv4 como IPv6, puedes experimentar conectándote a ellos. Al igual que con los sockets TCP, puedes experimentar con los sockets UDP usando la utilidad netcat.

Para conectarte al socket UDP de ejemplo en el puerto 123 que creaste en la sección anterior de este tutorial, ejecuta el siguiente comando netcat:

  1. nc -4 -u -vz 127.0.0.1 123
  • La bandera -4 le indica a netcat que use IPv4.
  • La opción -u instruye a netcat a usar UDP en lugar de TCP.
  • La bandera -v se usa para imprimir una salida detallada en tu terminal.
  • La opción -z asegura que netcat solo se conecte a un socket, sin enviar ningún dato.
  • La dirección IP de bucle local 127.0.0.1 se utiliza ya que su sistema tendrá su propia dirección IP única. Si conoce la IP de su sistema, también puede probar utilizando esa. Por ejemplo, si la dirección IP pública o privada de su sistema es 203.0.113.1, podría usar esa en lugar de la dirección IP de bucle local.

Recibirá una salida como la siguiente:

Output
Connection to 127.0.0.1 123 port [udp/ntp] succeeded!

La salida indica que netcat no recibió un error del socket UDP que escucha en la dirección IPv4 de bucle local 127.0.0.1 en el puerto 123. Esta falta de una respuesta de error se utiliza para inferir que el socket en 127.0.0.1:123 está disponible. Este comportamiento es diferente de los sockets TCP, que necesitan intercambiar paquetes para confirmar si un socket está disponible.

Nota: Si el socket en este ejemplo no estuviera disponible, el sistema remoto devolvería un mensaje tipo 3 ICMP (Destino Inalcanzable) con un Código de 3, lo que indica que el puerto no está disponible en el host remoto.

Inferir que un socket está disponible basado en la falta de respuesta de error asume que no hay firewalls o problemas de conectividad que estén bloqueando el tráfico ICMP. Sin enviar, recibir y verificar datos de aplicación sobre un socket UDP, no hay garantía de que un puerto UDP remoto esté abierto y aceptando paquetes.

Ahora puede repetir la misma prueba de conexión pero utilizando IPv6. Ejecute el siguiente comando de netcat:

  1. nc -6 -u -vz ::1 123

Debe recibir una salida como la siguiente:

Output
Connection to ::1 123 port [udp/ntp] succeeded!!

La salida indica que netcat no recibió ningún error del socket UDP escuchando en la dirección IPv6 de bucle local ::1 en el puerto 123. Una vez más, esta falta de respuesta de error se utiliza para inferir que el socket en ::1:123 está disponible.

Para limpiar tus sockets, necesitarás ejecutar el comando fg (foreground) para cada proceso socat que hayas creado. Luego utilizarás CTRL+C para cerrar cada socat.

Ejecuta fg para llevar la segunda instancia de socat IPv6 al primer plano de tu terminal. Luego ejecuta CTRL+C para cerrarla.

  1. fg

Recibirás una salida como la siguiente:

Output
sudo socat UDP6-LISTEN:123,ipv6only=1,fork /dev/null

Pulsa CTRL+C para detener el proceso.

Ahora ejecuta fg nuevamente para limpiar el primer socket IPv4. Tendrás una salida como la siguiente:

Output
sudo socat UDP4-LISTEN:123,fork /dev/null

Pulsa CTRL+C para detener el proceso.

Ahora has creado, examinado y probado sockets UDP IPv4 e IPv6 en tu sistema. Intenta experimentar con cada herramienta para familiarizarte más con cómo se pueden usar para probar y solucionar problemas de sockets UDP.

¿Qué es un Socket de Dominio Unix?

Los programas que se ejecutan en el mismo servidor también pueden comunicarse entre sí utilizando Sockets de Dominio Unix (UDS). Los Sockets de Dominio Unix pueden ser basados en secuencias o en datagramas. Al utilizar sockets de dominio, los datos se intercambian entre programas directamente en el núcleo del sistema operativo a través de archivos en el sistema de archivos del host. Para enviar o recibir datos utilizando sockets de dominio, los programas leen y escriben en su archivo de socket compartido, evitando completamente los sockets y protocolos basados en red.

Los Sockets de Dominio Unix son ampliamente utilizados por sistemas de bases de datos que no necesitan estar conectados a una interfaz de red. Por ejemplo, MySQL en Ubuntu por defecto utiliza un archivo llamado /var/run/mysqld/mysql.sock para comunicarse con clientes locales. Los clientes leen desde y escriben en el socket, al igual que el propio servidor MySQL.

PostgreSQL es otro sistema de bases de datos que utiliza un socket para comunicación local, no de red. Típicamente, por defecto utiliza /run/postgresql/.s.PGSQL.5432 como su archivo de socket.

Creación de Sockets de Dominio Unix

En las secciones anteriores exploraste cómo se usa TCP con sockets de flujo y cómo se usa UDP con sockets de datagrama. En esta sección utilizarás socat para crear tanto sockets Unix de flujo como de datagrama sin usar TCP o UDP para encapsular datos que enviar por redes. Luego examinarás los sockets que creaste utilizando los comandos ss y nc. Finalmente, aprenderás sobre cómo probar sockets Unix utilizando netcat.

Para empezar, ejecuta los siguientes comandos socat para crear dos archivos de socket:

  1. socat unix-listen:/tmp/stream.sock,fork /dev/null&
  2. socat unix-recvfrom:/tmp/datagram.sock,fork /dev/null&
  • El primer comando instruye a socat para crear un socket usando el tipo de dirección unix-listen, lo que creará un UDS basado en flujo.
  • El segundo comando especifica unix-recvfrom como el tipo de socket, lo que creará un UDS basado en datagramas
  • Ambos comandos especifican un nombre de archivo después del separador :. El nombre de archivo es la dirección del propio socket. Para el primer ejemplo de flujo es /tmp/stream.sock y para el segundo ejemplo de datagrama es /tmp/datagram.sock. Ten en cuenta que el nombre de un socket es arbitrario, pero ayuda si es descriptivo cuando estás solucionando problemas.
  • Los argumentos fork y /dev/null se utilizan de la misma manera que se describe en las secciones de ejemplo de socket de flujo y de datagrama.

Ahora que has creado tus dos sockets UDS, puedes examinarlos usando las utilidades ss y nc.

Examinando los Sockets de Dominio Unix

Para listar todos los sockets de dominio Unix en escucha, ejecuta el comando ss -xln. La bandera x asegura que solo se muestren los sockets de dominio.

  1. ss -xln

Recibirás una salida como la siguiente:

Output
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process . . . u_str LISTEN 0 5 /tmp/stream.sock 436470 * 0 u_dgr UNCONN 0 0 /tmp/datagram.sock 433843 * 0 . . .

Observa la parte resaltada u_str de la línea /tmp/stream/sock. Este campo indica que el tipo de socket es UDS basado en flujo. La segunda línea muestra que el tipo es u_dgr, lo que significa que el tipo de socket es basado en datagramas.

Dado que los Sockets de Dominio Unix son archivos, los permisos usuales de usuario y grupo de Linux y los controles de acceso pueden ser usados para restringir quién puede conectarse al socket. También puedes usar herramientas del sistema de archivos como ls, mv, chown y chmod para examinar y manipular archivos UDS. Herramientas como SELinux también pueden ser usadas para etiquetar archivos UDS con diferentes contextos de seguridad.

Para verificar si un archivo es un socket UDS, utiliza las utilidades ls, file o stat. Sin embargo, es importante tener en cuenta que ninguna de estas herramientas puede determinar si un UDS está basado en flujo o en datagramas. Utiliza la herramienta ss para obtener la información más completa sobre un Socket de Dominio Unix.

Para examinar un socket en el sistema de archivos, la utilidad stat muestra la información más relevante. Ejecútala en los sockets que creaste anteriormente:

  1. stat /tmp/stream.sock /tmp/datagram.sock

Recibirás una salida como la siguiente:

Output
File: /tmp/stream.sock Size: 0 Blocks: 1 IO Block: 131072 socket Device: 48h/72d Inode: 1742 Links: 1 Access: (0755/srwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2021-03-01 18:10:25.025755168 +0000 Modify: 2021-03-01 18:10:25.025755168 +0000 Change: 2021-03-01 18:22:42.678231700 +0000 Birth: - File: /tmp/datagram.sock Size: 0 Blocks: 1 IO Block: 131072 socket Device: 48h/72d Inode: 1743 Links: 1 Access: (0755/srwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2021-03-01 18:10:25.025755168 +0000 Modify: 2021-03-01 18:10:25.025755168 +0000 Change: 2021-03-01 18:10:25.025755168 +0000 Birth: -

Nota que para cada archivo, el tipo es socket (destacado en el extremo derecho de la salida) y el modo de acceso tiene un carácter s precediendo los permisos del archivo.

La utilidad ls también indicará si un archivo es un socket. Ejecuta ls -l para examinar los archivos:

  1. ls -l /tmp/stream.sock /tmp/datagram.sock

Recibirás una salida como la siguiente. Nuevamente, nota que para los sockets, el modo de archivo incluye el carácter s antes de los campos de permisos del archivo:

Output
srwxr-xr-x 1 root root 0 Mar 1 18:10 /tmp/datagram.sock srwxr-xr-x 1 root root 0 Mar 1 18:10 /tmp/stream.sock

Ahora que has creado Sockets de Dominio Unix y aprendido cómo examinarlos usando ss y varias herramientas basadas en el sistema de archivos, el siguiente paso es probar los sockets usando una herramienta como netcat.

Prueba de Sockets de Dominio Unix

La utilidad netcat se puede utilizar para conectar con Sockets de Dominio Unix, así como con sockets TCP y UDP que ya aprendiste anteriormente en este tutorial. Para conectar con los ejemplos de sockets que creaste, deberás especificar una bandera adicional -U al ejecutar el comando netcat. Esta bandera le indica a netcat que se conecte a un UDS, en lugar de un socket de red basado en TCP o UDP.

Además, si el socket está basado en datagramas, usarás la bandera -u para instruir a netcat que utilice datagramas como aprendimos en la sección de Socket de Datagrama de este tutorial.

Comencemos examinando los sockets UDS conectándonos al socket basado en flujo con el siguiente comando:

  1. nc -U -z /tmp/stream.sock

La opción -U indica a netcat que se está conectando a un Unix Domain Socket.
La opción -z garantiza que netcat solo se conecte a un socket, sin enviar ningún dato.
/tmp/stream.sock es la dirección del socket en el sistema de archivos.

No recibirás ninguna salida de netcat cuando ejecutes el comando. Sin embargo, si un socket no está disponible, netcat mostrará un mensaje de error como el siguiente:

Output
nc: unix connect failed: No such file or directory nc: /tmp/stream.sock: No such file or directory

Por lo tanto, la ausencia de salida de netcat al probar un socket UDS basado en flujo significa que la conexión fue exitosa.

Repite el proceso de prueba, esta vez para el UDS basado en datagramas:

  1. nc -uU -z /tmp/datagram.sock

Se añade la bandera adicional -u para indicar a netcat que el socket remoto es un socket de datagrama. Nuevamente, no recibirás ninguna salida si la prueba es exitosa.

Si no hay ningún socket en la dirección, recibirás un error como el siguiente:

Output
nc: unix connect failed: No such file or directory nc: /tmp/datagram.sock: No such file or directory

Para limpiar tus sockets, necesitarás ejecutar el comando fg (foreground) para cada proceso de socat que hayas creado. Luego utilizarás CTRL+C para cerrar cada socat.

Ejecuta fg para llevar la instancia de socat basada en datagramas al primer plano de tu terminal:

  1. fg

Recibirás una salida como la siguiente:

Output
socat unix-recvfrom:/tmp/datagram.sock,fork /dev/null

Ejecuta CTRL+C para cerrarlo. No recibirás ninguna salida.

Ahora ejecuta fg nuevamente para limpiar el primer socket UDS basado en flujo.

Nuevamente deberías tener una salida como la siguiente:

Output
socat unix-listen:/tmp/stream.sock,fork /dev/null

Ejecute CTRL+C para finalizar el proceso. No recibirá ninguna salida.

Ahora ha creado, examinado y probado sockets de datagrama Unix en su sistema. Intente experimentar con netcat y socat para familiarizarse más con cómo puede enviar y recibir datos a través de un UDS, así como cómo puede probar y solucionar problemas con sockets de dominio Unix.

Conclusión

En este tutorial exploró cómo se utilizan diferentes tipos de sockets en un sistema Linux. Aprendió sobre sockets basados en flujo, que típicamente utilizan TCP para la comunicación en red. También aprendió sobre sockets basados en datagramas, que utilizan UDP para enviar datos a través de redes. Finalmente, exploró cómo los sockets de dominio Unix pueden ser tanto de flujo como de datagrama en un servidor local.

En cada sección utilizó la utilidad ss para recopilar información sobre sockets en un sistema Linux. Aprendió cómo las diferentes banderas que proporciona la herramienta ss pueden ayudarlo a limitar su salida a tipos específicos de sockets cuando está examinando sockets en un sistema.

Finalmente, utilizaste las herramientas netcat y socat para crear y conectarte a cada uno de los tres tipos diferentes de sockets discutidos en este tutorial. La utilidad netcat es ampliamente utilizada para conectarse a sockets, pero también puede crear sockets. Su documentación (man nc) contiene muchos ejemplos de cómo puede ser utilizado en cualquiera de sus modos. La utilidad socat es una herramienta más avanzada que puede ser utilizada para conectarse a y a muchos tipos diferentes de sockets que no están cubiertos en este tutorial. Su documentación (man socat) también contiene numerosos ejemplos de las diferentes formas en que puede ser utilizada.

Entender qué son los sockets y cómo funcionan es una habilidad central de administración de sistemas. Las herramientas y técnicas con las que experimentaste en este tutorial te ayudarán a familiarizarte más con los sockets y cómo solucionar problemas si tus servidores y aplicaciones no están comunicándose entre sí correctamente.

Source:
https://www.digitalocean.com/community/tutorials/understanding-sockets