É possível iniciar uma conexão IP entre duas NICs no mesmo PC externamente?

6

Se duas NICs em uma máquina Linux estiverem conectadas diretamente usando um cabo externo, será possível iniciar uma conexão IP entre essas duas NICs por esse cabo?

Eu configurei minhas duas NICs eth2 e eth3 com os endereços IP 10.10.123.2/24 e 10.10.123.3/24 , respectivamente. Em seguida, removi todas as regras associadas a essas duas interfaces de local table:

# ip rule
0:      from all lookup local 
32766:  from all lookup main 
32767:  from all lookup default 
# ip route show table local | grep -E "eth2|eth3"
# 

.. e regras adicionadas à main table que as conexões com 10.10.123.3 devem exceder eth2 e as conexões com 10.10.123.2 devem ultrapassar eth3 :

# ip route get 10.10.123.3
10.10.123.3 dev eth2  src 10.10.123.2 
    cache 
# ip route get 10.10.123.2
10.10.123.2 dev eth3  src 10.10.123.3 
    cache 
# 

Agora, se eu enviar uma mensagem ICMP "echo request" para 10.10.123.2 (o IP de origem será 10.10.123.3 ), as mensagens de solicitação ARP serão colocadas na conexão e será possível ver que eth2 interface recebe Request who-has 10.10.123.2 tell 10.10.123.3 mas, por algum motivo, não responde a isso. Alguma idéia por quê?

    
por Martin 05.04.2016 / 19:29

3 respostas

1

Este é um script ipcrossover que escrevi há pouco, mas ainda deve funcionar. Ele configura o iptables para que você possa enviar pacotes "para si mesmo", que normalmente é curto-circuitado pelo kernel. Ele se baseia em essas respostas .

#!/bin/bash
# posted in http://unix.stackexchange.com/a/275888/119298 by meuh
# see https://serverfault.com/q/127636/294707
#  cmcginty Apr 2 '10 and Steve Kehlet answered Sep 8 '11

usage(){
        echo "$0: usage:
 config interface1 interface2
 show
 test
 tcpdump
 undo
This script sets up an iptables address translation to allow packets
to circulate over an external loopback cable between two interfaces.
You need to be root. Example usage:
 $0 config eth0:1 eth1
 $0 test
" >&2
        exit 1
}

getmac(){
        $setdebug
        local interface=${1?'interface'}
        ip link show $interface |
        awk '/link\/ether/ { print $2 }'
}
getaddr(){
        $setdebug
        local interface=${1?'interface'}
        ip addr show $interface |
        awk '/ inet / { split($2,x,"/"); print x[1] }'
}
# return true if have name of 2 interfaces
haveconfig(){
        $setdebug
        [ -n "$if1" -a -n "$if2" ] &&
        ip link show "$if1" &&
        ip link show "$if2"
}
# set variables from $if1 and $if2
setup(){
        $setdebug
        if ! haveconfig >/dev/null
        then    haveconfig >&2
                echo "Start with 'config' and 2 valid interfaces" >&2
                usage
        fi
        realprefix=10.50
        fakeprefix=10.60
        real1=$realprefix.0.1
        fake1=$fakeprefix.0.1
        real2=$realprefix.1.1
        fake2=$fakeprefix.1.1
        mac1=$(getmac $if1)
        mac2=$(getmac $if2)
}
doconfig(){
        doifconfig
        doiptables
        doroute
        doarp
        echo "eg: ping $fake2"
}
# Give IPs to the interfaces, and put them on separate networks:
doifconfig(){
        $setdebug
        ifconfig $if1 $real1/24
        ifconfig $if2 $real2/24
}

# set up a double NAT scenario: two new fake networks used to reach the
# other. On the way out, source NAT to your fake network. On the way in,
# fix the destination. And vice versa for the other network:
doiptables(){
        $setdebug
        # nat source IP $real1 -> $fake1 when going to $fake2
        iptables -t nat -A POSTROUTING -s $real1 -d $fake2 -j SNAT --to-source $fake1
        # nat source IP $real2 -> $fake2 when going to $fake1
        iptables -t nat -A POSTROUTING -s $real2 -d $fake1 -j SNAT --to-source $fake2

        # nat inbound $fake1 -> $real1
        iptables -t nat -A PREROUTING -d $fake1 -j DNAT --to-destination $real1
        # nat inbound $fake2 -> $real2
        iptables -t nat -A PREROUTING -d $fake2 -j DNAT --to-destination $real2
}

# tell the system how to get to each fake network
doroute(){
        $setdebug
        ip route flush cache
        ip route add $fake2 dev $if1 src $real1
        ip route add $fake1 dev $if2 src $real2
}
# prepopulate the arp entries
doarp(){
        $setdebug
        ip neigh add $fake2 lladdr $mac2 dev $if1
        ip neigh add $fake1 lladdr $mac1 dev $if2
}
doshow(){
        $setdebug
        iptables -L -t nat -v -n -x
        ip route get $fake1
        ip route get $fake2
        arp -n
}
# undo all configuration
doundo(){
        iptables -F -t nat
        ip route del $fake2 dev $if1
        ip route del $fake1 dev $if2 
        ip route flush cache
        #arp -i $realif1 -d $fake2
        #arp -i $realif2 -d $fake1
        ip neigh del $fake2 lladdr $mac2 dev $if1
        ip neigh del $fake1 lladdr $mac1 dev $if2
        ip addr del $real1/24 dev $if1
        ip addr del $real2/24 dev $if2
}
# tcpdump of just the wanted packets, in case using nfs on interface
dotcpdump(){
        tcpdump -n -e -i fm1-gb1 ether src $mac1 or ether src $mac2 or ether dst $mac1 or ether dst $mac2
}
showpacketcounts(){
        echo -n "$1 "
        local realif=${1%:*}
        ifconfig "$realif" |
        awk '/packets/{printf "%s %-20s",$1,$2; if(/TX/)printf "\n"}'
}
showiptablescounts(){
        iptables -L -t nat -v -x |
        awk '       $3~/[SD]NAT/ { result = result " " $1 " " $3}
                END {print "iptables counts " result }'
}
showcounts(){
        showpacketcounts $if1
        showpacketcounts $if2
        showiptablescounts
}
showdiffs(){
        echo -e "==\n$old\n==\n$new" |
        awk '/^==/{ part++; i = 0; next }
                { inp[part][++i] = $0 }
        END { end = i; for(i = 1;i<=end;i++)print inp[1][i] "\n" inp[2][i] }'
}
# use netstat -l -t to see what services you could test
dotest(){
        old=$(showcounts)
        for ip in $fake1 $fake2
        do      ping -c 4 $ip # -W 1
                echo
                traceroute -M udp $ip # -m 2
                echo
                rpcinfo -p $ip | head -3
                echo
        done
        new=$(showcounts)
        showdiffs
}

# eg ping $fake2 goes out $if1, the source IP $real1 gets NATted to $fake1,
# and as it comes into $if2 the destination $fake2 gets NATted to $real2.
# And the reply takes a similar journey.

# to use iperf to test throughput. Bind to the correct IPs, and be certain
# which IP you're contacting (the other end's fake address):
# server
#./iperf -B $real2 -s
# client: your destination is the other end's fake address
#./iperf -B $real1 -c $fake2 -t 60 -i 10

setdebug= 
case $- in
*x*)        setdebug='set -x' ;; 
esac
PATH=$PATH:/sbin:/usr/sbin

# read saved config
CONFIGFILE=~/.ipcrossover
if [ -s $CONFIGFILE ]
then        source $CONFIGFILE
fi

while [ $# -gt 0 ]
do      cmd=$1; shift
        case $cmd in
        config) if [ $# -ge 2 ] && ip link show "$1" >/dev/null
                then    if1=$1
                        if2=$2
                        shift 2
                        echo "if1=$if1; if2=$if2" >$CONFIGFILE
                fi
                setup
                doconfig ;;
        show|test|undo|tcpdump)
                setup
                do$cmd ;;
        *)      usage ;;
        esac
done

O uso é bastante simples

sudo ipcrossover config eth0 eth1
ping 10.60.0.1
ping 10.60.1.1
sudo ipcrossover test

(ou use aliases eth0:1 eth1:1 se você não quiser perturbar sua rede existente nessas interfaces). Derrube a configuração com sudo ipcrossover undo . Ele funciona adicionando novos endereços IP 10.50.0.1 e 10.60.0.1 na primeira interface e 10.50.1.1 e 10.60.1.1 na segunda, e conforme definido no script:

        realprefix=10.50
        fakeprefix=10.60
        real1=$realprefix.0.1
        fake1=$fakeprefix.0.1
        real2=$realprefix.1.1
        fake2=$fakeprefix.1.1

Por exemplo, ping $fake2 sai da interface $ if1, a origem do IP $ real1 é NATted para $ fake1, e como ele entra em $ if2, o destino $ fake2 recebe NATted para $ real2. E a resposta leva uma jornada similar.

Para usar iperf para testar a taxa de transferência, ligue-se aos IPs corretos e tenha certeza qual IP você está contatando (o endereço falso da outra extremidade): No servidor ./iperf -B $real2 -s . No cliente, o seu destino é o endereço falso da outra extremidade: %código%.

Verifique se está funcionando desconectando o cabo e verificando as paradas de ping. Certifique-se de ler as respostas vinculadas para entender o que está acontecendo.

    
por 12.04.2016 / 08:43
1

Tente novamente sem sua manipulação de rota, mas com

ip netns add not-me
ip set eth2 netns not-me

Isso removerá o eth2 do namespace de rede padrão e você não poderá visualizá-lo. Para restaurar: ip set eth2 netns 1 . Para executar comandos no novo namespace: ip netns exec not-me command... . O comando pode ser bash para abrir um segundo shell (aninhado).

    
por 12.04.2016 / 09:22
1

Por padrão, o kernel Linux responde a qualquer solicitação ARP para qualquer interface que tenha de qualquer interface. Este comportamento é por vezes indesejável.

Para mudar esse comportamento, você precisa modificar alguns parâmetros do kernel com:

echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore 
echo 1 > /proc/sys/net/ipv4/conf/eth1/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_announce
echo 2 > /proc/sys/net/ipv4/conf/eth1/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_filter
echo 1 > /proc/sys/net/ipv4/conf/eth1/arp_filter

Você também pode alterar isso para todas as interfaces na sua máquina com:

echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore 
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter

Dê uma olhada no que esses parâmetros de kernel de rede significam e ajuste-os para suas necessidades específicas se esses últimos comandos não funcionarem como esperado:

arp_ignore - INTEGER

Define different modes for sending replies in response to received ARP requests that resolve local target IP addresses:

  • 0 - (default): reply for any local target IP address, configured on any interface
  • 1 - reply only if the target IP address is local address configured on the incoming interface
  • 2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender's IP address are part from same subnet on this interface
  • 3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied
  • 4-7 - reserved
  • 8 - do not reply for all local addresses

The max value from conf/{all,interface}/arp_ignore is used when ARP request is received on the {interface}

arp_announce - INTEGER

Define different restriction levels for announcing the local source IP address from IP packets in ARP requests sent on interface:

  • 0 - (default) Use any local address, configured on any interface
  • 1 - Try to avoid local addresses that are not in the target's subnet for this interface. This mode is useful when target hosts reachable via this interface require the source IP address in ARP requests to be part of their logical network configured on the receiving interface. When we generate the request we will check all our subnets that include the target IP and will preserve the source address if it is from such subnet. If there is no such subnet we select source address according to the rules for level 2.
  • 2 - Always use the best local address for this target. In this mode we ignore the source address in the IP packet and try to select local address that we prefer for talks with the target host. Such local address is selected by looking for primary IP addresses on all our subnets on the outgoing interface that include the target IP address. If no suitable local address is found we select the first local address we have on the outgoing interface or on all other interfaces, with the hope we will receive reply for our request and even sometimes no matter the source IP address we announce.

The max value from conf/{all,interface}/arp_announce is used.

Increasing the restriction level gives more chance for receiving answer from the resolved target while decreasing the level announces more valid sender's information.

arp_filter - BOOLEAN

  • 1 - Allows you to have multiple network interfaces on the same subnet, and have the ARPs for each interface be answered based on whether or not the kernel would route a packet from the ARP'd IP out that interface (therefore you must use source based routing for this to work). In other words it allows control of which cards (usually 1) will respond to an arp request.

  • 0 - (default) The kernel can respond to arp requests with addresses from other interfaces. This may seem wrong but it usually makes sense, because it increases the chance of successful communication. IP addresses are owned by the complete host on Linux, not by particular interfaces. Only for more complex setups like load- balancing, does this behaviour cause problems.

arp_filter for the interface will be enabled if at least one of conf/{all,interface}/arp_filter is set to TRUE, it will be disabled otherwise

Você pode ver os parâmetros de rede mais relevantes no link

    
por 12.04.2016 / 11:23

Tags