Páginas

lunes, 22 de agosto de 2011

¿de quien carajo es este socket? II

Continuando con lo explicado la semana pasada vamos a ver donde podemos encontrar la información que conseguimos por comandos, pero esta vez lo haremos de el fabuloso FS "/proc".

"/proc" realmente es un pseudo-file system (tipo procfs), este no consume espacio de almacenamiento y ocupa una cantidad de memoria baja, en él el kernel nos vuelca información sobre los procesos, hardware, memoria, almacenamiento, vamos información sobre el sistema en si.

Para un estudio mas profundo aconsejo mirar un "man proc" donde viene explicado el contenido de sus directorios y ficheros.

Yendo la grano, para encontrar información sobre los sockets, podemos mirar en el siguiente directorio "/proc/net/", ahí dependiendo del tipo de socket del que queramos información miraremos en el archivo con dicho nombre, en nuestro caso vamos a mirar sockets tcp (tcp6 para ipv6).

Dentro de este archivo nos encontramos con algo como esto.

#cat /proc/net/tcp
sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                    
   0: 0301A8C0:994C BF9255D1:0050 01 00000000:00000000 00:00000000 00000000  1000        0 120913 1 00000000 30 4 28 5 3   


Vale, una vez tenemos este armatoste de datos en hexadecimal little-endian, vamos a ver las columnas que tienen los datos que nos hacen falta para lanzar nuestro tcpdump, como ya hicimos en el articulo anterior. 

local_addres -> aqui tenemos la ip:puerto origen.
rem_address -> ip:puerto destino
inode -> inode del socket (este dato viene en decimal).

Ya sabemos los datos ahora solo nos falta pasarlos a formato decimal, mas que nada para enterarnos nosotros de que pone.

Al estar en little-endian se lee de derecha a izquierda, por ejemplo para la ip y el puerto tenemos lo siguiente según la salida.

ip:port ------> 0301A8C0:994C

Sabemos que la ip es de la forma x1.x2.x3.x4, la parte de la ip consta de 8 digitos hexadecimales por lo que cada dos digitos corresponden a una de las x del formato ip, y al estar en little-endian x1 es la pareja de digitos mas a la derecha, vamos a verlo en nuestra salida.

Hexadecimal              Decimal               
03.01.A8.C0      ---->   3.1.168.192

De tal modo si lo pasamos a big-endian, cambiando el orden de los digitos de izquierda a derecha, obtenemos nuestra dirección ip.

192.168.1.3

El puerto seria igual, pero ya que solo hay un digito no habría que darle la vuelta. 

Hexadecimal              Decimal               
994C               ---->    39244

Una vez tenemos todos los datos en decimal, podemos obtener información del socket con tcpdump igual que hicimos en el articulo anterior. Lo único que nos queda es saber a que proceso pertenece.

Entre los directorios que podemos encontrar en /proc vamos a fijar nuestra atención en aquellos que tienen por nombres números. Cada vez que se ejecuta un proceso, durante el tiempo que este corriendo se le asigna una de estas carpetas cuyo nombre coincide con su pid. Dentro de cada una de estas carpetas hay un directorio llamado fd, pues bien aquí se encuentran lo descriptores de ficheros de los archivos que tiene abiertos, y como nuestro socket necesita un descriptor de fichero pues aquí lo encontraremos.

Bien, ya sabemos la carpeta donde buscar, ahora nos hace falta saber como saber que un determinado fd es un socket y que inode tiene ese socket, un listado del directorio con -l nos sacara de dudas, escogeremos un pid al azar, el uno por ejemplo.

#ls -li
total 0
167690 lrwx------ 1 root root 64 2011-08-22 21:02 0 -> /dev/null
167691 lrwx------ 1 root root 64 2011-08-22 21:02 1 -> /dev/null
167700 lrwx------ 1 root root 64 2011-08-22 21:02 10 -> socket:[7298]



Antes de proseguir, apuntar un par de cosas sobre el archivo, primero vamos a ver como esta formado su nombre. 

fd->tipo:[inode]
10->socket:[7298]

Como ya os estaréis preguntando, si la primera columna que sale es el inode, ¿como que no es el mismo?  


167700 lrwx------ 1 root root 64 2011-08-22 21:02 10 -> socket:[7298]

La respuesta es que el inode que nos muestra "ls -i" es el del descriptor de fichero y el que sale entre paréntesis es del socket.

Pues por fin solo nos queda buscar /proc el directorio donde esté uno de estos archivos y tendremos el pid del proceso dueño del socket, una posible solución podría ser la siguiente, aunque es un poco enrevesada, si tenéis alguna manera mejor, soy todo oídos.

#find /proc -inum `ls -Rli /proc/[0-9]{1,}/fd|egrep 'socket:\[120913\]'|awk '{print $1}'` 2> /dev/null
/proc/3514/fd/13

Ahí lo tenemos pid 3514 con el fd 13, en mi caso si miro en /proc/3514/cmdline veo que el pid pertenece a firefox.

#cat /proc/3514/cmdline
/usr/lib/firefox-6.0/firefox-bin

Esto es todo por hoy, la próxima semana pondré como hacerlo por C.

Un saludo.

lunes, 15 de agosto de 2011

¿de quien carajo es este socket?

En su día estuve bastantes horas hasta que descubrí como se podía obtener información de un determinado socket en una determinada aplicación para Linux, por lo que dejo aquí mi experiencia para quien pueda ser de utilidad o para quien pueda corregirme en mis errores.

Lo primero es saber con que herramientas podemos trabajar para obtener esa información, lo primero si queremos saber que sockets hay abiertos en nuestro sistema de una manera rápida, yo optaría por

#lsof -i

Lo cual nos generaría una salida parecida a esta:

COMMAND    PID      USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
firefox-b 3743 usuario   65u  IPv4 144930      0t0  TCP nuestropc:50449->209.222.128.176:www (ESTABLISHED)

Veamos que nos ha dicho este comando y que hace este comando.

Por definición lsof nos muestra los archivos abiertos que hay actualmente en nuestro sistema, entendiendo por archivo copiando literalmente del man de lsof "a regular file, a directory, a block special file, a character special file, an executing text reference, a library, a stream or a network file  (Internet  socket,  NFS  file  or  UNIX  domain socket.)"

De toda esta lista solo nos interesa los últimos tipos, por lo que le decimos a lsof la opción -i la cual nos da los sockets con datos ip que le indiquemos, en nuestro caso no le aportamos nada, para que nos de todas las conexiones.

La salida nos ofrece la siguiente información:

COMMAND    

firefox-b
Aplicación propietaria del socket.

PID      
3743
pid de la aplicación propietaria. 

USER   
usuario
usuario que lanzo la aplicación.

FD
65u
es el numero del descriptor de fichero, seguido de los permisos.

TYPE
IPv4
tipo de servicio.

DEVICE
144930
el numero del dispositivo asociado al socket.

SIZE/OFF
0t0
tamaño u offset, en nuestro caso "0t" nos indica offset.

NODE 
TCP
protocolo del socket.

NAME
nuestropc:50449->209.222.128.176:www (ESTABLISHED)
información del socket: source:port->dest:port(Estado).

Ya sabemos que sockets tenemos abiertos, si queremos saber información sobre el socket y su contenido, tenemos a nuestro gran amigo tcpdump, el cual nos dirá toda la información que queramos sobre el. una posible ejecucion con los datos obtenidos seria.

#tcpdump -vvv -A -i eth1 src host nuestropc and src port 50449 and dst host 209.22.128.176 and dst port www

Con este comando obtenemos los paquetes de los sockets, recomiendo pasar la salida a un archivo ya que esto manda un chorrazo por pantalla bastante dificil de seguir.

En el lanzamiento del comando podemos diferenciar dos zonas, la primera de opciones las cuales nos indican:

-vvv: esto es para obtener el maximo de informacion posible, tambien se puede obtener menos quitandole uves, hasta el minimo omientiendolas.

-A: nos ofrece la informacion en formato ascii.

-i eth1: sirve para indicarle por que tarjeta debemos escuchar.

La segunda parte, de parametros es para indicarle las especificaciones que debe tener el socket, la sintaxis y opciones disponibles las podemos encontrar ejecutando "man pcap-filter".

Bueno ya podemos elegir que socket escuchar y asi saber que esta comunicando nuestro pc al mundo.

En la proxima entrada hablare sobre "/proc/net/tcp", "/proc/net/udp" y "/proc/PID/fd", desde donde tambien podremos obtener informacion para su posterior captacion con tcpdump.

Espero vuestras aportaciones a mi primer post :).