Imprimer les données de paquets TCP

En communication TCP, lorsque le paquet est transféré d’Ethernet vers la couche réseau (IP), je souhaite imprimer les données présentes dans ce paquet?

Je travaille sur Linux.

J’ai eu quelques informations que cela peut être fait avec l’aide du code du kernel Linux, c’est-à-dire dans le code du pare-feu NAT Linux. Mais où vais-je obtenir le code source du kernel? Où ces codages sont-ils effectués?

Comment imprimer des données à partir de paquets TCP

Vous trouverez ci-dessous un exemple qui fait exactement ce dont vous avez besoin: raccrocher les paquets TCP reçus et imprimer leurs données utiles. Si vous souhaitez imprimer d’autres informations à partir du paquet reçu (comme des données binarys), il vous suffit de modifier un peu la section sous ce commentaire:

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

Si vous devez suivre les paquets transmis au lieu de ceux reçus , vous pouvez remplacer cette ligne:

 nfho.hooknum = NF_INET_PRE_ROUTING; 

avec celui-ci:

 nfho.hooknum = NF_INET_POST_ROUTING; 

Enregistrez les fichiers suivants et lancez la commande make pour construire le module du kernel. Ensuite, faites sudo insmod print_tcp.ko pour le charger. Après cela, vous pourrez voir les informations dmesg aide de la commande dmesg . Si vous souhaitez décharger votre module, exécutez la commande sudo rmmod print_tcp .

print_tcp.c :

 #include  #include  #include  #include  #include  #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 

Explication

Je vous recommande de lire ce livre: [4]. Vous êtes particulièrement intéressé par les prochains chapitres:

  • chapitre 11: Protocoles de couche 4
    • TCP (protocole de contrôle de transmission)
      • Réception de paquets de la couche réseau (L3) avec TCP
      • Envoi de paquets avec TCP
  • chapitre 9: Netfilter
    • Crochets Netfilter

Comment obtenir le code source du kernel Linux

Vous pouvez obtenir le code source du kernel de l’une des manières que vous préférez:

  1. Noyau Vanilla de kernel.org (plus précisément de kernel / git / torvalds / linux.git ), utilisant Git . Par exemple, si vous avez besoin de K3.13, vous pouvez le faire de la manière suivante:

     $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git $ cd linux/ $ git checkout v3.13 
  2. Les sources du kernel de votre dissortingbution. Par exemple, dans Debian, vous pouvez simplement installer le paquet linux-source (les sources seront installées dans /usr/src ). Pour Ubuntu, voir ces instructions .


Détails:

[1] Comment obtenir l'en-tête TCP de sk_buff

[2] Contrôle de stream réseau dans le kernel Linux

[3] Ecriture de modules de kernel chargeables à l'aide de hooks netfilter

[4] "Réseaux dans les kernelx Linux: implémentation et théorie" de Rami Rosen

[5] Comment accéder aux données / charge utile depuis tcphdr


METTRE À JOUR

où le crochet capture les paquets pour cet exemple? En d'autres termes, est-ce que c'est sur la stack TCP que je n'ai pas besoin de m'occuper de la perte de paquets, de la réorganisation, etc.?

Le hook Netfilter est appelé dans la fonction ip_rcv() ( ici ), vous travaillez donc essentiellement dans la couche IPv4 (qui est la couche réseau dans l'OSI). Je pense donc que la gestion des pertes de paquets, la réorganisation des paquets, etc. ne sont pas encore gérées dans ce hook netfilter.

Voir les liens suivants pour plus d'informations:

  • Flux de paquets Netfilter
  • Flux de contrôle dans les réseaux Linux
  • Flux de données réseau via le kernel (diagramme)

Si vous souhaitez un hook sur la couche de transport (TCP) - netfilter ne suffit pas pour cette tâche car il fonctionne exclusivement dans la couche réseau (IPv4).

Pas sûr au niveau du kernel.

Vous pouvez utiliser les utilitaires libpcap pour capturer un paquet et le disséquer. Par exemple ceci:

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

Vous souhaitez utiliser l’outil tcpdump pour inspecter les paquets TCP sur le fil.

Vous n’avez pas indiqué le type de données que vous essayez d’afficher.

Cela déchargerait le trafic sur le port 53 pour DNS

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

Cette page a un bon aperçu.

Vous pouvez utiliser tcpdump comme ceci:

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

Ou mieux:

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