viernes, enero 25, 2008

FreeBSD + Tomcat 5.5 + Apache SOAP (2da parte)

Configuraciones particulares (web.xml):

Listado de directorios:

Para habilitar el listado en algun directorio de nuestras webapps, es necesario modificar el archivo $tomcat_dir/webapps/$nombre_webapp/WEB-INF/web.xml
<servlet>
<servletname>NOMBRE_CUALQUIERA</servletname>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
...
<servlet-mapping>
<servlet-name>MISMO_NOMBRE_QUE_ARRIBA</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Ojo que url-pattern es respecto a la url de nuestra webapp.

Proteccion de directorios con contraseña:

Ojo que .htaccess no va a funcionar en este caso, es necesario editar el archivo web.xml para realizar esta accion.
<resource-env-ref>
<description>Link a la base de datos de usuarios</description>
<resource-env-ref-name>UserDatabase</resource-env-ref-name>
<resource-env-ref-type>org.apache.catalina.UserDatabase</resource-env-ref-type>
</resource-env-ref>
Con esto definiremos que la informacion de user/pass la obtendremos de un archivo
llamado tomcat-users.xml ubicado en $tomcat_dir/conf/ (ver server.xml <resource name ="UserDatabase" ), podemos cambiar esta configuracion en server.xml para tomar los user/pass de una base de datos accedida por JDBC.
<security-constraint>
<web-resource-collection>
<web-resource-name>CUALQUIER_NOMBRE</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>NOMBRE_DEL_ROL</role-name>
</auth-constraint>
</security-constraint>

<login-config>
<auth-method>BASIC</auth-method>
<realm-name>NOMBRE_CUALQUIERA</realm-name>
</login-config>
<security-role>
<description>DESCRIPCION</description>
<role-name>NOMBRE_DEL_ROL</role-name>
</security-role>

Por ultimo el método de autentificación existen 4: BASIC el que todos conocemos cuando se abre una ventanita y te pregunta la clave, CLIENT-CERT que es con certificado X509, FORM para utilizar un formulario jsp y DIGEST que que es una forma de encriptación.
El nombre del rol lo debemos tener definido en tomcat-users.xml y el nuevamente el url-pattern es realtivo a la webapp de la cual estamos editando el web.xml.
Ejemplo de tomcat-users.xml:
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="tomcat"/>
<role rolename="role1"/>
<role rolename="manager"/>
<role rolename="admin"/>
<user username="tomcat" password="tomcat" roles="tomcat"/>
<user username="role1" password="tomcat" roles="role1"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
</tomcat-users>

Instalar Driver Oracle:

Descargar Driver jdbc (ojdbc14.jar) de oracle ojo con la versión de la DB y la versión del jdk
http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html
Copiar ojdbc14.jar a $tomcat_dir/common/lib/

lunes, enero 21, 2008

FreeBSD + Tomcat 5.5 + Apache SOAP

Mi tercera tarea consiste en implementar/migrar un servidor apache/soap + tomcat, para ser utilizado en producción, para ello cuento con un equipo DELL PowerEdge 1950 con FreeBSD, el primer paso es revisar la configuración general del tomcat ubicada en /usr/local/tomcat5.5/conf/server.xml, eliminar de ella lo que no vamos a utilizar, lo ideal es hacer una copia de esta configuración por defecto ya que contiene bastante información comentada y complica la revisión de la configuración final.

HTTP connector: Por defecto vienen dos de estos conectores definidos uno con SSL y otro sin, tambien es posible utilizar compresion gzip en ellos.

<Connector port="8080"
maxThreads="700" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true" />
Connector sin SSL
<Connector port="8443"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" debug="0" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
Connector con SSL
compression="on"
compressionMinSize="2048"
noCompressionUserAgents="gozilla, traviata"
compressableMimeType="text/html,text/xml"
Parámetros para habilitar compresión gzip

AJP Connector: Este connector se usa para comunicar tomcat con otro servidor web nativo, esta forma de conexion es mucho mas rapida y eficiente que un proxy http.

<Connector port="8009"
enableLookups="false" address="127.0.0.1" redirectPort="8443" protocol="AJP/1.3" />
Conexion AJP
<Connector port="8082"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" acceptCount="100" connectionTimeout="20000"
proxyPort="80" disableUploadTimeout="true" />
Conexion proxy http



LOGS: si estamos interesados en los logs de acceso y consultas al servidor debemos usar, en el caso de servidor de producción, org.apache.catalina.valves.FastCommonAccessLogValve

<Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"
directory="logs" prefix="localhost_access_log." suffix=".txt"
pattern="common" resolveHosts="false"/>
Apache Portable Runtime (APR): Es una libreria altamente portable que Apache utiliza para mejorar su integración, escalabilidad y performance, nos permite acceso a funcionalidades propias del SO, y manejo de procesos (memoria compartida, Sockets, etc) entre otras cosas, para utilizar esta característica basta con compilar la libreria. Los sources están en $tomcar_dir/bin/tomcat-native.tar.gz, para poder realizar una compilación exitosa es necesario contar con APR 1.2+, OpenSSL 0.9.7+ (en el caso de utilizar connector HTTP-SSL), gcc y make en nuestro sistema.
En FreeBSD basta con instalar el port APR:

#cd /usr/ports/devel/apr/ && make install clean


luego de /usr/ports/distfiles copiar el archivo apr-x.x.x.tar.gz y descomprimirlo en algún lugar (ej /usr/local/tomcat5.5/apr) y luego descomprimir el archivo tomcat5.5/bin/tomcat-native.tar.gz. En su interior encontraremos la carpeta jni/native/ donde debemos ejecutar los comandos:

#export JAVA_HOME=/usr/local/diablo-jdk1.5.0/ <-
solo si no esta definido $JAVA_HOME previamente.
# sh buildconf --with-apr=(directorio donde previamente descomprimimos los sources de APR).
# ./configure --with-apr=/usr/bin/ --with-ssl=directorio de instalación de openssl (opcional)
# make

Con lo que se creara el archivo libtcnative-1.so en /usr/local/apr/lib, copiarlo a /usr/local/lib/ luego reiniciar Tomcat, tomcat detecta solo la presencia de la librería y comienza a usarla automáticamente, las configuraciones por defecto de esta librería suelen ser suficientes, pero de querer cambiar las opciones ver http://tomcat.apache.org/tomcat-5.5-doc/apr.html

Con esto el servidor debiera quedar en condiciones de producción, en el siguiente post me referire a algunas configuraciones particulares de las aplicaciones sobre tomcat (web.xml)

lunes, enero 14, 2008

M0n0wall, QoS (Quality Of Service) y VoIP

Mi segunda tarea fue mejorar la calidad de las comunicaciones a través de teléfonos IP al interior de la empresa para ello contamos con una red interna de 100mb y un enlace hacia inet de 2mb, todo esto manejado por un firewall m0n0wall (FreeBSD), la verdad es que esta tarea no es tan compleja desde el hecho que m0n0wall es un muy buen traffic-shaper.

Existen dos formas de manejo del ancho de banda uno estático y otro dinámico:

Estático: consiste en definir un ancho de banda exclusivo en base a ciertas reglas, por ejemplo designar 512 kbits/s para telefonía IP y 1,5 mbits/s para el resto de las conexiones, este sistema es el mas sencillo pero el menos óptimo ya que mientras no se establece ninguna comunicación VoIP esos 512kb/s no son utilizados por nadie aunque los necesite.
Dinámico: consiste en establecer pesos a cada tipo de conexión y asignar dinámicamente el uso del ancho de banda, esta fue la opción que decidimos implementar.

En m0n0wall existen 3 piezas clave para el manejo del ancho de banda, las reglas (rules), las colas (queue) y las cañerias (pipes):

Las cañerías se usan para establecer anchos de banda estáticos y las colas para racionar estos anchos de banda de manera dinámica, obviamente la reglas determinaran que paquetes acceden a que colas. Por lo tanto necesitamos definir estas tres piezas para tener un uso eficiente de nuestro ancho de banda (para informacion mas detallada ver guia "Traffic shaper 'manual' (alpha)" )

Las cañerías: En este caso (ancho de banda dinamico) definiremos dos cañerías levemente mas pequeñas que nuestro ancho de banda total una de entrada y otra de salida, se definen medianamente mas pequeñas, ya que m0n0wall dispondrá del total de esta cañería para realizar el traffic-shape y en el caso que este valor sea mayor al real (congestión o simplemente tu ISP no te da tus prometidos 2mb sino mas bien 1950kb/s) la distribución de ancho de banda ficticia puede afectar la calidad de la conexión que estas tratando de resguardar, y por ser esta, un factor critico en VoIP mejor prevenir que curar.

Colas: se deben definir dos colas (una de subida y otra de bajada) por cada peso que se quiera asignar, en este caso voy a definir dos colas para VoIP y dos para el resto del trafico Inet, he aquí una de las cosas mas importantes en este proceso los "pesos", para determinar el ancho de banda a utilizar por cada conexión no se utilizan prioridades sino que pesos, lo que quiere decir que aunque tenga mucho trafico VoIP nunca voy a dejar de permitir trafico del otro (web, telnet, ssh, ftp, etc) una prioridad mas alta me pondría en un lugar mas adelante de la cola mientras que un peso me dice cuantos paquetes de cada cola deben pasar a la cañería. Ej: si el peso VoIP es de 70 y el de la otra cola es 30, de cada 100 paquetes que entren a la pipa 70 serán VoIP y 30 de otro tipo, en el caso que existan, de no existir el 100% de la cañería sera usado por la cola que tenga paquetes para enviar.

Reglas: Las reglas determinaran que tipo de paquetes deben ir a que cola, no es muy complejo realizar este proceso gracias a la interfaz gráfica amigable que posee m0n0wall, lo importante es tener en cuenta que las reglas se ejecutan en orden y que en cuanto un paquete cumple una regla no se sigue evaluando, por lo tanto es recomendable siempre poner una regla al final con * para "agarrar" los paquetes que no cumplan ninguna regla de lo contrario estos paquetes se saltarían las colas y arruinarían el traffic-shaper. Para este caso particular la regla que establecí para el trafico VoIP fue en función del servidor de VoIP o PBX es decir todo trafico entrante o saliente de la PBX se marca como trafico VoIP y utiliza la cola de mas alto peso (determinar el peso ideal es un ejercicio de ensayo y error ;) )

Evaluación de la calidad VoIP

Para evaluar la calidad de la comunicación VoIP aparte de pedirle a los usuarios finales que realizaran llamadas y que estuvieran atentos a la calidad, instale un monitor (sniffer) especializado el AdventNet VQManager muy bueno y de fácil instalación tanto en Windows como en Linux, para el correcto funcionamiento de este sniffer, como el de cualquier otro, es necesario conectar la tarjeta de red en un puerto de nuestra topología que permita monitoreo, en el caso de un hub eso no es un problema pero en un switch no cualquier boca sirve, en mi caso utilice el puerto uplink del switch principal que esta fuera del firewall, pero con switch programables es posible poner cualquier otra boca en modo port-mirroring. Para saber mas al respecto es necesario referirse al manual de cada switch.

lunes, enero 07, 2008

Mantención servidor DNS

Mi primera tarea fue revisar que el servidor DNS de la empresa no tuviese entradas repetidas, ni zonas que ya no son clientes o algún otro tipo de problema de configuración.
Primero obtuve una lista de todos los dominios (zonas) definidas en el archivo de configuración del bind, normalmente /etc/namedb/named.conf, para ello escribí este script en perl:

#!/usr/bin/perl
open(my $in, "<", "named.conf") or die "No se puede abrir named.conf: $!"; open(my $out, ">", "dominios.txt") or die "no se puede escribir la salida: $!";

while (<$in>) {
if (/zone\s\"([\w\-\.]+)\"/) {
print $out "$1\n";
}
}

close $in;
close $out;
Mi experiencia en perl antes de esta tarea es igual a 0 (cero) por lo que pido comprensión a la hora de criticar el código :)

Luego con la lista de 1200 zonas que obtuve como resultado, la pase por un script que genera dos ficheros, uno con los dominios .cl y otro con los demás (ya que la respuesta al whois es diferente para diferentes raíces de dominio):

#!/usr/bin/perl
open(my $in, "<", "dominios.txt") or die "No se puede abrir named.conf: $!"; open(my $out, ">", "cl.txt") or die "no se puede escribir la salida:
$!";
open(my $otro, ">", "otros.txt") or die "no se puede escribir la
salida:
$!";

while (<$in>) {
if (/\w\.(cl)/) {
print $out "$_";
} else {
print $otro "$_";
}
}

close $in;
close $out;
El objetivo de esto es realizar una consulta whois por cada dominio de la lista, en mi caso particular la gran mayoría (unos 1000) eran .cl y el resto otros, así es que genere dos scripts mas para esto ultimo:

#!/usr/bin/perl
open(my $in, "<", "otros.txt") or die "No se puede abrir named.conf: $!"; open(my $out, ">", "reporte.otros.txt") or die "no se puede escribir la
salida: $!";

while (<$in>) {
print $out "\n\n$_";
# $dominio=$_;
$resultado = qx/whois -H $_/;
@lineas = split(/\n/,$resultado);
foreach (@lineas) {
if (/Name Server:\s*([\w\-\.]+)/) {
# print "$dominio\n";
print $out "$1\n";
}
}
}

close $in;
close $out;

#!/usr/bin/perl
open(my $in, "<", "cl.txt"); open(my $out, ">", "reporte.cl.txt");

while (<$in>) {
print $out "\n\n$_";
$resultado = qx/whois -H $_/;
@lineas = split(/\n/,$resultado);
foreach (@lineas) {
if (/([\w\.\-]+)\s\([\d\.]+\)/) {
print $out "$1\n";
}
}
}
close $in;
Close $out;
El primero guarda en reporte.otros.txt los nameserver registrados en donde corresponda para todos los dominios NO .cl y el segundo guarda en otro archivo (reporte.cl.txt) los nameservers registrados en nic.cl de los dominios .cl, luego con el gedit edite estos archivos y al buscar mi servidor DNS se destacaron todos los dóminos de los cuales actualmente somos servidor ya sea primario o secundario, y me permitió realizar la primera vuelta de eliminación de dóminos (aquellos de los cuales ya no somos nameserver, y aquellos que ya expiraron).

El siguiente problema era las zonas repetidas y/o mal definidas, para ello es útil referirse a los logs, en ellos encontré una linea que decía "cannot redefine zone 'dominio.dom' " lo que indica que existe un dominio definido mas de una vez, para ubicar todos estos errores en el log utilice el siguiente script perl:

#!/usr/bin/perl
open (IN,"named.log");
open (my $out,">", "repetidos.txt");

$i=0;

while() {
chomp;
if (/cannot redefine zone\s\'([\w\-\.]+)/) {
print $out "$1\n";
}
}
close IN;
close $out;
Otra información que encontré en los logs es " Err/TO getting serial# for "dominio.dom" " lo que significa que existen problemas para obtener información del DNS primario (por que nosotros somos servidor secundario para ese dominio) sobre ese dominio, lo que puede ser síntoma de que el dns primario que tenemos definido en nuestra configuración dejo de ser valido, a continuación script para encontrar esos dominios en el archivo de log.

#!/usr/bin/perl
open (IN,"named.log");
open (my $out,">", "serialerror.txt");

$i=0;

while() {
chomp;
if (/xfer-in: Err\/TO getting serial# for\s\"([\w\-\.]+)/) {
print $out "$1\n";
}
}
close IN;
close $out;
Otro error común que se puede detectar en los logs es "sysquery: findns error (NXDOMAIN) on " en mi caso correspondía a misspelling (meter mal los dedos al teclado) a la hora de definir zonas, sabrán que las zonas se definen en ficheros de texto independientes por lo tanto tratar de encontrar donde escribimos nas.dominio.dom en vez de ns.dominio.dom abriendo uno por uno los archivos de zona no es una opción para ellos tenemos find:

# find /ubicacion/deficheros/dezona -type f | xargs grep nas.domino
Bueno en base a esto pude generar un reporte con los dominios que debían ser reparados y aquellos que debían ser eliminados espero le sirva a alguien.

Saludos