2009-12-02 2 views
0

Est-ce que quelqu'un a fait le travail de s'asseoir sur une interface de capture de paquets (comme jpcap) avec une implémentation de UDPSocket (pour les datagrammes UDP) et InputStream (pour les flux TCP)?Possibilité de s'asseoir sur le réseau et recevoir un datagramme TCP/UDP?

Je suppose que ce ne serait pas trop difficile à faire étant donné l'API de rappel dans jpcap, mais est-ce que quelqu'un l'a déjà fait? Y a-t-il des problèmes à le faire (dois-je trouver comment réassembler un flux TCP moi-même, par exemple?)

Répondre

2

Je n'ai pas fait ce truc en particulier, mais je fais beaucoup de travail avec l'analyse des paquets capturés en C/C++. Je ne sais pas s'il existe des bibliothèques Java pour tout cela. Essentiellement, vous devez travailler votre chemin vers le haut de la pile de protocole, en commençant par l'adresse IP. Les données pcap commencent par l'en-tête de niveau lien, mais je ne pense pas qu'il y ait beaucoup de choses qui vous préoccupent, à part ignorer les paquets non-IP. La chose la plus difficile avec IP est le réassemblage des datagrammes fragmentés. Ceci est fait en utilisant le bit More Fragments dans le champ Flags et le champ Fragment Offset, combiné avec le champ Identification pour distinguer les fragments de différents datagrammes. Ensuite, vous utilisez le champ Protocol pour identifier les paquets TCP et UDP, et le champ Header Length pour trouver le début de l'en-tête correspondant. L'étape suivante, pour TCP et UDP, est le démultiplexage, qui sépare les différentes connexions du flux de paquets capturés. Les deux protocoles identifient les connexions (eh bien, UDP n'a pas de connexions en soi, mais je n'ai pas de meilleur mot à portée de main) par le 4-tuple de l'adresse IP source et destination et le port source et destination, donc une connexion être une séquence de paquets correspondant aux 4 de ces valeurs.

Une fois cela fait, pour UDP, vous êtes presque fini, sauf si vous voulez vérifier la somme de contrôle. Le champ Longueur dans l'en-tête UDP vous indique combien de temps le paquet est; soustrayez 8 octets pour l'en-tête et il y a vos données.

TCP est un peu plus compliqué, car vous devez en effet réassembler le flux, ce qui est fait en utilisant le numéro de séquence dans l'en-tête, combiné avec la longueur. La somme de ces deux vous indique le numéro de séquence suivant dans le flux. Rappelez-vous que vous suivez le trafic dans deux directions.

(Ceci est beaucoup plus facile que d'écrire une implémentation TCP réelle, comme vous devez mettre en œuvre l'algorithme Nagle et d'autres menus détails.)

Il y a beaucoup d'informations sur le net sur les formats d'en-tête; google "en-tête IP" pour les débutants. Un analyseur de réseau comme Wireshark est indispensable pour ce travail, car il vous montrera comment vos données capturées sont censées regarder. En effet, comme Wireshark est open source, vous pouvez probablement en savoir beaucoup en regardant comment il fait les choses

+0

Je vais ajouter une chose: je trouve qu'il est plus facile de tirer l'en-tête de paquet dans une structure de type C qui reproduit la disposition du paquet. Cela nécessite une directive de préprocesseur pour empêcher le remplissage interne de la structure, et vous devez vous rappeler de convertir les valeurs de 16 et 32 ​​bits en ordre d'octets de l'hôte en utilisant respectivement ntohs() et ntohl(). Je ne sais pas si une approche similaire est réalisable en Java, – ceo

2

Le réassemblage Tcp peut être fait avec JNetPcap. Voici un exemple complet:

final String SOME_PORT = 8888; 

StringBuilder errbuf = new StringBuilder(); 
Pcap pcap = Pcap.openOffline("/dir/someFile.pcap", errbuf); //Can be replace with .openLive(...) 

if (pcap == null) { 
    System.err.printf("Error: "+errbuf.toString()); 
    return; 
} 

//Handler that receive Tcp Event one by one 
AnalyzerListener<TcpStreamEvent> handler = new AnalyzerListener<TcpStreamEvent>() { 

    @Override 
    public void processAnalyzerEvent(TcpStreamEvent evt) { 
     JPacket packet = evt.getPacket(); 

     Tcp tcp = new Tcp(); 
     if (packet.hasHeader(tcp)) { 

       //Limiting the analysis to a specific protocol 
       if (tcp.destination() == SOME_PORT || tcp.source() == SOME_PORT) { 
        String data = new String(tcp.getPayload()); 
        System.out.println("Capture data:{"+data+"}"); 
       } 
     } 
    } 
}; 

TcpAnalyzer tcpAnalyzer = JRegistry.getAnalyzer(TcpAnalyzer.class); 
tcpAnalyzer.addTcpStreamListener(handler, null); 

//Starting the capture 
pcap.loop(Pcap.LOOP_INFINATE, JRegistry.getAnalyzer(JController.class), null); 
Questions connexes