Detectar el pais de procedencia de una direccion IP con PHP
Por th3r0rn | 21 de November de 2009 |2 comentarios
Hola, jugando un poco con php se me ocurrio como poder detectar el pais de procedencia de una direccion ip, esto nos viene muy util como por ejemplo para hacer alguna tienda virtual y poder calcular la moneda local del pais de nuestro visitante o interactuar contenido de acuerdo a su pais de origen, para obtener una direccion ip contamos con varias funciones en php, el problema aqui es como hacerle para saber el pais de dicha direccion. Pues bueno esto es lo que voy a poner aqui :).
En primer lugar lo que necesitamos para detectar el pais de una direccion ip es saber que rangos de direcciones ip pertenecen a cada pais, entonces necesitaremos una “amplia” base de datos con esta informacion.
Es aqui cuando nace el trabajo de ip-to-countrry Este sitio nos brinda una base de datos con todos los rangos de ips de todos los paises, la base de datos esta en formato CSV (del inglés comma-separated values.)
Procedemos a descargarla y la descomprimimos a fin de tener el archivo .csv en un directorio. Ahora lo que necesitamos es pasar esos datos de esa base de datos a nuestra base de datos en mysql.
Para esto podemos hacerlo con un script muy sencillo en php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php $conexion=@mysql_connect("localhost","root","123456"); if (!$conexion) die ("NO SE PUDO CONECTAR CON LA DB"); @mysql_select_db("PAISES",$conexion); // Se crea la tabla de los rangos de IP, y se verifica. $consulta="CREATE TABLE ipCountry (ipStart DOUBLE NOT NULL, ipEnd DOUBLE NOT NULL, countryCode2 CHAR(2) NOT NULL default '', countryCode3 CHAR(3) NOT NULL default '', countryName VARCHAR(50) NOT NULL default '', PRIMARY KEY (ipStart, ipEnd)) TYPE=MyISAM;"; $hacerConsulta=@mysql_query($consulta, $conexion); if (!$hacerConsulta) die ("LA TABLA NO PUDO SER CREADA."); // Se abre el fichero csv de los rangos de IP's. $manejadorFichero=fopen("ip-to-country.csv","r"); // Se define una matriz para almacenar los rangos. $matriz=array(); /* Mientras haya datos, se lee cada línea y se almacena en un elemento de $matriz. Cada elemento es, a su vez, una matriz con cinco elementos. */ while (!feof($manejadorFichero)){ $matriz[]=fgetcsv($manejadorFichero); } /* Se recorre la matriz y se desglosa cada elemento, para insertar una nueva fila de la tabla. */ foreach ($matriz as $rangoIPs){ /* Se comprueba que el elemento tenga un contenido real.*/ if ($rangoIPs[0]!=""){ $consulta="INSERT INTO ipCountry (ipStart, ipEnd, countryCode2, countryCode3, countryName) VALUES (\"$rangoIPs[0]\", \"$rangoIPs[1]\", \"$rangoIPs[2]\", \"$rangoIPs[3]\", \"$rangoIPs[4]\");"; $hacerConsulta=mysql_query($consulta, $conexion); } } /* Se cierra el fichero CSV y la BBDD.*/ fclose ($manejadorFichero); mysql_close($conexion); /* Se muestra el resultado.*/ echo ("La BBDD y la tabla han sido creadas.<br>"); ?> |
Aqui creamos una matriz. En cada elemento de la misma pretendemos almacenar todos los datos del fichero, es decir de uno de los rangos de IP’S. Para ello, leemos el fichero con un bucle que se estara ejecutando mientras no se encuentre el final (!feof) con esta funcion detectamos el final del fichero.
Los datos de cada linea generan un nuevo elemento de la matriz. Y aqui aparece la funcion fgetcsv() Esta funcion ha sido implementada en PHP especificamente para la lectura de ficheros CSV. Como argumento recibe el manejador con el que hemos abierto el archivo. El resultado es la lectura de una linea completa hasta el salto de linea. Atraves de las comas identifica cual es cada dato. Cuyo valor debe aparecer entrecomillado, con todos los datos genera una matriz indexeada, con un elemento por dato. En este caso, la matriz tendra cinco elementos. Supongamos que aplicamos la funcion para leer la primera linea, exclusivamente. La matriz tendra los siguientes elementos:
1 2 3 4 5 6 7 | Array( [0]"33996344" [1]"33996351" [2]"GB" [3]"GRB" [4]"UNITED KINGDOM" ) |
Esto es por que el formato de los ficheros CSV es de esta manera, y si lo revisamos veremos las ips y los demas datos estan en dicho formato:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | "50331648","69956103","US","USA","UNITED STATES" "69956104","69956111","BM","BMU","BERMUDA" "69956112","72349055","US","USA","UNITED STATES" "72349056","72349119","BM","BMU","BERMUDA" "72349120","83886079","US","USA","UNITED STATES" "100663296","121195295","US","USA","UNITED STATES" "121195296","121195327","IT","ITA","ITALY" "121195328","134693119","US","USA","UNITED STATES" "134693120","134693375","CA","CAN","CANADA" "134693376","134730239","US","USA","UNITED STATES" "134730240","134730495","CA","CAN","CANADA" |
En el caso del bucle de nuestro codigo, esta matriz se almacena en un elemento de la matriz que hemos llamado $matriz. Esto significa que $matriz al final del bucle, tendra mas de 99753 elementos (uno por cada linea del ficheri CSV) y cada uno sera una pequeña matriz con cinco elementos. Asi pues, $matriz es realmente, una matriz de dos dimensiones. Observemos que a $matriz No le hemos asignado un indice especifico, asi que en cada iteraccion del bucle se generara un nuevo elemento.
Tras generar $matriz se usa el bucle foreach para recorrerla entera. Cada elemento que ya sabemos que es asu vez, una pequeña matriz, contiene cinco datos. Estos se usan para generar un nuevo registro en la tabla MYSQL. Vemos que dentro del bucle foreach se comprueba si la IP inicial (elemento [0] de la matriz) tiene contenido. Esto se hace por que el fichero CSV puede contener lineas en blanco al final del mismo y estas tambien generan elementos en la matriz principal, pero no debemos almacenarlas en la tabla MySQL.
Ahora el siguiente paso es crear una funcion que encuentre la ip del cliente que se conecta al servidor, esto lo hacemos en un archivo por aparte al que llamaremos obtenerIP.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <? function obtenerIPCliente() { /* En la variable $ip se almacenará la dirección del cliente. */ $ip = 0; /* Si la variable $_SERVER['HTTP_CLIENT_IP'] tiene algún contenido, se asigna a la variable $ip. */ if (!empty($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP']; /* Si la variable $_SERVER['HTTP_X_FORWARDED_FOR'] tiene algún contenido, se asigna a la variable $ip. En ese caso debe separarse la IP pública del cliente de las obtenidas a través de posibles redes locales. */ if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { /* Se abre la matriz de IP's obtenidas de $_SERVER['HTTP_X_FORWARDED_FOR']. */ $ListaDeip = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']); /* Si ya hay contenido en $ip, se añade a la matriz. */ if ($ip) { array_unshift($ListaDeip, $ip); $ip = 0; } /* Se eliminan IP's privadas, procedentes de posibles redes locales, así como la dirección de bucle local. Cuando se encuentra una IP pública (externa) se devuelve como resultado de la función. */ foreach ($ListaDeip as $direccion) if (!eregi("^(192\.168|172\.16|10|224|240|127|0)\.", $direccion)) return $direccion; } /* Si no había contenido en $_SERVER['HTTP_X_FORWARDED_FOR'] se devuelve la IP obtenida mediante $_SERVER['REMOTE_ADDR']. */ return $ip ? $ip : $_SERVER['REMOTE_ADDR']; } ?> |
Como podemos ver el script es bastante sencillo y no pretendo explicarlo con mas detalles ya que en los comentarios queda mas que claro, ademas si sabemos algo de php esto no sera mayor problema.
Y bueno ahora lo que necesitamos es el script que determinara el pais de la direccion ip:
determinarPais.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | <?php //Conectamos y seleccionamos la base de datos $conexion=mysql_connect ("localhost", "root", "123456")or die("No se puedo conectar con la base de datos"); $base=mysql_select_db("phpmexic_pruebas", $conexion)or die("Problemas para seleccionar la base de datos"); /* Se incluye el archivo que contiene la función para obtener la IP del cliente. */ include ("obtenerIP.php"); /* Se obtiene la IP del cliente, en el formato típico: "xxx.xxx.xxx.xxx". */ $direccionReal=obtenerIPCliente(); /* Se convierte la IP a valor numérico. */ $direccionNumerica=ip2long($direccionReal); /* Se localiza el registro que corresponde a la ip numérica. */ $consulta="SELECT countryCode2, countryName FROM ipCountry WHERE ipStart<=$direccionNumerica AND ipEnd>=$direccionNumerica;"; $hacerConsulta=mysql_query($consulta, $conexion); /* Se recuperan los datos de "código del país de dos letras y nombre del país. */ $datosDePais=mysql_fetch_array ($hacerConsulta); $codigoDePais=strtolower($datosDePais["countryCode2"]); $nombreDePais=$datosDePais["countryName"]; /* Se obtiene el nombre de la imagen de la bandera del país. */ $nombreDeImagen="imagenes/banderas/".$codigoDePais.".gif"; /* Se muestran los resultados. */ echo ("El pais que corresponde a la IP $direccionReal es: $nombreDePais. "); echo ("<IMG SRC='$nombreDeImagen' ALT='$nombreDEPais'>"); /* Se liberan recursos y se cierra la BBDD. */ // mysql_free_result ($hacerConsulta); mysql_close ($conexion); ?> |
En primer lugar nos conectamos con la base de datos, despues incluimos la funcion que creamos destinada a obtener la ip del cliente. Usando esta funcion se obtiene la IP de la variable $direccionReal. Esta IP esta en formato tipico IPv4, es decir cuatro valores entre 0 y 255, separados por puntos. Este valor se almacena como una cadena.
Sin embargo, los rangos de IP’s que tenemos en la tabla de MySQL estan almacenados como valores numericos, asi que necesitariamos convertir la cadena con la IP de la conexion a un valor numerico. Para estos casos PHP implementa la funcion ip2long(), que recibe una cadena representando una IP y la transforma a un valor numerico es decir:
1 2 3 4 5 | <?PHP $ip=192.168.1.254 $IPNumertica=ip2long($ip); echo $ip; ?> |
Como resultado tendriamos en pantalla 1921681254 que equivale a la ip que le pasamos la cual es 192.168.1.254
Tambien tenemos la funcion long2ip() que lleva acabo el cometido inverso, recibe un valor de tipo long y devuelve una cadena con una IP.
Una vez convertida la IP a su correspondiente valor numerico, tenemos que localizar en la tabla un registro en el que el limite inferior del rango sea menor o igual al valor obtenido y el limite superior sea mayor o igual a dicho valor. Para ello creamos la consulta:
1 2 3 | $consulta="SELECT countryCode2, countryName FROM ipCountry WHERE ipStart<=$direccionNumerica AND ipEnd>=$direccionNumerica;"; |
Y bueno todo lo que sigue despeus de esto no lo pienso explicar ya que esta mas que claro.
He subido el script para que lo prueben dando clic aqui
Tambien he dejado el archivo .sql de la base de datos de ip para aquellos que quieran importar la base de datos ya directamente a mysql, esto lo hago por que en algunos hostings tienen limitada la memoria para el interprete de php por lo cual si intentan ejecutar el script de php que pasa los datos del archivo CSV sature la memoria y no logren importar nada, aqui la soluicion mas viable seria importar el archivo sql desde la consola de comandos de SQL mediante ssh
Archivo.sql
Tambien dejo un archivo comprimido en formato .tar que contiene todas las banderas de los paises para mostrar al igual que el script completo:
Clic para descargar
PD. para aquellos que usan windows necesitan tener winrar instalado para descomprimir dicho archivo.
Saludos.
![- [root@Linux th3r0rn]# ./header](http://www.imgeek.net/wp-content/themes/milbits/imagenes/web.logo.png)










En caso de que sea una red abierta (sin encriptación) nos pondrá 00000000, etc...
Esta ha sido una pausa para seguir explicando el resto, siempre es bueno tener en cuenta esta utilidad muy útil.
7. Desencriptando nuestra captura
Ahora introducimos el uso de otro programa que nos servirá de mucho en el mundo del hacking wireless, este es el ethereal

En Number of decrypted WEP packets nos pondrá cuantos paquetes se han
desencriptado con éxito, si todo va bien debería ser el mismo número de
Total number of WEP data packets, aunque si hemos capturado datos de
diferentes redes nos pondra un numero menor, si te da 0 es porque has
puesto mal la clave.
Si ha salido bien vemos en la carpeta donde
estaba el archivo "captura.cap" y notaremos que se ha generado otro
llamado "captura-dec.cap", que es precisamente el archivo de captura ya
desencriptado.
8. Solucionando DHCP deshabilitado
¿Qué es dhcp deshabilitado? Bueno, creo que este es el tema que más se habla dentro del mundo del hacking wireless.
DHCP (sigla en inglés de Dynamic Host Configuration Protocol) es un
protocolo de red que permite a los nodos de una red IP obtener sus
parámetros de configuración automáticamente. Se trata de un protocolo
de tipo cliente/servidor en el que generalmente un servidor posee una
lista de direcciones IP dinámicas y las va asignando a los clientes
conforme éstas van estando libres, sabiendo en todo momento quién ha
estado en posesión de esa IP, cuánto tiempo la ha tenido y a quién se
la ha asignado después.
Ok, no hay problema, para todo hay solución. :
Recordemos que tenemos el archivo captura-dec.cap que tiene los
paquetes ya desencriptados. Vamos a analizarlo con el Ethereal.
Simplemente le damos doble clic al archivo (al instalar el Ethereal
asocia los archivos .cap al programa automáticamente).
Voy a
tomarme el atrevimiento de postear una de las imagenes del manual de
Uxío, al fin de cuentas el ethereal de Windows es lo mismo que el de
linux:
El amigo Uxío nos lo explica muy bien, yo no podría haberlo hecho
mejor. Creo que no tiene sentido seguir escribiendo el resto del manual
porque ya lo tenemos bien explicado, el resto en windows, recuerden el
manual está aquí: 












