Zpět na domů

Traceroute na Rustu: jak funguje trasování trasy

Článek rozkládá implementaci traceroute na Rustu. Ukázáno, jak TTL a ICMP zprávy staví mapu trasy. Uveden kód s vysvětlením práce raw soketů a zpracování síťových paketů.

Jak traceroute staví trasu: technická analýza na Rustu
Advertisement 728x90

# Jak funguje Traceroute: implementace v Rustu od nuly

Traceroute je nástroj pro síťovou diagnostiku, který odhaluje cestu paketů přes internet. Jeho fungování je založeno na dvou klíčových mechanismech: TTL (doba životnosti) v IP hlavičkách a ICMP zprávách o chybách. Při postupném zvyšování TTL na každém kroku vracejí směrovače upozornění na překročení doby životnosti paketu a vytvářejí tak mapu trasy. Implementace vlastní verze v Rustu za 80 řádků kódu ukazuje, jak se nízkourovňové síťové operace stávají srozumitelnými při hlubokém ponoru do protokolů.

Architektura UDP sondy

Klíčovým prvkem fungování traceroute je cílené odesílání paketů s omezeným TTL. K tomu se používá UDP protokol místo TCP z tří důvodů:

  • Absence handshake snižuje réžii
  • Žádná záruka doručení — pakety mají být ztraceny
  • Vysoká čísla portů (začínající 33434) minimalizují konflikty s běžícími službami

Kód inicializuje dva sockety:

Google AdInline article slot
let send_sock = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;
send_sock.set_ttl_v4(ttl)?;

let recv_sock = Socket::new(
    Domain::IPV4,
    Type::from(libc::SOCK_RAW),
    Some(Protocol::ICMPV4),
)?;

První socket odesílá „smrtící“ pakety s daným TTL, druhý zachytává ICMP odpovědi. Důležité: raw socket vyžaduje práva roota, protože pracuje na úrovni síťového zásobníku.

Parsování ICMP odpovědí

Když směrovač zahodí paket při TTL=0, pošle ICMP zprávu typu 11 (překročení času). Struktura dat obsahuje:

  • Prvních 20 bajtů — IP hlavička odpovědi
  • Bajty 12-15 — IP adresa směrovače
  • Bajt 20 — typ ICMP zprávy

Počáteční implementace analyzovala jen IP adresu:

Google AdInline article slot
if buf.len() >= 20 {
    let ip = Ipv4Addr::new(buf[12], buf[13], buf[14], buf[15]);
    Ok(Some(ip))
}

To vedlo k chybám v určení koncového bodu. Správné zpracování vyžaduje kontrolu typu ICMP:

match buf[20] {
    11 => Ok(ProbeResult::Hop(ip)),
    3 if ip == target => Ok(ProbeResult::Reached(ip)),
    3 => Ok(ProbeResult::Hop(ip)),
    _ => Ok(ProbeResult::Timeout),
}

Typ 3 (cíl nedosažitelný) indikuje dosažení cíle jen při shodě IP adresy.

Optimalizace trasování

Původní traceroute používá dvě techniky chybějící v základní implementaci:

Google AdInline article slot
  • Inkrementální číslo portu — každý další paket se odesílá na port +1. To umožňuje jednoznačně přiřadit ICMP odpovědi k požadavkům díky poli Identification v UDP hlavičce.
  • Podpora TCP režimu — při blokování UDP firewally se používá SYN paket s nízkým TTL. Mechanismus detekce hopů zůstává stejný.

Kritická chyba v raných verzích kódu spočívala v ignorování kontroly IP adresy při typu 3. Bez podmínky if ip == target se trasování zastavilo na prvním směrovači vracejícím cíl nedosažitelný.

Co je důležité

  • TTL jako nástroj kontroly — postupné zvyšování hodnoty umožňuje objevovat každý hop postupně
  • ICMP zprávy — základ diagnostiky — překročení času (typ 11) a cíl nedosažitelný (typ 3) tvoří mapu trasy
  • Raw sockety vyžadují privilegia — práce s nízkourovňovými síťovými operacemi není možná bez práv roota
  • UDP vs TCP — volba protokolu ovlivňuje obcházení firewallů, ale ne základní algoritmus
  • Parsování binárních dat — přímý přístup k bajtům paketu vyžaduje znalost struktury IP/ICMP hlaviček

Implementace podmínky zastavení

Klíčové zlepšení je správné určení dosažení cíle. Výčet ProbeResult nahrazuje jednoduchý Option<Ipv4Addr>:

enum ProbeResult {
    Hop(Ipv4Addr),
    Reached(Ipv4Addr),
    Timeout,
}

V hlavní smyčce zpracování výsledku vypadá takto:

match hop {
    ProbeResult::Hop(ip) => println!("{:>2}  {}", ttl, ip),
    ProbeResult::Reached(ip) => {
        println!("{:>2}  {}", ttl, ip);
        break;
    }
    ProbeResult::Timeout => println!("{:>2}  *", ttl),
}

To zajišťuje zastavení trasování při dosažení cílového hosta, ne podle timeoutu. V reálných podmínkách je nutné přidat:

  • Tři sondy na každý TTL pro statistiku zpoždění
  • Zpracování fragmentovaných paketů
  • Podporu IPv6
  • Timeauty v závislosti na vzdálenosti k cíli

Závěry a omezení

Vytvořená implementace demonstruje jádro traceroute, ale má omezení:

  • Nezohledňuje asymetrické trasy
  • Nezpracovává ICMP Rate Limiting
  • Ignoruje MPLS tagy v moderních sítích
  • Vyžaduje práva superuživatele

Pro produkční řešení doporučujeme knihovny jako pnet_packet, které se vyhýbají manuálnímu parsování bajtů. Přesto je napsání „syrové“ verze nejlepší cestou k pochopení síťových základů. Každý síťový inženýr by si měl traceroute alespoň jednou implementovat sám, aby pochopil, jak data putují internetem.

— Editorial Team

Advertisement 728x90

Číst dál