Category: Tips

Problemas de acceso a una IP o dominio público desde una red LAN

En ocasiones más de uno se habrá encontrado con el problema de que tiene una dirección IP pública (fija o dinámica) o un dominio público (mediante DNS fijo o dinámico) que apunta al router que tenemos dispuesto, permitiendo acceder a un servicio de una máquina que corre en nuestra red de área local (LAN) desde fuera de ella, pero desde la red local es imposible acceder con dicha dirección o dominio. Si alguna vez te ha pasado esto, te explico las causas y las posible soluciones.

La causa de este comportamiento está sujeta habitualmente a medidas de seguridad que evitan las conexiones loopback como característica de seguridad. La dirección lookback es una dirección especial que los host utilizan para dirigir el tráfico hacia ellos mismos. Esta característica suele ser una extensión de la NAT llamada NAT loopback.

NAT loopback es una extensión de NAT que te permite acceder a tu dirección pública de Internet (WAN) desde dentro de tu propia red (LAN). Esto es práctico cuando tenemos algún servidor dentro de nuestra propia red, ya que nos permite acceder a ese servidor usando la misma IP pública (y por lo tanto también dominio) tanto desde dentro de la LAN, como desde el exterior.

Esta característica desgraciadamente no está presente en la mayoría de los routers que nos proporcionan nuestros proveedores de Internet. Con lo cual lo único que puedes hacer es comprobar si es posible activar esta característica en la zona de administración del router o contactando a tu proveedor de acceso a Internet para que te lo solucione.

La ausencia de esta característica provoca que por ejemplo si te haces con un NAS, dispositivos de almacenamiento en la red que últimamente están teniendo una gran aceptación, no se pueda acceder desde el dominio a tu NAS si estás en la misma red local que el NAS. Es decir, terminas usando la IP local de la LAN (ejemplo: 192.168.1.177) cuando estás en la misma red y el dominio (mi_nas.com) para acceder desde fuera de la red LAN. Dos formas de acceder que vuelven complicado configurar aplicaciones, como por ejemplo un cliente de sincronización del estilo Dropbox, debido a que no tienes una única forma de acceder al NAS, la cual debería ser el dominio.

Si el equipo con el que accedes al NAS, es de sobremesa aún puedes solucionarlo editando el archivo “hosts” del sistema, pero en caso contrario tendrás que o bien cambiar el router o funcionar con IP local y dominio dependiendo si estás dentro o fuera de la red local del NAS.

Paso a explicar como solucionar la resolución de dominio tanto para Windows como para GNU/Linux mediante la edición del archivo “hosts” de tu ordenador.

 

Windows


  1. Abrir un editor de texto en “modo administrador
  2. Abrir el fichero ubicado en la siguiente ruta C:\Windows\System32\Drivers\etc\hosts
  3. Añadir el host mediante la adición de una línea al final del fichero. Usando el ejemplo anterior del NAS sería:
    192.168.1.177 mi_nas.com
  4. Guardar y a partir de ahora mi_nas.com resolverá directamente como 192.168.1.177

 

GNU/Linux


  1. Abrir un terminar y poner el siguiente comando en el terminal
    sudo nano /etc/hosts
  2. Añadir el host mediante la adición de una línea al final del fichero. Usando el ejemplo anterior del NAS sería:
    192.168.1.177 mi_nas.com
  3. Guardar y a partir de ahora mi_nas.com resolverá directamente como 192.168.1.177

 

Espero que este artículo sirva para arrojar un poco de luz en toda esta problemática.

Solucionar error “failed to create process” en herramientas instaladas de Python

Hoy me encontraba revisando dependencias de las herramientas, librerías y frameworks que tenía en Python y me he encontrado con la herramienta pipdeptree, una herramienta que nos permite enumerar las herramientas, librerías y frameworks al estilo del comando “pip freeze” pero mostrando además cada una de las dependencias que tiene con otras librerías.

Como suele ser la costumbre realicé las instalación con el clásico:

pip install pipdeptree

La instalación resultó satisfactoria pero al ejecutar la herramienta devuelve un error:

$ pipdeptree

failed to create process.

El error “failed to create process” se produce por un problema de la ruta en el script de ejecución. Concretamente por culpa de espacios en la ruta donde tenemos instalados Python y donde se instalan los paquetes mediante el comando “pip“. Si eres de los que tiene instalado Python en “Archivos de Programa” o “Program File”, vas a tener este problema si además estás usando una versión de “setuptools” anterior a la versión 24.3.1 del 23 de Julio del 2016.

Para ver la versión de “setuptools” que estás usando actualmente ejecuta el siguiente comando:

easy_install --version

Si tienes una versión anterior y no quieres actualizar, puedes corregir el error si vas a la carpeta “Scripts” dentro de tu instalación de Python y buscas el archivo “pipdeptree-script.py” que es el que ejecuta la herramienta gracias al binario “pipdeptree.exe” que lo invoca:

#!d:\program files (x86)\python35-32\python.exe
# EASY-INSTALL-ENTRY-SCRIPT: 'pipdeptree==0.10.1','console_scripts','pipdeptree'
__requires__ = 'pipdeptree==0.10.1'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(
        load_entry_point('pipdeptree==0.10.1', 'console_scripts', 'pipdeptree')()
    )

Para corregir el problema basta con añadir unas comillas a la ruta de la primera línea:

#!"d:\program files (x86)\python35-32\python.exe"

Si no tienes inconveniente alguno en actualizar “setuptools”, basta con que ejecutes el comando de actualización estándar de “pip“:

pip install --upgrade setuptools

Obviamente la segunda solución es la más recomendable, pero la explicación de la primera puede servir para solucionar errores similares en otras herramientas si se presentan, y si la actualización no funciona o no es una opción.

Averiguar dominio final de un nombre de dominio alternativo

Recientemente me he encontrado en la situación de tener que usar un SMTP para mandar emails. En estos casos el servicio suele estar vinculado a un dominio que apunta a la maquina donde se encuentra corriendo el servidor SMTP corriendo el servicio. Suele ser cada vez más muy habitual que además estos  servicios estén securizados con SSL para proteger las conexiones.

Por otro lado, puede darse que para un dominio se tengan dominios alternativos que aseguren el acceso a la máquina, que en mi caso, es la que corre el servidor SMTP. Esto asegura que se pueda acceder a la máquina usando distintos dominios que se proveen desde distintos proveedores de dominio. Esta no es la única situación que lo justifica, sino que también puede hacerse porque un proveedor de servicios ofrezca personalización de los servicios con el dominio del cliente, permitiendo que una empresa o un usuario particular, tenga dichos servicios usando su propio dominio.

Aquí  es donde ocurre el problema, porque los certificados SSL para cifrar las conesxiones se asocian a un dominio y la redirección de dominios alternativos  provoca que no coincida el certificado del dominio final con el dominio alternativo con el que se accede, dando como resultado un error del tipo:

Error: Hostname/IP doesn't match certificate's altnames: "Host: smtp.mascandobits.es. is not in the cert's altnames: DNS:*.servidoresdns.net, DNS:servidoresdns.net"

Los certificados SSL se asocian a un único demonio por normal general, aunque es posible generar certificados que abarquen varios dominios (dominio + dominios alternativos).

Si tienes este problema y quieres seguir usando la conexión segura con SSL, tu única opción (si has contratado con el proveedor de servicios) es averiguar el dominio principal para el que es válido el certificado. Normalmente va a ser el del dominio final.

Desde Linux esta tarea es bien sencilla, basta con usar primero el comando “nslookup” para comprobar la dirección IP final, obteniendo cómo resuelve el DNS dicho dominio. Pongamos un ejemplo de un servicicio SMTP con dominio “smtp.mascandobits.es“:

nslookup smtp.mascandobits.es
Server:         208.67.222.223
Address:        208.67.222.223#53

Non-authoritative answer:
Name:   smtp.mascandobits.es
Address: 217.76.127.101

En la parte de “Address” de la sección “Non-authoritative answer” obtenemos la dirección IP final. Con esa IP aplicamos el comando “host” que permite resolver de manera inversa el dominio. Es decir, pasar de una IP a un nombre de dominio.

host 217.76.127.101
100.128.76.218.in-addr.arpa domain name pointer smtp-13.servidoresdns.net.

En este ejemplo el comando nos resuelve que el dominio principal que apunta a esa IP es “smtp-13.servidoresdns.net“. Este dominio resulta ser el que coincide con el certificado SSL, solventando el error que se presentaba al inicio de la entrada.

Alguno pensará que para qué complicarse tanto si se puede obtener la IP final de la máquina que da el servicio. La respuesta es bien sencilla. En un dominio se puede redirigir hacia donde apunta, y de manera transparente un cambio de IP en la máquina que aloja el servicio, no conlleva el cambiar el nombre de dominio hacia donde se apunta el servicio. Es decir, basta con que el dominio apunte a la nueva IP donde se encuentra la máquina.

Solucionar problema de Autoridad de Certificación en los binarios .EXE generados con PY2EXE

Últimamente he empezado a utilizar la herramienta py2exe para poder mejorar la distribución de mis desarrollos en Python en sistemas Windows, mediante la generación de un ejecutable .exe autocontenido que evite tener que pedir al usuario que instale Python y las correspondientes librerías.

La herramienta py2exe puede ser instalada de manera sencilla con el comando:

pip install py2exe

Y puedes compilar rápidamente cualquier programa en Python realizando un fichero setup.py simple como este:

from distutils.core import setup
import py2exe

setup(console=['mi_programa.py'])

El cual deberemos ejecutar desde una consola de comandos de la siguiente forma:

python setup.py install

Al ejecutarlo nos resolverá todas las dependencias y dejará la versión autcontenida con el ejecutable mi_programa.exe en la carpeta dist.

Si trabajas con servicios o mínimamente con conexiones seguras haciendo peticiones, seguro que acabas usando la librería requests o puede que la librería con la que trabajes, la use como base para hacer conexiones seguras con SSL. Si intentas usar estas librerías que trabajan con certificados SSL te encontrarás con el siguiente error cuando ejecutas tu binario .exe:

requests.exceptions.SSLError: [Errno 2] No such file or directory

El cual viene dado porque cuando se empaqueta todo, el certificado de la Autoridad de Certificación no se incluye al ser un fichero que no es de Python. A causa de esto, cuando se empaquetan todas la librerías y se llama de manera relativa al certificado de la librería desde nuestro empaquetado con nuestro binario .exe de py2exe, éste no se encuentra porque ninguna parte.

Para solucionarlo es tan sencillo como proporcionar un certificado válido del tipo cacert.pem en la variable de entorno de Python REQUESTS_CA_BUNDLE de nuestro programa. Pero para resolverlo, vamos a hacerlo de manera elegante parcheando dicha variable sólo si es necesario, para poder seguir tirando de los certificados de las propias librería mientras desarrollamos.

Para ello vamos a instalar certifi, una librería que nos facilita una serie de Certificados Raíz que nos van a permitir validar la integridad de certificados, tanto de SSL, como de TSL de los servicios a los que nos conectemos.

pip install py2exe

Ahora vamos a modificar un poco nuestro setup.py:

from distutils.core import setup
import py2exe
import certifi

setup(console=['mi_programa.py'], data_files=[certifi.where()])

Hemos añadido únicamente el import de certifi y en los parámetros de setup hemos añadido el fichero de certificado que nos devuelve certifi gracias al método where. Este fichero se copiará en dist al mismo nivel que nuestro .exe.

Por último añadiremos en mi_programa.py al inicio de nuestro programa el siguiente código:

cacert_path = os.path.join(os.getcwd(), 'cacert.pem')
if os.path.exists(cacert_path):
    os.environ['REQUESTS_CA_BUNDLE'] = cacert_path

El código genera la ruta hasta certificado cacert.pem, usando el directorio de trabajo que será dist. Esa ruta se busca si existe entre las rutas que maneja Python para resolver las librerías y dependencias. Si se ejecuta desde el entorno de desarrollo, encontrará el de la propia librería que lo este usando, sino parcheará añadirá la ruta para que coja certificado que hemos copiado en dist.

De esta forma no sólo se soluciona el problema del certificado de la Autoridad de Certificación, sino que el parche se aplica selectivamente copiando fichero de certificado necesario. Esto es importante porque los certificados pueden cambiar y basta con volver a generar los binarios .exe con py2exe, teniendo las librerías actualizadas y con los certificados en regla, para que el ejecutable creado también los tenga.