Daten über ethernet empfangen und von SQL-Datenbank abholen lassen



  • Hallo an alle!

    Ich habe folgendes Problem. Ich soll sämtlichen Inhalt eines Protokolls an einem PC aufnhemen und die Daten entweder direkt in eien SQL-Datenbank schreiben oder eben in irgendeiner Form dieser zur Verfügung stellen. Der 2. Teil sollte kein Problem darstellen.
    Mein Problem ist, wie komme ich an die ethernet Daten ran? Wäre es ein File welcher Art auch immer, wäre das weniger ein Problem, aber so fhelt mir momentan jegliche Idee.
    Vorgabe ist, dass alles mit C++ programmiert wird und dann eben in eine SQL-Server 2005 Datenbank geschrieben wird. Protokollauslese-Tools sind also nicht geünscht, sondern ich soll eben einen C++ Code schreiben, der die Daten von der ethernet Schnittstelle aufnimmt.
    Vielen Dank shconmal für jede Hilfe!



  • Keiner ein Ahnung?

    Also geht in erster Linie wirklich nur darum, einen Datenstrom der über ethernet ankommt zu empfangen.



  • Also etwas konkreter musst du schon werden. Welche Daten kommen denn überhaupt am PC an? Sollst du nur die Telegramme loggen, die an einem bestimmten Port anfallen, oder sollst du den gesamten Ethernet Traffic des PCs loggen?



  • außerdem, für welchen os? das kann man nämlich nicht mit standard mittteln machen



  • Was für "ethernet Daten"? Willst/sollst du die rohen Ethernet-Frames abfangen und abspeichern?
    Dafür gibt es zumindest unter Windows keine direkte Schnittstelle. Bin mir nichtmal sicher ob das mit Hilfstreibern ala WinPCap geht.



  • Okay, hier die fehlenden Infos:

    Es sind Positionsdaten, die ein einem selbstentwickelten (nicht von mir) Protokoll gesendet werden, was bis einschließlich Layer5 ethernet ist, also auf TCP und IP dann aufbaut. Darin steht z.b. Fritz hat Position 6.
    Die Daten dann in die Datenbank zu sortieren ist kein Problem, aber ich muss ja erstmal die Daten von der Netzwerkarte irgendwie herholen.

    Habe mittelgute C++ und SQLDeveloper Erfahrungen, aber keinen Schimmer, wie ich bei dem Problem starten soll. Wären die Daten in einer Datei (CSV o.ä.) wäre das ja kein Problem, sowas lernt man im Studium, aber wie man an Daten die nicht in einer Datei sind rankommt...


  • Mod

    Netzwerkkarte ansteuern ist hochgradig betriebssystemabhängig. Welches System?

    Wenn ich dich recht verstehe, willst du sogar irgendwo in die untersten Ebenen des Netzwerkprotokolls eingreifen. Ich wäre mir nicht so sicher, ob das überhaupt möglich ist, ohne einen eigenen Treiber zu schreiben. edit: Nein, das wolltest du wohl doch nicht. Wieso nicht einfach so etwas wie Boost ASIO? Dann hast du die betriebssystemabhängigkeit sogar weggekapselt.



  • Nein, das hilft immer noch kein Stück weiter.

    Bitte beschreib´ doch mal die aktuelle Situation, insbesondere wie die Kommunikation aussieht und wo dein Logger steht. Soll dein Logger die Kommunikation selbst abwickeln oder eine fremde Verbindung belauschen?



  • TCP/IP ist in Unterschied zu UDP ein bidirektionales Protokoll. Das bedeutet bevor ein Rechner irgendwas senden/empfangen kann muss die Verbindung schon stehen ;). Also muss ein Prozess/Rechner darauf warten bis der von dem anderen die Anfrage bekommt usw.
    Stichwort Sockets..
    Dort wirst Du deine Daten finden..



  • Johannes40481 schrieb:

    die ein einem selbstentwickelten (nicht von mir) Protokoll gesendet werden, was bis einschließlich Layer5 ethernet ist, also auf TCP und IP dann aufbaut.

    Ethernet betrifft Layer 1 und 2, Layer 3-5 haben mit Ethernet nichts zu tun.

    OK, es handelt sich also um TCP/IP, das wäre die relevante Info gewesen. Ist auch keine Überraschung, ist ja auch bloss das meist verwendetste L5 Protokoll.

    TCP/IP Connections kannst du mit den sog. Socket-Funktionen machen. connect, accept, recv, send etc.
    Oder eben etwas wie Boost.ASIO verwenden, was die Funktionalität in mehr oder weniger einfach zu verwendende C++ Klassen einwickelt.



  • IP arbeitet auf Layer 3 und TCP auf Layer 4. Mit Layer 5 hat das wenig zu tun. Just sayin.



  • UDP ist klar L4.

    TCP passt nicht so ganz ins OSI Modell, weil es Layer 4 und Teile von 5 übernimmt. Wobei es sehr oft der Fall ist, dass die nicht von TCP implementierten L5 Features einfach gar nicht verwendet werden, oder in L7 implementiert werden.

    Guckst du hier:
    http://en.wikipedia.org/wiki/OSI_model#Examples

    Heisst: in L5 ist in vielen Fällen "nix" ausser TCP, daher bezeichne ich TCP als L5 Protokoll.

    Wobei es wohl üblicher ist TCP als L4 Protokoll zu bezeichnen - auch wenn ich das nicht ganz nachvollziehen kann. Vielleicht L4/5?



  • Hier ist nochmal ein Link allgemein über die Infrastruktur von Netzwerk Programmierung
    http://www.phoenixcontact.de/local_content_pdf/pdf_eng/Ethernet_Basics_rev2_de.pdf
    Falss du Linux benutzt könntest du dich außerdem mit RAW-Sockets befassen. Das sähe dann z.b. so aus:

    sock = socket(AF_INET,SOCK_PACKET,htons(ETH_P_ARP));
    

    SOCK_PACKET steht dafür ,dass man auf Ethernet Ebene Aufbaut. Achtung man darf RAW_SOCKETS nur als Administrator erstellen sonst schlägt socket() fehl.



  • Vielen Dank der Infos! Das hilft mir sehr weiter, denke ich, muss ich nochmals genauer studieren!

    Und das ethernet Layer 1&2 kennzeichnet, IP Layer3 und TCP Layer4 war mir bewusst, aber man verstand (zum Glück) auch so was ich meinte.

    Und die Verbindung will ich nur belauschen, ich häng nur mit einer Art Tap dazwischen. Die beiden Controller die miteinander kommunizieren haben ebenfalls ein selbstentwickeltes Betriebssystem (was ja egal sein sollte) und der PC mit dem ich zuhören will muss Windows XP haben.

    Ich danke nochmals, werde erstmal eure ganzen Infos anschauen und verdauen und mich ggf. nochmals melden!



  • Johannes40481 schrieb:

    Und das ethernet Layer 1&2 kennzeichnet, IP Layer3 und TCP Layer4 war mir bewusst, aber man verstand (zum Glück) auch so was ich meinte.

    Nein, war überhaupt nicht klar.

    Wird sowieso jetzt erst klar, nachdem du schreibst...

    Und die Verbindung will ich nur belauschen, ich häng nur mit einer Art Tap dazwischen. Die beiden Controller die miteinander kommunizieren haben ebenfalls ein selbstentwickeltes Betriebssystem (was ja egal sein sollte) und der PC mit dem ich zuhören will muss Windows XP haben.

    Ach, das wäre aber auch ne wichtige Info gewesen.
    Dann musst du erstmal deine Netzwerkkarte wo du "mitlauschen" willst in den "promiscuous" Mode schalten, sonst wirst du nämlich von dem was die zwei Controller miteinander plauschen nix mitbekommen.
    Und du brauchst einen Hilfstreiber der Pakete capturen kann, wie eben WinPCap.



  • Und wenn du hinter einem Switch sitzt muss der Switch den Port ebenfalls in den Promiscuous Modus schalten, sonst bekommste nur Pakete, die an dich adressiert sind.



  • okay... tut mir Leid... bin noch im blutigen Anfängerstatus!

    Und promiscuous-Mode weiß ich, brauch eh eine Karte mnit 2 Netzwerkanschlüssen, da der Netzwerk Tap (vermutlich ein Netoptics TP-CU) das Signal auf Tx und Rx auftrennt und je an eine Leitung al Rx weitergibt. Macht auch die Auswertung der Datenrichtung einfacher.



  • Na dann ist das ganze doch garnicht sooo schwierig... mit WinPCap solltest du das eigentlich lösen können. Die API ist inzwischen ziemlich komfortabel, dazu braucht man nur etwas mehr als C/C++ Anfängerwissen.



  • Habe nun mit der WinPcap einige geschafft, dank ver Tutorials, allerdings nun einen Fehler, den ich nicht beseitigt bekomme. Umgebung ist immernoch WinXp und Visual Studio 2008.

    #include <pcap.h>
    #include <winsock2.h>
    
    #include <Tchar.h>
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    using namespace std;
    
    // default snap length (maximum bytes per packet to capture)
    #define SNAP_LEN 1518
    
    // ethernet headers are always exactly 14 bytes
    #define SIZE_ETHERNET 14
    
    // Ethernet addresses are 6 bytes
    #define ETHER_ADDR_LEN	6
    
    // Ethernet header
    struct sniff_ethernet {
    	u_char ether_dhost[ETHER_ADDR_LEN]; // Destination host address 
    	u_char ether_shost[ETHER_ADDR_LEN]; // Source host address 
    	u_short ether_type;					// IP? ARP? RARP? etc 
    };
    
    // IP header 
    struct sniff_ip {
    	u_char ip_vhl;				// version << 4 | header length >> 2 
    	u_char ip_tos;				// type of service 
    	u_short ip_len;				// total length 
    	u_short ip_id;				// identification 
    	u_short ip_off;				// fragment offset field 
    #define IP_RF 0x8000			// reserved fragment flag 
    #define IP_DF 0x4000			// dont fragment flag 
    #define IP_MF 0x2000			// more fragments flag 
    #define IP_OFFMASK 0x1fff		// mask for fragmenting bits 
    	u_char ip_ttl;				// time to live 
    	u_char ip_p;				// protocol 
    	u_short ip_sum;				// checksum 
    	struct in_addr ip_src,ip_dst;	// source and dest address 
    };
    #define IP_HL(ip)		(((ip)->ip_vhl) & 0x0f)
    #define IP_V(ip)		(((ip)->ip_vhl) >> 4)
    
    //TCP header 
    struct sniff_tcp {
    	u_short th_sport;	// source port 
    	u_short th_dport;	// destination port 
    	//tcp_seq th_seq;	// sequence number 
    	//tcp_seq th_ack;	// acknowledgement number 
    
    	u_char th_offx2;	// data offset, rsvd 
    #define TH_OFF(th)	(((th)->th_offx2 & 0xf0) >> 4)
    	u_char th_flags;
    #define TH_FIN 0x01
    #define TH_SYN 0x02
    #define TH_RST 0x04
    #define TH_PUSH 0x08
    #define TH_ACK 0x10
    #define TH_URG 0x20
    #define TH_ECE 0x40
    #define TH_CWR 0x80
    #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
    	u_short th_win;		// window 
    	u_short th_sum;		// checksum 
    	u_short th_urp;		// urgent pointer 
    };
    
    // ethernet headers are always exactly 14 bytes 
    #define SIZE_ETHERNET 14
    
    struct sniff_ethernet *ethernet;	// The ethernet header 
    struct sniff_ip *ip;				// The IP header 
    struct sniff_tcp *tcp;				// The TCP header 
    u_char *payload;					// Packet payload 
    
    u_int size_ip;
    u_int size_tcp;
    
    // print payload in ascii signs
    void print_hex_ascii_line(const u_char *payload, int len, int offset)
    {
    	int i;
    	int gap;
    	const u_char *ch;
    
    	// offset
    	printf("%05d   ", offset);
    
    	// hex
    	ch = payload;
    	for(i = 0; i < len; i++) {
    		printf("%02x ", *ch);
    		ch++;
    		// print extra space after 8th byte for visual aid
    		if (i == 7)
    			printf(" ");
    	}
    	//print space to handle line less than 8 bytes
    	if (len < 8)
    		printf(" ");
    
    	//fill hex gap with spaces if not full line
    	if (len < 16) {
    		gap = 16 - len;
    		for (i = 0; i < gap; i++) {
    			printf("   ");
    		}
    	}
    	printf("   ");
    
    	// ascii (if printable)
    	ch = payload;
    	for(i = 0; i < len; i++) {
    		if (isprint(*ch))
    			printf("%c", *ch);
    		else
    			printf(".");
    		ch++;
    	}
    
    	printf("\n");
    
    return;
    }
    
    // print the TCP payload
    void print_payload(const u_char *payload, int len)
    {
    
    	int len_rem = len;
    	int line_width = 16;			// number of bytes per line
    	int line_len;
    	int offset = 0;					// zero-based offset counter
    	const u_char *ch = payload;
    
    	if (len <= 0)
    		return;
    
    	// data fits on one line
    	if (len <= line_width) {
    		print_hex_ascii_line(ch, len, offset);
    		return;
    	}
    
    	// data spans multiple lines
    	for ( ;; ) {
    		// compute current line length
    		line_len = line_width % len_rem;
    		// print line
    		print_hex_ascii_line(ch, line_len, offset);
    		// compute total remaining
    		len_rem = len_rem - line_len;
    		// shift pointer to remaining bytes to print
    		ch = ch + line_len;
    		// add offset
    		offset = offset + line_width;
    		// check if we have line width chars or less
    		if (len_rem <= line_width) {
    			// print last line and get out
    			print_hex_ascii_line(ch, len_rem, offset);
    			break;
    		}
    	}
    
    return;
    }
    
    void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
    {
    
    	static int count = 1;                   // packet counter
    
    	// declare pointers to packet headers
    	const struct sniff_ethernet *ethernet;  // The ethernet header
    	const struct sniff_ip *ip;              // The IP header
    	const struct sniff_tcp *tcp;            // The TCP header
    	u_char *payload;						// Packet payload
    
    	int size_ip;
    	int size_tcp;
    	int size_payload;
    
    	printf("\nPacket number %d:\n", count);
    	count++;
    
    	// define ethernet header
    	ethernet = (struct sniff_ethernet*)(packet);
    
    	// define/compute ip header offset
    	ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
    	size_ip = IP_HL(ip)*4;
    	if (size_ip < 20) {
    		printf("   * Invalid IP header length: %u bytes\n", size_ip);
    		return;
    	}
    	printf("    From: %s\n", inet_ntoa(ip->ip_src));
    	printf("      To: %s\n", inet_ntoa(ip->ip_dst));
    
    	// determine protocol	
    	switch(ip->ip_p) {
    		case IPPROTO_TCP:
    			printf("   Protocol: TCP\n");
    			break;
    		case IPPROTO_UDP:
    			printf("   Protocol: UDP\n");
    			return;
    		case IPPROTO_ICMP:
    			printf("   Protocol: ICMP\n");
    			return;
    		case IPPROTO_IP:
    			printf("   Protocol: IP\n");
    			return;
    		default:
    			printf("   Protocol: unknown\n");
    			return;
    	}
    
    	// define/compute tcp header offset
    	tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
    	size_tcp = TH_OFF(tcp)*4;
    	if (size_tcp < 20) {
    		printf("   * Invalid TCP header length: %u bytes\n", size_tcp);
    		return;
    	}	
    	printf("   Src port: %d\n", ntohs(tcp->th_sport));
    	printf("   Dst port: %d\n", ntohs(tcp->th_dport));
    
    	// define/compute tcp payload (segment) offset
    	payload = (u_char*) (packet + SIZE_ETHERNET + size_ip + size_tcp); // <--- hier Fehler-------------------------------------------------------------------
    	//-------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	// compute tcp payload (segment) size
    	size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);
    
    	// Print payload data; it might be binary, so don't just treat it as a string.
    	if (size_payload > 0) {
    		printf("   Payload (%d bytes):\n", size_payload);
    		print_payload(payload, size_payload);
    	}
    return;
    }
    
    // main programm
    int _tmain(int argc, _TCHAR* argv[])
    {
        pcap_if_t * allAdapters;						// output device, all
        pcap_if_t * adapter;							// selected output device
        pcap_t * adapterHandle;							// packet capture handle 
        char errorBuffer[ PCAP_ERRBUF_SIZE ];			// error buffer
    
    	unsigned int netmask = 0xffffff;				// netmask to recieve from all IPs
    	char packet_filter[] = "tcp port 5055";			// Filter set to TCP Port 5055 for SCIP
    	struct bpf_program filtercode;					// compiled filter version
    	int num_packets = -1;							// number of packets to capture, set negative for endless
    
    //--------------------------------------------------------------------------
        // retrieve the adapters from the computer
    	// you can choose which adapter you want to use
    	// also Filter for Port 5055 (can be changed above) is set here, to keep traffic as low as possible
    
        if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, 
                &allAdapters, errorBuffer ) == -1 )
        {
            fprintf( stderr, "Error in pcap_findalldevs_ex function: %s\n", errorBuffer );
            return -1;
        }
    
        // if there are no adapters, print an error
        if( allAdapters == NULL )
        {
        printf( "\nNo adapters found! Make sure WinPcap is installed.\n" );
            return 0;
        }
    
        // print the list of adapters along with basic information about an adapter
        int crtAdapter = 0;
        for( adapter = allAdapters; adapter != NULL; adapter = adapter->next)
        {
        printf( "\n%d.%s ", ++crtAdapter, adapter->name );
        printf( "-- %s\n", adapter->description );
        }
    
        printf( "\n" );
    
        int adapterNumber;
    	// select an adapter
        printf( "Enter the adapter number between 1 and %d:", crtAdapter );
        scanf_s( "%d", &adapterNumber );
    
        if( adapterNumber < 1 || adapterNumber > crtAdapter )
        {
            printf( "\nAdapter number out of range.\n" );
    
            // Free the adapter list
            pcap_freealldevs( allAdapters );
    
            return -1;
        }
    
        // parse the list until we reach the desired adapter
        adapter = allAdapters;
        for( crtAdapter = 0; crtAdapter < adapterNumber - 1; crtAdapter++ )
        adapter = adapter->next;
    
    	// open the adapter with promiscous mode enabled
        adapterHandle = pcap_open( adapter->name,	// name of the adapter
                                   65536,			// portion of the packet to capture
    												// 65536 guarantees that the whole
    												// packet will be captured
                                   PCAP_OPENFLAG_PROMISCUOUS,	// promiscuous mode
                                   1000,            // read timeout - 1 millisecond
                                   NULL,			// authentication on the remote machine
                                   errorBuffer		// error buffer
                                  );
    
        if( adapterHandle == NULL )
        {
            fprintf( stderr, "\nUnable to open the adapter\n", adapter->name );
    
    	// Check the link layer. We support only Ethernet for simplicity.
        if(pcap_datalink(adapterHandle) != DLT_EN10MB)
        {
            fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
            // Free the device list
            pcap_freealldevs(allAdapters);
            return -1;
        }
    
    	// compile the filter
    	if (pcap_compile(adapterHandle, &filtercode, packet_filter, 1, netmask) > 0)
    	{
    		cout<<endl<<"Unable to compile the packet filter. Check Syntax!"<<endl;
    		pcap_freealldevs(allAdapters);
    		return -1;
    	}
    
    	// setting the filter
    	if (pcap_setfilter(adapterHandle, &filtercode) > 0)
    	{
    		cout<<endl<<"Error setting filter!"<<endl;
    		pcap_freealldevs(allAdapters);
    		return -1;
    	}
            // Free the adapter list
            pcap_freealldevs( allAdapters );
            return -1;
        }
    
        printf( "\nCapture session started on  adapter %s...\n", adapter->name );
    
        // free the adapter list
        pcap_freealldevs( allAdapters );
    
    //--------------------------------------------------------------------------
        // this is the most important part of the application
        // here we start receiving packet traffic
    // then save information inside the packet into array or somethign like that
    
    	pcap_loop(adapterHandle, num_packets, got_packet, NULL);
    
    	// cleanup variables
    	pcap_freecode(&filtercode);
    	pcap_close(adapterHandle);
    
        system( "PAUSE" );
        return 0;
    }
    

    Ich möchte eben den payload aus dem TCP als Ascii Zeichen Kette haben und dann weiterverarbeiten. Die Weiterverarbeitung hätte ich auch funktionierend, aber bekomme an der einen Stelle, zum lokalisieren des Payload, also der Psotition im ethernet frame immer wieder einen Fehler, den ich nicht beseitigen kann.
    Ist auch Code makriert wo!
    In der Version wie oben, wo ich versuche explizit des Datenformat zu ändern, meckert, er das es 2 unaufgelöste externe Symbole gibt, und zwar innerhalb der got_packet funktion, wo genau, sagt er nicht.
    Lass ich das Wandeln weg, funktioniert es nicht, da er ein const u_cahr* nicht in ein u_char* wandeln kann. Klar, deswegen wollte ich es ja wandeln... der Grund ist, dass die pcap das als const erwartet.



  • Bitte gewöhn´ dir an, präzise Fehlerbeschreibung zu liefern. Aussagen wie "immer noch einen Fehler, den ich nicht beseitigen kann" enthalten keine Informationen, die irgendwie zur Problemlösung beitragen.


Anmelden zum Antworten