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...
-
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#ExamplesHeisst: 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.