리눅스 커널에서 ICMP 터널 구현: Echo Request에 TCP/UDP 캡슐화
리눅스 커널 레벨의 ICMP 터널은 ICMP Echo Request 패킷 내부에 TCP/UDP 트래픽을 캡슐화하여 표준 네트워크 필터를 우회할 수 있게 합니다. 이 접근 방식은 네트워크 스택 연구, 패킷 차단 테스트, Netfilter 작동 원리 이해에 유용합니다. 이 글에서는 tasklet을 사용하여 비동기 전송을 구현하는 NF_INET_POST_ROUTING 및 NF_INET_LOCAL_IN 훅을 통해 트래픽 변환을 수행하는 커널 모듈의 아키텍처를 자세히 분해하여 설명합니다.
리눅스 커널에서의 ICMP 터널 아키텍처
이 모듈은 세 가지 주요 구성 요소로 이루어져 있습니다: 두 개의 Netfilter 훅과 패킷 전송을 위한 tasklet입니다. NF_INET_POST_ROUTING 훅은 네트워크로 전송되기 전에 나가는 TCP/UDP 패킷을 가로채서 ICMP echo request로 변환한 후 tasklet으로 제어를 넘깁니다. 두 번째 훅인 NF_INET_LOCAL_IN은 들어오는 ICMP 패킷을 포착하여 원본 트래픽을 추출하고 루프백 인터페이스로 라우팅하여 애플리케이션에 전달합니다. tasklet은 dev_queue_xmit을 통해 지연된 패킷 전송을 처리하여 인터럽트 컨텍스트에서의 블로킹을 최소화합니다.
훅 등록은 NF_IP_PRI_FIRST 우선순위를 사용하여 첫 번째 순서로 처리되도록 합니다. 이는 다른 모듈의 사전 간섭이 캡슐화 또는 디캡슐화 무결성을 방해할 수 있기 때문에 중요합니다. 메모리 관리는 리눅스 네트워크 스택의 핵심 구조인 sk_buff에 의존하며, 오류 발생 시 kfree_skb를 통해 적절히 해제해야 합니다.
output_hook 및 create_packet_output 상세 분석
output_hook 함수는 모든 나가는 패킷에 대해 호출됩니다. 이 함수는 ICMP 래퍼 생성을 create_packet_output 함수에 위임하며, 해당 함수는 다음 작업을 수행합니다:
- 프로토콜이 TCP 또는 UDP인지 확인—아니면 NULL을 반환하고 패킷은 변경 없이 원래 경로를 따릅니다.
- 이더넷 헤더 형성을 위해
__ipv4_neigh_lookup을 통해 수신자 MAC 주소를 가져옵니다. - 후속 데이터 복사 작업을 위해 연속 버퍼가 필요하므로
skb_linearize로sk_buff를 선형화합니다. - 전송 프로토콜 유형(UDP는 0, TCP는 1), 헤더 길이, 페이로드 크기를 결정합니다.
- 헤더 아래 예약 공간(
LL_RESERVED_SPACE)과 꼬리 데이터(needed_tailroom)를 고려하여 새로운sk_buff를 할당합니다. - 이더넷, IPv4, ICMP 헤더를 순차적으로 빌드하고 전송 헤더와 데이터를 ICMP 본문으로 복사합니다.
ip_fast_csum및ip_compute_csum을 사용하여 IP와 ICMP 체크섬을 계산합니다.- 전송 준비가 된 패킷을 반환합니다.
중요한 세부 사항은 icmp->un.echo.id 필드를 사용하여 원본 프로토콜 유형과 스트림 식별자에 대한 서비스 정보를 전달한다는 점입니다. 이를 통해 수신 측에서 ICMP 구조 외부의 추가 메타데이터 없이 원본 패킷을 올바르게 재구성할 수 있습니다.
들어오는 패킷 처리 및 루프백 라우팅
수신 측에서 input_hook은 모든 들어오는 ICMP 패킷을 분석합니다. 터널 형식(알려진 ID 필드 패턴을 가진 Echo Request)과 일치하면 모듈은:
- ICMP 본문에서 전송 헤더와 데이터를 추출합니다.
- 들어오는 TCP/UDP 패킷을 모방하는 새로운
sk_buff를 생성합니다. - 목적지 장치를 루프백 인터페이스(
dev_set_name(skb, "lo"))로 설정합니다. - MAC 주소를 localhost로 변경하고
netif_rx_ni()를 호출하여 네트워크 스택에 패킷을 주입합니다.
이렇게 하면 커널이 패킷을 외부에서 온 것처럼 처리하지만 lo 인터페이스를 통해 처리합니다. 애플리케이션은 캡슐화에 전혀 인지하지 못한 채 데이터를 그대로 받습니다. 중요하게도 여기서는 NF_STOLEN을 사용하지 않습니다—패킷이 "도난"당하는 것이 아니라 교체되므로 성공적인 주입 후 NF_ACCEPT를 반환합니다.
핵심 기술 세부 사항 및 제한점
이 구현은 여러 기술적 제한을 안고 있습니다:
- 분할: ICMP 패킷이 경로 중 분할될 수 있지만 현재 구현은 프래그먼트를 처리하지 않으며—전체 캡슐화를 위한 충분한 MTU를 가정합니다.
- 보안: 암호화나 인증 부재로 인해 스푸핑 및 중간자 공격에 취약합니다.
- 성능: 각 패킷마다 새로운
sk_buff할당, 데이터 복사, 체크섬 계산이 필요해 CPU 오버헤드가 발생합니다. - IPv4 전용:
ip_hdr와__ipv4_neigh_lookup사용으로 IPv6를 지원하지 않습니다. - MAC 의존성: 대상 IP에 대한 ARP 항목이 필요하며, 없으면 패킷이 드롭됩니다.
이러한 제한에도 불구하고 이 프로젝트는 학습에 탁월합니다: Netfilter 작업, 커널 메모리 관리, 네트워크 헤더 구성, 실시간 OSI 계층 상호작용을 다룹니다.
주요 요점
- ICMP 터널은 Echo request에 TCP/UDP를 캡슐화하여 일부 네트워크 필터를 우회합니다.
- 라우팅 전/후 트래픽 가로채기를 위해 최대 우선순위의 Netfilter 훅을 사용합니다.
- tasklet이 인터럽트 컨텍스트 블로킹 없이 비동기 전송을 가능하게 합니다.
- 수신 측에서 패킷을 루프백에 주입하여 애플리케이션에 원활하게 전달합니다.
- 이 구현은 교육 목적이며 보안 및 프래그먼트 처리 부재로 프로덕션 사용에 적합하지 않습니다.
— Editorial Team
아직 댓글이 없습니다.