Wie kann ich diesen Socket an eine bestimmte Netzwerkschnittstelle (z. B. eth1) binden?
Warum würden Sie das tun wollen? Ihr Programm verliert die Portabilität, es sei denn, Sie sind sicher, dass Ihre Maschinen Schnittstellen mit den vordefinierten Namen haben werden.
– Andreas Schlitten
22. Oktober 2010 um 16:52 Uhr
Es ist für eingebettete Geräte, die Portabilität ist nicht erforderlich. Ich habe 6 Ethernet-Ports und muss Daten über eine bestimmte Schnittstelle senden
– Dima
22. Oktober 2010 um 17:47 Uhr
Andreas Schlitten
const char *opt;
opt = "eth0";
const len = strnlen(opt, IFNAMSIZ);
if (len == IFNAMSIZ) {
fprintf(stderr, "Too long iface name");
return 1;
}
setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, len);
Erste Zeile: Richten Sie Ihre Variable ein
Zweite Zeile: Teilen Sie dem Programm mit, an welche Schnittstelle es sich binden soll
Zeilen 3-5: Ermitteln Sie die Länge des Schnittstellennamens und prüfen Sie, ob die Größe nicht zu groß ist.
Sechszeilig: Stellen Sie die Socket-Optionen für Socket ein sdBindung an das Gerät opt.
Setsockopt-Prototyp:
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
Stellen Sie außerdem sicher, dass Sie die enthalten if.h, socket.h und string.h Header-Dateien
Danke, es funktioniert, aber mit einer kleinen Änderung: ifreq Interface; memset(&Interface, 0, sizeof(Interface)); strncpy(Interface.ifr_ifrn.ifrn_name, “eth1”, IFNAMSIZ); if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &Interface, sizeof(Interface)) < 0) { close(sd); // Fehler }
– Dima
22. Oktober 2010 um 20:14 Uhr
SO_BINDTODEVICE funktioniert nur, wenn Sie es als root ausführen, richtig? (zumindest unter Linux)
– 332. September
27. November 2012 um 21:29 Uhr
Das erste Element von “struct ifreq” ist das Zeichen[] Name der Schnittstelle. Außerdem geben Sie noch IFNAMSIZ an. Dies sollte also identisch sein (so wie das Anhängen eines zufälligen Puffers an “eth0” funktionieren sollte)
– gsk
23. Mai 2016 um 20:56 Uhr
Laut dieser anderen SO-Antwort und meiner Erfahrung mit CentOS 7 funktioniert dies nicht für einen Raw-Socket. Stattdessen müssen Sie verwenden bind()nicht der setsockopt() hier gezeigte Vorgehensweise.
– Jason R
8. Februar 2019 um 16:20 Uhr
@JasonR: Ihr Kommentar hat mir und meinem Kollegen nur kurze Stunden der Frustration gekürzt. (Wir wechseln endlich von CentOS 6 auf 7 und haben uns die Köpfe darüber zerbrochen, warum irgendein Legacy-Code nicht funktioniert.) Vielen Dank!
– Nemo
1. März 2019 um 18:09 Uhr
Wie bereits erwähnt, ist es richtig, die zu verwenden struct ifreq um den Schnittstellennamen anzugeben. Hier ist mein Codebeispiel.
#define SERVERPORT 5555
...
struct ifreq ifr;
/* Create the socket */
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0)
{
printf("Error in socket() creation - %s", strerror(errno));
}
/* Bind to eth1 interface only - this is a private VLAN */
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth1");
if ((rc = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) < 0)
{
perror("Server-setsockopt() error for SO_BINDTODEVICE");
printf("%s\n", strerror(errno));
close(sd);
exit(-1);
}
/* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVERPORT);
serveraddr.sin_addr.s_addr = inet_addr("9.1.2.3");
int rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
Ich möchte auch hinzufügen, dass es aus Sicherheitsgründen zwar gut ist, den Socket an eine Schnittstelle zu binden, die Verwendung jedoch keinen Sinn macht INADDR_ANY als lauschende IP-Adresse. Dadurch würde der Port in netstat auf allen Netzwerkschnittstellen als offen erscheinen.
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN 0 210898 26996/myserver
Stattdessen habe ich eine spezifische IP-Adresse für die verwendete Schnittstelle angegeben (ein privates VLAN). Dies hat auch die netstat-Ausgabe behoben:
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 9.1.2.3:5555 0.0.0.0:* LISTEN 0 210898 26996/myserver
Wo ist angegeben, dass Sie verwenden struct ifreq ? Meine Manpage sagt: “Die übergebene Option ist eine nullterminierte Schnittstellennamenzeichenfolge mit variabler Länge.”
– Bryan
18. Februar 2016 um 14:15 Uhr
Das von Ihnen vorgeschlagene Problem (INADDR_ANY für SOCK_STREAM-Sockets) tritt beim ursprünglichen Poster, das SOCK_RAW verwendet hat, nicht auf.
– Jon Watte
1. Mai 2016 um 17:49 Uhr
@Bryan Beide Methoden sollten zumindest unter Linux funktionieren. Laut netdevice(7) ist die ifr_name string ist das erste Mitglied von struct ifreqund daher ein Zeiger auf struct ifreq oder char gleich funktionieren.
– Will Eccles
18. Dezember 2020 um 16:22 Uhr
Binden Sie Socket an eine bestimmte Schnittstellen-IP-Adresse
Im bind_using_iface_ipum an einen beliebigen Port zu binden 0 sollte bestanden werden. Und auch wenn die fd Ist ein Raw-Socket, muss der Port als übergeben werden 0. Dieser Bindungsmechanismus ist für alle Arten von Sockets wie Raw, Dgram und Stream üblich.
Dies ist die richtige Antwort. Wir sollten an die IP-Adresse gebunden sein. Nicht zu einer Schnittstelle?
– abhiarora
25. Februar 2020 um 8:19 Uhr
aber unterschiedliche Schnittstellen können dieselbe IP haben
– Mehmet Fide
24. Juni 2021 um 18:31 Uhr
13874900cookie-checkSo binden Sie einen Raw-Socket an eine bestimmte Schnittstelleyes
Warum würden Sie das tun wollen? Ihr Programm verliert die Portabilität, es sei denn, Sie sind sicher, dass Ihre Maschinen Schnittstellen mit den vordefinierten Namen haben werden.
– Andreas Schlitten
22. Oktober 2010 um 16:52 Uhr
Es ist für eingebettete Geräte, die Portabilität ist nicht erforderlich. Ich habe 6 Ethernet-Ports und muss Daten über eine bestimmte Schnittstelle senden
– Dima
22. Oktober 2010 um 17:47 Uhr