이 저장소에는 다른 네트워크 프로토콜을 통해 TCP 및 UDP 트래픽을 터널링할 수 있는 클라이언트와 서버가 포함되어 있습니다.
현재 지원되는 터널은 다음과 같습니다.
주요 도구는 Rust로 작성되었으며 엔드투엔드 테스트는 Python으로 작성되었습니다.
docker pull ghcr.io/dlemel8/tunneler-server:latest
docker pull ghcr.io/dlemel8/tunneler-client:latest
cargo --version || curl --proto ' =https ' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release
로컬 도커 이미지를 빌드하려는 경우 도커 파일도 있습니다.
docker run -e LOCAL_PORT=45301
-e REMOTE_PORT=5201
-e REMOTE_ADDRESS=localhost
-e TUNNELED_TYPE=udp
--rm -p 45301:45301 ghcr.io/dlemel8/tunneler-server:latest tcp
./target/release/client
--tunneled-type tcp
--remote-address 1.1.1.1
--remote-port 53
--log-level debug
dns
--read-timeout-in-milliseconds 100
--idle-client-timeout-in-milliseconds 30000
자세한 내용을 보려면 --help
사용하여 docker 이미지 또는 컴파일된 바이너리를 실행하세요.
cargo test --all-targets
python3 -m pip install -r e2e_tests/requirements.txt
PYTHONPATH=. python3 -m pytest -v
이 저장소에는 Docker Compose를 사용한 몇 가지 서버 배포 예제가 포함되어 있습니다.
각 예제를 로컬에서 실행하거나 Terraform 및 Ansible을 사용하여 배포할 수 있습니다. 자세한 내용은 여기를 참조하세요.
각 실행 파일에는 클라이언트 스트림 채널(바이트 판독기 및 기록기의 튜플)을 통해 통신하는 2개의 구성 요소가 포함되어 있습니다.
TCP 기반 트래픽은 간단하게 스트림으로 변환됩니다. UDP 기반 트래픽 변환은 터널 프로토콜에 따라 다릅니다.
UDP 기반 트래픽에는 세션을 계속하려면 기존 클라이언트를 식별하는 방법도 필요합니다. 솔루션은 클라이언트의 식별자를 해당 스트림에 매핑하는 메모리 내 클라이언트 캐시입니다.
UDP 트래픽을 스트림으로 변환하기 위해 2바이트 크기 헤더(빅 엔디안)가 각 패킷 페이로드 앞에 옵니다.
UDP 수신기는 수신 패킷 피어 주소를 클라이언트 캐시의 키로 사용합니다.
여기에는 몇 가지 과제가 있습니다.
이러한 문제를 해결하기 위해 각 클라이언트 세션은 임의의 클라이언트 ID(4자리 영숫자 문자)를 생성하는 것으로 시작됩니다. 클라이언트는 데이터를 터널로 읽고 인코더 파이프라인을 통해 실행합니다.
그러면 인코딩된 데이터가 TXT DNS 쿼리의 이름으로 사용됩니다.
권한 있는 DNS 서버를 소유한 경우 클라이언트는 재귀 DNS 확인자에게 요청을 보낼 수 있습니다. Resolver는 도메인 이름 등록 기관에서 IP를 가져와 요청을 IP로 전달합니다. 또 다른 옵션(더 빠르지만 트래픽 분석기에 더 분명함)은 요청을 IP(포트 UDP/53 또는 수신 대기 중인 다른 포트)로 직접 보내도록 클라이언트를 구성하는 것입니다.
서버는 데이터를 디코딩하고(클라이언트가 아닌 트래픽은 모두 무시) 클라이언트 ID를 클라이언트 캐시의 키로 사용합니다.
대규모 서버 응답과 빈 TCP ACK를 처리하기 위해 클라이언트와 서버 모두에서 읽기 시간 초과가 사용됩니다. 읽기 제한 시간이 만료되면 빈 메시지가 전송됩니다. 클라이언트와 서버 모두 유휴 시간 제한을 사용하여 전달을 중지하고 로컬 리소스를 정리합니다.
상호 인증을 구현하기 위해 개인 인증 기관을 사용합니다.
클라이언트와 서버 모두 TLS 핸드셰이크에서 해당 키와 인증서를 사용하도록 구성되어 있습니다. CA 인증서는 루트 인증서로 사용됩니다.
서버 이름 표시 확장이 사용되므로 클라이언트는 특정 서버 이름을 요청하고 서버는 해당 이름이 요청된 경우에만 인증서를 제공합니다. 서버 이름은 예를 들어 주체 대체 이름과 같이 인증서의 일부여야 합니다.