터널을 통해 원격 /24에 도달하기: NETMAP, DNAT, 아니면 라우트?
NETMAP으로 전체 프리픽스를 매핑하거나, 호스트별 DNAT 규칙을 추가하거나, 실제 범위를 라우팅하세요. 그리고 원격 측이 무엇을 봐야 하는지와 누가 트래픽을 시작할 수 있는지로 결정하세요.
터널 엔드포인트 뒤의 서브넷에는 세 가지 방법으로 도달할 수 있으며, 사실을 일 분만 모아도 보통 두 가지는 탈락합니다. 확인할 사실은 저쪽 서버가 사용자를 구분해야 하는지, 저쪽에서 누군가 당신의 범위로 접속을 시도할 일이 있는지, 그리고 원격 라우터를 누가 편집할 수 있는지입니다. 이 세 가지에 답하면 설계는 저절로 정해집니다. 나머지는 당신이 엔드포인트를 운영하고 그 방화벽을 편집할 수 있다고 가정합니다.
세 가지 선택지, 그리고 각각이 실제로 바꾸는 것
프리픽스 매핑, 호스트별 DNAT, 라우팅된 프리픽스는 모두 같은 두 범위 사이에서 패킷을 옮기지만 서로 다른 것을 바꿉니다. 매핑은 별칭 범위를 만들어 내고 전송 중에 주소를 산술적으로 다시 씁니다. 호스트별 규칙도 다시 쓰지만 목적지는 하나씩 손으로 지정합니다. 라우팅된 프리픽스는 아무것도 다시 쓰지 않습니다. 패킷은 실제 주소를 유지하고 양쪽 끝이 그 주소가 어디에 있는지 합의합니다.
| What the far side needs | Prefix mapping | Per-host DNAT | Routed prefix |
|---|---|---|---|
| Users visible to its logs | Only without source NAT | Same condition | Yes, unchanged |
| To start a connection toward you | No, alias is local | No, same reason | Yes, both ends route |
| To absorb a new host | Yes, arithmetic only | No, one rule per address | Yes, it simply routes |
| To require no config change | Yes, with source NAT | Yes, same condition | No, it needs a route back |
제거는 원격 측에서 시작하세요. 제약을 바꾸기가 가장 어려운 곳입니다. 저쪽 서버가 클라이언트 주소를 로그에 쓰고, 허용 목록과 대조하고, 다른 시스템에 넘긴다면 소스를 변환하는 순간 유일한 식별자가 파괴됩니다. 원격 측이 역으로 접속해야 한다면 변환은 완전히 불가능합니다. 저쪽은 별칭이 존재하는지조차 모르기 때문입니다. 원격 측이 요청에 응답만 할 때에야 저렴한 선택지가 안전해집니다.
프리픽스 쌍, 그리고 크기가 일치해야 하는 이유
NETMAP은 길이가 같은 프리픽스 쌍에서 동작하는 nat 테이블 타깃입니다. 내부에 주소별 테이블은 없고, 프리픽스를 떼어 낸 뒤 호스트 비트를 유지한 채 새 프리픽스에 다시 붙이므로 /24는 /24에 매핑되고 /25에는 절대 매핑되지 않습니다. 위치가 방향을 결정합니다. PREROUTING의 목적지 일치는 패킷이 가는 곳을 다시 쓰고, POSTROUTING의 소스 일치는 어디서 왔는지를 다시 씁니다.
192.168.2.17의 호스트는 클라이언트에게 10.50.1.17로 보이며, 마지막 옥텟은 장식이 아니라 양쪽에서 같은 숫자입니다. 내일 192.168.2.40에 호스트를 추가하면 그 별칭은 10.50.1.40이 되고 편집할 규칙은 없습니다.
클라이언트에는 별칭 범위를 당신의 박스로 향하는 라우트가 여전히 필요하지만, 별칭이 이미 도달 가능한 서브넷 안에 있으면 필요 없습니다. 목적지 변환이 라우트 조회보다 앞선 PREROUTING에서 실행되므로 게이트웨이에는 별칭 라우트가 필요 없습니다. 포워딩도 켜져 있어야 합니다. 그렇지 않으면 커널이 다시 쓴 뒤 패킷을 버립니다. 아래 세 명령이 클라이언트가 br0에, 별칭이 10.50.1.0/24에, 터널이 tun0에 있는 Debian 스타일 게이트웨이의 전체 설정입니다.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -i br0 -d 10.50.1.0/24 -j NETMAP --to 192.168.2.0/24
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE응답은 스스로 돌아올 길을 찾아야 합니다
목적지를 다시 쓰는 것은 패킷이 어디로 배달되는지만 결정합니다. 원격 서버는 자신이 도달할 수 있는 주소에 응답해야 하며, 이를 마련하는 방법은 두 가지입니다. 소스를 변환해 응답이 당신의 박스로 돌아오게 하거나, 소스를 그대로 두고 원격 측에 클라이언트 범위의 라우트를 주는 것입니다.
나가는 쪽의 masquerade가 더 짧은 길입니다. POSTROUTING의 규칙 하나면 원격 측이 당신의 터널 주소를 보므로 자체 라우트가 필요 없습니다. 대가는 모든 사용자가 하나의 주소로 뭉개지고 사용자별 로그가 의미를 잃는다는 것입니다. 소스를 그대로 두면 그 정보는 유지되지만, 원격 사이트가 클라이언트 범위의 응답을 터널로 되돌려 보내야 합니다.OpenVPN 서버에서는 push되는 push "route 10.50.9.0 255.255.255.0", 그리고 route 192.168.2.0 255.255.255.0 줄입니다.
비싼 실패는 둘 다 반쯤 하는 것입니다. 일부 트래픽을 masquerade하면서 원격 측이 다른 트래픽용 반환 라우트도 들고 있으면, 응답은 연결 추적 항목이 한 번도 보이지 않은 인터페이스로 도착합니다. 클라이언트는 서버가 처리됨으로 기록한 요청에 대해 타임아웃을 보고합니다. 흐름의 양방향은 같은 netfilter 인스턴스를 지나야 합니다: 게이트웨이 하나가 변환하는 것이지, 두 방화벽을 직렬로 두는 것이 아닙니다.
conntrack -L -d 10.50.1.17
iptables -t nat -L PREROUTING -v -n항목을 양방향으로 읽으세요. 원본 tuple은 목적지에 당신의 별칭을 유지하고, 응답 tuple은 실제 주소를 담습니다. 응답 tuple이 없다면 문제는 규칙이 아니라 반환 경로입니다. PREROUTING 카운터가 한 번도 움직이지 않았다면 패킷이 그 hook에 도달하지 않은 것입니다.
충돌, 그리고 먼저 실행되는 조회
서로 다른 두 범위가 충돌할 수 있으며, 두 실패 모두 나쁜 규칙이 아니라 고장 난 터널처럼 보입니다. 당신이 만든 별칭은 전체 경로에서 사용되지 않아야 하고, 실제 원격 범위는 당신의 네트워크에 이미 존재해서는 안 됩니다. 중복은 간헐적으로 엉뚱한 호스트로 트래픽을 보내며, 이는 연결 거부보다 진단하기 어렵습니다. 규칙을 추가하기 전에 라우팅 테이블에 물어보세요.
게이트웨이에서, ip route get 192.168.2.17 는 터널 장치를 가리켜야 합니다. 로컬 브리지가 나온다면 원격 범위가 가려진 것이고 어떤 nat 규칙도 고치지 못합니다. 당신의 네트워크가 이미 192.168.2.0/24를 쓴다면 충돌 위에 매핑을 쌓는 대신 원격 사이트의 번호를 다시 매기세요.
실제 클라이언트에서 시험한 뒤 유지하기
별칭을 실제로 쓸 머신에서 시험하세요. 게이트웨이에서 하지 마세요. 로컬에서 생성된 트래픽은 PREROUTING을 결코 같은 방식으로 지나지 않습니다. 별칭이 붙은 호스트 하나에 연결을 열고 카운터와 conntrack 항목이 함께 나타나는 것을 지켜본 뒤, 닫고 항목이 사라지는지 확인하세요. 오래된 항목은 반쯤 열린 연결을 가리키며, 보통 응답이 돌아오지 않았다는 뜻입니다.
curl -sv http://10.50.1.17/ -o /dev/null
ss -tn dst 10.50.1.17
conntrack -L -d 10.50.1.17두세 번의 성공한 연결은 산술을 증명하지만 지속성이나 다음 엔지니어에 대해서는 아무것도 말해 주지 않습니다. 규칙은 부팅 과정이 읽는 곳에, Debian과 Ubuntu라면 netfilter-persistent를 켠 상태의 iptables-save > /etc/iptables/rules.v4로 저장하세요. 재부팅 때 사라지는 매핑은 탓할 최근 변경 없이 장애가 찾아오므로 없는 것보다 나쁩니다.
규칙 옆에 메모를 남기세요. 별칭 범위, 실제 범위, 쌍을 이룬 이유, 어느 쪽이 시작할 수 있는지입니다. 그 메모가 설계와 아무도 지우기 두려워하는 규칙 더미를 구분합니다. 나중의 질문도 정리합니다. 원격 사이트가 호스트를 추가했는데 아무도 설정하지 않은 주소가 이미 응답할 때입니다. 메모에 원격 측이 반환 라우트를 필요로 한다고 적혀 있다면, 다음 사람은 masquerade 규칙을 지우면 연결이 끊긴다는 것을 압니다. 여기서 문서화는 싸고, 새벽 세 시에 NAT 의존성을 다시 발견하는 것은 싸지 않습니다.