Capítulo 9


Algunas Aplicaciones de Red

Después de instalar correctamente el IP y el sistema de resolución, tiene que dedicarse a los servicios que quiera proporcionar a través de la red. Este capítulo trata la configuración de algunas sencillas aplicaciones de red, incluyendo el servidor inetd, y los programas de la familia rlogin. El interface de Llamada a Procedimiento Remoto o RPC1, en el que están basados servicios como el Sistema de Ficheros en Red o NFS2 y el Sistema de Información de Red o NIS3, también será tratado brevemente aquí. Las configuraciones de NFS y de NIS, sin embargo, ocupan mas espacio y serán descritas en capítulos aparte. Lo mismo sucede con el correo electrónico y el sistema de noticias.

Por supuesto, no podemos cubrir todas las aplicaciones de red en este libro. Si desea instalar alguna no tratada aquí, como talk, gopher, o Xmosaic, por favor, refiérase a su documentación.

9.1 El Super-Servidor inetd
9.2 La herramienta de control de acceso tcpd
9.3 Los ficheros services y protocols
9.4 Llamada a Procedimientos Remotos
9.5 Configurar los Comandos r

9.1 El Super-Servidor inetd

Frecuentemente, los servicios son llevados a cabo por los llamados demonios. Un demonio es un programa que abre un determinado puerto, y espera a recibir peticiones de conexión.

Si se recibe una petición de conexión, lanza un proceso hijo que aceptara la conexión, mientras el padre continúa escuchando a la espera de mas peticiones. Este concepto tiene el inconveniente de que por cada servicio ofrecido, se necesita ejecutar un demonio que escuche las conexiones a un puerto, lo que generalmente significa un desperdicio de recursos de sistema como, por ejemplo, de espacio de intercambio.

Por ello, casi todas las instalaciones UNIX corren un "super-servidor" que crea sockets para varios servicios, y escucha en todos ellos simultáneamente usando la llamada al sistema select(2). Cuando un nodo remoto requiere uno de los servicios, el super-servidor lo recibe y llama al servidor especificado para ese puerto.

_____________________________________________
1 N. del T.: Del inglés Remote Procedure Call
2 N. del T.: Del inglés Network File System
3 N. del T.: Del inglés Network Information System.

 

El super-servidor mas usado es inetd, el demonio Internet. Es iniciado en tiempo de arranque del sistema, y toma la lista de servicios que debe tratar de un fichero de configuración denominado /etc/inetd.conf. Aparte de esos servidores invocados por inetd, hay varios servicios triviales que el propio inetd se encarga de llevar a cabo, denominados servicios internos. Entre ellos, el chargen que simplemente genera una cadena de caracteres, y el daytime que devuelve la fecha y hora del sistema.

Una entrada de este fichero consiste en una única línea compuesta por los siguientes campos:

servicio tipo protocolo espera usuario servidor linea_de_comando

El significado de cada campo es como sigue:

servicio Proporciona el nombre del servicio. El nombre del servicio debe ser traducido a un número de puerto consultando el fichero /etc/services. Este fichero será descrito mas adelante en la sección 9.3.

tipo Especifica un tipo de socket, ya sea stream (para protocolos orientados a la conexión) o dgram (para protocolos no orientados a la conexión). Los Servicios basados en TCP deberán, por lo tanto, usar siempre stream, mientras que los servicios basados en UDP deberán usar siempre dgram.

protocolo Indica el protocolo de transporte usado por el servicio. Este debe ser un nombre de protocolo valido que se pueda encontrar en el fichero protocols, también descrito mas adelante.

espera Esta opción se aplica solo a sockets de tipo dgram. Puede tomar los valores wait o nowait. Si se especifica wait, inetd ejecutara solo un servidor cada vez para el puerto especificado. De otro modo, continuara escuchando por el puerto inmediatamente después de ejecutar el servidor. Esto es útil para servidores "single-threaded" que leen todos los datagramas que entran hasta que no llegan mas, y después acaban. La mayor parte de los servidores RPC son de este tipo y se deberá por ello especificar wait.
El otro tipo de servidores, los "multi-threaded", permiten un número ilimitado de instancias corriendo concurrentemente. Con estos servidores se deberá especificar nowait. Para sockets de tipo stream se deberá especificar siempre nowait.

usuario Este es el identificador del usuario bajo el que se ejecutara el proceso. Por lo general, éste suele ser el usuario root, aunque algunos servicios pueden usar diferentes cuentas. Es una buena idea el aplicar aquí el principio del menor privilegio, que indica que uno no debería ejecutar un comando bajo una cuenta privilegiada si el programa no lo requiere para funcionar correctamente. Por ejemplo, el servidor de noticias NNTP se ejecutara como news, mientras que otros servicios que podrían significar un riesgo para la seguridad (como tftp o finger ) son normalmente ejecutados como nobody.

servidor Proporciona el camino completo del programa servidor a ejecutar. Los servicios internos se indican con la palabra internal.

linea_de_comando
Esta es la línea de comando a pasar al servidor. Esto incluye el argumento 0, es decir, el nombre del comando. Normalmente, este será el nombre de programa del servidor, salvo que el programa se comporte de forma distinta cuando se le invoque con un nombre diferente. Este campo se deja vacío para los servicios internos.

En la figura 9.1 se muestra un ejemplo de fichero /etc/inetd.conf. La línea del servicio finger esta comentada, de forma que no este disponible. Esto se suele hacer normalmente por razones de seguridad porque podría ser usado por atacantes para obtener nombres de usuarios del sistema.

El tftp también se muestra deshabilitado. tftp implementa el Trivial File Transfer Protocol que permite transferir cualquier fichero del sistema que tenga permiso de lectura global sin chequeo de passwords, etc. Esto es especialmente peligroso con el fichero /etc/passwd, sobre todo si no se usa shadow password.

TFTP es usado comúnmente por clientes y terminales X sin unidad de discos para obtener su software de un servidor de arranque. Si necesita ejecutar tftp por ésta razón, asegúrese de limitar su acción a los directorios de los que los clientes obtendrán los ficheros añadiendo esos nombres de directorio a la línea de comando del tftpd. Esto se muestra en la segunda línea tftp del ejemplo.

 

#
# servicios inetd
ftp stream tcp nowait root /usr/sbin/ftpd in.ftpd -l
telnet stream tcp nowait root /usr/sbin/telnetd in.telnetd -b/etc/issue
#finger stream tcp nowait bin /usr/sbin/fingerd in.fingerd
#tftp dgram udp wait nobody /usr/sbin/tftpd in.tftpd
#tftp dgram udp wait nobody /usr/sbin/tftpd in.tftpd /boot/diskless
login stream tcp nowait root /usr/sbin/rlogind in.rlogind
shell stream tcp nowait root /usr/sbin/rshd in.rshd
exec stream tcp nowait root /usr/sbin/rexecd in.rexecd
#
# servicios internos inetd
#
daytime stream tcp nowait root internal
daytime dgram udp nowait root internal
time stream tcp nowait root internal
time dgram udp nowait root internal
echo stream tcp nowait root internal
echo dgram udp nowait root internal
discard stream tcp nowait root internal
discard dgram udp nowait root internal
chargen stream tcp nowait root internal
chargen dgram udp nowait root internal

Figura 9.1: Un ejemplo de fichero /etc/inetd.conf.

 

9.2 La herramienta de control de acceso tcpd

Ya que abrir un ordenador al acceso en red implica muchos riesgos de seguridad, las aplicaciones están diseñadas para protegerse ante varios tipos de ataques. Algunas de éstas aplicaciones, sin embargo, pueden ser reventadas (lo que quedo bastante demostrado con el RTM Internet worm), o pueden no distinguir entre un nodo seguro cuyas peticiones de un servicio particular deberían ser aceptadas, y otro nodo que no lo es y cuyas peticiones deberían ser rechazadas. Ya hemos discutido brevemente los servicios finger y tftp mas arriba. Así, uno podría querer limitar el acceso a esos servicios solamente a los "nodos de confianza", lo cual es imposible con la configuración usual, donde inetd o proporciona un servicio a todos los clientes, o a ninguno.

Una herramienta útil para esto es tcpd,4 el denominado demonio envoltorio5. Para los servicios TCP que quiera monitorizar o proteger, éste es invocado en lugar del programa servidor. tcpd informa de la petición al demonio syslog, chequea si el nodo remoto esta autorizado para usar ese servicio, y solo si la respuesta es satisfactoria, ejecutara el programa servidor real. Observe que esto no funciona con servicios basados en UDP.

Por ejemplo, para proteger el demonio finger, debe cambiar la línea correspondiente en inetd.conf así:

# Proteger el demonio de finger
finger stream tcp nowait root /usr/sbin/tcpd in.fingerd

Así, sin añadir ningún control de acceso, esto le hará parecer al cliente que es la típica configuración de finger, salvo que toda petición será registrada en la facilidad auth del syslog.

El control de acceso esta implementado mediante dos ficheros llamados /etc/hosts.allow y /etc/hosts.deny. Estos ficheros contienen entradas permitiendo y denegando acceso, respectivamente, para ciertos servicios y nodos. Cuando tcpd trata una petición de un servicio como finger de un nodo cliente denominado biff.foobar.com, busca en hosts.allow y hosts.deny (en éste orden) una entrada en la que el servicio y el nodo cliente coincidan. Si la entrada coincidente aparece en hosts.allow, se garantiza el acceso, sin importar lo que haya en hosts.deny. Si la coincidencia se encuentra en hosts.deny, la petición se rechaza cerrando la conexión. Si no hay coincidencia en ninguno, la petición es aceptada.

Las entradas en los ficheros de acceso tienen la siguiente estructura:

lista_servicios : lista_nodos [:cmd_shell ]

lista_servicios es una lista de nombres de servicios de /etc/services, o la palabra clave ALL. Para especificar todos los servicios excepto finger y tftp, usa "ALL EXCEPT finger, tftp".

lista_nodos es una lista de nombres de nodos o direcciones IP, o las palabras clave ALL, LOCAL, o UNKNOWN. ALL hace coincidir todos los nodos mientras que LOCAL hace coincidir todos los nombres de nodos que no contengan un punto6. UNKNOWN hace coincidir todos los nodos cuya búsqueda de nombre o dirección fallo. Un nombre comenzado por un punto incluye a todos los nodos cuyo dominio es el mismo a ese nombre. Por ejemplo, .foobar.com encajara con biff.foobar.com. También hay formas de especificar direcciones de red IP y números de subred. Por favor, refiérase a la página del manual de hosts_access(5) para más detalles.

_____________________________________________
4 Escrita por Wietse Venema, wietse@wzv.win.tue.nl.
5 N. del T.: Del inglés Wrapper Daemon

 

Para denegar acceso a los servicios finger y tftp a todos los nodos menos a los locales, ponga lo siguiente en /etc/hosts.deny, y deje /etc/hosts.allow vacío:

in.tftpd, in.fingerd: ALL EXCEPT LOCAL, .su.dominio

El campo opcional cmd_shell puede contener un comando de shell para que sea invocado cuando una búsqueda coincida con la entrada. Esto es útil para establecer trampas que puedan delatar a atacantes potenciales:

in.ftpd: ALL EXCEPT LOCAL, .vbrew.com : \
echo "petición de %d@%h" >> /var/log/finger.log; \
if [ %h != "vlager.vbrew.com" ]; then \
finger -l @%h >> /var/log/finger.log \
fi

Los argumentos %h y %d son expandidos por tcpd al nombre del nodo cliente y al nombre del servicio, respectivamente. Refiérase a la página del manual de hosts_access(5) para mas detalles.

 

9.3 Los ficheros services y protocols

Los números de puerto en los que se ofrecen ciertos servicios "estándar" están definidos en el RFC de "Números Asignados"7. Para permitir a los programas cliente y servidor convertir nombres de servicios en estos números, se almacenan en un fichero llamado /etc/services.

Una entrada se construye así:

servicio puerto /protocolo [aliases]

Aquí, servicio especifica el nombre del servicio, puerto define el puerto por el que se ofrece el servicio, y protocolo define que protocolo de transporte se usa. Comúnmente, este es udp o tcp. Es posible que un servicio sea ofrecido a mas de un protocolo, lo mismo que es posible ofrecer distintos servicios por el mismo número de puerto, siempre que el protocolo sea distinto. El campo aliases permite especificar nombres alternativos para el mismo servicio.

_____________________________________________
6 Normalmente solo los nombres de nodos locales obtenidos de búsquedas en /etc/hosts no contienen puntos.
7 N. del T.: A veces se conocen como Well Known Ports, es decir, Puertos Bien Conocidos

 

Usualmente, no se necesita cambiar el fichero de servicios que viene con el software de red en su sistema Linux. De todas formas, presentaremos un pequeño extracto de ese fichero.

# El fichero services:
#
# servicios conocidos (well-known)
echo 7/tcp # Eco
echo 7/udp #
discard 9/tcp sink null # Descartar
discard 9/udp sink null #
daytime 13/tcp # Fecha del sistema
daytime 13/udp #
chargen 19/tcp ttytst source # Generador de caracteres
chargen 19/udp ttytst source #
ftp-data 20/tcp # Protocolo FTP de ficheros (Datos)
ftp 21/tcp # Protocolo FTP de ficheros (Control)
telnet 23/tcp # Protocolo de Terminal
smtp 25/tcp # Protocolo de Correo
nntp 119/tcp readnews # Protocolo de Noticias
#
# servicios UNIX
exec 512/tcp # rexecd de BSD
biff 512/udp comsat # Notificacion de correo
login 513/tcp # login remoto
who 513/udp whod # who y uptime remotos
shell 514/tcp cmd # comando remoto, si contrase~na
syslog 514/udp # registro remoto del sistema
printer 515/tcp spooler # cola de impresion remota
route 520/udp router routed # informacion de encaminamiento

Observe que, por ejemplo, el servicio echo es ofrecido en el puerto 7 tanto para TCP como para UDP, y que el puerto 512 es usado para dos servicios diferentes; el demonio COMSAT (que notifica a los usuarios de correo recién llegado, vea xbiff(1x)), mediante UDP, y la ejecución remota (rexec(1)), usando TCP.

Ocurre algo similar con el fichero de protocolos: la librería de red necesita una forma de convertir nombres de protocolo _ por ejemplo, los usados en el fichero services_ a números de protocolo entendibles por el nivel IP en otros nodos. Esto se hace buscando el nombre en el fichero /etc/protocols. Contiene una entrada por línea, cada una con un nombre de protocolo y el número asociado. Necesitar modificar este fichero es todavía mas improbable que tener que hurgar en /etc/services. Le mostramos un fichero ejemplo:

#
# Internet (IP) protocols
#
ip 0 IP # protocolo internet, pseudo-protocolo
icmp 1 ICMP # protocolo de mensajes de control
igmp 2 IGMP # protocolo para mensajes multidestino
tcp 6 TCP # protocolo de control de transmision
udp 17 UDP # protocolo de datagramas de usuario
raw 255 RAW # interfaz IP directa (modo "crudo")
"

 

9.4 Llamada a Procedimientos Remotos

Un mecanismo muy general para aplicaciones cliente-servidor lo proporciona RPC, el paquete Remote Procedure Call. RPC fue desarrollado por Sun Microsystems, y es una colección de herramientas y funciones de librería. Ejemplos de aplicaciones construidas sobre RPC son NFS, el sistema de ficheros en red, y NIS, el sistema de información de red, que serán presentados en próximos capítulos.

Un servidor RPC consiste en una colección de procedimientos a los que el cliente puede llamar enviando una petición RPC al servidor, junto con los parámetros del procedimiento.

El servidor invocara al procedimiento indicado en nombre del cliente, devolviendo el valor del resultado, si lo hay. Para que sea independiente de la plataforma, todos los datos intercambiados entre el cliente y el servidor son convertidos al formato denominado de Representación Externa de Datos o XDR8 por el segundo, y convertidos otra vez a la representación de la máquina local por el receptor.

A veces, las mejoras en una aplicación RPC introducen cambios incompatibles en el interface de llamada a procedimiento. Por supuesto, solo cambiando el servidor dejaría de funcionar cualquier aplicación que todavía espere el comportamiento original. Por ello, los programas RPC tienen números de versión asignados, normalmente empezando con 1, y con cada nueva versión del interface RPC este contador se incrementara. A menudo, un servidor puede ofrecer varias versiones a la vez; entonces los clientes indicaran en sus peticiones mediante el número de versión que implementaron del servicio desean usar.

_____________________________________________
8 N. del T.: del inglés eXternal Data Representation

 

La comunicación por red entre servidores y clientes RPC es un poco peculiar. Un servidor RPC ofrece una o mas colecciones de procedimientos; cada conjunto de éstos es llamado programa, y es identificado unívocamente por un número de programa. En /etc/rpc se suele mantener una lista que mapea nombres de servicios con números de programa, reproducimos un extracto de éste en la figura 9.2.

#
# /etc/rpc - servicios variados basados en RPC
#
portmapper 100000 portmap sunrpc
rstatd 100001 rstat rstat_svc rup perfmeter
rusersd 100002 rusers
nfs 100003 nfsprog
ypserv 100004 ypprog
mountd 100005 mount showmount
ypbind 100007
walld 100008 rwall shutdown
yppasswdd 100009 yppasswd
bootparam 100026
ypupdated 100028 ypupdate

Figura 9.2: Un ejemplo de fichero /etc/rpc.

En redes TCP/IP, los autores de RPC se encontraron con el problema de mapear números de programa a servicios de red genéricos. Decidieron que cada servidor proporcionará ambos, un puerto TCP y otro UDP, para cada programa y para cada versión. Generalmente, las aplicaciones RPC usaran UDP cuando envíen datos, y solo recaerán en TCP cuando los datos a transferir no quepan en un datagrama UDP sencillo.

Por supuesto, los programas clientes tienen que tener una forma de encontrar a que puerto mapea un número de programa. Usando un fichero de configuración para esto sería muy inflexible: ya que las aplicaciones RPC no usan puertos reservados, no hay garantías de que un puerto originalmente pensado para ser usado por nuestra aplicación de base de datos no haya sido cogido por algún otro proceso. Por lo tanto, las aplicaciones RPC escogen cualquier puerto que puedan utilizar, y lo registran con el denominado demonio mapeador de puertos9. Este último actúa como un distribuidor de servicios para todos los servidores que corren en su máquina: un cliente que desee contactar con un servicio que tiene un número de programa dado, preguntara primero al mapeador de puertos del nodo del servidor quien devolverá los números de puerto TCP y UDP por los que el servicio puede ser accedido.

Este método tiene como mayor inconveniente que introduce un punto de ruptura único, muy parecido al que crea el demonio inetd en los servicios Berkeley estándar. De todas formas, este caso es un poco mas grave, porque cuando el mapeador de puertos cae, toda la información de puertos RPC se pierde; esto normalmente implica que hay que rearrancar todos los servidores RPC manualmente, o rearrancar toda la máquina.

En Linux, el mapeador de puertos se llama rpc.portmap y reside en /usr/sbin. Aparte de asegurarse de que es arrancado desde rc.inet2, el mapeador de puertos no necesita mas trabajo de configuración.

_____________________________________________
9 N. del T.: Del inglés Portmapper daemon

 

9.5 Configurar los Comandos r

Hay varios comandos para ejecutar programas en nodos remotos. Son rlogin, rsh, rcp y rcmd. Todos ellos lanzan un shell en el nodo remoto y permiten al usuario ejecutar comandos. Por supuesto, el cliente necesita tener una cuenta en el nodo en el que se van a ejecutar los comandos. Por ello todos estos comandos llevan a cabo un procedimiento de autorización. Normalmente, el cliente indicara el nombre de login del usuario al servidor, el cual requerirá un password que será validado de la forma habitual.

A veces, sin embargo, es deseable el relajar estos chequeos de autorización para ciertos usuarios. Por ejemplo, si usted tiene que entrar frecuentemente en otras máquinas de su LAN, tal vez desee ser admitido sin tener que escribir su password cada vez.

Deshabilitar autorizaciones solo es aconsejable en un número reducido de nodos cuyas bases de datos de passwords estén sincronizadas, o para un número reducido de usuarios privilegiados que necesiten acceder a muchas máquinas por razones administrativas. Siempre que desee permitir a gente entrar en su nodo sin tener que especificar un login o password, debe asegurarse de que no permite acceso accidentalmente a nadie mas.

Hay dos formas de deshabilitar chequeos de autorización para los comandos r. Una es que el superusuario permita a ciertos o a todos los usuarios el entrar, sin ser preguntados por un password, en ciertos o en todos los nodos (lo cual es ciertamente una mala idea).

Este acceso es controlado por un fichero denominado /etc/hosts.equiv. Este contiene una lista de nodos y nombres de usuarios que son considerados equivalentes a usuarios en el nodo local. Una opción alternativa es que un usuario permita acceso a otros usuarios de ciertos nodos a su cuenta. Estos serian listados en el fichero .rhosts en el directorio home del usuario. Por razones de seguridad, este fichero debe pertenecer al usuario o al superusuario, y no debe ser un enlace simbólico, de otro modo será ignorado.10

Cuando un cliente pide un servicio r, su nodo y nombre de usuario son buscados en el fichero /etc/hosts.equiv, y después en el fichero .rhosts del usuario con cuyo nombre se pretende entrar. Como ejemplo, asumamos que janet esta trabajando en gauss e intenta entrar en la cuenta de joe en euler. A partir de ahora, nos referiremos a Janet como el usuario cliente, y a Joe como el usuario local. Ahora, cuando Janet escriba

$ rlogin -l joe euler

en gauss, el servidor primero chequeara en hosts.equiv 11 si a Janet se le puede proporcionar acceso libre y, si esto falla, intentará localizarla en el fichero .rhosts del directorio home de joe.

_____________________________________________
10 En un entorno NFS, podría necesitar darle una protección de 444, porque el superusuario por lo general esta muy restringido en el acceso a ficheros en discos montados vía NFS.

 

El fichero hosts.equiv en euler es algo así:

gauss
euler
-public
quark.physics.groucho.edu andres

Una entrada consiste en un nombre de nodo, seguido opcionalmente por un nombre de usuario. Si aparece un nombre de nodo y nada mas, todos los usuarios de ese nodo serán admitidos en sus cuentas locales sin ninguna comprobación. En el ejemplo anterior, Janet hubiera sido autorizada a entrar en su cuenta janet si llamaba desde gauss, y lo mismo se aplicaría a cualquier otro usuario exceptuando a root. De todas formas, si Janet desea entrar como joe, se le pediría un password como siempre.

Si un nombre de nodo va seguido de un nombre de usuario, como en la ultima línea del fichero ejemplo, a ese usuario se le permite acceso libre de password a todas las cuentas excepto a la cuenta root.

El nombre de nodo también puede ir precedido de un signo menos, como en la entrada "-public". Esto requiere autorización para todas las cuentas en public, sin importar lo que permitan los usuarios individuales en sus ficheros .rhosts.

El formato del fichero .rhosts es idéntico al del hosts.equiv, pero su significado es un poco diferente. Consideremos el siguiente fichero .rhosts de Joe en euler:

chomp.cs.groucho.edu
gauss janet

La primera entrada permite a joe acceso libre cuando entra desde chomp.cs.groucho.edu, pero no afecta a los permisos de ninguna otra cuenta en euler o chomp. La segunda entrada es una pequeña variación de esto en que permite a janet acceso libre a la cuenta de Joe cuando entra desde gauss.

_____________________________________________
11 Observe que el fichero hosts.equiv no es examinado cuando alguien intenta entrar como root.

 

Observe que el nombre de nodo del cliente se obtiene mediante la resolución inversa de la dirección del que llama a un nombre, de forma que esta característica fallará con nodos desconocidos para el sistema de resolución. El nombre de nodo del cliente se considera que coincide con el nombre en los ficheros de nodos en uno de los siguientes casos:

o El nombre canónico del cliente (no un alias) coincide literalmente con el nombre de nodo en el fichero.

o Si el nombre de nodo del cliente es un nombre de dominio completamente cualificado (como el devuelto por el sistema de resolución cuando se tiene DNS en marcha), y no coincide literalmente con el nombre de nodo en el fichero de nodos, se compara con el nombre de nodo que se forma al expandirlo con el nombre de dominio local.