메뉴
HN
Hacker News 20일 전

사용자 공간 IP 스택 역할을 하는 클로드의 핑(Ping) 응답 속도

IMP
3/10
핵심 요약

개발자가 AI 모델인 Claude Code가 사용자 공간의 IP 스택으로 작동하여 Ping 요청에 응답하게 만드는 실험을 진행했습니다. Claude는 바이트 단위로 패킷을 읽고 직접 헤더를 파싱하여 체크섬을 계산한 뒤 유효한 Ping 응답을 생성합니다. 이는 토큰을 많이 소모하는 무모한 시도지만, LLM이 네트워크 프로토콜 로직까지도 완벽하게 이해하고 처리할 수 있다는 기술적 가능성을 보여줍니다.

번역된 본문

재미있는 상상을 하나 해봅시다. 만약 우리가 Claude Code에게 사용자 공간(userspace) IP 스택 역할을 하도록 지시한다면, 얼마나 빨리 핑(Ping)에 응답할 수 있을까요? 즉, Claude에게 IP 패킷을 바이트 단위로 읽고, 일반적인 IP 스택이 하는 방식대로 처리하도록 지시하는 것입니다. 최종 결과적으로 우리가 Claude에게 핑을 보내면, Claude가 제대로 형식화된 핑 응답(Ping reply)을 보내도록 만드는 것입니다. 황당한가요? 네. 토큰을 낭비하나요? 그럼요. 재미있나요? 당연하죠!

저는 Claude에게 이러한 네이티브 LLM IP 스택 역할을 수행할 명령어인 ping-respond.md를 개발하도록 요청했고, Claude는 다음과 같은 결과물을 만들어냈습니다:

ping-respond.md (클릭하여 확장)

Ping Respond — tun0에서 들어오는 하나의 ICMP echo request 처리하기

당신은 사용자 공간(userspace) IP 스택 역할을 하고 있습니다. TUN 헬퍼는 이미 FIFO 모드(sudo python3 scripts/tun_helper.py --fifo)로 실행 중입니다. 당신의 임무는 패킷 하나를 읽고, 파싱하고, 유효한 ICMP echo reply를 생성하여 다시 작성하는 것입니다. 모든 IP 로직은 당신의 추론(reasoning) 내에서 이루어집니다. 라이브러리도, 스크립트도 사용하지 마세요.

1단계: 패킷 읽기

다음 bash 명령어를 실행하여 TUN 장치에서 패킷 하나를 읽으세요: echo "READ" > /tmp/tun_cmd && timeout 35 cat /tmp/tun_resp

16진수(hex) 문자열(또는 "TIMEOUT")을 반환받을 것입니다. TIMEOUT인 경우 이를 보고하고 중단하세요. 이 16진수 문자열을 저장하세요. 이것이 원시 IPv4 패킷입니다.

2단계: IPv4 헤더 파싱

패킷은 16진수 바이트 시퀀스(16진수 문자 2개 = 1바이트)입니다. 다음 필드를 파싱하세요:

오프셋 (바이트) 길이 필드
0 1 버전 (상위 4비트) + IHL (하위 4비트, 32비트 워드 단위)
1 1 DSCP/ECN
2–3 2 총 길이(Total length)
4–5 2 식별자(Identification)
6–7 2 플래그(Flags, 3비트) + 단편화 오프셋(Fragment offset, 13비트)
8 1 TTL
9 1 프로토콜 (반드시 0x01 = ICMP여야 함)
10–11 2 헤더 체크섬(Header checksum)
12–15 4 출발지 IP(Source IP)
16–19 4 목적지 IP(Destination IP)

IHL은 헤더 길이를 나타냅니다: IHL × 4바이트. 표준은 IHL=5 → 20바이트입니다. 프로토콜이 0x01이 아니면 "not ICMP, ignoring(ICMP가 아님, 무시함)"을 보고하고 중단하세요.

3단계: ICMP 헤더 파싱

ICMP 헤더는 IP 헤더 바로 다음(바이트 오프셋 IHL×4 위치)부터 시작됩니다:

오프셋 (ICMP 시작 지점부터) 길이 필드
0 1 타입 (Type, 반드시 0x08 = echo request여야 함)
1 1 코드 (Code, 반드시 0x00이어야 함)
2–3 2 ICMP 체크섬
4–5 2 식별자(Identifier)
6–7 2 시퀀스 번호(Sequence number)
8+ 가변 페이로드(Payload, 변경 없이 그대로 복사)

타입이 0x08이 아니면 "not echo request, ignoring(echo request가 아님, 무시함)"을 보고하고 중단하세요.

4단계: echo reply 생성

특정 필드를 수정하여 응답 패킷을 생성합니다. 전체 과정은 16진수로 작업하세요.

4a: 응답을 위한 IP 헤더

원래의 IP 헤더 바이트에서 다음을 변경하세요:

  • 바이트 8 (TTL): 40 (십진수 64)으로 설정
  • 바이트 10–11 (헤더 체크섬): 임시로 0000으로 설정
  • 바이트 12–15 (출발지 IP): 원래의 목적지 IP로 설정
  • 바이트 16–19 (목적지 IP): 원래의 출발지 IP로 설정

이제 IP 헤더 체크섬을 계산하세요:

  1. 체크섬 필드가 0000인 IP 헤더(IHL×4 바이트)를 가져옵니다.
  2. 16비트 워드(각 2바이트)로 분할합니다.
  3. 모든 워드를 부호 없는 정수(unsigned integer)로 합산합니다.
  4. 합계가 0xFFFF를 초과하는 동안: 캐리(sum >> 16)를 하위 16비트(sum & 0xFFFF)에 더합니다.
  5. 1의 보수를 취합니다: 결과 = 0xFFFF - folded_sum
  6. 이 값을 바이트 10–11에 빅 엔디언(big-endian) 형식으로 기록합니다.

4b: 응답을 위한 ICMP 페이로드

원래의 ICMP 데이터(ICMP 시작 지점부터 패킷 끝까지)에서 다음을 변경하세요:

  • 바이트 0 (타입): 00 (echo reply)으로 설정
  • 바이트 1 (코드): 00 유지
  • 바이트 2–3 (ICMP 체크섬): 임시로 0000으로 설정
  • 바이트 4 이상 (식별자, 시퀀스, 페이로드): 변경 없이 그대로 유지

이제 IP 체크섬과 동일한 알고리즘을 사용하여 ICMP 체크섬을 계산합니다:

  1. 체크섬 필드가 0000인 전체 ICMP 메시지(타입부터 페이로드 끝까지)를 가져옵니다.
  2. 16비트 워드로 분할합니다. 바이트 수가 홀수인 경우, 체크섬 계산을 위해 끝에 0바이트 하나를 패딩합니다.
  3. 모든 워드를 부호 없는 정수로 합산합니다.
  4. 캐리를 접습니다(Fold carries): 합계가 0xFFFF보다 큰 동안, sum = (sum >> 16) + (sum & 0xFFFF)를 수행합니다.
  5. 1의 보수: 결과 =
원문 보기
원문 보기 (영어)
Here is a fun thought: if we ask Claude Code to act as a user space IP stack, how quickly will it be able to respond to a ping? That is, we instruct Claude to read IP packets, byte by byte, and process them as a normal IP stack would do. With the end result being that we can ping Claude and have it reply to us with a properly formed ping reply. Ridiculous? Yes. Wasteful of tokens? Sure. Fun? Oh yeah! I asked Claude to develop a command, ping-respond.md , that would act as such a native LLM IP stack, and this is what it came up with: ping-respond.md (click to expand) # Ping Respond — Process one ICMP echo request from tun0 You are acting as a userspace IP stack. The TUN helper is already running in FIFO mode (`sudo python3 scripts/tun_helper.py --fifo`). Your job: read one packet, parse it, construct a valid ICMP echo reply, and write it back. All IP logic happens in your reasoning — no libraries, no scripts. ## Step 1: Read a packet Run this bash command to read one packet from the TUN device: echo "READ" > /tmp/tun_cmd && timeout 35 cat /tmp/tun_resp You will get back a hex string (or "TIMEOUT"). If TIMEOUT, report it and stop. Save the hex string — this is the raw IPv4 packet. ## Step 2: Parse the IPv4 header The packet is a sequence of hex bytes (2 hex chars = 1 byte). Parse these fields: | Offset (bytes) | Length | Field | | -------------- | ------ | --------------------------------------------------------- | | 0 | 1 | Version (high nibble) + IHL (low nibble, in 32-bit words) | | 1 | 1 | DSCP/ECN | | 2–3 | 2 | Total length | | 4–5 | 2 | Identification | | 6–7 | 2 | Flags (3 bits) + Fragment offset (13 bits) | | 8 | 1 | TTL | | 9 | 1 | Protocol (must be 0x01 = ICMP) | | 10–11 | 2 | Header checksum | | 12–15 | 4 | Source IP | | 16–19 | 4 | Destination IP | IHL tells you the header length: IHL × 4 bytes. Standard is IHL=5 → 20 bytes. If protocol is not 0x01, report "not ICMP, ignoring" and stop. ## Step 3: Parse the ICMP header The ICMP header starts right after the IP header (at byte offset IHL×4): | Offset (from ICMP start) | Length | Field | | ------------------------ | -------- | ---------------------------------- | | 0 | 1 | Type (must be 0x08 = echo request) | | 1 | 1 | Code (must be 0x00) | | 2–3 | 2 | ICMP checksum | | 4–5 | 2 | Identifier | | 6–7 | 2 | Sequence number | | 8+ | variable | Payload (copy unchanged) | If type is not 0x08, report "not echo request, ignoring" and stop. ## Step 4: Construct the echo reply Build the reply packet by modifying specific fields. Work in hex throughout. ### 4a: IP header for the reply Start with the original IP header bytes and change: - **Byte 8 (TTL):** set to `40` (decimal 64) - **Bytes 10–11 (header checksum):** set to `0000` temporarily - **Bytes 12–15 (source IP):** set to the original **destination** IP - **Bytes 16–19 (destination IP):** set to the original **source** IP Now compute the IP header checksum: 1. Take the IP header (IHL×4 bytes) with checksum field = 0000 2. Split into 16-bit words (2 bytes each) 3. Sum all words as unsigned integers 4. While the sum exceeds 0xFFFF: add the carry (sum >> 16) to the lower 16 bits (sum & 0xFFFF) 5. Take the one's complement: result = 0xFFFF - folded_sum 6. Write this value into bytes 10–11 (big-endian) ### 4b: ICMP payload for the reply Start with the original ICMP data (from ICMP start to end of packet) and change: - **Byte 0 (type):** set to `00` (echo reply) - **Byte 1 (code):** keep `00` - **Bytes 2–3 (ICMP checksum):** set to `0000` temporarily - **Bytes 4+ (identifier, sequence, payload):** keep unchanged Now compute the ICMP checksum using the same algorithm as the IP checksum: 1. Take the entire ICMP message (type through end of payload) with checksum field = 0000 2. Split into 16-bit words. If odd number of bytes, pad with one zero byte at the end for checksum computation only. 3. Sum all words as unsigned integers 4. Fold carries: while sum > 0xFFFF, do sum = (sum >> 16) + (sum & 0xFFFF) 5. One's complement: result = 0xFFFF - folded_sum 6. If result is 0x0000, use 0xFFFF instead 7. Write into ICMP bytes 2–3 (big-endian) ### 4c: Assemble the reply Concatenate: IP header (with correct checksum) + ICMP message (with correct checksum) ## Step 5: Write the reply Run this bash command with your assembled hex string: echo "WRITE <your_hex_here>" > /tmp/tun_cmd && timeout 5 cat /tmp/tun_resp You should get "OK" back. ## Step 6: Report Print a summary: - Source IP → Destination IP - ICMP echo request seq number - Packet sizes (request and reply) - "Reply sent successfully" or any error ## Important rules - Do ALL arithmetic yourself. Do not use Python, bc, or any calculator tool. - Show your work for checksum calculations so errors can be debugged. - Every hex value you produce must have the correct number of digits (pad with leading zeros). - If anything looks wrong (bad version, unexpected protocol), report it and stop rather than sending a malformed packet. The command reads bytes from a /dev/tun0 device, with a thin Python helper to get all the stty options right, then computes the IP checksum and, if it sees an ICMP echo message, it responds with an ICMP echo reply message, with all the checksums computed correctly. Running this will make Claude produce output like this: Received packet: 45000054812840004001615dac100001ac100002080054f5000d0001a1fb006a0000000041c4000000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 Parsing the IP header (first 40 hex chars = 20 bytes): - 45 → version=4, IHL=5 (20 bytes) - 0054 → total length = 84 - TTL=40 (64), Protocol=01 (ICMP) - Source: ac100001 = 172.16.0.1 - Dest: ac100002 = 172.16.0.2 ICMP: type=08 (echo request), code=00, id=000d, seq=0001 Now constructing the reply. IP header: swap src/dst, TTL=64, recompute checksum. ICMP: type=00 (echo reply), recompute checksum. IP header checksum — header with zeroed checksum and swapped IPs: 4500 0054 8128 4000 4001 0000 ac10 0002 ac10 0001 Sum: 4500+0054+8128+4000+4001+0000+ac10+0002+ac10+0001 = 0x29F20 Fold: 0x9F20+0x2 = 0x9F22 Complement: 0xFFFF-0x9F22 = 0x60DD ICMP checksum — type changed 08→00, checksum zeroed: Original checksum 54F5 corresponded to folded sum 0xAB0A. Changing type 08→00 reduces sum by 0x0800: 0xAB0A-0x0800 = 0xA30A. Complement: 0xFFFF-0xA30A = 0x5CF5 Reply packet: 4500005481284000400160ddac100002ac10000100005cf5000d0001a1fb006a0000000041c4000000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 And we get results! $ ping -W 300 -c 1 172.16.0.2 PING 172.16.0.2 (172.16.0.2) 56(84) bytes of data. 64 bytes from 172.16.0.2: icmp_seq=1 ttl=64 time=42593 ms --- 172.16.0.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 42592.723/42592.723/42592.723/0.000 ms This one was run with Haiku 4.5, which is a pretty fast model. But with a round-trip time of 45 seconds, that’s a slow ping. Not quite as slow as these ones though.