Imprimir datos del paquete TCP

11 minutos de lectura

avatar de usuario
RBM

En la comunicación TCP, cuando el paquete se transfiere de Ethernet a la capa de red (IP), ¿quiero imprimir los datos presentes en ese paquete?

Estoy trabajando en linux.

Obtuve cierta información de que se puede hacer con la ayuda del código del núcleo de Linux, es decir, en el código del cortafuegos NAT de Linux. Pero, ¿dónde obtendré el código fuente del kernel? ¿Dónde se está realizando esta codificación?

  • ¿Qué distribución de Linux?

    – tacos

    10 de abril de 2015 a las 5:26

  • wireshark es otra opción…

    – rabi shaw

    10 de abril de 2015 a las 6:12

  • No quería usar wiresahrk.

    – rbm

    10 de abril de 2015 a las 7:46

  • Quiero buscar en el código del kernel de Linux. tengo uno linux-3.13.0

    – rbm

    10 de abril de 2015 a las 7:47

  • @rbm No tienes que hacerlo utilizar tiburón alambre Pero como hace exactamente lo que quieres hacer, al menos deberías estudiarlo, aprender cómo lo hace, y luego podrás hacerlo de la misma manera.

    –David Schwartz

    10 de abril de 2015 a las 18:49

avatar de usuario
sam protsenko

Cómo imprimir datos de paquetes TCP

A continuación se muestra un ejemplo que hace exactamente lo que necesita: enganche los paquetes TCP recibidos e imprima sus cargas útiles. Si desea imprimir alguna otra información del paquete recibido (como datos binarios), solo necesita modificar un poco la sección debajo de este comentario:

/* ----- Print all needed information from received TCP packet ------ */

Si necesitas rastrear transmitido paquetes en lugar de recibió ones, puede reemplazar esta línea:

nfho.hooknum = NF_INET_PRE_ROUTING;

Con este:

nfho.hooknum = NF_INET_POST_ROUTING;

Guarde los siguientes archivos y emita make comando para construir el módulo del kernel. Entonces hazlo sudo insmod print_tcp.ko para cargarlo Después de eso, podrá ver la información rastreada usando dmesg mando. Si desea descargar su módulo, ejecute sudo rmmod print_tcp mando.

imprimir_tcp.c:

#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#define PTCP_WATCH_PORT     80  /* HTTP port */

static struct nf_hook_ops nfho;

static unsigned int ptcp_hook_func(const struct nf_hook_ops *ops,
                                   struct sk_buff *skb,
                                   const struct net_device *in,
                                   const struct net_device *out,
                                   int (*okfn)(struct sk_buff *))
{
    struct iphdr *iph;          /* IPv4 header */
    struct tcphdr *tcph;        /* TCP header */
    u16 sport, dport;           /* Source and destination ports */
    u32 saddr, daddr;           /* Source and destination addresses */
    unsigned char *user_data;   /* TCP data begin pointer */
    unsigned char *tail;        /* TCP data end pointer */
    unsigned char *it;          /* TCP data iterator */

    /* Network packet is empty, seems like some problem occurred. Skip it */
    if (!skb)
        return NF_ACCEPT;

    iph = ip_hdr(skb);          /* get IP header */

    /* Skip if it's not TCP packet */
    if (iph->protocol != IPPROTO_TCP)
        return NF_ACCEPT;

    tcph = tcp_hdr(skb);        /* get TCP header */

    /* Convert network endianness to host endiannes */
    saddr = ntohl(iph->saddr);
    daddr = ntohl(iph->daddr);
    sport = ntohs(tcph->source);
    dport = ntohs(tcph->dest);

    /* Watch only port of interest */
    if (sport != PTCP_WATCH_PORT)
        return NF_ACCEPT;

    /* Calculate pointers for begin and end of TCP packet data */
    user_data = (unsigned char *)((unsigned char *)tcph + (tcph->doff * 4));
    tail = skb_tail_pointer(skb);

    /* ----- Print all needed information from received TCP packet ------ */

    /* Show only HTTP packets */
    if (user_data[0] != 'H' || user_data[1] != 'T' || user_data[2] != 'T' ||
            user_data[3] != 'P') {
        return NF_ACCEPT;
    }

    /* Print packet route */
    pr_debug("print_tcp: %pI4h:%d -> %pI4h:%d\n", &saddr, sport,
                              &daddr, dport);

    /* Print TCP packet data (payload) */
    pr_debug("print_tcp: data:\n");
    for (it = user_data; it != tail; ++it) {
        char c = *(char *)it;

        if (c == '\0')
            break;

        printk("%c", c);
    }
    printk("\n\n");

    return NF_ACCEPT;
}

static int __init ptcp_init(void)
{
    int res;

    nfho.hook = (nf_hookfn *)ptcp_hook_func;    /* hook function */
    nfho.hooknum = NF_INET_PRE_ROUTING;         /* received packets */
    nfho.pf = PF_INET;                          /* IPv4 */
    nfho.priority = NF_IP_PRI_FIRST;            /* max hook priority */

    res = nf_register_hook(&nfho);
    if (res < 0) {
        pr_err("print_tcp: error in nf_register_hook()\n");
        return res;
    }

    pr_debug("print_tcp: loaded\n");
    return 0;
}

static void __exit ptcp_exit(void)
{
    nf_unregister_hook(&nfho);
    pr_debug("print_tcp: unloaded\n");
}

module_init(ptcp_init);
module_exit(ptcp_exit);

MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Module for printing TCP packet data");
MODULE_LICENSE("GPL");

Makefile:

ifeq ($(KERNELRELEASE),)

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

module:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) C=1 modules

clean:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) C=1 clean

.PHONY: module clean

else

MODULE = print_tcp.o
CFLAGS_$(MODULE) := -DDEBUG
obj-m := $(MODULE)

endif

Explicación

Te recomiendo que leas este libro: [4]. Particularmente te interesan los próximos capítulos:

  • capítulo 11: Protocolos de capa 4
    • TCP (Protocolo de control de transmisión)
      • Recepción de paquetes desde la capa de red (L3) con TCP
      • Envío de paquetes con TCP
  • capítulo 9: filtro de red
    • Ganchos de filtro de red

Cómo obtener el código fuente del kernel de Linux

Puede obtener el código fuente del kernel utilizando una de las formas que prefiera:

  1. semilla de vainilla de kernel.org (más específicamente de kernel/git/torvalds/linux.git), utilizando Git. Por ejemplo, si necesita k3.13, se puede hacer de la siguiente manera:

    $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
    $ cd linux/
    $ git checkout v3.13
    
  2. Fuentes del kernel de su distribución. Por ejemplo, en Debian puedes simplemente instalar linux-source paquete (las fuentes se instalarán en /usr/src). Para Ubuntu ver estas instrucciones.


Detalles:

[1] Cómo obtener el encabezado TCP de sk_buff

[2] Control de flujo de red en el kernel de Linux

[3] Escribir módulos de kernel cargables usando ganchos de netfilter

[4] “Linux Kernel Networking: Implementación y teoría” por Rami Rosen

[5] Cómo acceder a datos/carga útil desde tcphdr


ACTUALIZAR

donde el gancho captura paquetes para este ejemplo? En otras palabras, ¿está en la pila TCP para que no tenga que encargarme de la pérdida de paquetes, el reordenamiento, etc.?

Se llama al gancho de Netfilter ip_rcv() función (aquí), por lo que básicamente está trabajando en la capa IPv4 (que es la capa de red en OSI). Así que creo que el manejo de la pérdida de paquetes, el reordenamiento de paquetes, etc. es no manejado todavía en ese gancho netfilter.

Consulte los siguientes enlaces para obtener información:

Si desea enganchar paquetes en la capa de transporte (TCP), netfilter no es suficiente para esta tarea, ya que funciona exclusivamente en la capa de red (IPv4).

  • Hola Sam, ¿puedo preguntar dónde captura el gancho los paquetes para este ejemplo? En otras palabras, ¿está en la pila TCP para que no tenga que encargarme de la pérdida de paquetes, el reordenamiento, etc.? ¡Gracias!

    – zzy

    31 de mayo de 2016 a las 13:46

  • @zzy he respondido a tu pregunta en ACTUALIZAR sección (en mi respuesta anterior).

    – Sam Protsenko

    31 mayo 2016 a las 18:45


  • @AlirezaSanaee Suena como una pregunta en la entrevista 🙂 No soy un experto en redes del núcleo, así que no puedo decírtelo con certeza. Pero puedo suponer que sí, puedes hacer eso. La forma más rápida de saberlo con certeza es realizar algún tipo de prueba, debería ser relativamente fácil. Use esta respuesta (especialmente el diagrama) como referencia, cree un código para realizar el intercambio y luego verifique si funciona, por ejemplo, con Wireshark. Asegúrese de proporcionar sus comentarios aquí en caso de que vaya a hacer un experimento de este tipo, porque ahora también tengo curiosidad;)

    – Sam Protsenko

    8 de marzo de 2018 a las 14:04

  • @AlirezaSanaee Hmm, hallazgos interesantes. Le sugiero que cree una nueva pregunta en SO (y probablemente vincule este hilo allí). Porque me temo que no puedo ayudarte con esto, no es mi competencia, por desgracia.

    – Sam Protsenko

    9 de marzo de 2018 a las 1:30

  • @zzy iptables admite nfqueue (cola de netfilter), así como filtros para protocolos de capa 4 como tcp, udp, icmp, etc. Si lo desea (en una situación a gran escala, será muy lento), puede configurar un filtro y una cola de iptables paquetes interceptados desde el espacio del kernel a un socket de espacio de usuario, modifique/lea o haga lo que quiera con él desde un programa de espacio de usuario que está enganchado a esa cola, luego déle un veredicto (RECHAZAR, ABANDONAR, ACEPTAR). ACCEPT es el único que lo enviará para que lo atrape el próximo enlace o lo procese el núcleo después de eso. Busque en iptables nfqueue

    – rassa45

    27 de junio de 2019 a las 3:30


No estoy seguro a nivel de Kernel.

Puedes usar el libpcap utilidades para capturar un paquete y diseccionarlo. Por ejemplo esto:

http://yuba.stanford.edu/~casado/pcap/section2.html

avatar de usuario
tacos

Quieres usar el tcpdump herramienta para inspeccionar paquetes TCP en el cable.

No dijiste qué tipo de datos estás tratando de ver.

Esta volcaría el tráfico en el puerto 53 para DNS

tcpdump -vvv -s 0 -l -n port 53

Esta página tiene una buena visión general.

  • Quiero buscar en el código del kernel de Linux. tengo uno linux-3.13.0

    – rbm

    10 de abril de 2015 a las 7:47

No tengo idea de lo que quiere decir con “transferido de Ethernet a la capa de red”. ¿Quiere decir cuando el kernel deja de procesar los encabezados de la capa 2 y pasa a los encabezados de la capa 3?

Voy a dejar que tú uses esta información como quieras. Si desea filtrar e interceptar paquetes de capa 3 (paquetes IP), tiene dos opciones principales en Linux. Primero, puede escribir un gancho de netfilter (para lo cual necesitará conocimientos de programación del kernel y cierta habilidad con C). Este es básicamente un módulo del núcleo, por lo que tendrá que escribir los filtros de la capa 4 usted mismo. Linux tiene struct tcphdr y struct ip en sus bibliotecas, simplemente busque en Google y podrá encontrar las definiciones de inclusión.

Otra opción, que no recomendaría en un entorno en el que desea que esto funcione bien, es poner en cola el paquete en el espacio de usuario mediante iptables o nftables. Esto es mucho más fácil de programar porque puede usar IPtables y nftables hooks directamente desde la cli y no necesita preocuparse por aprender a programar módulos del kernel. Un ejemplo de enlace de iptables para esto es iptables -A PREROUTING -p tcp --dport 8000 -j NFQUEUE --queue-num 0. Esto enrutará cualquier paquete tcp capturado en PREROUTING destinado al puerto 8000 a la cola de netfilter número 0 (que es básicamente un socket de espacio de usuario). Necesitarás instalar libnetfilter_queue o el paquete equivalente para su distribución, y luego puede capturar y modificar los paquetes capturados por este filtro en una variedad de idiomas. Personalmente, conozco y he escrito scripts para estos en C, Python, Rust y Golang (aunque golang era un poco bleh en términos de velocidad y Python es, bueno, Python, pero scapy tiene algunas cosas geniales de manipulación de paquetes). Sugerencia para usted: si está modificando los paquetes de la capa 4 de esta manera, las sumas de verificación son un problema para trabajar. No pude hacer que netfilter calculara las sumas de verificación automáticamente después de configurarlo en cero, recomendaría encontrar una función de cálculo de suma de verificación que funcione en línea tanto para IP como para TCP porque ya está escribiendo algo que nunca debería estar en producción.

Si desea interceptar tramas de capa 2 (tramas de ethernet), sé que ebtables existe en Linux desde los días del kernel 2.x. Sin embargo, esto no tiene una solución de tipo NFQUEUE fácil que yo sepa, por lo que está atascado escribiendo su propio código. Creo que tiene API de espacio de usuario para crear filtros y modificar paquetes, por lo que puede tener suerte allí. Si la API del espacio de usuario no funciona, diviértete escribiendo un módulo de kernel :).

Gracias por la respuesta de @Sam Protsenko. pero para la versión del kernel >= 4.13, la función nf_register_hook(&nfho) y nf_unregister_hook(&nfho) han sido reemplazados a nf_register_net_hook(&init__net, &nfho) y nf_unregister_net_hook(&init__net, &nfho).

Si desea probar el código, verifique la versión de su kernel y modifique el código de acuerdo con su situación.

Además, para los principiantes, es posible que desee apt install sparseque es un verificador de errores de código del núcleo utilizado en Makefile.

avatar de usuario
sam protsenko

Puedes usar tcpdump así:

tcpdump -vvv -s 0 -l -n port 80 -i NameOfYourDevice

O mejor:

tcpdump -i NameOfYourDevice -a -x -n port 80

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad