Un nuevo servidor de eMule/eD2K: eNode

He dejado de lado la programación de la nueva web porque me he metido en otro proyecto.

Me gustaría tener un servidor de eMule para los usuarios de HispaShare pero el único programa existente (Lugdunum) no es de código abierto ni tiene las funcionalidades que yo quiero. Por lo tanto me he propuesto programar uno yo mismo y liberar el código para que cualquiera pueda mejorarlo.

Ya tengo lista una versión alfa. Para quien quiera revisarlo o contribuir al proyecto, puede descargarlo o hacer un fork en GitHub. En la red local funciona bastante bien (habrá que ver cómo rinde en el mundo real con cientos de miles de usuarios).

Como veréis está escrito en Node.js y el almacenamiento lo hace en bases de datos MySQL. No sé si el almacenamiento SQL es la mejor opción para este caso pero es muy simple cambiarlo a otro sistema, tal vez pruebe algún NoSQL como Cassandra o CouchDB o un indexador tipo Sphinx. ¿Alguien me recomienda un sistema eficiente para buscar cadenas de texto en tablas de 50 millones de filas?

Estoy ahorrando para contratar una máquina más potente para poner en marcha el servidor y trasladar la web actual (la publicidad de la web es un fastidio pero paga estas cosas…). En cuanto pueda anunciaré la dirección para que podáis añadirlo a vuestra lista de servidores.

Para más detalles sobre eNode, características, instalación y configuración, visitad el GitHub del proyecto.

Anuncios

Sistema de comentarios terminado

A partir de hoy, si estás registrado/a en la web, ya puedes escribir tus comentarios de las películas que hayas visto. Además puedes valorar los comentarios que hagan los demás (algo así como en Youtube).

Si una película tiene varios comentarios, inicialmente sólo mostrará el mejor valorado. Para verlos todos, hay un botón.

Todo el sistema esta hecho en AJAX y como acabo de ponerlo en marcha tal vez tenga algunos fallos que iré corrigiendo sobre la marcha.

Sobre cómo obtener el número de fuentes de un elink

Puede que ya no lo recuerde nadie, en los tiempos de Razorback2, HispaShare tenía una funcionalidad que permitía ver (casi) en tiempo real el número de fuentes de cada elink. Pinchando un icono al lado de cada elink se veía una gráfica que mostraba el número de fuentes completas, parciales y peticiones que había tenido el elink en los últimos días y así comprobar el estado “de salud” de cada elink.

Obtener esos datos era facilísimo ya que el servidor Razorback2 tenía una web donde proporcionaba esa información. El servidor tuvo problemas legales y la web se cerró.

Desde ese momento, para obtener el número de fuentes lo que hice fue hacer un programilla que simulaba las peticiones UDP que hace eMule para obtener el número de fuentes de un elink determinado en cada servidor. Pero con el tiempo los servidores perdieron esa funcionalidad.

Había otra solución, en vez de hacer una petición UDP preguntando por el número de fuentes, hacías una petición con distintos opcodes que el servidor interpretaba como una búsqueda. Si buscas “ed2k::<hash>”, el servidor te devuelve el número de clientes que tienen un archivo con ese hash. Pero desde hace medio año, o puede que más, los servidores tampoco permiten hacer búsquedas de tipo “global” (es decir, por UDP). Prueba de ello es que si con eMule haces una búsqueda local y global obtienes los mismos resultados (puede que en global recibas SPAM si no tienes los filtros de IPs, otro día hablaré sobre ello…)

Resumiendo, ahora mismo, la única forma (que yo sepa!!!) de averiguar las fuentes que tiene un elink es conectarte vía TCP al servidor y preguntarle. Pero claro, eso ya no es tan fácil de programar… buscar por KAD queda descartado ya que no permite hacer búsquedas por Hash. Tendría que hacer un programa que se conectara a la vez a todos los servidores que pudiera para ir enviando las peticiones en paralelo. Haciendo una petición cada 5 segundos al cabo del día habría comprobado 17280 elinks, casi todos los de la web. Dando prioridad a los nuevos elinks podría hacer que las fuentes de éstos se vieran casi en tiempo real.

El protocolo no es muy complicado (aunque sí feo) pero no encuentro documentación decente y actualizada sobre él y no voy a perder el tiempo haciendo ingeniería inversa con un servidor local… eso ya lo hice con los UDPs xD

Tengo pensado reutilizar código de aMule (el eMule para Linux) pero mi nivel de C++ no alcanza esa categoría y me cuesta entenderlo pero tampoco me apetece traducir las funciones a otro lenguaje que me sea más familiar. Si alguien tiene experiencia en programar aplicaciones multihilo con sockets en C++ y le interesa explicarme cuatro cosillas, lo agradeceré. Sino ya me buscaré la vida… porque lo de obtener el número de fuentes es una obsesión…

Comprobar si un email es válido (II)

Ya he terminado el script que comprueba si un email es válido o no. Básicamente hace lo que comenté en el post anterior:

  1. Averigua los registros MX del dominio
  2. Los va probando hasta encontrar uno que funcione
  3. Simula el envío de un email para ver que dice el servidor sobre la dirección

He colgado un ejemplo con mensajes de debug por si alguien quiere ver como funciona o probarlo. Si estás interesado en el código, pídemelo.

Algunos problemas que tiene:

  1. Puede validar alguna dirección como correcta sin serlo ya que ciertos servidores como hotmail se lo tragan todo (seguramente para evitar comprobaciones masivas por spammers).
  2. Hay servidores como yahoo que, aparte de no implementar correctamente el protocolo, muchos de sus servidores MX rechazan las peticiones.
  3. Otros servidores, como telepolis.es dan error: 550 Reverse DNS lookup failed for host 64.235.***.***. Pero supongo que eso es problema de ellos.
  4. No es una comprobación inmediata. Algunos servidores se toman su tiempo.

Comprobar si un email es válido

Muchos usuarios al registrarse en la web escriben direcciones de email inválidas (hotmeil.com, hotmaill.com, jotmail.com… y cosas peores, no es broma!) y esto hace que sendmail se vuelva loco. Constantemente trata de reenviarlos, resolver dominios que no existen o conectar a puertos que no responden… esto provoca que los logs de error crezcan de una forma espectacular y consume recursos de una forma que no había visto antes (sin duda por una configuración chapucera mía). Pero como la documentación de sendmail es para volverse loco y no me apetece probar otras cosas (como qmail o mail() de PEAR), haré un script en PHP que me haga la tarea de comprobar direcciones y mandar emails.

¿Cómo saber si una dirección es válida? Lo más simple sería mirar si responde a un ping.

sonic@XTC:~$ ping gmail.com
PING gmail.com (64.233.161.83) 56(84) bytes of data.
64 bytes from od-in-f83.google.com (64.233.161.83): icmp_seq=1 ttl=240 time=183 ms
64 bytes from od-in-f83.google.com (64.233.161.83): icmp_seq=2 ttl=240 time=224 ms
--- gmail.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 183.999/204.274/224.550/20.280 ms

Pero claro, eso no significa nada. Podría ser un servidor de cualquier cosa. Habría que comprobar el puerto 25, pero…

sonic@XTC:~$ telnet gmail.com 25
Trying 64.233.161.83...
Trying 66.249.91.83...
Trying 209.85.171.83...
telnet: Unable to connect to remote host: Connection timed out

Lo más normal es que no responda ya que antes deberíamos mirar los registros MX. Se suelen utilizar distintos servidores para el correo. Es muy fácil de averiguar.

sonic@XTC:~$ dig -t MX gmail.com
; <<>> DiG 9.4.2-P2 <<>> -t MX gmail.com
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25761
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 10
;; QUESTION SECTION:
;gmail.com.            IN    MX
;; ANSWER SECTION:
gmail.com.        244    IN    MX    10 alt2.gmail-smtp-in.l.google.com.
gmail.com.        244    IN    MX    50 gsmtp147.google.com.
gmail.com.        244    IN    MX    50 gsmtp183.google.com.
gmail.com.        244    IN    MX    5 gmail-smtp-in.l.google.com.
gmail.com.        244    IN    MX    10 alt1.gmail-smtp-in.l.google.com.
;; AUTHORITY SECTION:
gmail.com.        241375    IN    NS    ns4.google.com.
gmail.com.        241375    IN    NS    ns1.google.com.
gmail.com.        241375    IN    NS    ns2.google.com.
gmail.com.        241375    IN    NS    ns3.google.com.
;; ADDITIONAL SECTION:
gmail-smtp-in.l.google.com.   238   IN    A    209.85.129.114
gmail-smtp-in.l.google.com.   238   IN    A    209.85.129.27
alt1.gmail-smtp-in.l.google.com. 44 IN    A    209.85.147.27
alt2.gmail-smtp-in.l.google.com. 37 IN    A    209.85.133.27
alt2.gmail-smtp-in.l.google.com. 37 IN    A    209.85.133.114
gsmtp147.google.com.        4720    IN    A    209.85.147.27
gsmtp183.google.com.        5711    IN    A    64.233.183.27
ns1.google.com.           345591    IN    A    216.239.32.10
ns2.google.com.           336560    IN    A    216.239.34.10
ns4.google.com.           336560    IN    A    216.239.38.10
;; Query time: 273 msec
;; SERVER: 192.168.0.1#53(192.168.0.1)
;; WHEN: Fri Oct 24 20:58:36 2008
;; MSG SIZE  rcvd: 390

Ahora sí podemos hacer un telnet al servidor correcto:

sonic@XTC:~$ telnet gmail-smtp-in.l.google.com 25
Trying 72.14.221.114...
Connected to gmail-smtp-in.l.google.com.
Escape character is '^]'.
220 mx.google.com ESMTP
HELO hispashare.com
250 mx.google.com at your service

Ya estamos conectados al servidor de correo de google y podemos comunicarnos con él. Para comprobar si pepe@gmail.com es válido podemos hacer lo siguiente:

sonic@XTC:~$ telnet gmail-smtp-in.l.google.com 25
Trying 209.85.129.27...
Connected to gmail-smtp-in.l.google.com.
Escape character is '^]'.
220 mx.google.com ESMTP
HELO hispashare.com
250 mx.google.com at your service
MAIL FROM: <webmaster@hispashare.com>
250 2.1.0 OK
RCPT TO: <pepe@gmail.com>
550-5.1.1 The email account that you tried to reach does not exist. Please
550-5.1.1 try double-checking the recipient's email address for typos
550-5.1.1 or unnecessary spaces. Learn more at
550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596
QUIT
221 2.0.0 closing connection
Connection closed by foreign host.

Y con estos pasos ya sabemos si un servidor existe, si es de correo y si la dirección es válida. Con una dirección correcta el resultado sería así:

RCPT TO: <hispashare@gmail.com>
250 2.1.5 OK

Eso es todo. No parece complicado de implementar en PHP así que este fin de semana haré mi propia función mail() para comprobar direcciones y mandar correo. Así podré quitar sendmail del servidor, que no me da más que dolores de cabeza (sí, lo más probable es que tenga algo mal configurado).

El registro de usuarios

Es una ironía

Como habréis podido comprobar, he puesto un cuadro para registrarse en la web.

De momento, para el usuario normal no sirve para nada. Mi intención es que más adelante (cuando lo programe…) los usuarios registrados podrán comentar las películas, crearse un listado de sus preferidas y compartirlo (algo así como youtube). No es necesario estar registrado para bajarse las películas. Y, por supuesto, no se revelará ningún dato privado ni tu e-mail a nadie.

Sin embargo, actualmente el registro sirve para que los colaboradores de la web, los cuales tienen una cuenta con más privilegios, puedan publicar sus trabajos y modificarlos si fuese necesario. Anteriormente los colaboradores tenían acceso total a la web lo cual era un grave problema de seguridad y, por desgracia, sólo me podía permitir confiar en unos pocos. En cambio ahora, cada colaborador sólo tiene acceso a sus cosas. Esto me permitirá abrir el sistema a más gente que esté interesada en compartir sus trabajos.

Clasificación por edades

RUna de las peticiones que tenía pendientes era la clasificación por edades de las películas. Puede parecer algo sencillo pero no lo es tanto…

Cada país tiene un sistema de clasificación distinto y también cambian los criterios con los cuales clasifican a las películas. En EE.UU. son muy estrictos con los temas de drogas y sexo pero con la violencia son más permisivos, en otros países ocurre lo contrario.

He hecho un programa que actualizará las fichas y poco a poco irá clasificando todas las películas que pueda, en principio adoptará el sistema estadounidense porque es el más fácil de obtener y el más difundido. Para películas donde esta clasificación no esté disponible, mirará si otro país ha creado una clasificación y tratará de convertirla al equivalente norteamericano.

Todo esto, como siempre, es muy subjetivo y habrá padres muy puritanos y otros más liberales. Del mismo modo habrá niños muy inocentes y otros que ya han visto de todo… La decisión final debería depender de los padres y lo que indica la web es simplemente una referencia.

Si alguien discrepa con la clasificación que tiene una película determinada, que deje un comentario en el blog.