나가는 모든 DNS 쿼리를 127.0.0.1:53의 로컬 스텁 확인자로 리디렉션합니다.

나가는 모든 DNS 쿼리를 127.0.0.1:53의 로컬 스텁 확인자로 리디렉션합니다.

Linux 시스템에서 나가는 모든 DNS 쿼리를 로컬 캐시 스텁 확인자(바인딩되지 않음)로 리디렉션하려고 합니다.

iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to 1.1.1.1:53
iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to 1.1.1.1:53
iptables -t nat -A POSTROUTING -j MASQUERADE

위의 규칙을 사용하면 나가는 모든 DNS 쿼리가 차단되어 1.1.1.1에 있는 DNS 서버로 리디렉션됩니다.

그러나 "1.1.1.1"을 "127.0.0.1"로 바꾸면 모든 DNS 쿼리가 실패하고 로컬 스텁 확인자로 연결되지 않습니다.

아래 sysctl 매개변수를 전달했습니다.

sysctl -w net.ipv4.conf.eth0.route_localnet=1

하지만 내 문제는 여전히 동일합니다. 어떤 충고?

답변1

strace, 및 /를 사용하여 nc디버깅 하면 원래 나가기 위해 선택한 주소가 변경 되지 않는다는 socat것이 분명해집니다 . 아마도 여전히 "라우팅"할 로컬 주소로 간주되기 때문에 변경할 필요가 없습니다. 여기서는 해당 규칙이 작동하지 않습니다.nat/POSTROUTINGMASQUERADEloMASQUERADE

아무튼 그런 일이 일어났습니다. 그래서 답장할 때UDP 프로토콜쿼리할 때 서버는 실제로 데이터를 보낸 소스에 다시 연결되며, 이는 이제 대상으로 사용됩니다. 당연히 해당 목적지, 즉 동일한 로컬 주소에 대해 최상의 소스가 선택됩니다.아니요127.0.0.1. 따라서 conntrack -E예제 로컬 IP 192.0.2.2와 대상 198.51.100.1 UDP 포트 53을 사용하면 다음과 같은 결과가 발생합니다.

    [NEW] udp      17 30 src=192.0.2.2 dst=198.51.100.1 sport=40037 dport=53 [UNREPLIED] src=127.0.0.1 dst=192.0.2.2 sport=53 dport=40037
    [NEW] udp      17 30 src=192.0.2.2 dst=192.0.2.2 sport=53 dport=40037 [UNREPLIED] src=172.16.0.22 dst=172.16.0.22 sport=40037 dport=53

응답은 초기 쿼리와 관련이 없으므로(소스 IP가 127.0.0.1이 아니기 때문에) conntrack은 이를 두 번째 스트림으로 처리합니다. 동시에 클라이언트는 UDP 소켓을 연결 모드로 설정합니다. 이는 잘못된 소스 IP(올바른 포트라도)에서 수신된 UDP 패킷이 거부되고 서버가 ICMP 오류를 수신함을 의미합니다(이는 목격을 통해 가능함 tcpdump -i lo).

수정은 매우 간단합니다. MASQUERADEbut 을 사용하지 마십시오 SNAT. 물론 이제 이 특정 스트림에 특정해야 하므로( SNAT모든 것을 127.0.0.1로 변환하고 싶지는 않음) MASQUERADE이 줄을 다음으로 바꿉니다.

iptables -t nat -A POSTROUTING -p udp --dport 53 -j SNAT --to-source 127.0.0.1

수정된 흐름을 사용하면 이제 로컬 서버가 conntrack의 예상 주소로 응답합니다. 이제 이를 이전 흐름과 연관시키고 올바르게 SNAT를 해제합니다.

    [NEW] udp      17 30 src=192.0.2.2 dst=198.51.100.1 sport=38871 dport=53 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=53 dport=38871
 [UPDATE] udp      17 30 src=192.0.2.2 dst=198.51.100.1 sport=38871 dport=53 src=127.0.0.1 dst=127.0.0.1 sport=53 dport=38871

클라이언트는 예상 소스 198.51.100.1을 수신하고 모든 것이 예상대로 작동합니다.

전송 제어 프로토콜192.0.2.2와 127.0.0.1 사이에 연결이 설정되면 응답은 설정된 동일한 연결 내에 있기 때문에 동일한 결과가 발생하지 않습니다. 이는 UDP와 같은 새 연결이 아니므로 이미 예상 소스가 있고 올바르게 처리됩니다. conntrack으로. 일관성을 위해 다음을 추가하는 것이 좋습니다.

iptables -t nat -A POSTROUTING -p tcp --dport 53 -j SNAT --to-source 127.0.0.1

두 가지 참고사항:

  • 특정 경우에는 route_localnet모든 패킷이 로컬이고 에 남아 있으므로 필요하지 않습니다 lo. 반대로 127.0.0.1로 전송된 패킷을 전달하려면 (다른 트릭과 함께) 필요합니다.

  • DNS 서버가 외부로 쿼리를 보내는 DNS 클라이언트이기도 한 경우(재귀 DNS 서버의 경우) 또는 자체 쿼리가 자체적으로 다시 라우팅되어 루프를 생성하는 경우 추가 예외 규칙이 필요할 수 있습니다. 일반적으로 서버를 특정 사용자로 실행하고 iptables를 사용하여 해결됩니다.-m owner성냥. 각 규칙 세트( nat/OUTPUTnat/POSTROUTING) 앞에 다음과 같은 내용을 삽입하는 것과 같습니다.

    iptables -t nat -I .... -m owner --uid-owner unbound -j RETURN
    

관련 정보