Usando Linux, come specificare su quali dati dell'interfaccia ethernet vengono trasmessi

StackOverflow https://stackoverflow.com/questions/172905

  •  05-07-2019
  •  | 
  •  

Domanda

Sto lavorando su un sistema server basato su Linux in cui ci sono due interfacce di rete, entrambe sulla stessa sottorete (per ora, diciamo solo che sono 172.17.32.10 & amp; 172.17.32.11 ). Quando invio dati a un host sulla rete, vorrei specificare su quale interfaccia sul mio server vengono trasmessi i dati. Devo essere in grado di passare da un'interfaccia all'altra (o forse anche trasmettere su entrambi) nel software (le regole di routing statico non funzioneranno per questa applicazione).

Ho trovato una domanda correlata in StackOverflow che mi ha suggerito di utilizzare la libreria netlink per modificare i percorsi al volo. Questo sembra intuitivamente che dovrebbe funzionare, ma mi chiedevo se ci fossero altre opzioni per ottenere lo stesso risultato.

È stato utile?

Soluzione

Nessuna offesa, ma la risposta sull'uso di bind () è piuttosto sbagliata. bind () controllerà l'indirizzo IP di origine inserito nell'intestazione IP del pacchetto. Non controlla quale interfaccia verrà utilizzata per inviare il pacchetto: la tabella di routing del kernel verrà consultata per determinare quale interfaccia ha il costo più basso per raggiungere una determinata destinazione. (* vedi nota)

Invece, dovresti usare un SO_BINDTODEVICE sockopt. Questo fa due cose:

  • I pacchetti usciranno sempre dall'interfaccia specificata, indipendentemente da ciò che dicono le tabelle di routing del kernel.
  • Solo i pacchetti che arrivano sull'interfaccia specificata verranno consegnati al socket. I pacchetti che arrivano su altre interfacce non lo faranno.

Se hai più interfacce tra cui passare, ti suggerirei di creare un socket per interfaccia. Poiché riceverai anche pacchetti solo all'interfaccia a cui sei associato, dovrai aggiungere tutti questi socket al tuo select () / poll () / qualunque cosa tu usi.

#include <net/if.h>

struct ifreq ifr;

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth1", sizeof(ifr.ifr_name));
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
            (void *)&ifr, sizeof(ifr)) < 0) {
    perror("SO_BINDTODEVICE failed");
}

(* nota) Associa () a un indirizzo IP di interfaccia può portare a comportamenti confusi ma comunque corretti. Ad esempio, se associa () all'indirizzo IP per eth1, ma la tabella di routing invia il pacchetto eth0, quindi un pacchetto apparirà sul cavo eth0 ma portando l'indirizzo IP di origine dell'interfaccia eth1 . Questo è strano ma permesso, anche se i pacchetti rinviati all'indirizzo IP eth1 verrebbero reindirizzati a eth1. Puoi testarlo usando un sistema Linux con due interfacce iP. Ne ho uno e l'ho provato, e bind () non è efficace nel far uscire il pacchetto da un'interfaccia fisica.

Sebbene tecnicamente consentito, a seconda della topologia potrebbe non funzionare. Per smorzare gli attacchi di denial of service distribuiti in cui gli aggressori utilizzano indirizzi di origine IP falsi, molti router ora eseguono controlli di inversione di percorso (RPF). Pacchetti con un indirizzo IP di origine su " errato " il percorso potrebbe essere eliminato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top