Moin zusammen, ich tausche mit einem arduino daten per raw sockets aus. (das habe ich vor 4 jahren mal angefangen und dann beiseite gelegt. und nun wieder ausgegraben.) es funktioniert auch, aber es kommen ständig daten auf dem socket an, obwohl der arduino gar nichts schickt. auch wenn ich das interface tot lege (kabel ab) liefert recvfrom daten. und das sind keine "echten" daten. es ist kein traffic auf dem interface. jedenfalls definitiv nicht so viel, wie recvfrom lesen kann. während tcpdump nichts (oder nur wenig) ausgaben liefert, wenn ich keine packets auf den weg schicke, liefert mir im gleichen moment das hier: numbytes = recvfrom(rawrsockfd, recbufs, BUF_SIZ, 0, NULL, NULL); if (numbytes==-1) return 0; if (debug & deb_recpkt) printf("listener: got packet %lu bytes\n", numbytes); so ein resultat: listener: got packet 530 bytes listener: got packet 626 bytes listener: got packet 66 bytes listener: got packet 242 bytes listener: got packet 310 bytes listener: got packet 66 bytes und das in rasender geschwindigkeit..... ich habe keine ahnung, was das sein soll und wo es her kommt. sehe ich den wald vor lauter bäumen nicht? irgendwer eine idee dazu? hier wird das socket erzeugt: -------------------------------- int init_raw_rec_socket(char devn[]){ printf("init_rec_socket. DEV:[%s]\n",devn); rawrsockfd=socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) ); if (rawrsockfd<0) { perror("setsockopt1"); close(rawrsockfd); return(EXIT_FAILURE); } strncpy(ifopts.ifr_name, devn, IFNAMSIZ-1); ioctl(rawrsockfd, SIOCGIFFLAGS, &ifopts); ifopts.ifr_flags |= IFF_PROMISC; ioctl(rawrsockfd, SIOCSIFFLAGS, &ifopts); /* Bind to device */ if (setsockopt(rawrsockfd, SOL_SOCKET, SO_BINDTODEVICE, dev_name, IFNAMSIZ-1) == -1) { perror("SO_BINDTODEVICE"); close(rawrsockfd); return(EXIT_FAILURE); } int flags = fcntl(rawrsockfd, F_GETFL); flags |= O_NONBLOCK; fcntl(rawrsockfd, F_SETFL, flags); memset(&if_ip, 0, sizeof(struct ifreq)); if ((rawrsockfd = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL))) == -1) { perror("non blocking listener: socket"); return(EXIT_FAILURE); } flags = fcntl(rawrsockfd, F_GETFL); flags |= O_NONBLOCK; fcntl(rawrsockfd, F_SETFL, flags); return 0; } --------------------------- tcpdump benimmt sich von rechner zu rechner auch immer mal etwas seltsam: commandlie ist immer "tcpdump -i interface -s 2000" tcpdump version 4.9.2 libpcap version 1.8.1 OpenSSL 1.1.1 11 Sep 2018 das liefert: 07:44:55.904261 06:05:04:03:02:01 > 01:02:03:04:05:06, 802.3, length 0: LLC, dsap Null (0x00) Individual, ssap Null (0x00) Command, ctrl 0x3c00: Information, send seq 0, rcv seq 30, Flags [Command], length 50 0x0000: 0000 003c 0000 0000 0000 2600 0000 0000 ...<......&..... 0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0030: 0000 .. 07:44:55.910384 06:05:04:03:02:01 > 01:02:03:04:05:06, 802.3, length 0: LLC, dsap Null (0x00) Individual, ssap Null (0x00) Command, ctrl 0x3e00: Information, send seq 0, rcv seq 31, Flags [Command], length 50 0x0000: 0000 003e 0000 0000 0000 2700 0000 0000 ...>......'..... 0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0030: 0000 .. 07:44:55.918284 06:05:04:03:02:01 > 01:02:03:04:05:06, 802.3, length 0: LLC, dsap Null (0x00) Individual, ssap Null (0x00) Command, ctrl 0x3f00: Information, send seq 0, rcv seq 31, Flags [Poll], length 50 0x0000: 0000 003f 0000 0000 0000 2800 0000 0000 ...?......(..... 0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0030: 0000 .. tcpdump version 4.99.1 libpcap version 1.10.1 (with TPACKET_V3) OpenSSL 3.0.2 15 Mar 2022 das liefert: 07:40:42.950850 [|llc] 07:40:42.957939 [|llc] 07:40:42.959007 [|llc] 07:40:42.961276 [|llc] 07:40:42.966739 [|llc] 07:40:42.967930 [|llc]
Du setzt den Socket in den Non-Blocking-Mode. Außerdem wertest Du den Fehlercode nach recvfrom(...) < 0 nicht aus.
Wicki W. schrieb: > es kommen ständig daten auf dem socket an Ja, dafür ist ein "raw socket" nach meinem bescheidenen Halbwissen da. Ein Socket ist eine Telefonnummer zum Betriebssystem bezüglich "Networking" und kann alles geschickt kriegen, was im Netzwerkbereich wichtig ist. Raw sockets sind nicht einheitlich, sondern betriebssystemabhängig. Unter Anderem dienen sie dazu, entweder "network sniffer" für etablierte Protokolle zu bauen oder eigene Protokolle zu implementieren (wie ja auch in diesem Fall gewünscht). Insofern erstaunt es mich, daß ein Programm wie tcpdump, das (zumindest dem Namen nach) zwei Ebenen höher arbeitet, hier überhaupt sinnvolle Daten liefern soll. Kann aber an meiner Unkenntnis liegen. Ich würde beispielsweise vermuten, daß sämtliche Broadcastnachrichten im raw socket auftauchen, wie soll ich sonst eine eigene "address resolution" aufbauen, wenn ich ein eigenes Protokoll mit eigener Adressierung implementieren will? @Wilhelm M. Das mit der fehlenden Errorauswertung verstehe ich, aber was ist am "non blocking mode" kritisch? Wenn nichts da ist, bekomme ich "0 bytes received" zurück und weiter gehts. Just my 2 cents Klaus (der soundsovielte)
Klaus S. schrieb: > @Wilhelm M. > Das mit der fehlenden Errorauswertung verstehe ich, aber was ist am "non > blocking mode" kritisch? Wenn nichts da ist, bekomme ich "0 bytes > received" zurück und weiter gehts. Gar nichts. Nur an dem Code des TO kann ich nicht erkennen, dass er darauf vorbereitet ist bzw. weiß, dass er damit eine Polling-Strategie realisiert.
Klaus S. schrieb: > Insofern erstaunt es mich, daß ein Programm wie tcpdump, das (zumindest > dem Namen nach) zwei Ebenen höher arbeitet, hier überhaupt sinnvolle > Daten liefern soll. Kann aber an meiner Unkenntnis liegen. Offenbar trifft letzteres zu. Tcpdump kann schon lange nicht mehr nur TCP-Verkehr anzeigen, sondern alles mögliche. Unter MS Windows setzt man Tcpdump und Wireshark meist in Verbindung mit der libpcap o.ä. ein, wodurch der direkte Zugriff am Protokollstack vorbei auf die entsprechenden Netzwerkinterfaces erfolgt. Mittlerweile gibt es z.B. auch USBPcap, mit dem man auf die gleiche Art und Weise den USB-Verkehr mitschneiden kann, und zwar tatsächlich auch mit tcpdump und Wireshark.
Wilhelm M. schrieb: > Gar nichts. Andreas S. schrieb: > Offenbar trifft letzteres zu. Danke für die Erläuterungen, ich lerne immer gern dazu. Gruß Klaus (der soundsovielte)
hi nochmal, nein, einen error werte ich nicht aus. und dass ich das ganze im no-blocking-mode laufen haben will, das hat schon seinen grund. (das ist für einen RT-kern gebaut worden) und dass sich auf dem socket natürlich alles mögliche herumtreiben kann, das ist mir auch klar. aber das sollte es halt eigentlich nicht - denn wenn da was wäre, dann würde es z.b. auch von tcpdump oder w-shark gemeldet. aber hier sagt recvfrom ja: "ich hab da xxx bytes daten für dich" - die können aber eigentlich nicht da sein. weil auf dem interface nichts weiter passiert. und wenn ich sie lese, dann steht auch müll drin. ich konnte bislang jedesfalls noch nichts sinnvolles herauslesen - ausser mal ein ARPs, DHCPs und sowas. aber nichts was dieser menge an daten entspricht, die ich aus dem socket herauslesen kann. daher frage ich mich nun schon länger: was mach ich falsch? oder wo denke ich falsch? ein kollege meinte schon, "das bind zum interface hat vielleicht nicht geklappt und dann nimmt das socket alle interfaces die da sind". aber selbst auf allen interfaces zugleich dürfe nicht so viel los sein.
Was willst du überhaupt machen? Ein raw-socket mit ETH_P_ALL bekommt alles, u.U. auch den eigenen ausgehenden Traffic. Warum keine Beschränkung auf einen Protokolltyp? Dann promiscuous Mode: das schaltet den Paketfilter im Netzwerkchip ab - du bekommst alle Pakete, auch die, die nicht für diesen Rechner sind. Und letztendlich machst du einen zweiten (nicht an ein Interface gebundenen) Socket auf und vergisst den (gebundenen) ersten. Cut-n-Paste Fehler? Mir scheint, du willst Schrauben mit nem Hammer einschlagen ...
Foobar schrieb: > Was willst du überhaupt machen? ich will die daten haben, bevor irgendwer oder -was sich damit befasst. > Ein raw-socket mit ETH_P_ALL bekommt alles. genau so soll es auch sein. > , u.U. auch den eigenen ausgehenden Traffic. das mit dem eigenen ausgehenden traffic, das wäre mir neu und mir bestimt schon mal aufgefallen. die manpage sagt auch nichts davon. (s.u.) > Warum keine Beschränkung auf einen Protokolltyp? weil jedes protokoll overhead bedeutet. und den will ich vermeiden. > Dann promiscuous Mode: das schaltet den Paketfilter im Netzwerkchip ab - > du bekommst alle Pakete, auch die, die nicht für diesen Rechner sind. > Und letztendlich machst du einen zweiten (nicht an ein Interface > gebundenen) Socket auf und vergisst den (gebundenen) ersten. > Cut-n-Paste Fehler? den verdacht hatte ich auch schon. aber wenn ich das raus nehme, dann ändert sich dennoch nichts am verhalten. > Mir scheint, du willst Schrauben mit nem Hammer einschlagen ... ein unpassender vergleich. und ob die anwendung überhaupt so realisiert wird, ist eh noch völlig offen. ist ein experiment, das ich vor 4 jahren mal angefangen habe. was bleibt, ist die frage: warum sagt recvfrom "ich habe daten" wenn da keine sein sollten. wo kommen sie her? und warum? ------------- When protocol is set to htons(ETH_P_ALL), then all protocols are received. All incoming packets of that protocol type will be passed to the packet socket before they are passed to the protocols implemented in the kernel.
Wicki W. schrieb: >> Warum keine Beschränkung auf einen Protokolltyp? > > weil jedes protokoll overhead bedeutet. und den will ich vermeiden. Der CPU Overhead davon dürfte weit darunter liegen, deine Anwendung bei jedem Paket informieren zu müssen, dort hin zu switchen, und dieses die Daten lesen/kopieren zu lassen, nur damit es dann meistens doch nichts damit macht.
>> Was willst du überhaupt machen? > > ich will die daten haben, bevor irgendwer oder -was sich damit befasst. Das wird schwer. Du bekommst eh nur ne Kopie und bevor die im Userspace landet, hat das Kernel das Original schon längst weiterverarbeitet. >> Ein raw-socket mit ETH_P_ALL bekommt alles. > > genau so soll es auch sein. Für eine Kommunikation mit einem Arduino eher ungewöhnlich. >> , u.U. auch den eigenen ausgehenden Traffic. > > das mit dem eigenen ausgehenden traffic, das wäre mir neu und mir > bestimt schon mal aufgefallen. Dann schau noch mal genauer - insb das Feld sll_pkttype (i.e. PACKET_OUTGOING) in der von dir verworfenen sockaddr das recvfrom. S. man 7 packet). Btw, mein tcpdump zeigt ausgehenden Traffic ... Ich weiß aber, dass einige wenige ausgehenden Pakete nicht gemeldet werden (an die genauen Bedingungen kann ich mich nicht erinnern). Hatte das Problem (vor vielen Jahren) mal. Kommentar vom Kernel-Maintainer: wissen wir, wird aber vorraussichtlich nicht gefixt. Kann sein, dass das mit der Turbo-Packet API zusammenhing (bin mir aber nicht sicher). >> Warum keine Beschränkung auf einen Protokolltyp? > > weil jedes protokoll overhead bedeutet. und den will ich vermeiden. Das wird eh verarbeitet. Es wird nur ein etwas späterer Hook aktiviert. Und das Kopieren/Weiterleiten jedes einzelnen Pakets zum Userspace ist um Größenordnungen aufwändiger als der Kernel-interner Filter, der dann nur relevante Pakete kopiert. Wenn du wirklich sowas haben willst (im Prinzip ein Packet-sniffer), solltest du dir überlegen, ob du nicht eher libpcap einsetzt. Da ist viel Kram drin, um das ganze halbwegs performant (Turbo-Paket btw dessen Nachfolger) und korrekt zu implementieren. Außerdem wäre das weitgehend platformneutral. Auf diese Weise ein Kommunikationsprotokoll zu implementieren, wäre mMn allerdings ein Irrweg.
> >> Ein raw-socket mit ETH_P_ALL bekommt alles. > > genau so soll es auch sein. > Für eine Kommunikation mit einem Arduino eher ungewöhnlich. ja - sicher. ungewöhnlich ist das.... im prinzip ist es so, dass ein shmem-bereich eines linuxcnc auf die io-ports eines arduino oder raspberry oder das shmem eines anderen PC (oder was auch immer) gemappt werden. die echtzeitfähigkeiten, die ich mir gewünscht hatte, habe ich aber vor 4 jahren leider nicht hinbekommen. nun will ichs nochmal versuchen. > >> , u.U. auch den eigenen ausgehenden Traffic. > > > > das mit dem eigenen ausgehenden traffic, das wäre mir neu und mir > > bestimt schon mal aufgefallen. > Dann schau noch mal genauer - insb das Feld sll_pkttype (i.e. bin dabei, genauer zu schauen. und wie es scheint, komm ich der sache auf die spur. ich habe das grade auf eine minimal-version reduziert und es scheint so zu sein, dass der fehler irgendwo im programm liegt (und nicht beim handling des recvfrom) > PACKET_OUTGOING) in der von dir verworfenen sockaddr das recvfrom. S. > man 7 packet). Btw, mein tcpdump zeigt ausgehenden Traffic ... na klar zeigt der tcpdump ausgehenden traffic - aber das rec-socket des sendenden devices sollte doch nicht den eigenen traffic.... ? warum denn eigentlich nicht??? na klar! vielleicht ist genau das mein denkfehler gewesen! ? wirklich wald vor lauter bäumen nicht gesehen? ich lote das mal weiter aus. aber schön, das wir drüber geredet haben. melde mich, wenn ich weiter bin. munter bleiben wicki
> im prinzip ist es so, dass ein shmem-bereich eines linuxcnc > auf die io-ports eines arduino oder raspberry oder das shmem > eines anderen PC (oder was auch immer) gemappt werden. Nun ja, ich hoffe nicht, dass du die Step-Impulse aufgelöst bekommen willst - das wird nichts. Mit einem separaten Eth-Controller und einer direkten Verbindung (also kein Switch, keine anderen Rechner) wirst du <1ms gut hinbekommen, mehr als 0.1ms würd ich aber nicht erwarten. Entspräche Pulsraten von 500-5000Hz. Die Ethernet-Verarbeitung im Arduino stell ich mir noch spannend vor - ist ja nicht so, dass die üblicherweise Ethernet on-Chip haben ... Aber für so eine Anwendung nimmt man doch nicht ETH_P_ALL - definier dir einen eigenen Typ. Und berücksichtigen: auch ein RAW-socket hat Empfangs- und Sendebuffer, die überlaufen können - wenn zuviel ankommt werden Pakete weggeschmissen. Ein ausgelastetes 100mbit-Netz per simplen raw-socket mitzuschneiden, wird nicht ohne Verluste klappen. Dafür wurden z.B. die Turbo-Packets eingeführt (ein Ring-Buffer im Userspace, der direkt vom Kernel gefüllt wird, fast wie DMA). Das sinnvollste wäre mMn aber reguläre UDP-Pakete. Warum was neues Erfinden?
nun bin ich wohl weiter.... aber leider gefrustet: man kann scheinbar kein raw-socket an ein device binden. das nimmt immer alle devices. SO_BINDTODEVICE nickt das zwar brav ab - aber es funktioniert nur bei nicht-raw-sockets. wenn man von einem spezifischen device lesen will, dann muss das mit "bind" gemacht werden. bind funktioniert aber nicht mit raw sockets. weil die eben keine IP haben. bislang habe ich noch keine möglichkeit gefunden, um herauszufinden, von welchem device die daten, die von einem raw-socket kommen nun wirklich stammen. mit einem ID-header im telegramm könnte ich das problem zwar umgehen - aber ich mag nicht so recht glauben, dass es keine möglichkeit gibt, das auf der receiver-seite festzulegen. vielleicht weiss ja jemand as dazu. aber bitte keine grundsatzdiskussionen über IP-layer und sowas. ich weiss, dass man damit diese probleme nicht hätte.
> Nun ja, ich hoffe nicht, dass du die Step-Impulse aufgelöst bekommen > willst - doch, das war mal die grundidee > das wird nichts. Mit einem separaten Eth-Controller und einer > direkten Verbindung (also kein Switch, keine anderen Rechner) wirst du > <1ms gut hinbekommen, mehr als 0.1ms würd ich aber nicht erwarten. > Entspräche Pulsraten von 500-5000Hz. Die Ethernet-Verarbeitung im > Arduino stell ich mir noch spannend vor - ist ja nicht so, dass die > üblicherweise Ethernet on-Chip haben ... richtig - das ist auch das, was dabei herauskam. 5kHz viel mehr war stabil nicht machbar. aber mit einer neuen idee könnte das besser werden. > Die Ethernet-Verarbeitung im > Arduino stell ich mir noch spannend vor - ist ja nicht so, dass die > üblicherweise Ethernet on-Chip haben ... ja, die ist "gewöhnungsbedürftig". aber ausbaufähig. bei arduino war das aber mehr zur verarbeitung von rotary-encodern gebaut und zur ansteuerung von gross-DROs, die dann aber auch via rasberry und UDP funktionierten. > Das sinnvollste wäre mMn aber reguläre UDP-Pakete. Warum was neues > Erfinden? aus dem gleichen grund, warum sich hunde die eier lecken.... ich will einfach wissen ob es geht. wegwerfen kann man es immer noch. UDP ist ja schon drin..... ;-)
> man kann scheinbar kein raw-socket an ein device binden. > das nimmt immer alle devices. Du hast aber schon den zweiten socket-call in deinem init_raw_rec_socket rausgenommen, oder? > bind funktioniert aber nicht mit raw sockets. weil die eben keine IP haben. Bei tcpdump geht das:
1 | $ strace -e trace=network,close tcpdump -i ppp0 |
2 | ... |
3 | socket(PF_PACKET, SOCK_DGRAM, 768) = 3 |
4 | bind(3, {sa_family=AF_PACKET, proto=0x03, if30, pkttype=PACKET_HOST, addr(0)={0, }, 20) = 0 |
5 | ... |
> bislang habe ich noch keine möglichkeit gefunden, um herauszufinden, > von welchem device die daten, die von einem raw-socket kommen nun > wirklich stammen. Im sockaddr_ll gibt es nicht nur den Pakettyp (sll_pkttype) sondern auch noch eine Interfacenummer (sll_ifindex). Check das mal.
Wicki W. schrieb: > was bleibt, ist die frage: > warum sagt recvfrom "ich habe daten" wenn da keine sein sollten. Du siehst das Problem aus der falschen Richtung. Nur du glaubst, das da nichts sein sollte. > wo kommen sie her? und warum? Broadcasts. In jedem üblichen Netz anzutreffen und erreichen auch an jedem Port eines Switches den Peer. Genau das ist schließlich der Sinn von Broadcasts... Wenn du noch nie was davon gehört hast, solltest du dich nicht mit Netzwerkprogrammierung beschäftigen, sondern erstmal Netzwerk-Kompetenz anlesen.
>> wo kommen sie her? und warum? > > Broadcasts. In jedem üblichen Netz anzutreffen und erreichen auch an > jedem Port eines Switches den Peer. Genau das ist schließlich der Sinn > von Broadcasts... > > Wenn du noch nie was davon gehört hast, solltest du dich nicht mit > Netzwerkprogrammierung beschäftigen, sondern erstmal Netzwerk-Kompetenz > anlesen. das ist es, was ich in solchen foren immer so liebe: der liebevolle umgang miteinander. so viele broadcasts können da nicht sein, weil das system nichts zu broadcasten hat. jedenfalls nicht so viel. und wenn es broadcasts wären: warum sieht tcpdump sie nicht? ein erklärungsversuch im nächsten post...
Foobar schrieb: >> man kann scheinbar kein raw-socket an ein device binden. >> das nimmt immer alle devices. > > Du hast aber schon den zweiten socket-call in deinem init_raw_rec_socket > rausgenommen, oder? in dem testprog: ja das hatte ich auch im hauptprogramm schon - ohne erfolg. die ursache ist eine andere ein erklärungsversuch: (unvollständig und ins unreine geschrieben - und vielleicht auch falsch - testprogramm dazu folgt noch) dass tcpdump die ganze pakete nicht sah, das lag daran, dass ich immer mit "-i ifname" gearbeitet habe. und nicht "-i any". >> bind funktioniert aber nicht mit raw sockets. weil die eben keine IP haben. > > Bei tcpdump geht das: >
1 | > $ strace -e trace=network,close tcpdump -i ppp0 |
2 | > ... |
3 | > socket(PF_PACKET, SOCK_DGRAM, 768) = 3 |
4 | > bind(3, {sa_family=AF_PACKET, proto=0x03, if30, pkttype=PACKET_HOST, |
5 | > addr(0)={0, }, 20) = 0 |
6 | > ... |
7 | > |
da ist aber "pkttype=PACKET_HOST" * sll_pkttype contains the packet type. Valid types are PACKET_HOST for a packet addressed to the local host, aber auf dieser ebene sind wir ja bei raw-packets gar nicht. das ist nur ein datenstrom, der weder mac-adressen noch IPs kennt. die muss man ja selbst ausfiltern. dass der datenstrom auch nicht interface kennt, von dem er stammt, das erstaunt mich nun doch. >> bislang habe ich noch keine möglichkeit gefunden, um herauszufinden, >> von welchem device die daten, die von einem raw-socket kommen nun >> wirklich stammen. > > Im sockaddr_ll gibt es nicht nur den Pakettyp (sll_pkttype) sondern auch > noch eine Interfacenummer (sll_ifindex). Check das mal. ja, aber das setzt wieder voraus, dass man sich in einem bestimmten protokoll bewegt. aber: When protocol is set to htons(ETH_P_ALL), then all protocols are received. All incoming packets of that protocol type will be passed to the packet socket before they are passed to the protocols implemented in the kernel. und: If a socket is bound to an interface, only packets received from that particular interface are processed by the socket. Note that this only works for some socket types, particularly AF_INET sockets. It is not supported for packet sockets (use normal bind(2) there). und an dem problem haben sich auch bei stapelüberlauf schon vor 4 jahren leute festgebissen: According to this other SO answer, and my experience on CentOS 7, this does not work for a raw socket. Instead, you need to use bind(), not the setsockopt() approach shown here wie auch immer: ich teste weiter. ich finds grad spannend ;-)
der testcode: #include <stdbool.h> #include <signal.h> #include <arpa/inet.h> #include <linux/if_packet.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/io.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <netinet/ether.h> #include <linux/if.h> #include <linux/if_packet.h> #include <linux/if_ether.h> #include <arpa/inet.h> #define BUF_SIZ 2048 int rawrsockfd; int sockopt; static char dev_name[20]; static unsigned char recbuf[BUF_SIZ]; ssize_t numbytes; int tx_len = 0; int rawrsockfd; int sockopt; struct ifreq ifopts; /* set promiscuous mode */ struct ethhdr *rec_header = (struct ethhdr *)(recbuf); struct sockaddr_ll socket_address; typedef struct { unsigned char dh[6]; unsigned char sh[6]; unsigned char tp[2]; unsigned char spare2[1500]; // spare.... } rasport_t; static rasport_t portval; static rasport_t* port_data_array = &portval; static rasport_t *recbufs = (rasport_t *)(recbuf); int init_raw_rec_socket(char devn[]){ printf("init_rec_socket. DEV:[%s]\n",devn); rawrsockfd = socket(AF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) ); // rawrsockfd=socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) ); // aha..... Thus, today, there really should be no difference between AF_foo and PF_foo. if (rawrsockfd<0) { perror("setsockopt"); close(rawrsockfd); return(EXIT_FAILURE); } strncpy(ifopts.ifr_name, devn, IFNAMSIZ-1); ioctl(rawrsockfd, SIOCGIFFLAGS, &ifopts); ifopts.ifr_flags |= IFF_PROMISC; ioctl(rawrsockfd, SIOCSIFFLAGS, &ifopts); /* Bind to device */ if (setsockopt(rawrsockfd, SOL_SOCKET, SO_BINDTODEVICE, dev_name, IFNAMSIZ-1) == -1) { perror("SO_BINDTODEVICE"); close(rawrsockfd); return(EXIT_FAILURE); } int flags = fcntl(rawrsockfd, F_GETFL); flags |= O_NONBLOCK; fcntl(rawrsockfd, F_SETFL, flags); return 0; } int rec_raw(){ // raw-eth-receive // we hatve to check: is this really a packet for us? bool isForMe=false; // is it a packet for me? // numbytes = recvfrom(rawrsockfd, recbufs, BUF_SIZ, 0, NULL, NULL); struct sockaddr_ll src_addr; socklen_t addr_len = sizeof src_addr; numbytes = recvfrom(rawrsockfd, recbufs, 2048, 0, (struct sockaddr*)&src_addr, &addr_len); if (numbytes==-1){ // perror("rec_raw"); printf("E\b"); return 0; } printf("listener: got packet %lu bytes from iface-index: %i\n", numbytes,src_addr.sll_ifindex); return 1; } void main() { int c=0; printf("start\n"); if (init_raw_rec_socket("lo")<0)exit(-1); printf("init done\n"); while (c<10000000) { int got=rec_raw(); c++; } printf("\nall done\n"); } und so sieht es dann aus: start init_rec_socket. DEV:[lo] init done listener: got packet 203 bytes from iface-index: 17 listener: got packet 42 bytes from iface-index: 2 listener: got packet 42 bytes from iface-index: 2 listener: got packet 42 bytes from iface-index: 2 listener: got packet 42 bytes from iface-index: 2 listener: got packet 126 bytes from iface-index: 1 listener: got packet 126 bytes from iface-index: 1 listener: got packet 42 bytes from iface-index: 2 listener: got packet 182 bytes from iface-index: 2 listener: got packet 170 bytes from iface-index: 2 listener: got packet 353 bytes from iface-index: 17 listener: got packet 42 bytes from iface-index: 2 listener: got packet 170 bytes from iface-index: 2 listener: got packet 126 bytes from iface-index: 1 listener: got packet 42 bytes from iface-index: 2 listener: got packet 126 bytes from iface-index: 1 E all done das erklärt nun einiges - als nöchstes werde ich mal versuchen ob das mittels bind nun doch auf ein einzelnes interface einzugrenzen ist.
Klaus S. schrieb: > Wenn nichts da ist, bekomme ich "0 bytes received" zurück und weiter > gehts. Nein. Wenn nichts da ist, kommt -1 zurück und errno wird auf EAGAIN gesetzt. Wicki W. schrieb: > if ((rawrsockfd = socket( PF_PACKET, SOCK_RAW, htons( > ETH_P_ALL))) == -1) { Das ist nicht nur einfach ein Raw-Socket, sondern sogar ein Packet Socket. Der ist nochmal eine Ebene tiefer. Das heißt, dass das System dir beim Empfang sogar den MAC-Header mitschickt und du beim Senden diesen selbst erzeugen musst. Zum Thema packet sockets lohnt es sich, "man packet" durchzulesen. Zum Thema binden an ein Interface sagt diese Manpage: "To get packets only from a specific interface use bind(2) specifying an address in a struct sockaddr_ll to bind the packet socket to an interface. Fields used for binding are sll_family (should be AF_PACKET), sll_protocol, and sll_ifindex." Zum lesen wäre evtl. recvmsg besser geeignet, denn das beinhaltet zusätzliche Informationen. Wicki W. schrieb: > der testcode: Bitte die Regeln unter "Wichtige Regeln - erst lesen, dann posten!" erst lesen, und dann posten!
:
Bearbeitet durch User
Wicki W. schrieb: > Foobar schrieb: >> Warum keine Beschränkung auf einen Protokolltyp? > > weil jedes protokoll overhead bedeutet. und den will ich vermeiden. Du glaubst also, das im Userspace effizienter implementieren zu können als die optimierten Protokollstacks in gängiger Betriebssysteme? Das erscheint mir dann doch... ein bisschen optimistisch.
Rolf M. schrieb: > Klaus S. schrieb: >> Wenn nichts da ist, bekomme ich "0 bytes received" zurück und weiter >> gehts. > > Nein. Wenn nichts da ist, kommt -1 zurück und errno wird auf EAGAIN > gesetzt. das ist korrekt. aber eine auswirkung hat es ja nicht, ob ich auf ==0 oder <=0 prüfe. es heist immer: "da sind keine daten" > Wicki W. schrieb: >> if ((rawrsockfd = socket( PF_PACKET, SOCK_RAW, htons( >> ETH_P_ALL))) == -1) { > > Das ist nicht nur einfach ein Raw-Socket, sondern sogar ein Packet > Socket. Der ist nochmal eine Ebene tiefer. Das heißt, dass das System > dir beim Empfang sogar den MAC-Header mitschickt und du beim Senden > diesen selbst erzeugen musst. genau das mache ich auch. ich habs aber noch nicht hinbekommen, das revfrom nur an ein interface zu binden. das ist aber zunächst nicht schlimm, weil ich inzischen die quelle mit ll_ifindex ausfindig mache. und da ich mir die mac-adressen eh selbst zusammenbaue bzw. diese prüfe kann ich auch gleich das IF mit prüfen. > Manpage: > "To get packets only from a specific interface use bind(2) specifying an > address in a struct sockaddr_ll to bind the packet socket to an > interface. Fields used for binding are sll_family (should be > AF_PACKET), sll_protocol, and sll_ifindex." ich hatte weiter oben schon mal was widersprüchliches gepostet: dass das "bind" bei raw-sockets nicht gehen soll. (war in mehreren foren zu finden) aber gerade eben habe ich es getestet. mit bind(sock_fd, (struct sockaddr*)&socket_address, sizeof(socket_address)) kommt tatsächlich nur das an, was auf dem interface passiert. grundsätzlich läuft es aber nun erst mal wieder so, wie es vor 4 jahren schonmal lief bzw. laufen sollte. besten dank an alle, die hier mit guten tips und schubsen in die richtige richtung geholfen haben ;-) >> der testcode: > > Bitte die Regeln unter "Wichtige Regeln - erst lesen, dann posten!" erst > lesen, und dann posten! den fand ich mit rund 100 zeilen nicht so dramatisch lang.... aber ok.
> Du glaubst also, das im Userspace effizienter implementieren zu können > als die optimierten Protokollstacks in gängiger Betriebssysteme? Das > erscheint mir dann doch... ein bisschen optimistisch. das weiss ich nicht - ich werde es sehen. ich sehe die probleme ehr auf der seite von geräten, die kleine "optimierten Protokollstacks" haben. beim arduino ist es so, dass er eth-packtes maximal im ms-bereich versenden kann. da scheint die limitierung in der hardware zu liegen. das ergebnis 2019 war: Frustrierenderweise ist aber beim Arduino tatsaechlich bei rund 1ms Zykuszeit Schluss. dann hatte ich noch mit einem raspberry und einem STM32 NUCLEO-H743ZI experimentiert - aber dann alles beiseite gelegt. schaun wir mal....
Rolf M. schrieb: > Klaus S. schrieb: >> Wenn nichts da ist, bekomme ich "0 bytes received" zurück und weiter >> gehts. > > Nein. Wenn nichts da ist, kommt -1 zurück und errno wird auf EAGAIN > gesetzt. So kann man sich die Wirklichkeit zurechtbiegen und mit Detailkenntnissen glänzen. Ich habe absichtlich "ich bekomme... " geschrieben, da ich die krude Logik der Berkeleysockets nur mit einem drüberliegenden Layer ertrage, den ich schon seit MS-DOS mit Wollongong TCP-Paket darüberlege, wenn ich denn überhaupt C nutze. Im Moment nutze ich Tcl/Tk, und da kommt auch keine -1 zurück :-)) Insofern ist mein Satz ohne weitere Einschränkungen richtig. Die Korrektur meines Satzes ist nur dann richtig, wenn man implizit die Logik der Berkeley-Sockets voraussetzt. Soviel Genauigkeit sollte meines Erachtens schon sein, wenn man komplizierte Probleme lösen möchte, sonst wirds eventuell nichts. Peace, Shalom umd Salam aleikum Klaus (der soundsovielte) P.S. Die Logik, eine Kommunikation mit zwei ungleichen Partnern durch ein fettes Host- und ein mageres Client-Protokoll zu erledigen hat USB doch ebenfalls vorgemacht. Auf Ethernet war meines Wissens das IPX-Protokoll auch asymmetrisch aufgebaut, aber eben ziemlich "closed source". Mich würde ein solches Protokoll ebenfalls reizen, der Aufwand hat mich aber bisher abgeschreckt. Isofern bin ich gespannt auf Fortschritte.
Wicki W. schrieb: > aber eine auswirkung hat es ja nicht, ob ich auf ==0 oder <=0 prüfe. > es heist immer: "da sind keine daten" Wenn eine 0 zurück kommt, hat das eine andere Bedeutung. Es sagt, dass ein Datagramm mit einer Länge von 0 angekommen ist. Ob das bei Packet-Sockets passieren kann, weiß ich nicht so genau, aber es ist generell was anderes als "kein Datagramm". >> Bitte die Regeln unter "Wichtige Regeln - erst lesen, dann posten!" erst >> lesen, und dann posten! > > den fand ich mit rund 100 zeilen nicht so dramatisch lang.... > aber ok. Du hast noch nicht alles gelesen. 😉 Quellcode sollte man in Code-Tags stecken. Klaus S. schrieb: > Insofern ist mein Satz ohne weitere Einschränkungen richtig. Die > Korrektur meines Satzes ist nur dann richtig, wenn man implizit die > Logik der Berkeley-Sockets voraussetzt. Du hast aber schon gesehen, dass es hier genau um diese geht? Natürlich kann das auch komplett anders aussehen, wenn du irgendeine ganz andere API nutzt, aber das bringt uns hier nicht wirklich weiter. > die krude Logik der Berkeleysockets Man sollte halt bedenken, dass sie 1. eine low-level-API direkt auf syscall-Ebene und 2. bereits 40 Jahre alt sind. Sie stammen noch aus einer Zeit, in der es in C den Datentyp void noch nicht gab. Deshalb braucht man bei den Adressen auch diese nervigen Casts. Ansonsten haben sie finde ich ihre Vor- und Nachteile.
:
Bearbeitet durch User
Rolf M. schrieb: > aber das bringt uns hier nicht wirklich weiter Sehr einverstanden, wie mit fast allem, was Du sagst. Mir war nur die eine Klarstellung für spätere Leser wichtig, so wie Wilhelm M. ja auch seine Gründe für die Erwähnung des non-blocking-modes erläuterte. Gruß Klaus (der soundsovielte)
> beim arduino ist es so, dass er eth-packtes > maximal im ms-bereich versenden kann. Redest du etwa von einem Arduino mit einem WizNet W5100 Ethernet-Krüppel?
Foobar schrieb: >> beim arduino ist es so, dass er eth-packtes >> maximal im ms-bereich versenden kann. > > Redest du etwa von einem Arduino mit einem WizNet W5100 > Ethernet-Krüppel? ja - für sachen, die sich im ms-bereich abspielen scheint er ganz brauchbar zu sein. ansonsten halte ich den arduino mit seinen 1000en von sich dauend ändernden und dann auch noch gleichnamigen libs für recht ätzend. aver irgendwie alternativlos. als die teile noch für spotpreise aus chinesien zu bekommen waren, da waren sie schon OK. inzwischen ist alles unlustig: 200 eur für raspberry werden teilweise aufgerufen: Raspberry Pi 4 Model B 8 GB RAM 64-Bit 1,5 GHz Quad-Core-Board - 8 GB RAM Motherboard (8 GB) 229,99€ Statt: 239,99€ Lieferung Mittwoch, 3. Mai – Donnerstag, 4. Mai KOSTENLOSE Lieferung hallo??? vielleicht sollte ich meine sammlung verkaufen.... ? man könnte fast in die versuchung geraten, wieder TTLs zu löten ;-)
>> Redest du etwa von einem Arduino mit einem WizNet W5100 >> Ethernet-Krüppel? > > ja Das macht den ganzen Thread zu ner Farce. Ciao.
Foobar schrieb: > Das macht den ganzen Thread zu ner Farce. aber das war jetzt soo wichtig, dass du das noch eben schnell um mittern8 posten musstest? hier ging es um die linux-seite von 2 kommunikationspartnern. was auf der anderen seite hängt spielt für die anwendung keine rolle. das kann ein PC, eine rapsi, ein arduino oder irgendeine andere hardware sein. meine fragen sind beantwortet und das problem gelöst. schönen tag noch....
Wicki W. schrieb: > so viele broadcasts können da nicht sein, weil das system nichts zu > broadcasten hat. jedenfalls nicht so viel. Das "System" ist hier aber typisch die Gesamtheit aller an den Switch angeschlossenen Geräte (bzw. natürlich bei managebaren Switches nur der Teil davon, der in derselben Broadcast-Domäne liegt). Und die Normalität bei praktisch genutzten Geräten ist: sie sondern recht häufig Broadcasts ab, weil sehr viele Protokolle halt direkt oder indirekt Broadcasts benötigen, um funktionieren zu können. Eine Aufzählung erspare ich mir hier... > und wenn es broadcasts wären: warum sieht tcpdump sie nicht? Das könnte z.B. daran liegen, dass du zu blöd oder zu faul bist, die Doku zu tcpdump zu lesen und es passend zu konfigurieren, um diese zu sehen...
C-hater schrieb: > Wicki W. schrieb: > >> so viele broadcasts können da nicht sein, weil das system nichts zu >> broadcasten hat. jedenfalls nicht so viel. > > Das "System" ist hier aber typisch die Gesamtheit aller an den Switch > angeschlossenen Geräte (bzw. natürlich bei managebaren Switches nur der > Teil davon, der in derselben Broadcast-Domäne liegt). wenn das aber ein system ist, an dem nichts dran hängt, dann sollte sich auch die broadcasts in_sehr_ überschaubaren grenzen halten. >> und wenn es broadcasts wären: warum sieht tcpdump sie nicht? > > Das könnte z.B. daran liegen, dass du zu blöd oder zu faul bist, die > Doku zu tcpdump zu lesen und es passend zu konfigurieren, um diese zu > sehen... das könnte auch dran liegen, dass tcpdump in unterschiedlichen implementationen bei gleichen parametern eine unterschiedliches verhalten zeigt. genau das ist nämlich der fall. s.o. es ist wenig konstruktiv, anderen erstemal faul- oder blödheit oder eine geistige behinderung zu unterstellen.... die ursache war: SO_BINDTODEVICE funktioniert bei raw sockets nicht. (ohne dass es einen error gibt) und ein tcpdump ohne "-i any" liefert im gegensatz dem recvfrom nicht den traffic aller interfaces.
Wicki W. schrieb: > wenn das aber ein system ist, an dem nichts dran hängt, dann > sollte sich auch die broadcasts in_sehr_ überschaubaren grenzen halten. Dass auf dem loopback-Device Sachen kommmen, sollte klar sein. Dann gibt's ggf. noch andere virtuelle Netzwerkgeräte wie z.B. für Docker oder VirtualBox u.s.w., wo auch Traffic entstehen kann, ohne dass physisch irgendwas angeschlossen sein muss. Lass dir doch mal die Namen der Devices ausgeben, auf denen du den Traffic empfängst. > es ist wenig konstruktiv, anderen erstemal faul- oder blödheit > oder eine geistige behinderung zu unterstellen.... C-Hater schafft es leider nicht sehr oft, Antworten zu verfassen, ohne dabei sein Gegenüber zu beleidigen.
Wicki W. schrieb: > wenn das aber ein system ist, an dem nichts dran hängt, dann > sollte sich auch die broadcasts in_sehr_ überschaubaren grenzen halten. Bleibt immer noch noch mehr als genug über. Je nachdem, was halt auf den beteiligten Maschinen an Software läuft. Darüber hast du aber nichts verlauten lassen. > das könnte auch dran liegen, dass tcpdump in unterschiedlichen > implementationen bei gleichen parametern eine unterschiedliches > verhalten zeigt. Man liest typisch die Doku, die zu der konkret verwendeten Implementierung passt. Alles andere ist mehr oder weniger offensichtlich sinnlos.
Rolf M. schrieb: > C-Hater schafft es leider nicht sehr oft, Antworten zu verfassen, ohne > dabei sein Gegenüber zu beleidigen. Das sieht nur für diejenigen so aus, die die ungeschminkte Nennung offensichtlicher Fakten für eine Beleidigung halten. Etwas entspanntere Leute bemängeln höchstens das Fehlen von "Höflichkeit". Ja, meine Lebenszeit mit der Erfindung falscher (und letztlich wohl im sinne der Sache irreführender!) Höflichkeiten zu verschwenden, das ist tatsächlich nicht mein Ding.
können wir vielleicht wieder zum thema zurückkehren? den "bind" löst das problem doch nicht: listener: got packet 98 bytes from iface-index: 1 listener: got packet 125 bytes from iface-index: 3 das passiert, wenn ich es mit der unten stehenden und auf 58 zeilen abgespeckten version versuche. egal, mit welchem interface ich das probiere. und das gilt - wie es scheint - für "bind" und "bindtodevice" gleichermassen. dass es mit raw-packets und bindtodevice nicht geht (auch wenn ich IFF_PROMISC rausnehme) und immer alle interfaces geliefert werden, das kann ja wohl als gesichert gelten. (obwohl openai und manche suchmaschinen was andere behaupten) aber auch "bind" liefert den traffic aller interfaces. dabei war ich mir sicher, dass es mit "bind" schon mal funktioniert hatte beim testen.
1 | #include <stdbool.h> |
2 | #include <stdio.h> |
3 | #include <stdlib.h> |
4 | #include <unistd.h> |
5 | #include <fcntl.h> |
6 | #include <stdio.h> |
7 | #include <string.h> |
8 | #include <sys/ioctl.h> |
9 | #include <sys/socket.h> |
10 | #include <linux/if.h> |
11 | #include <linux/if_packet.h> |
12 | #include <linux/if_ether.h> |
13 | #include <arpa/inet.h> |
14 | |
15 | int rawrsockfd; |
16 | int sockopt; |
17 | char dev_name[20]; |
18 | unsigned char recbuf[2048]; |
19 | struct ifreq ifopts; /* set promiscuous mode */ |
20 | struct sockaddr_ll socket_address; |
21 | ssize_t numbytes; |
22 | |
23 | int init_raw_rec_socket(char devn[]){ |
24 | printf("init_rec_socket. DEV:[%s]\n",devn); |
25 | rawrsockfd = socket(AF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) ); |
26 | if (rawrsockfd<0) { perror("setsockopt"); close(rawrsockfd); return(EXIT_FAILURE); } |
27 | strncpy(ifopts.ifr_name, devn, IFNAMSIZ-1); |
28 | ioctl(rawrsockfd, SIOCGIFFLAGS, &ifopts); |
29 | ifopts.ifr_flags |= IFF_PROMISC; |
30 | ioctl(rawrsockfd, SIOCSIFFLAGS, &ifopts); |
31 | /* Bind to device */
|
32 | bind(rawrsockfd, (struct sockaddr*)&socket_address, sizeof(socket_address)); |
33 | int flags = fcntl(rawrsockfd, F_GETFL); |
34 | flags |= O_NONBLOCK; |
35 | fcntl(rawrsockfd, F_SETFL, flags); |
36 | return 0; |
37 | }
|
38 | |
39 | |
40 | int rec_raw(){ // raw-eth-receive |
41 | socklen_t addr_len = sizeof socket_address; |
42 | numbytes = recvfrom(rawrsockfd, recbuf, 2048, 0, (struct |
43 | sockaddr*)&socket_address, &addr_len); |
44 | if (numbytes<=-1){ printf("wait\b\b\b\b\b"); return 0; } |
45 | printf("listener: got packet %lu bytes from iface-index: %i\n", |
46 | numbytes,socket_address.sll_ifindex); |
47 | return 1; |
48 | }
|
49 | |
50 | void main() { |
51 | int c=0; |
52 | printf("start\n"); |
53 | if (init_raw_rec_socket("lo")<0)exit(-1); |
54 | printf("init done\n"); |
55 | while (c<100000000) { int got=rec_raw(); c++; } |
56 | printf("\nall done\n"); |
57 | }
|
[Mod: C-Tags zur Formatierung eingefügt]
:
Bearbeitet durch Moderator
@Wicki: Bitte bei C-Code auch die C-Tags verwenden, sonst sieht Dein Quellcode auf Mobilgeräten nur wie Matsche aus, siehe Anhang. Ich habe das für Deinen Beitrag oben mal gemacht. Dazu einfach
1 | [ c ] |
2 | C-Code.... |
3 | [ /c ] |
(ohne die Leerzeichen) schreiben.
> auf Mobilgeräten nur wie Matsche aus, siehe Anhang. > Ich habe das für Deinen Beitrag oben mal gemacht. Dazu einfach > [ c ]C-Code....[ /c ] > (ohne die Leerzeichen) schreiben. hätt ichs gewusst, hätt ichs gemacht - aber nach der antwort durfte ich nicht mehr editieren.
guten morgen zusammen, nachdem ich nun das problem auf 58 zeilen heruntergebrochen habe kommt plötzlich von an den vielen erfahrenen entwicklern hier keine antwort mehr.... daher habe ich meine theorie und den obigen code dazu mit openai diskutiert. und die ist zum einen genauso widersprüchlich, wie die vielen infos, die man dazu im netz findet. zum anderen kommt sie aber ebenfalls zu dem gleichen ergebnis: "Das heißt, dieser Code empfängt tatsächlich Pakete von allen Netzwerkinterfaces auf dem System." denn für mich stellt es sich so dar, dass der gesamte eth-verkehr im system ein einzigerdatenstrom (respektive ein einziger speicherbereich) ist, in dem neben den header- und payload-informationen ebenfalls das interfache (bzw. dessen index aller interfaces) enthalten ist. deshalb kann ein "bind" nicht nach interfacen filtern, wenn man auf der untersten protokollebene ist. wenn ich mit dieser - ja, sehr vereinfachten - darstellung falsch liege, dann freue ich mich über rückmeldungen.
Schau halt einfach mal, an was für eine Adresse du dich binden willst(Argumente vom bind-call). Da sind noch mehr bugs ...
Foobar schrieb: > Schau halt einfach mal, an was für eine Adresse du dich binden > willst(Argumente vom bind-call). danke! mit socket_address.sll_ifindex = if_nametoindex("lo"); funktioniert auch "bind" wieder. wenn ich socket_address.sll_ifindex = 0; setze, dann kommen wieder alle interfaces durch. klingt auch irgendwie logisch oder zumindest nachvollziehbar. das war jetzt aber nur ein kurztest. ich bin ganz sicher kein-entwickler und inzwischen reichlich betriebsblind. war mir aber fast sicher, dass es mal funktioniert hatte. > Da sind noch mehr bugs ... bestimmt. welche siehst du noch?
Wicki W. schrieb: > hätt ichs gewusst, hätt ichs gemacht Deshalb hatte ich das oben bereits erwähnt. Wicki W. schrieb: > wenn ich > socket_address.sll_ifindex = 0; > setze, dann kommen wieder alle interfaces durch. > > klingt auch irgendwie logisch oder zumindest > nachvollziehbar. Steht ja auch genau so in der auch schon erwähnten man-Page drin: "sll_ifindex is the interface index of the interface (see netdevice(7)); 0 matches any interface (only permitted for binding)." Wie gesagt: Es lohnt sich, die auch zu lesen…
Rolf M. schrieb: > "sll_ifindex is the interface index of the interface (see netdevice(7)); > 0 matches any interface (only permitted for binding)." > > Wie gesagt: Es lohnt sich, die auch zu lesen… ja, du hast recht. und ich muss gestehen, dass ich dem inhalt der dieser alten nachricht nicht wirklich bedeutung beigemessen habe, weil er mir auch noch erklärte, dass in einem raw-packet auch die mac-adressen und das protokoll drin stehen. (genau deswegen wollte ich das ja benutzen) meine gestrige mails konnte ich nicht mehr korrigieren. da sollte stehen: ich bin kein c-entwickler. und auch deswegen sehe ich oft den wald vor lautern bäumen nicht. jemand der das seit jahren täglich macht, der wirft einen blick drauf und sieht sofort wo das problem liegt. leider sagen aber auch oft leute, die das selbst nur mal angelesen haben, etwas zu einem thema - gern dann auch mal im "du-hast-ja-gar-keine-ahnung-tonfall". und dann gehen die wirklich wichtigen und hilfreichen nachrichten unter. und bei diesem bind-prpblem haben sich schon seit jahren die leute in den foren die köpfe heissgeredet und man weiss nie, welche infos nur wirklich stimmen und welche inzwischen schon überholt oder nur bei einer bestimmten hardware oder os-version richtig sind. ich habe mehr als 4 jahre lang keine einzige zeile c programmiert und auch davor nur dann, wenn es gar nicht zu vermeiden war. jedenfalls werde ich mir das bind/bind2device noch mal näher ansehen, das ergebnis zusammenfassen und posten. ich finde es grade sehr spannend ;-)
so, hier nun mal die zusammenfassung.... je nachdem, ob man "bind" oder "bindtodevice" aktiviert, klappt es mal (bind) oder eben nicht (bind2dev) mit der beschränkung auf ein bestimmtes interface. vergisst man aber beim bind socket_address.sll_ifindex zu setzen oder hat verstehentlich eine 0 drin stehen, dann wird auch wieder jedes interace geliefert. nun bin ich nur mal gespannt, ob das hier mit c-tags im posting funktioniert.....
1 | #include <stdbool.h> |
2 | #include <stdio.h> |
3 | #include <stdlib.h> |
4 | #include <unistd.h> |
5 | #include <fcntl.h> |
6 | #include <stdio.h> |
7 | #include <string.h> |
8 | #include <sys/ioctl.h> |
9 | #include <sys/socket.h> |
10 | #include <linux/if_packet.h> |
11 | #include <linux/if_ether.h> |
12 | #include <arpa/inet.h> |
13 | #include <net/if.h> // if_nametoindex |
14 | |
15 | /*
|
16 | gcc socket_read.c -o socket_read
|
17 | |
18 | blockierendes/nicht-blockierendes lesen von einem
|
19 | nw-interface oder von _allen_.
|
20 | |
21 | die beschränkung auf ein einzelnes device funktioniert _nur_
|
22 | mit "bind" und nicht mit setsockopt/SO_BINDTODEVICE.
|
23 | |
24 | nur root kann ETH_P_ALL und SOCK_RAW verwenden!
|
25 | |
26 | */
|
27 | |
28 | int rawrsockfd; |
29 | int sockopt; |
30 | unsigned char recbuf[2048]; |
31 | struct ifreq ifopts; |
32 | struct sockaddr_ll socket_address; |
33 | ssize_t numbytes; |
34 | |
35 | |
36 | int init_raw_rec_socket(char devn[]){ |
37 | printf("init_rec_socket. DEV:[%s]\n",devn); |
38 | rawrsockfd = socket(AF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) ); |
39 | if (rawrsockfd<0) { perror("setsockopt - (root?)"); close(rawrsockfd); return(EXIT_FAILURE); } |
40 | strncpy(ifopts.ifr_name, devn, IFNAMSIZ-1); |
41 | ioctl(rawrsockfd, SIOCGIFFLAGS, &ifopts); |
42 | ifopts.ifr_flags |= IFF_PROMISC; |
43 | ioctl(rawrsockfd, SIOCSIFFLAGS, &ifopts); |
44 | |
45 | |
46 | /* Bind to device */
|
47 | socket_address.sll_family = AF_PACKET; |
48 | //socket_address.sll_protocol = htons(ETH_P_ALL); // z.B. IPv4
|
49 | socket_address.sll_ifindex = if_nametoindex(devn); // Index der Netzwerkschnittstelle |
50 | printf("sll_ifindex of %s is :%i\n",devn,socket_address.sll_ifindex); |
51 | //socket_address.sll_ifindex = 0; // 0 = lies _alle_ schnittstellen
|
52 | |
53 | |
54 | /*
|
55 | //funktioniert _nicht_ bei raw-sockets !
|
56 | if (setsockopt(rawrsockfd, SOL_SOCKET, SO_BINDTODEVICE, devn, IFNAMSIZ-1) == -1) {
|
57 | perror("SO_BINDTODEVICE");
|
58 | close(rawrsockfd);
|
59 | return -4;
|
60 | }
|
61 | */
|
62 | |
63 | // da klappt es nur mit "bind"
|
64 | bind(rawrsockfd, (struct sockaddr*)&socket_address, sizeof(socket_address)); |
65 | |
66 | |
67 | int flags = fcntl(rawrsockfd, F_GETFL); |
68 | |
69 | // flags |= O_ASYNC; // blockierend lesen oder
|
70 | flags |= O_NONBLOCK; // nicht blockierend lesen |
71 | |
72 | fcntl(rawrsockfd, F_SETFL, flags); |
73 | return 0; |
74 | }
|
75 | |
76 | |
77 | int rec_raw(){ // raw-eth-receive |
78 | char ifname[IFNAMSIZ]; |
79 | socklen_t addr_len = sizeof socket_address; |
80 | numbytes = recvfrom(rawrsockfd, recbuf, 2048, 0, (struct |
81 | sockaddr*)&socket_address, &addr_len); |
82 | if (numbytes<=-1){ printf("wait\b\b\b\b\b"); return 0; } |
83 | printf("listener: got packet %lu bytes from iface-index: %i ", |
84 | numbytes,socket_address.sll_ifindex); |
85 | |
86 | if (if_indextoname(socket_address.sll_ifindex, ifname) == NULL) { |
87 | perror("if_indextoname"); |
88 | return 1; |
89 | }
|
90 | |
91 | printf("interface name: %s\n", ifname); |
92 | |
93 | |
94 | |
95 | return 1; |
96 | }
|
97 | |
98 | void main() { |
99 | int c=0; |
100 | printf("start\n"); |
101 | if (init_raw_rec_socket("lo")<0)exit(-1); |
102 | printf("init done\n"); |
103 | while (c<100000000) { int got=rec_raw(); c++; } |
104 | printf("\nall done\n"); |
105 | }
|
Hi, in meinem eigenen Projekt hatte ich, statt Raw-Sockets selber zu programmieren, einfach die libpcap eingebunden und verwendet. Damit bekommt man auch schöne Filtermöglichkeiten. Und es hat auch unter Linux und Windows gleichermaßen funktioniert. Bei Interesse kann ich ein Beispiel liefern. Gruß Olaf
hi olaf, Olaf D. schrieb: > .....einfach die libpcap eingebunden und > verwendet. Damit bekommt man auch schöne Filtermöglichkeiten. > Und es hat auch unter Linux und Windows gleichermaßen funktioniert. > > Bei Interesse kann ich ein Beispiel liefern. ich hab mich jetzt auf den weg zu fuss eingeschossen - aber es ist sicher nicht schlecht, wenn man das hier in dem zusammenhang mal direkt vergleichen kann. also gern ein beispiel... ;-) viele gruesse wicki
Hi, sorry für die späte Antwort. Dies Beispiel ist Qt basiert. Bei Unklarheiten, einfach nochmal fragen. Helfe gerne. Gruß Olaf
Foobar schrieb: > Ein raw-socket mit ETH_P_ALL bekommt alles, u.U. auch den eigenen > ausgehenden Traffic. Also soweit ich weiss kann das kein Socket einfach so. Dazu ist das loopback Interface da, welches durch ein separates Socket & Binding Daten zurücklesen könnte... (sind meine Erfahrungen unter Ubuntu, da habe ich einmal Wochen mit Fehlersuchen verbracht) Wicki W. schrieb: > Foobar schrieb: >> Was willst du überhaupt machen? > > ich will die daten haben, bevor irgendwer oder -was sich damit befasst. Dann wäre XDP allenfalls ein Thema für dich. Aber da funktioniert dann tcpdump nicht mehr, da die Daten komplett beim TCP/IP Stack vorbei geschleust werden!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.