2026년 7월 10일 금요일

Res – Tracker that tracks torrents used in North Korea - Part - 4

Sub Topic - EP.04 - How Does a Tracker Return Peer Lists?

===== Intro =====

1.     제 나름대로 구상한 방식입니다

2.     막히면 돌아가고 깊이가 방대하면 포기하고 다음으로!

3.     구성 : 토픽 기반기술 학습 기반기술 기반 실습(되는데로..) – 최종 프로젝트

 

===== Overall story =====

1.     1 = 북한 ip의 구성

2.     2 = Torrent 이용중 IP 동작

3.     3 = 마그넷 링크를 뜯어보고 토렌트가 무엇으로 파일을 식별하는지 이해

4.     4 = Tracker Peer 목록을 어떻게 알려줄까? (실제 통신)

 

 

Step – 0

== InfoHash를 알게되면 Peer는 어떻게 찾는 거지?

지난 글에서 Magnet Link 안에 있는 InfoHash가 무엇인지 살펴 보며 토렌트 네트워크에서 파일은 이름이 아니라 InfoHash 로 식별되는 사실도 확인했는데.. 궁금한점이 생긴다

è InfoHash 를 알게되면 Peer는 어떻게 찾는건데?

토렌트 클라이언트가 무작정 인터넷 전체를 뒤질수 없기 때문에 Tracker 서버에게 물어본다, 그리고 Tracker 서버는 해당 Torrent 를 공유하고 있는 Peer 들의 정보를 반환한다

 

이번 에피소드에서 Tracker와 실제로 어떤 데이터를 주고받는지 살펴보자

(실제 패킷을 보는 단계까지 해봅시다)

 

Step – 1

== Tracker?

Tracker를 간단히 정의하면!

è 이 토렌트를 공유하고 있는 사람들의 명단을 관리하는 서버

지난번부터 사용하고 있는 ubuntu infoHash Abcdefg12345 이고 만약 참여중인 Peer = 1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4 라고 하면 Tracker InfoHash를 질의하면 Peer정보를 반환한다

 

Step – 2

== Tracker에게 보내는 첫 메시지

Tracker에 보내는 메시지중 첫번째 메시지를 Announce Request라고 부르며 Client(사용자) Tracker에게 보내는 메시지는 다음과 같음

GET /announce?

info_hash=...

peer_id=...

port=6881

uploaded=0

downloaded=0

left=123456

event=started

그리고 이를 url 형태로 붙혀서 보내는데 이런식으로 뒤에 QueryString 형태로 정보가 붙는다

è http://tracker.example.com/announce

이때 파라미터를 살펴보자

Info_hash

지난화에 설명한 InfoHash

peer_id=...

클라이언트 식별값(-UT2210-abcdefgh1234 = utorrent 식별값)

*다양한 Torrent client 가 있음)

port=6881

Peer가 연결을 받을 포트

uploaded=0

업로드한 바이트

downloaded=0

다운로드한 바이트

left=123456

남은 다운로드 크기

event=

현재 상태 started / completed / stopped 3가지 상태가 있음

 

이를 기반으로 통신 순서를 정리하면 다음과 같이 진행 된다

è Client ----(Announce) ------>Tracker ------(Peer List) ----> Client

è 매우 단순함

 

Step – 3

== Tracker응답은 어떻게 생겼지?

Tracker응답은 JSON이 아니다, 보통 이런 다양한 값을 보내면 응답이 JSON으로 오는 경우가 많은데 (아래 그림처럼 생긴게 JSON 타입)

{

  "peers":[]

}

 

토렌트는 오래된 프로토콜이라 Bencode라는 자체 포맷을 사용한다!

è Bencode = 토렌트에서 사용하는 직렬화 포맷 (아래를 보자)

 

타입

예시

의미

문자열

4:spam

Spam

숫자

i123e

123

리스트

l

4:spam

4:eggs

e

["spam","eggs"]

딕셔너리

d

3:cow

3:moo

4:spam

4:eggs

e

{

  "cow":"moo",

  "spam":"eggs"

}

*리스트와 딕셔너리에 시작에 l d로 구분하고 e로 마지막임을 표시한부분을 잘 보자*

 

실제 Tracker응답을 보자

d

8:interval

i1800e

 

5:peers

12:

...

e

*d로 시작하니 딕셔너리임을 알수 있다

*실제로는 한 줄의 바이너리 데이터로 온다

JSON 타입으로 해석하면

{

    "interval":1800,

    "peers":"..."

}

**Interval = 30분뒤에 다시 요청하라(Tracker의 과부하를 막기 위한 값)

 

여기서 핵심 정보가 바로 peer 정보이다(실제 Peer 목록이 들어있다)

 

Peer List 형식 = 2가지 방식이 있음

 

1.딕셔너리 방식

[

  {

    "ip":"1.2.3.4",

    "port":6881

  }

]

 

2.Compact 방식

=대부분 사용하며 훨씬 크기도 작다

 

Compact Peer Format

=Peer 하나당 ( IP 4바이트 , Port 2바이트 = 6 바이트만 사용)

=ex) 01 02 03 04 1A E1 -> 4바이트 1.2.3.4  2바이트 6881

è 01 02 03 04 1A E1   1.2.3.4:6881 가 된다

 

여러 Peer가 있을때 상황을 보면

01 02 03 04 1A E1

05 06 07 08 1A E1

09 0A 0B 0C 1A E1

1.2.3.4:6881

5.6.7.8:6881

9.10.11.12:6881

으로 6 바이트씩 끊어서 읽으면 된다

 

Step – 4

== Tracker 통신 분석

패킷의 관점에서 살펴보면 다음과 같이 Tracer에게 질의한다

è Client---------(infoHash, Peer_id, port)----------> Tracker

그럼 Tracker는 다음과 같이 응답해 준다

interval = 1800

 

peers =

[

  1.2.3.4:6881

  5.6.7.8:51413

  9.9.9.9:6881

]

 

그럼 이제 Client 는 전달받은 Peer 1.2.3.4 에게 연결을 시도하고 실패하면 다음 5.6.7.8에 연결을 시도하며 순차적으로 진행한다

 

 

Step – 5

==다음화 예고 – Peer HandShack 는 어떻게 이루어 질까?

l   BitTorrent Handshake

l   Peer ID

l   Reserved Bytes

l   InfoHash 검증

l   C#으로 Handshake 생성하기

 

Tracker에게 Peer를 받았다고 끝이 아니고 이제부터 진짜 본격적입니다~

Peer TCP 연결이 성공하면 BitTorrent 프로토콜의 첫번째 메시지인 HandShacke가 시작 되기 때문입니다

 

===== 실습 =====

=C# 콘솔 프로그램으로 진행

==Compact Peer를 파싱하는 프로그램을 만들어 보자

 

예제 데이터

byte[] peers =

{

    1, 2, 3, 4, 0x1A, 0xE1,

           5, 6, 7, 8, 0x1A, 0xE1,

    9, 10, 11, 12, 0xC8, 0xD5

};

 

파싱 코드

using System;

 

namespace TorrentTrackerDemo

{

    class Program

    {

        static void Main(string[] args)

        {

            // Tracker가 보내준 Peer 데이터라고 가정

            byte[] peers =

            {

                // 1.2.3.4:6881

                1, 2, 3, 4, 0x1A, 0xE1,

 

                // 5.6.7.8:6881

                5, 6, 7, 8, 0x1A, 0xE1,

 

                // 9.10.11.12:51413

                9, 10, 11, 12, 0xC8, 0xD5

            };

 

            Console.WriteLine("=== Peer List ===");

            Console.WriteLine();

 

            for (int i = 0; i < peers.Length; i += 6)

            {

                string ip =

                    $"{peers[i]}." +

                    $"{peers[i + 1]}." +

                    $"{peers[i + 2]}." +

                    $"{peers[i + 3]}";

 

                ushort port =

                    (ushort)((peers[i + 4] << 8) | peers[i + 5]);

 

                Console.WriteLine($"{ip}:{port}");

            }

 

            Console.WriteLine();

            Console.WriteLine("Press any key...");

            Console.ReadKey();

        }

    }

}

 

=변환이 잘 됫네요~

 

***당부의 말***

만들려고 하는 Torrent Tracker 프로젝트 목표는 이거에요

è 어떤 토렌트가, 어떤 Peer에 의해 , 어디서 공유되고 있는지 관찰한다

그 첫번째가 바로 Tracker 응답 분석이에요! 그래서 Tracker를 읽을수 있으면

l   현재 참여 Peer

l   Peer IP

l   Peer Port

l   토렌트 활성도

를 수집할수 있답니다! 그래서 지금까지 두 번의 실습이 문자열 파싱이나 바이트 데이터 해석 정도라서 "이게 뭐가 중요한 거지?" 라고 생각하실 수도 있습니다

하지만 실제 네트워크 프로그래밍에서는 데이터를 주고받는 것보다도, 받은 데이터를 정확하게 해석하는 과정이 훨씬 중요할 때가 많습니다

지금까지 만든 기능들은 모두 최종 목표인 Torrent Tracker를 구성하는 부품들입니다..

아직은 각각의 기능을 따로 살펴보고 있지만, 이후 글에서 하나씩 연결하다 보면 결국 하나의 프로그램으로 완성되는 모습을 보실 수 있을 거에요

Res – Tracker that tracks torrents used in North Korea - Part - 3

Sub Topic - EP.03 - What is inside a Magnet Link?

===== Intro =====

1.     제 나름대로 구상한 방식입니다

2.     막히면 돌아가고 깊이가 방대하면 포기하고 다음으로!

3.     구성 : 토픽 기반기술 학습 기반기술 기반 실습(되는데로..) – 최종 프로젝트

 

===== Overall story =====

1.     1 = 북한 ip의 구성

2.     2 = Torrent 이용중 IP 동작

3.     3 = 마그넷 링크를 뜯어보고 토렌트가 무엇으로 파일을 식별하는지 이해

 

Step – 0

== 토렌트 파일(.torrent) 없이도 다운로드가 시작되는 이유는 뭘까?

지난시간에 토렌트 네트워크의 동작을 알아보았죠? 토렌트에 참여하는 Peer들은 서로 직접 연결되어 이 과정에서 IP 주소가 노출될 수 있다~ 이말이죠 (심연을 오래 들여다보면 심연 또한 그대를 들여다 본다는~)

그럼 이때 의문이 듭니다!(너만 그렇다..) 토렌트 파일 없이도 다운로드가 가능한 이유는 뭐지? (실제로 많은 토렌트 사이트에서 .Torrent 파일대신 Magnet Link 만 제공합니다)

실험을 위해 Torrent Ubuntu Linux Torrent 를 가지고 실험합니다~

(Torrent사이트에서 제공하는 파일 다운로드와 마그넷, 우측은 실험을 위해 만든 토렌트)

****Torrent 자체는 불법이 아닙니다!! 토렌트로 공유되는 파일들이 저작권을 무시하고 공유되는 경우가 많아 불법으로 아시는 분들이 많은 것!! ****

 

일단 Magnet Link 를 분해해 보면 아래와 같이 생겼습니다

è magnet:?xt=urn:btih:dafc8c076ca2f3ed (중략)

è 얼핏 보면 알수 없는 문자열 같이 생겼지만 이 안에 토렌트 네트워크가 파일을 찾기 위해 필요한 중요한 정보들이 있습니다



(프리즘처럼 링크를 쪼개 보자)

 

Step – 1

== Magnet Link?

마그넷 링크란 이 파일의 정보는 이 해시(Hash)로 식별됩니다라고 알려주는 URL(Uniform Resource Identifier) 입니다, 웹페이지 주소가 특정 서버를 가리킨다면 마그넷 링크는 파일을 가리키죠

 

(어떤 값을 넣어도 정해진 길이의 문자열을 반환 하는 해시함수)

 

Step – 2

== Magnet Link 분석 시작

예제로 사용할 마그넷(ubuntu Linux 26.04 iso파일의 torrent입니다)

è magnet:?xt=urn:btih:dafc8c076ca2f3ed376eeae7c76a0d6be2415c45&dn=ubuntu-26.04-desktop-amd64.iso&xl=6518974464&tr=https%3A%2F%2Ftorrent.ubuntu.com%2Fannounce&tr=https%3A%2F%2Fipv6.torrent.ubuntu.com%2Fannounce

 

1.xt

è magnet:?xt=urn:btih:dafc8c076ca2f3ed376eeae7c76a0d6be2415c45&dn=ubuntu-26.04-desktop-amd64.iso&xl=6518974464&tr=https%3A%2F%2Ftorrent.ubuntu.com%2Fannounce&tr=https%3A%2F%2Fipv6.torrent.ubuntu.com%2Fannounce

=xtExact Topic 의 약자로 토렌트에서 보이는 형태는 urn:bith:INFOHASH 형태임

=이때 bith BitTorrent Info Hash 로 쉽게말하면 이 토렌트를 대표하는 고유 식별자

 

**InfoHash?**

토렌트 내부 파일의 info 딕셔너리를 해시한 값, 지금처럼 Unbuntu ISO 파일의 토렌트를 예를 들면 “SHA1 + 구조로 생성되어 전세계 모든 Peer 들은 이 값만 알고 있어도 같은 토렌트를 탐색이 가능함! 이를테면 토렌트 네트워크의 주민등록번호



(이런 느낌의 정보가 InfoHash~)

 

2.dn

è magnet:?xt=urn:btih:dafc8c076ca2f3ed376eeae7c76a0d6be2415c45&dn=ubuntu-26.04-desktop-amd64.iso&xl=6518974464&tr=https%3A%2F%2Ftorrent.ubuntu.com%2Fannounce&tr=https%3A%2F%2Fipv6.torrent.ubuntu.com%2Fannounce

=dn Display Name 의 약자로 사용자 화면에 표시될 파일 이름, dn은 없어도 작동할수있음, 실제 핵심 정보는 InfoHash 이다

 

3.tr

è magnet:?xt=urn:btih:dafc8c076ca2f3ed376eeae7c76a0d6be2415c45&dn=ubuntu-26.04-desktop-amd64.iso&xl=6518974464&tr=https%3A%2F%2Ftorrent.ubuntu.com%2Fannounce&tr=https%3A%2F%2Fipv6.torrent.ubuntu.com%2Fannounce

=tr Tracker 로써 주소를 말함, 토렌트 클라이언트는 이 주소로 접속하여 이 해시를 가진 Peer 목록을 알려달라라고 요청하면 Tracker 가 응답으로 Peer 정보를 반환한다

 

**Tracker없어도 다운로드 되는데?**

요즘 토렌트는 DHT, PEX, Local Peer Discovery 기능을 사용함, 따라서 Tracker 가 없거나 최소한만 포함되는 경우도 많음!

 

Step – 3

== Torrent Tracker 관점에서 중요한건?

그래서 만들려는 Torrent Tracker는 결국 InfoHash를 중심으로 동작하고 추적의 목표인 누가 어떤 토렌트에 참여하고 있는가를 추적하려면 먼저 어떤 InfoHash를 감시할건가?” 라는 것을 정해야 하기 때문임!

 

즉 정리하면 추적의 흐름을 정리하면 이렇게 된다

è Magnet Link -> InfoHash 추출 -> Peer 탐색 -> IP 수집

 

(순서대로 만들어야 한다~)

 

Step – 4

==다음화 예고 - Tracker 서버는 Peer 목록을 어떻게 알려줄까?

l   Announce 요청

l   Bencode

l   Peer List

l   Compact Peer Format

l   Tracker 통신 분석

l   C#으로 Tracker 응답 파싱하기

 

여기까지 진행하면 드디어 "토렌트 참여자(IP)를 실제로 수집하는 원리"에 본격적으로 들어가게 됩니당~

 

===== 실습 =====

=C# 콘솔 프로그램으로 진행

==Magnet Link 파싱하는 프로그램을 만들어보자(Ex_3_Magnet_Parser)

 

using System;

using System.Web;

 

class Program

{

    static void Main()

    {

        Console.WriteLine("Magnet Link 입력:");

        string magnet = Console.ReadLine();

 

        Uri uri = new Uri(magnet);

 

        var query = HttpUtility.ParseQueryString(uri.Query);

 

        string xt = query["xt"];

        string dn = query["dn"];

        string tr = query["tr"];

 

        string infoHash = "";

 

        if (!string.IsNullOrEmpty(xt))

        {

            int idx = xt.LastIndexOf(':');

 

            if (idx >= 0)

                infoHash = xt.Substring(idx + 1);

        }

 

        Console.WriteLine();

        Console.WriteLine("=== 분석 결과 ===");

        Console.WriteLine($"InfoHash   : {infoHash}");

        Console.WriteLine($"DisplayName: {dn}");

        Console.WriteLine($"Tracker    : {tr}");

    }

}

 

Ubuntu iso Torrent 로 실험해 봅시다

ubuntu-26.04-desktop-amd64.iso

 

ubuntu-26.04-live-server-amd64.iso