GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Linux:UDP Listening Socket an eine bestimmte Schnittstelle binden (oder die Schnittstelle herausfinden, von der ein Datagramm kam)?

Die Lösung, die ich gefunden habe, um zu funktionieren, ist wie folgt. Zunächst müssen wir die ARP- und RP-Einstellungen ändern. Fügen Sie zu /etc/sysctl.conf Folgendes hinzu und starten Sie neu (es gibt auch einen Befehl, um dies dynamisch festzulegen):

net.ipv4.conf.default.arp_filter = 1
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.all.arp_filter = 1
net.ipv4.conf.all.rp_filter = 2

Der arp-Filter war notwendig, damit Antworten von eth0 über ein WAN geleitet werden konnten. Die rp-Filteroption war notwendig, um eingehende Pakete strikt der NIC zuzuordnen, auf der sie eintrafen (im Gegensatz zum schwachen Modell, das sie jeder NIC zuordnet, die dem Subnetz entspricht). Ein Kommentar von EJP führte mich zu diesem entscheidenden Schritt.

Danach begann SO_BINDTODEVICE zu arbeiten. Jeder der beiden Sockets war an seine eigene NIC gebunden, und ich konnte daher anhand des Sockets, von dem eine Nachricht kam, erkennen, von welcher NIC eine Nachricht kam.

s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
rc=setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, nic, IF_NAMESIZE);
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(LISTEN_PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
rc=bind(s, (struct sockaddr *)&si_me, sizeof(si_me))

Als nächstes wollte ich auf eingehende Datagramme mit Datagrammen antworten, deren Quelladresse die der NIC ist, von der die ursprüngliche Anfrage kam. Die Antwort dort ist, einfach die Adresse dieser NIC nachzuschlagen und den ausgehenden Socket an diese Adresse zu binden (unter Verwendung von bind ).

s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
get_nic_addr(nics, (struct sockaddr *)&sa)
sa.sin_port = 0;
rc = bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr));
sendto(s, ...);

int get_nic_addr(const char *nic, struct sockaddr *sa)
{
    struct ifreq ifr;
    int fd, r;
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) return -1;
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, nic, IFNAMSIZ);
    r = ioctl(fd, SIOCGIFADDR, &ifr);
    if (r < 0) { ... }
    close(fd);
    *sa = *(struct sockaddr *)&ifr.ifr_addr;
    return 0;
}

(Vielleicht scheint es verschwenderisch zu sein, jedes Mal die Adresse der NIC nachzuschlagen, aber es ist viel mehr Code, um informiert zu werden, wenn sich eine Adresse ändert, und diese Transaktionen finden nur einmal alle paar Sekunden auf einem System statt, das nicht mit Akku betrieben wird.)


Die vom Absender verwendete Zieladresse erhalten Sie über die IP_RECVDSTADDR Option, wenn Ihre Plattform dies unterstützt, indem Sie recvmsg() verwenden . Es ist ziemlich kompliziert und wird in Unix-Netzwerkprogrammierung beschrieben Band I, 3. Auflage, Nr. 22.2, und im Mann Seite.

In Bezug auf Ihre Bearbeitung stehen Sie dem sogenannten „Weak-End-Systemmodell“ von TCP/IP gegenüber. Grundsätzlich kann das System, sobald ein Paket ankommt, wählen, es über jede geeignete Schnittstelle zuzustellen, die den richtigen Port abhört. Es wird irgendwo in den TCP/IP-RFCs diskutiert.


Sie übergeben einen unzulässigen Wert an setsockopt .

rc=setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, nic, strlen(nic));

Die Manpage sagt von SO_BIND_TO_DEVICE :

Die übergebene Option ist eine nullterminierte variabler Länge Zeichenfolge des Schnittstellennamens mit der maximalen Größe von IFNAMSIZ

strlen enthält nicht die abschließende Null. Sie können Folgendes versuchen:

rc=setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, nic, 1 + strlen(nic));

dnsmasq hat dies richtig funktioniert, und verwendet

setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE)

Linux
  1. So finden Sie das Paket, das eine bestimmte Datei in Linux bereitstellt

  2. Linux:Finden Sie heraus, wer auf dem Server angemeldet ist

  3. So finden Sie die Socket-Puffergröße von Linux

  4. Wie finde ich Details zur Hardware auf dem Linux-Rechner heraus?

  5. Wie finde ich den Virtualisierungstyp eines Linux-VPS heraus?

3 Möglichkeiten, um herauszufinden, welcher Prozess auf einem bestimmten Port lauscht

So finden Sie die öffentliche IP-Adresse über die Befehlszeile unter Linux heraus

So ermitteln Sie den Verbindungsstatus eines Netzwerkkabels in Linux

So finden Sie die Liste der installierten Repositories über die Befehlszeile in Linux

So suchen Sie nach Dateien über die Linux-Befehlszeile

Linux:Finden Sie heraus, auf welcher Portnummer ein Prozess lauscht