DNS 서버를 통해 IPv4 데이터를 터널링하여 방화벽 제한을 우회하고 침투 테스트를 위한 은밀한 네트워크 접근을 제공합니다.
이 소프트웨어는 DNS 서버를 통해 IPv4 데이터를 터널링할 수 있게 해주는 프로그램입니다. 이는 인터넷 접속이 방화벽으로 차단되어 있지만 DNS 쿼리는 허용되는 다양한 상황에서 유용하게 사용할 수 있습니다.
iodine을 컴파일하려면 meson이 필요합니다.
build 디렉터리 안에서 컴파일하려면 다음 명령을 실행하십시오:
meson setup build
cd build
ninja
테스트를 빌드하고 실행하려면 check 라이브러리가 필요합니다. 빌드 디렉터리 안에서
ninja test를 실행하여 테스트를 시작하세요.
자신의 LAN 안에서 직접 사용해 보세요! 다음의 간단한 단계를 따르면 됩니다:
./iodined -f 10.0.0.1 test.com을 실행하세요.
이미 10.0.0.0 네트워크를 사용 중이라면 172.16.0.0과 같은
다른 내부 네트워크를 사용하세요../iodine -f -r 192.168.0.1 test.com을 실행하세요.
192.168.0.1을 서버의 IP 주소로 바꾸세요.10.0.0.2를, 서버는 10.0.0.1을 갖게 됩니다.중계 네임서버를 통해 실제로 사용하려면 아래를 참고하세요.
참고: 서버와 클라이언트는 정확히 동일한 프로토콜을 사용해야 합니다. 대부분의 경우 이는 동일한 iodine 버전을 실행한다는 것을 의미합니다. 안타깝게도 하위 및 상위 프로토콜 호환성을 구현하는 것은 대개 실현 가능하지 않습니다.
이 터널을 사용하려면 실제 도메인(예: mydomain.com)에 대한 제어 권한과
iodined를 실행할 공인 IP 주소를 가진 서버가 필요합니다. 이 서버에서
이미 DNS 프로그램을 실행 중이라면, 해당 프로그램의 수신 포트를 변경한 다음
iodined의 -b 옵션을 사용하여 iodined가 DNS 요청을 포워딩하도록 하세요.
(이 절차는 iodined의 DNS 포워딩이 완전히 투명하지 않기 때문에, 예를 들어
존 전송이 작동하지 않으므로, 프로덕션 환경에서는 권장되지 않습니다.)
또는 DNS 서버에서 서브도메인을 iodined로 포워딩할 수 있으며, 이 경우
iodined는 다른 포트(-p)에서 실행되어야 합니다.
그런 다음 서브도메인(예: t1.mydomain.com)을 iodined 서버에 위임하세요.
도메인에 BIND를 사용한다면, 존 파일에 다음과 같은 두 줄을 추가하세요:
t1 IN NS t1ns.mydomain.com. ; note the dot!
t1ns IN A 10.15.213.99
NS 줄은 t1 서브도메인에 대한 쿼리를 t1ns 서버로 라우팅하는 데
필요한 전부입니다. 데이터 트래픽을 위해 가능한 한 많은 공간을 확보하기 위해
서브도메인에는 짧은 이름을 사용합니다. NS 줄의 끝에는 iodined 서버의
이름이 옵니다. 이 이름은 어디를 가리키든 임의의 이름이 될 수 있지만,
이 경우에는 같은 존 파일에 쉽게 유지됩니다. 이는 이름(IP 주소가 아님)이어야
하며, 그 이름 자체에 A 레코드가 있어야 합니다(CNAME이 아님).
iodined 서버가 동적 IP를 가지고 있다면, 동적 DNS 제공업체를 사용하세요.
간단히 NS 줄을 해당 제공업체를 가리키도록 하고, A 줄은 생략하세요:
t1 IN NS myname.mydyndnsprovider.com. ; note the dot!
그런 다음 네임서버 프로그램을 다시 로드하거나 재시작하세요. 이제
t1.mydomain.com으로 끝나는 도메인에 대한 모든 DNS 쿼리가 iodined 서버로
전송됩니다.
마지막으로 서버에서 iodined를 시작하세요. 첫 번째 인수는 터널 내부의
IP 주소로, 아직 사용하지 않는 임의의 범위(예: 192.168.99.1)에서 선택할 수
있으며, 두 번째 인수는 할당된 도메인(이 경우 t1.mydomain.com)입니다.
-f 옵션을 사용하면 iodined가 포그라운드에서 계속 실행되므로 테스트할 때
유용합니다. iodined는 가상 인터페이스("tun device")를 열고, UDP 포트 53에서
DNS 쿼리 수신도 시작합니다. 명령줄에서(-P pass) 또는 서버가 시작된 후에
비밀번호를 입력하세요. 이제 클라이언트를 위한 모든 준비가 완료되었습니다.
예상치 못한 환경에서 iodine 터널을 사용할 가능성이 있다면, -c 옵션과 함께
iodined를 시작하세요.
이 예시 상황에서의 결과 명령줄은 다음과 같습니다:
./iodined -f -c -P secretpassword 192.168.99.1 t1.mydomain.com
모든 설정이 완료되었으니, iodine을 시작하기만 하면 됩니다. 이 명령은 하나
또는 두 개의 인수를 받는데, 첫 번째는 로컬 중계 DNS 서버(선택 사항)이고
두 번째는 사용한 도메인(t1.mydomain.com)입니다. 첫 번째 인수를 지정하지
않으면 시스템의 현재 DNS 설정이 참조됩니다.
DNS 쿼리가 모든 컴퓨터에 허용되는 경우, iodined 서버의 주소를 첫 번째 인수로 직접 지정할 수 있습니다(예시에서는 t1ns.mydomain.com 또는 10.15.213.99). 이 경우 모든 컴퓨터의 DNS 포트(53 UDP)로 모든 트래픽이 허용될 수도 있습니다. Iodine은 이를 감지하고 가능하면 원시 UDP 터널링으로 전환합니다. 어떤 경우든 DNS 터널링을 강제하려면 -r 옵션을 사용하십시오(특히 자체 네트워크 내에서 테스트할 때 유용합니다).
클라이언트의 터널 인터페이스에는 서버에 가까운 IP(이 경우 192.168.99.2 또는 .3 등)와 적절한 MTU가 할당됩니다. 서버와 동일한 비밀번호를 명령줄 옵션으로 입력하거나 클라이언트가 시작된 후에 입력하십시오. -f 옵션을 사용하면 iodine 클라이언트가 포그라운드에서 계속 실행됩니다.
이 예시 상황에서의 결과 명령줄이며, -r을 추가하면 원시 UDP 터널링이 가능하더라도 DNS 터널링을 강제합니다:
./iodine -f -P secretpassword t1.mydomain.com
이제 어느 쪽에서든 터널 반대편 끝의 IP 주소로 ping을 보낼 수 있어야 합니다. 이 경우 iodine 클라이언트에서는 ping 192.168.99.1, iodine 서버에서는 192.168.99.2를 사용합니다.
터널 내부의 데이터는 IPv4 전용입니다.
서버는 기본적으로 들어오는 요청에 대해 IPv4와 IPv6 모두에서 수신 대기합니다. 한 프로토콜에서만 수신 대기하려면 -4 또는 -6 옵션을 사용하십시오. 원시 모드는 로그인에 사용된 것과 동일한 프로토콜에서 시도됩니다.
클라이언트는 IPv4 또는 IPv6 네임서버를 사용하여 iodined에 연결할 수 있습니다. 필요하면 릴레이 네임서버가 프로토콜 간을 자동으로 변환합니다. 클라이언트가 DNS 쿼리에 특정 IP 버전을 사용하도록 강제하려면 -4 또는 -6 옵션을 사용하십시오.
서버가 IPv6에서 수신 대기 중이고 접근 가능하다면, DNS 설정에 AAAA 레코드를 추가하십시오. 위 예시를 확장하면 다음과 같습니다:
t1 IN NS t1ns.mydomain.com. ; note the dot!
t1ns IN A 10.15.213.99
t1ns IN AAAA 2001:db8::1001:99
모든 트래픽을 DNS 터널을 통해 라우팅하는 것이 가능합니다. 이를 위해서는 먼저 기본 게이트웨이를 게이트웨이로 하여 유선/무선 인터페이스를 통해 iodine이 사용하는 네임서버에 대한 호스트 경로를 추가하십시오. 그런 다음 기본 게이트웨이를 DNS 터널 내부의 iodined 서버 IP 주소로 교체하고, 서버가 NAT를 수행하도록 구성하십시오.
그러나 터널링된 데이터 트래픽은 전혀 암호화되지 않으며, 외부 당사자가 비교적 쉽게 읽고 변경할 수 있다는 점에 유의하십시오. 최대 보안을 위해서는 DNS 터널을 통해 VPN을 실행하거나(=이중 터널링), 포트 포워딩과 함께 보안 셸(SSH) 접근을 사용하십시오. 후자는 서버에서 웹 프록시(예: Privoxy)를 실행할 때 웹 브라우징에도 사용할 수 있습니다.
iodined 서버는 터널 도메인의 하위 도메인에 대해 전송된 NS 요청에 응답합니다. iodined 하위 도메인이 t1.mydomain.com이라면, foo123.t1.mydomain.com에 대한 NS 요청을 보내 위임이 작동하는지 확인하십시오.
dig는 이를 위한 좋은 도구입니다:
% dig -t NS foo123.t1.mydomain.com
ns.io.citronna.de.
또한 iodined 서버는 지원되는 모든 요청 유형에 대해 'z'로 시작하는 요청에 응답합니다. 예를 들어:
dig -t TXT z456.t1.mydomain.com
dig -t SRV z456.t1.mydomain.com
dig -t CNAME z456.t1.mydomain.com
이 모든 경우에 응답은 깨진 텍스트처럼 보여야 합니다.
macOS 10.6 이상에서 iodine은 OS에 내장된 네이티브 utun 장치를 지원합니다 - -d utunX를 사용하십시오.
DNS 응답 조각 크기는 최대 대역폭을 얻기 위해 일반적으로 자동으로 탐지됩니다. 특정 값을 강제하려면(그리고 속도를 높이려면) -m 옵션을 사용하십시오.
DNS 호스트 이름은 일반적으로 최대 길이인 255자까지 사용됩니다.
일부 DNS 릴레이에서 전체 길이 쿼리에 대해 신뢰할 수 없게 응답하여
반복 시도 시 프래그먼트 크기 자동 탐색에서 크게 변동하는(대부분 매우 나쁜)
결과를 내는 사례가 발견되었습니다. 이러한 경우 -M 스위치를 사용하여
DNS 호스트 이름 길이를 예를 들어 200자로 줄이면 이러한 DNS 릴레이가
훨씬 더 안정적으로 동작합니다. 이는 응답에 쿼리의 전체 복사본 두 개를
채워 넣어 다운스트림 데이터를 위한 공간을 거의 남기지 않는 일부 "비최적화"
DNS 릴레이(EDNS0도 지원하지 않음)에서도 유용합니다. -M 스위치는
업스트림 대역폭 일부를 다운스트림 대역폭과 맞바꿀 수 있습니다. 프로토콜이
패킷(최대 1200바이트)을 16개의 프래그먼트로만 분할할 수 있어 프래그먼트당
최소 75바이트의 실제 데이터가 필요하므로 -M의 최솟값은 약 100입니다.
업스트림 데이터는 Base32로 gzip 인코딩되어 전송됩니다. 또는 릴레이 서버가
도메인 이름에서 대소문자 혼용과 +를 지원하면 Base64로, _를 대신
지원하면 Base64u로, 높은 바이트 값 문자를 지원하면 Base128로 전송됩니다.
이 업스트림 인코딩은 자동 감지됩니다. DNS 프로토콜은 패킷당 하나의 쿼리를
허용하며, 하나의 쿼리는 최대 256자입니다. 각 도메인 이름 부분은 최대
63자입니다. 따라서 최대 업스트림 처리량을 허용하려면 도메인 이름과
서브도메인을 가능한 한 짧게 해야 합니다.
여러 DNS 요청 유형이 지원되며, NULL 및 PRIVATE 유형이 가장 큰
다운스트림 대역폭을 제공할 것으로 예상됩니다. PRIVATE 유형은
사설 사용 범위의 값 65399를 사용합니다. 사용 가능한 다른 유형으로는
TXT, SRV, MX, CNAME 및 A(CNAME 반환)가 있으며 대역폭이
감소하는 순서입니다. 일반적으로 "최적" 요청 유형이 자동 감지되어
사용됩니다. 그러나 DNS 릴레이는 예를 들어 NULL 및 TXT에 제한을 부과할 수
있어 SRV 또는 MX가 실제로 최선의 선택이 될 수 있습니다. 이는 자동
감지되지 않지만 -T 옵션을 사용하여 강제할 수 있습니다. 특히 자동 감지된
요청 유형이 200바이트 미만의 다운스트림 프래그먼트 크기를 제공하는 경우
다양한 대안을 시도해 보는 것이 좋습니다.
SRV, MX 및 A(CNAME 반환) 쿼리는 "스마트" 캐싱 네임서버가 실제
IP 주소를 얻기 위해 추가 조회를 수행하게 할 수 있으며, 이는 속도를
늦추거나 완전히 실패할 수 있습니다.
비-NULL/PRIVATE 쿼리에 대한 DNS 응답은 업스트림 데이터와 동일한
코덱 집합으로 인코딩될 수 있습니다. 이 역시 일반적으로 자동 감지되지만
완전히 철저한 테스트는 수행되지 않으므로 더 고급 코덱을 선택할 때 일부
문제가 발견되지 않을 수 있습니다. 그런 경우 프래그먼트 크기 자동 탐색에서
실패/손상이 나타납니다. 특히 일부 DNS 릴레이는 호스트 이름(SRV, MX,
CNAME, A)을 반환하는 응답에서 해당 호스트 이름이 약 180자를 초과할
때만 소문자로 변경하는 사례가 발견되었습니다. 이러한 경우 및 유사한
경우에는 -O 옵션을 사용하여 다른 다운스트림 코덱을 시도하십시오.
Base32는 항상 작동합니다.
이제 정상 동작은 서버가 다음 DNS 요청이 들어올 때까지 DNS 요청에
응답하지 않는 것, 즉 "게으른(lazy)" 방식입니다. 이렇게 하면 서버는
새 다운스트림 데이터를 보내야 할 때 항상 DNS 요청을 준비해 둘 수
있습니다. 이는 (대화형) 성능과 지연 시간을 크게 개선하며, 유휴 핑 요청을
기본적으로 4초 간격으로, 그리고 경우에 따라 훨씬 더 느리게 늦출 수
있습니다. 실제로 이제 핑의 주된 목적은 이전 핑에 대한 응답을 강제하고
DNS 서버 타임아웃(보통 RFC1035에 따라 최소 5-10초)을 방지하는 것입니다.
일부 DNS 서버는 더 조급하여 터널링된 데이터 트래픽이 없는 기간에
SERVFAIL 오류(타임아웃)를 발생시킵니다. 이러한 경우에도 모든 데이터는
여전히 전달되어야 하지만, iodine은 오류 메시지 수를 줄이기 위해
핑 간격을 어쨌든 1초(-I1)로 줄입니다. 이는 1초 또는 그보다 짧은 시간에
타임아웃되는 dnsadvantage.com(ultradns)과 같은 매우 조급한 DNS
릴레이에는 도움이 되지 않을 수 있습니다. 그래도 데이터는 여전히 전달되며
SERVFAIL 오류는 무시할 수 있습니다.
로컬 네트워크에서 중간에 DNS 서버 없이 실행 중이라면 -I 50을 시도하십시오(iodine과 iodined는 60초간 침묵이 있으면 연결을 닫습니다).
속도 저하를 느낄 수 있는 유일한 경우는 DNS 응답 패킷이 유실될 때입니다.
그러면 iodined 서버는 데이터를 다시 보내기 위해 새로운 ping을 기다려야 합니다.
업스트림 트래픽(키 입력, ping)을 생성하여 속도를 높일 수 있습니다. 이런 일이 자주 발생하면 네트워크의 병목 현상을 확인하거나 -I1로 실행하십시오.
lazy 모드에서의 지연 응답은 일부 "통신사급" 상용 DNS 릴레이가 동일한 DNS 쿼리를 iodined 서버로 반복해서 다시 보내도록 만들 수 있습니다.
DNS 릴레이가 실제로 병렬 서버 풀로 구현된 경우, 중복 요청이 여러 소스에서 도착할 수도 있습니다. 이 효과는 iodined 서버의 네트워크 트래픽에서만 보이며, 클라이언트의 연결에는 영향을 주지 않습니다. Iodined는 이러한 중복을 감지하고, (응답할 시점이 되면) 동일한 응답을 원래 쿼리와 가장 최근의 중복 쿼리 모두에 보냅니다. 그 후 전체 응답은 잠시 동안 캐시됩니다. 서버에 더 늦게 도착하는 지연된 중복 요청에는 iodine 클라이언트가 무시할 응답이 전송됩니다(클라이언트에 도달하는 경우).