가상 인터페이스 및 PREROUTING 체인

가상 인터페이스 및 PREROUTING 체인

내 일반적인 질문은 다음과 같습니다. 명령줄에서 단일 호스트(예: 네트워크 연결 없음)에서 로컬로 iptables NAT 규칙을 확인하는 가장 좋은 방법(가장 간단하고, 가장 쉽고, 가장 빠르고, 오류 발생 가능성이 가장 적은 등)은 무엇입니까?

다음은 NetCat을 사용하여 간단한 DNAT 규칙을 확인하려는 특정(실패한) 시도에 대한 세부 정보입니다. 이 경우 내 구체적인 질문이 해결되기를 바라지만 일반적인 질문에도 답변이 제공됩니다.


저는 Debian 8(Jessie)을 사용하여 VirtualBox 가상 머신을 실행하고 있습니다. 간단한 DNAT 규칙에 대한 기본 테스트를 수행하기 위해 netcat을 사용하고 싶습니다.

내 테스트에서 내가 원하는 것은 일부 데이터를 하나의 로컬 주소(예: 192.168.0.1)로 보내고 다른 로컬 주소(예: 192.168.0.2)에 도착하도록 하는 것입니다.

나는 지금까지 몇 가지 다른 접근 방식을 시도했습니다.

  1. 가상 인터페이스 및 PREROUTING 체인

  2. 가상 인터페이스 및 PREROUTING 체인

  3. PREROUTING 대신 OUTPUT 체인을 사용하세요.

가상 인터페이스 및 PREROUTING 체인

나의 첫 번째 시도는 PREROUTING 체인에 DNAT 규칙을 추가하고 적절한 주소를 가진 두 개의 가상 인터페이스를 추가하는 것이었습니다.

내 규칙은 다음과 같습니다.

sudo iptables \
-t nat \
-A PREROUTING \
-d 192.168.0.1 \
-j DNAT --to-destination 192.168.0.2

방화벽에는 다른 netfilter 규칙이 없습니다. 그러나 확실히 하기 위해 출력은 다음과 같습니다 iptables-save.

# iptables-save v1.4.21에 의해 생성됨

*낫
:사전 라우팅 허용[0:0]
:입력 승인[0:0]
: 출력 허용[0:0]
: 라우팅 후 승인[0:0]
-A 사전 경로 -d 192.168.0.1/32 -j DNAT --목적지 192.168.0.2
범죄

*필터
:입력 승인[0:0]
: 전달 수락[0:0]
: 출력 허용[0:0]
범죄

다시 말하지만, 내가 원하는 것은 192.168.0.1일부 데이터를 해당 주소로 보내고 해당 주소에 도착하도록 하는 것입니다 192.168.0.2.

192.168.0.0/24내 VM에서는 서브넷이 사용되지 않는다는 점을 언급할 가치가 있을 것입니다 . 먼저 몇 가지 가상 인터페이스를 추가합니다.

sudo ip link add dummy1 type dummy

sudo ip link add dummy2 type dummy

다음으로 원하는 서브넷 범위의 가상 인터페이스에 IP 주소를 할당합니다.

sudo ip addr add 192.168.0.1/24 dev dummy1

sudo ip addr add 192.168.0.2/24 dev dummy2

그런 다음 인터페이스를 엽니다.

sudo ip link set dummy1 up

sudo ip link set dummy2 up

현재 내 라우팅 테이블은 다음과 같습니다.

10.0.2.2 dev eth0을 통한 기본값
10.0.2.0/24 dev eth0 프로토타입 커널 범위 링크 src 10.0.2.15
192.168.0.0/24 dev dummy1 proto 커널 범위 링크 src 192.168.0.1
192.168.0.0/24 dev dummy2 proto 커널 범위 링크 src 192.168.0.2
192.168.56.0/24 dev eth1 프로토타입 커널 범위 링크 src 192.168.56.100

이제 netcat을 사용하여 첫 번째(소스) 주소를 수신합니다.

nc -l -p 1234 -s 192.168.0.1

나는 netcat 클라이언트를 사용하여 netcat 서버에 연결합니다(별도의 터미널 창에서):

nc 192.168.0.1 1234

한 창에 입력한 텍스트가 예상대로 다른 창에 나타납니다.

두 번째 주소에도 동일한 작업을 수행했습니다.

nc -l -p 1234 -s 192.168.0.2

nc 192.168.0.2 1234

마찬가지로 한 창에 입력한 텍스트가 예상대로 다른 창에 나타납니다.

마지막으로 대상(DNAT) 주소에서 수신 대기하고 소스(DNAT) 주소를 통해 연결을 시도했습니다.

nc -l -p 1234 -s 192.168.0.2

nc 192.168.0.1 1234

안타깝게도 다음 오류로 인해 연결이 실패합니다.

(알 수 없음) [192.168.0.1] 1234(?): 연결이 거부되었습니다.

또한 DNAT가 작동하는지 확인하려고 했지만 ping -c 1 -R 192.168.0.1다음과 같이 보이지 않습니다.

PING 192.168.0.1 (192.168.0.1) 56(124) 바이트의 데이터.
192.168.0.1의 64바이트: icmp_seq=1 ttl=64 time=0.047 ms
RR: 192.168.0.1
        192.168.0.1
        192.168.0.1
        192.168.0.1


--- 192.168.0.1 핑 통계 ---
1개의 데이터 패킷 전송, 1개의 데이터 패킷 수신, 패킷 손실 0%, 시간 0ms
rtt 최소/평균/최대/mdev = 0.047/0.047/0.047/0.000밀리초

왜 이것이 작동하지 않습니까? 내가 뭘 잘못했나요?

tcpdump를 이용한 진단

tcpdump이 문제를 진단하기 위해 가상 인터페이스에서 트래픽을 청취 해 보았습니다 . 모든 인터페이스에서 청취를 시도했습니다(그리고 SSH와 DNS를 필터링했습니다): .

sudo tcpdump -i any -e port not 22 and port not 53

dummy1그런 다음 인터페이스에 ping을 보냅니다 .

ping -n -c 1 -I dummy1 192.168.0.1

이로 인해 다음과 같은 결과가 나왔습니다.

listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
In 00:00:00:00:00:00 (oui Ethernet) ethertype IPv4 (0x0800), length 100: 192.168.0.1 > 192.168.0.1: ICMP echo request, id 8071, seq 1, length 64
In 00:00:00:00:00:00 (oui Ethernet) ethertype IPv4 (0x0800), length 100: 192.168.0.1 > 192.168.0.1: ICMP echo reply, id 8071, seq 1, length 64

그래서 가상 인터페이스가 루프백 인터페이스에 연결된 것처럼 보입니다. 이는 iptables 규칙이 완전히 우회됨을 의미할 수 있습니다.

가상 인터페이스 및 PREROUTING 체인

두 번째 시도로 가상 인터페이스 대신 소위 가상 IP 주소를 사용해 보았습니다.

eth0 및 eth1 인터페이스에 "가상" IP 주소를 추가하는 방법은 다음과 같습니다.

sudo ip addr add 192.168.0.100/24 dev eth0
sudo ip addr add 192.168.0.101/24 dev eth1

노트:이러한 인터페이스에는 가상 인터페이스와 다른 IP 주소를 사용했습니다.

그런 다음 iptables NAT 규칙을 새로 고치고 업데이트했습니다.

sudo iptables -F -t nat

sudo iptables \
-t nat \
-A PREROUTING \
-d 192.168.0.100 \
-j DNAT --to-destination 192.168.0.101

핑 테스트를 다시 시도했습니다.

ping -n -c 1 -R 192.168.0.100

주사위 없음:

PING 192.168.0.100 (192.168.0.100) 56(124)바이트의 데이터입니다.
192.168.0.100의 64바이트: icmp_seq=1 ttl=64 time=0.023 ms
경로: 192.168.0.100
        192.168.0.100
        192.168.0.100
        192.168.0.100


--- 192.168.0.100 핑 통계---
1개의 데이터 패킷 전송, 1개의 데이터 패킷 수신, 패킷 손실 0%, 시간 0ms
rtt 최소/평균/최대/mdev = 0.023/0.023/0.023/0.000밀리초

그런 다음 netcat 테스트를 다시 수행하십시오. 서버를 시작합니다:

nc -l -p 1234 -s 192.168.0.101

클라이언트 연결을 시도합니다.

nc 192.168.0.100 1234

주사위도 없습니다:

(알 수 없음) [192.168.0.100] 1234(?): 연결이 거부되었습니다.

PREROUTING 대신 OUTPUT 체인을 사용하세요.

그런 다음 PREROUTING 체인에서 OUTPUT 체인으로 두 개의 DNAT 규칙을 이동해 보았습니다.

sudo iptables -F -t nat

sudo iptables \
-t nat \
-A OUTPUT \
-d 192.168.0.1 \
-j DNAT --to-destination 192.168.0.2

sudo iptables \
-t nat \
-A OUTPUT \
-d 192.168.0.100 \
-j DNAT --to-destination 192.168.0.101

이제 가상 인터페이스와 가상 인터페이스 모두에 대해 ping을 시도합니다.

사용자@호스트:~$ ping -c 1 -R 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(124) 바이트의 데이터.
192.168.0.1의 64바이트: icmp_seq=1 ttl=64 time=0.061 ms
RR: 192.168.0.1
        192.168.0.2
        192.168.0.2
        192.168.0.1


--- 192.168.0.1 핑 통계 ---
1개의 데이터 패킷 전송, 1개의 데이터 패킷 수신, 패킷 손실 0%, 시간 0ms
rtt 최소/평균/최대/mdev = 0.061/0.061/0.061/0.000밀리초

사용자@호스트:~$ ping -c 1 -R 192.168.0.100

PING 192.168.0.100 (192.168.0.100) 56(124)바이트의 데이터입니다.
192.168.0.100의 64바이트: icmp_seq=1 ttl=64 time=0.058 ms
경로: 192.168.0.100
        192.168.0.101
        192.168.0.101
        192.168.0.100


--- 192.168.0.100 핑 통계---
1개의 데이터 패킷 전송, 1개의 데이터 패킷 수신, 패킷 손실 0%, 시간 0ms
rtt 최소/평균/최대/mdev = 0.058/0.058/0.058/0.000밀리초

또한 각 IP 주소 쌍에 대해 netcat 클라이언트-서버 테스트를 시도했습니다.

nc -l -p 1234 -s 192.168.0.2

nc 192.168.0.1 1234

그리고:

nc -l -p 1234 -s 192.168.0.101

nc 192.168.0.100 1234

이번 테스트도 성공적이었습니다.

따라서 DNAT 규칙이 PREROUTING 체인이 아닌 OUTPUT 체인에 있을 때 가상 인터페이스와 가상 인터페이스가 모두 작동하는 것처럼 보입니다.

내 문제의 일부는 어떤 패킷이 어떤 체인을 통과하는지 명확하게 알 수 없다는 것입니다.

답변1

간단한 설명: 가상 인터페이스와 가상 IP 주소는 PREROUTING 체인의 영향을 받지 않는 루프백 인터페이스를 통해 패킷을 보냅니다. veth 인터페이스가 있는 네트워크 네임스페이스를 사용하면 한 IP 주소에서 다른 IP 주소로 트래픽을 보낼 수 있으므로 다중 호스트 네트워크 트래픽을 보다 정확하게 시뮬레이션하고 필요에 따라 PREROUTING 체인에서 DNAT 규칙을 테스트할 수 있습니다.

아래는 솔루션에 대한 자세한 설명입니다.


다음은 한 쌍의 네트워크 인터페이스를 구성하고 DNAT 규칙이 예상대로 작동하는지 테스트하는 Bash 스크립트입니다.

# Create a network namespace to represent a client
sudo ip netns add 'client'

# Create a network namespace to represent a server
sudo ip netns add 'server'

# Create a veth virtual-interface pair
sudo ip link add 'client-eth0' type veth peer name 'server-eth0'

# Assign the interfaces to the namespaces
sudo ip link set 'client-eth0' netns 'client'
sudo ip link set 'server-eth0' netns 'server'

# Change the names of the interfaces (I prefer to use standard interface names)
sudo ip netns exec 'client' ip link set 'client-eth0' name 'eth0'
sudo ip netns exec 'server' ip link set 'server-eth0' name 'eth0'

# Assign an address to each interface
sudo ip netns exec 'client' ip addr add 192.168.1.1/24 dev eth0
sudo ip netns exec 'server' ip addr add 192.168.2.1/24 dev eth0

# Bring up the interfaces (the veth interfaces the loopback interfaces)
sudo ip netns exec 'client' ip link set 'lo' up
sudo ip netns exec 'client' ip link set 'eth0' up
sudo ip netns exec 'server' ip link set 'lo' up
sudo ip netns exec 'server' ip link set 'eth0' up

# Configure routes
sudo ip netns exec 'client' ip route add default via 192.168.1.1 dev eth0
sudo ip netns exec 'server' ip route add default via 192.168.2.1 dev eth0

# Test the connection (in both directions)
sudo ip netns exec 'client' ping -c 1 192.168.2.1
sudo ip netns exec 'server' ping -c 1 192.168.1.1

# Add a DNAT rule to the server namespace
sudo ip netns exec 'server' \
iptables \
-t nat \
-A PREROUTING \
-d 192.168.2.1 \
-j DNAT --to-destination 192.168.2.2

# Add a dummy interface to the server (we need a target for the destination address)
sudo ip netns exec 'server' ip link add dummy type dummy
sudo ip netns exec 'server' ip addr add 192.168.2.2/24 dev dummy
sudo ip netns exec 'server' ip link set 'dummy' up

# Test the DNAT rule using ping
sudo ip netns exec 'client' ping -c 1 -R 192.168.2.1

핑 테스트의 출력은 규칙이 실행 중임을 보여줍니다.

PING 192.168.2.1 (192.168.2.1) 56(124) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.025 ms
RR:     192.168.1.1
        192.168.2.2
        192.168.2.2
        192.168.1.1


--- 192.168.2.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.025/0.025/0.025/0.000 ms

이제 NetCat 테스트도 수행할 수 있습니다. 먼저 서버에서 수신합니다.

sudo ip netns exec 'server' nc -l -p 1234 -s 192.168.2.2

그런 다음 클라이언트를 통해 연결합니다(별도의 터미널 창에서).

sudo ip netns exec 'client' nc 192.168.2.1 1234

한 터미널 창에 입력한 텍스트가 다른 창에 나타납니다. 성공했습니다!

관련 정보