2011-12-16 11 views
5

Ho il seguente ambiente: 2 host, ciascuno con 2 interfacce Ethernet collegati alla vicenda (come su schema sottostante):come evitare il routing attraverso la pila locale in Linux

+---------+    +---------+      
|  (1)+---------------+(2)  |  
| host1 |    | host2 | 
|   |    |   | 
|  (3)+---------------+(4)  | 
+---------+    +---------+ 

vorrei scrivere client/strumento socket del server che aprirà i socket client e server su host1. Vorrei che il client inviasse i pacchetti TCP attraverso l'interfaccia (1) e il server per l'ascolto sull'interfaccia (3), che i pacchetti passino attraverso host2.

Normalmente lo stack di Linux instraderà questi pacchetti attraverso lo stack TCP/IP locale senza inviarli a host2.

Ho provato ad utilizzare SO_BINDTODEVICE opzione sia per il server e client e sembra che in effetti è assistente binded per interfacciare (3) e non è in ascolto del traffico localhost. Ho verificato che il client da host1 non possa essere accettato mentre il client da host2 lo fa.

Purtroppo i pacchetti client non vengono inviati (anche tcpdump sull'interfaccia (1) non vedono i pacchetti) tramite l'interfaccia (1) all'interfaccia (2). Ovviamente il routing è corretto (posso eseguire il ping (2) da (1), (4) da (1), (4) da (3) e così via).

La mia domanda è se è possibile implementarlo senza utilizzare lo stack TCP/IP personalizzato?

forse dovrei provare a cambiare l'indirizzo IP di destinazione (dal client) per essere da rete esterna (e quindi sarà inviata utilizzando gateway predefinito dall'interfaccia (1) - Interfaccia (2)) e poi in POSTROUTING cambiare quelli di nuovo per quelli originali? È possibile che una tale soluzione funzioni?

Sto scrivendo la mia domanda in C sotto Debian.

Aggiunta alcuni dettagli e chiarimenti:

  1. naturalmente entrambe le coppie (1) - (2) e (3) - (4) sono diverse sottoreti
  2. quello che si vuole raggiungere è (1) -> (2) -> (4) -> (3)
  3. host2 è blackbox quindi non posso installare lì alcun forwarder di pacchetti (che aprirà la presa di ascolto sull'interfaccia (2) e li inoltrerà a Da (3) a (4)) - questo è esattamente ciò che voglio evitare

T il problema principale sembra essere la consegna locale. Quando apro il socket su host1 e voglio connettermi al socket, che è in ascolto su un altro indirizzo dello stesso kernel host, usa lo stack locale per consegnare i pacchetti. Vedere schema netfilter di seguito:

--->[1]--->[ROUTE]--->[3]--->[4]---> 
      |   ^
      |   | 
      |   [ROUTE] 
      v   | 
      [2]   [5] 
      |   ^
      |   | 
      v   | 

pacchetti stanno attraversando [5] NF_IP_LOCAL_OUT e [2] NF_IP_LOCAL_IN mentre io voglio costringerli a passare attraverso [4].

+0

solo per capire che si desidera che il percorso del messaggio di essere (1) -> (2) -> (4) -> (3)? –

+0

Non hai certamente bisogno di uno stack TCP personalizzato per questo. Non è sicuro che sia il modo migliore, ma potresti eseguire una traduzione di indirizzi di rete su host2 che mapperebbe un indirizzo IP univoco all'indirizzo di interfaccia (3) e assicurarti che i pacchetti a (3) da host2 vengano instradati via (4)). Host1 si collegherebbe quindi a quell'indirizzo IP univoco. – NPE

+0

Se un socket si connette da (1) a (2) su una macchina diversa e un altro socket si collega da (4) a (3) sulla prima macchina, perché lo stack TCP di Linux salta l'invio di pacchetti tramite la rete? In che modo lo stack TCP poteva conoscere, in modo impercettibile, questa insolita topologia e in che modo potrebbe _possibilmente_ conoscere le tue intenzioni? – Damon

risposta

-1

È possibile assegnare diverse sottoreti alle coppie (1) - (2) e (3) - (4) e disporre di host2 in avanti i pacchetti da (2) a (3). Il client su host1 si connetterà all'indirizzo di (2), quindi lo stack di rete locale non saprà che il server di destinazione è effettivamente in esecuzione anche localmente.

+0

In realtà ci sono diverse sottoreti tra (1) - (2) e (3) - (4). Per utilizzare questa soluzione ho bisogno di un certo forwarder su host2, che ascolterà i pacchetti dall'interfaccia (2) e invierà all'interfaccia (3) - tramite l'interfaccia (4). Host2 è blackbox, quindi non posso installare alcun software aggiuntivo lì. In ogni caso il client da host1 sarà connesso al server di ascolto su interfaccia (2), che cosa è esattamente quello che voglio evitare. – codewarrior

+0

È necessario * qualcosa * per riflettere i pacchetti inviati dall'interfaccia (1) all'interfaccia (3) - un PC che funge da router, un'impostazione junkbox di linksys con nat, qualsiasi cosa. Diventa creativo. –

+0

Il problema è con l'invio di pacchetti di host1 nuovamente.Anche se il routing è impostato per inviare tutti i pacchetti attraverso il gateway predefinito impostato su interface (2), i pacchetti inviati alla seconda interfaccia dello stesso dispositivo non vengono instradati tramite il gateway predefinito. Se lego esplicitamente il socket client all'interfece (1) i pacchetti vengono rilasciati dal kernel (anche i tcpdump eseguiti sull'interfaccia (1) non vedono i pacchetti). Quindi il problema sembra non essere con il routing stesso, ma piuttosto con la consegna dello stack locale. – codewarrior

4

testato (dovrebbe funzionare, ma forse ho perso qualcosa):

Linux ha diverse tabelle di routing.La tabella locale contiene alcune route che il kernel aggiunge automaticamente per ogni indirizzo IP aggiunto all'host. Li puoi vedere con ip route show table local. Percorsi indicati come locale indicano percorsi locali che passano attraverso l'interfaccia di loopback. Si potrebbe eliminare tale percorso e aggiungere un normale unicast percorso per sostituirlo:

ip route del table local <ip> dev <NIC> 
ip route add table local <ip> dev <NIC> 
ip route flush cache 

Ora la vostra prima scatola tenterà di inviare i pacchetti IP a quell'indirizzo IP come se si trattasse di un indirizzo remoto, ad esempio: sarà usa ARP. Così, il vostro secondo contenitore dovrà né rispondere alle richieste ARP se agisce come un router o sta facendo proxy ARP, oppure si dovrà aggiungere un'associazione per la cache ARP:

arp -s <ip> <MAC> 

Poi, probabilmente si dovrà disabilitare rp_filter sulle interfacce:

echo 0 > /proc/sys/net/ipv4/conf/<NIC>/rp_filter 

di nuovo, se questo non funziona, probabilmente si potrebbe creare qualcosa con L2 NAT, utilizzando ebtables.

+0

Intendevi 'unicast' invece di' local' su quella seconda riga 'ip'? –

+0

@NikolaiNFetissov: ** local ** è per il nome della tabella. Non ho effettivamente specificato il tipo di percorso in entrambi i comandi, per il primo l'IP sarà probabilmente sufficiente per selezionare un percorso unico da eliminare, per il secondo ** unicast ** è il tipo di percorso predefinito. – ninjalj

+0

@NikolaiNFetissov: e sì, ho provato quella parte, il pacchetto è visto su 'tcpdump -ni eth0'. Non ho provato l'intero setup, sono troppo pigro per quello. Ad ogni modo, l'OP probabilmente non ha bisogno né della parte 'ARP' né di quella 'rp_filter'. – ninjalj

2

Per un compito molto simile che sto utilizzando tale script:

ip rule add from all lookup local # add one more local table lookup rule with high pref 
ip rule del pref 0 # delete default local table lookup rule 
ip rout add ${ip3} via ${ip2} src ${ip1} table 100 # add correct route to some table 
ip rule add from all lookup 100 pref 1000 # add rule to lookup new table before local table 
Problemi correlati