viernes, 10 de mayo de 2013

servidor OpenVPN en tu Raspberry Pi

Desde hace ya un tiempo tuve la necesidad de montar una VPN. Me decanté por OpenVPN ya que siempre he pensado que era de lo más completo, en lo referente a la seguridad pudiendo acceder mediante user/pass + fichero.
Bueno pues... si haceis una simple busqueda en Google encontraremos manuales, algunos muy bien detallados y otros ... no tanto pero lo sorprendente que a todos ellos les funciona su servidor cosa que a mi nunca ha sido así. Siempre con problemas "una de las interfaces no hace MASQUERADE", "el paquete llega pero no pasa...", "me he confundido de puerto, AIS!!", "se conecta pero no navega..." Bueno un sin fin de problemas y ninguna solución. Y me he encontrado en varias ocasiones en las que ni calcando el ejemplo del propio manual he conseguido resultados. 

Pues bien! hace unos días después de insistir en mil intentos inútiles me puse manos a la obra, pasando de manuales que ya me he leído muchos y creo que ya se perfectamente que tengo que hacer. El problema que nunca conseguí resultados. Solo espero que esto no sea un manual más donde solo a mi me funciona y al resto del mundo no. Así que intentaré ser lo más claro en los detalles.

Un resumen de mi red.
(Equipo externo)=> {INTERNET} <=> [RouterWifi] <=> |Raspberry Pi| <= (Equipo local)
Por supuesto no falta decir que los equipos local y externo se conectan a la wifi. El local a la propia del router y el externo en la de un.... Starbucks para que sea molón el ejemplo. Y detalle importante OJO AL DATO la Raspberry Pi para el que no tenga una sólo tiene UNA interface FÍSICA de red ETH0. Ni una más ni una menos. Por supuesto en el router wifi tiene que estar abierto el puerto UDP 1194 o el que se configure en el servidor.

Como todos los manuales comenzamos.
apt-get install openvpn openssl
posteriormente copiamos y nos movemos de directorio
cp -R /usr/share/doc/openvpn/examples/easy-rsa /etc/openvpn
cd /etc/openvpn/easy-rsa/2.0
Y comenzamos a crear los ficheros clave y certificados
. ./vars
./clean-all
./build-ca
./build-key-server server
Ahora generamos tantas claves de clientes cómo usuarios queramos
./build-key client-movil
./build-key client-movilPapa
./build-key client-pcMio
./build-key client-pcPapa
./build-key client-invitado
Cuando tengamos todas las claves de clientes que queramos lanzamos lo siguiente
./build-dh
BUFFF esto tarda mucho. Si has generado muchas claves, vete a tomar un café o a sacar al perro.

Cuando termine si aun sigues despierto, copiamos las claves necesarias en el servidor
cd /etc/openvpn/easy-rsa/2.0/keys
cp ca.crt ca.key dh1024.pem server.crt server.key /etc/openvpn
Copiamos los ficheros clave de cada cliente.
Lo guardamos en nuestra propia carpeta. Así que en mi caso me creo una carpeta
mkdir /home/endika/MisClavesVPN
y copio en ella
cp client*.crt, client*.key ca.crt /home/endika/MisClavesVPN
Recodar donde lo hemos copiado que necesitaremos los ficheros para conectar los clientes

Ahora copiamos el fichero de configuración del servidor que tiene openvpn por defecto
cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn
gunzip /etc/openvpn/server.conf.gz
y lo editamos para que concuerde con nuestra configuración
nano /etc/openvpn/server.conf
De ese fichero solo he modificado lo siguiente modificar la IP local del servidor Raspberry Pi
local 192.168.1.33 
El puerto si queremos modificarlo
port 1194
El protocolo si queremos cambiar UDP por TCP
proto UDP
La interface virtual si queremos modificar el nombre de TUN por TAP
dev tun
La Red virtual de la VPN
server 10.8.0.0 255.255.255.0
La Red local de nuestra wifi
push "route 192.168.1.0 255.255.255.0"
Los servidores DNS si queremos poner alguno, por ejemplo los DNS de google
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
Si os dais cuenta no tiene # ni un ; delante de la instrucción. Todo lo que lo tenga estará comentado y no surgirá efecto. Así es como queda mi fichero server.conf
local 192.168.1.33
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh1024.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 192.168.1.0 255.255.255.0"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
client-to-client
keepalive 10 120
comp-lzo
user nobody
user nogroup
persist-key
persist-tun
status openvpn-status.log
verb 3
Últimos detalles, vamos a permitir que nuestra máquina actúe como un router
echo 1 > /proc/sys/net/ipv4/conf/all/forwarding
Y lo más importante las reglas del IPTABLES
#!/bin/bash
echo "Limpiando IPTables"
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

echo "Configurando las interfaces eth0 y tun0"
iptables -A INPUT -i tun0 -j ACCEPT
iptables -A INPUT -i eth0 -j ACCEPT
iptables -I FORWARD -i eth0 -o tun0 -j ACCEPT
iptables -I FORWARD -i tun0 -o eth0 -j ACCEPT

iptables -A OUTPUT -m state --state NEW -o eth0 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state NEW -o eth0 -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

echo "para el resto de los casos aceptamos el tráfico"
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
Revisar las reglas por si el nombre de las interfaces cambia o en el caso del masquerade por si la red no es la misma. Por otro lado las normas están echas para solo una ÚNICA interface de entrada y salida eth0. Ya solo queda lanzar el servidor
/etc/init.d/openvpn start
Para evitar que sea muy largo este post en la segunda parte configuraremos los clientes para que se conecten al servidor

lunes, 6 de mayo de 2013

modificar el valor del HASH en un fichero binario

Cada vez que modificamos un fichero su HASH obtiene un valor distinto. Pero que ocurre si el fichero es un binario? pues exactamente lo mismo. Aquí tenéis un pequeño script donde podemos indicar el nombre de nuestro binario y nos crea uno nuevo con 100 caracteres aleatorios añadidos al final del mismo. Esto no altera el funcionamiento pero si el valor de su hash.
import sys,os,random

def bytes_aleatorio(n):
    return "".join(chr(random.randrange(0,256)) for i in xrange(n))

nombre=str(sys.argv[1])
fichero=open(nombre,'rb').read()
fichero_nuevo=fichero+bytes_aleatorio(100)
open(nombre+str("_new"),'wb').write(fichero_nuevo)
os.system("md5sum "+nombre)
os.system("md5sum "+nombre+"_new")
y su uso:
python modificarHash.py NombreFicheroBinario
y PUM!! el "mismo" fichero con un hash diferente.

martes, 30 de abril de 2013

SAP ABAP: Recursividad VS ejecución lineal

Realizando pruebas para ver si es viable el uso de la recursividad en SAP. Me encuentro con el siguiente resultado que os mostraré a continuación.

Para realizar la prueba ejecuto el siguiente programa muy sencillo y creo que fácilmente comprensible. Bien según mis experiencias anteriores sobre la ejecución de métodos recursivos frente a los que no lo son, me dice la experiencia que la recursividad gana en la mayoría de los casos. Y claro dentro de la burbuja del mundo SAP, yo creía que un sistema donde se ejecuta en máquinas "BRUTALES" la recursividad sería perfecto para no derrochar recursos. Así que comienzo a ejecutar lo siguiente:

DATA: lv_total  TYPE i VALUE 0,
      lv_aux    TYPE i,
      lv_inicio TYPE i,
      lv_fin    TYPE i,
      operador  TYPE i VALUE 1000.

PARAMETER lp_suma TYPE i DEFAULT 9999.

START-OF-SELECTION.

  lv_aux = lp_suma. "Almacenamos el valor
  GET RUN TIME FIELD lv_inicio.
* Metodo con secursividad --------------------------------------------------------

  PERFORM suma USING lp_suma lv_total.

*  -------------------------------------------------------------------------------
  GET RUN TIME FIELD lv_fin.
  lv_fin = ( lv_fin - lv_inicio ) / operador.
  WRITE: / '(RECURSIVO) tiempo de respuesta: ', lv_fin , ' milisegundos'.
* ---------------------------------------------------------------------------------
* ---------------------------------------------------------------------------------
  WRITE: /.
  WRITE: /.
* ---------------------------------------------------------------------------------
* ---------------------------------------------------------------------------------
  lp_suma = lv_aux. "cargamos su valor
  lv_aux = lv_fin.
  lv_total = 0.
  GET RUN TIME FIELD lv_inicio.
* Metodo sin secursividad --------------------------------------------------------

  WHILE lp_suma > 0.
    lv_total = lv_total + lp_suma.
    lp_suma = lp_suma - 1.
  ENDWHILE.
  WRITE: 'resultado ', lv_total.

* --------------------------------------------------------------------------------
  GET RUN TIME FIELD lv_fin.
  lv_fin = ( lv_fin - lv_inicio ) / operador.
  WRITE: / '(NO RECURSIVO) tiempo de respuesta: ', lv_fin , ' milisegundos'.

  WRITE: /.
  WRITE: /.
  IF lv_aux < lv_fin.
    WRITE: / 'La recursividad es la mejor solución'.
  ELSEIF lv_aux = lv_fin.
    WRITE: / 'EMPATE!!!!'.
  ELSE.
    WRITE: / 'El while es la mejor solución'.
  ENDIF.

FORM suma USING lv_suma TYPE i
                lv_total TYPE i.

  IF lv_suma GT 0.
    lv_total = lv_total + lv_suma.
    lv_suma = lv_suma - 1.
    PERFORM suma USING lv_suma lv_total.
  ELSE.
    WRITE: 'resultado ', lv_total.
  ENDIF.

ENDFORM.

El programa ejecuta inicialmente una función recursiva y seguido ejecuta el mismo proceso sin aplicar recursividad. Finalmente en la pantalla muestra el resultado de la operación junto con los milisegundos que ha durado ambas. Y para mi sorpresa me encuentro lo siguiente:
resultado  49.995.000
(RECURSIVO) tiempo de respuesta:          49   milisegundos


resultado  49.995.000
(NO RECURSIVO) tiempo de respuesta:          24   milisegundos


El while es la mejor solución
Bueno para mi desgracia la recursividad no es una solución.

jueves, 25 de abril de 2013

Python excepciones, profundizando mucho más

Vale muy bien, ya sabemos cómo se usan los try. Pero..... no está mal saber que clases de excepciones estándar tenemos disponibles. Os paso un diagrama en árbol de las excepciones estándar más comunes. La más genérica es exception pero si queremos realizar diferentes tratamientos no estaría mal saber algunas más.
Exception(*)
 |
 +-- SystemExit
 +-- StandardError(*)
      |
      +-- KeyboardInterrupt
      +-- ImportError
      +-- EnvironmentError(*)
      |    |
      |    +-- IOError
      |    +-- OSError(*)
      |
      +-- EOFError
      +-- RuntimeError
      |    |
      |    +-- NotImplementedError(*)
      |
      +-- NameError
      +-- AttributeError
      +-- SyntaxError
      +-- TypeError
      +-- AssertionError
      +-- LookupError(*)
      |    |
      |    +-- IndexError
      |    +-- KeyError
      |
      +-- ArithmeticError(*)
      |    |
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      |    +-- FloatingPointError
      |
      +-- ValueError
      +-- SystemError
      +-- MemoryError
Un ejemplo de su uso
parsed = False
while not parsed:
    try:
        x = int(raw_input('Mete el primer valor: '))
        y = int(raw_input('Mete el segundo valor: '))
        result= x/y
    except ValueError:
        print 'Numero introducido erroneo!!!'
    except ZeroDivisionError:
        print "dividir por CERO!! LOKO!!"
    else:
        parsed = True
        print "resultado: ", result
Si queremos provocar la ejecución de una excepción podemos usar raiser.
try:
    raise Exception()
except:
    print "ERROR: ", sys.exc_type + ":", sys.exc_value
Por último nos crearemos nuestra propia excepción.
class MyPropioError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

try:
    raise MyPropioError("Algo muy gordo a pasado")
except MyPropioError, e:
    print 'Se ha ejecutado, value:', e.value
Esto mostrará el texto "Algo muy gordo a pasado"

Python excepciones, cómo se usan

La estructura de un try en python es la siguiente:
try:
    Sentencias que podrán dar a posible error
except IdentificarError:
    Que ejecutamos cuando se produce el error
finally:
    Sentencias que se ejecutan siempre. Exista o no el error
else:
    Sentencias que ejecutamos en caso de no existir el error
Os muestro un ejemplo clásico de la división por 0
try:
   result = 10 / 0
 except ZeroDivisionError:
      print "dividir por CERO!! LOKO!!"
 else:
      print "resultado: ", result
Si quereis entrar en más detalle. Os recomiendo Python - Errors and Exceptions

ABAP CRM: funciones estándar para sacar organización, grupo... de ventas

Desde la transacción SE37 podemos buscar la lista de todas las funciones buscando por:
CRM_MAPPING*

martes, 9 de abril de 2013

micro consejos para programadores - parte9


  1. Sí no recuerdo mal (a*a*a)*(a*a*a) es mejor que a*a*a*a*a*a está última son 5 líneas en ensamblador y la otra son 3
  2. Reutilizar variables por ejemplo de un objeto en java ejecutando de nuevo user=new Usuario() y listo para usar.
  3. Al construir una sentencia SQL son más optimas si respetamos el orden de los campos.

lunes, 8 de abril de 2013

micro consejos para programadores - parte8

Hoy extra de micro consejos

  1. Usar etiquetas eTags y expires es mejor que tener que obligar a descargar el site entero y Google te premiará.
  2. Entre los algoritmos de ordenación sort y qsort este último es mucho más rápido.
  3. Sí trabajas con ficheros es mejor cargarlo en bloques en memoria y trabajar desde hay (un clásico)

micro consejos para programadores - parte7


  1. Por supuesto tenía que decir que los métodos recursivos son mejores.
  2. Cada estilo CSS mejor en una línea que escritos en bloque. Más rápido leer una línea de un golpe que 5 o más.
  3. Usar algún loadscript para Js es una buena práctica para descargar simétricamente el contenido web.

viernes, 15 de marzo de 2013

ABAP CRM: Contar cuantos registro hay en una tabla interna

Antes de hacer un LOOP o cualquier otro bucle que se nos pueda ocurrir lanzar para conocer el numero total de registros que tenemos en nuestra tabla interna. Podemos lanzar lo siguiente:
DATA: lt_tabla TYPE TABLE OF mitabla,
      lv_total TYPE i.

"Mi SELECT
SELECT * INTO CORRESPONDING FIELDS OF TABLE lt_tabla FROM mitabla.

DESCRIBE TABLE lt_tabla LINES lv_total.
lv_total almacenará el valor total de registros.