Kathará is a container-based network emulator developed by researchers at Roma Tre University in Italy as a modern successor to the Netkit network emulator. Coincidentally, Roma Tre University is also the same organization that developed BGPlay, a tool used to investigate BGP incidents.
Kathará uses Docker containers to emulate network devices. This approach enables users to create complex network topologies comprised of dozens of routers on a modest laptop. Kathará uses simple text-based configuration files that are easy to version-control and share. It’s open source, actively maintained, and runs on Linux, Windows, and MacOS.
In this post, I will use the Kathará network emulator to recreate one of the most famous BGP hijacking incidents in Internet history, the 2008 YouTube hijack. By building a small network topology and simulating a similar attack, we will learn both the fundamentals of Kathará and to gain hands-on experience with BGP security concepts.
Install Kathará
First, we will install the Kathará network emulator and test it by setting up a basic lab environment.
Install Docker
Kathará uses Docker as its container runtime. Install Docker on your Linux system using the official Docker installation guide.
After that, add your user to the docker group so you can run containers without sudo:
$ sudo usermod -aG docker $USER
Log out and log back in for the group change to take effect. Verify Docker is working:
$ docker run hello-world
You should see a message confirming Docker is installed correctly.
Install Kathará
The install instructions on the Kathará wiki are outdated[^1] and do not work in Ubuntu 24.04 because they use the deprecated apt-key command. You can skip the apt-key command. Instead, follow the Kathara instructions on the Launchpad platform to add the Kathará PPA to Ubuntu, then install Kathará.
I summarize the modified install commands, below:
$ sudo add-apt-repository ppa:katharaframework/kathara
$ sudo apt update
$ sudo apt install kathara
Verify the installation:
$ kathara --version
You should see output showing the Kathará version, which was 3.8.0 when I wrote this post.
Verify Your Setup
Run a the check command to proactively download the Kathará base container and the Kathará network plugin container, and validate that Kathará can communicate with Docker:
$ kathara check
With your environment ready, we can move on to configuring Kathará.
Set the Terminal Emulator
Run the kathara settings command and set the terminal emulator used by emulated devices to be the Gnome Terminal. Alternatively, you could install xterm, because it is the default used by Kathará.
$ kathara settings
In the menu that appears, select 5, for Choose terminal:
╔═════════════════════════════════════════════════════════════════════════╗
║ ║
║ Kathara Settings ║
║ ║
╠═════════════════════════════════════════════════════════════════════════╣
║ ║
║ Choose the option to change. ║
║ ║
╠═════════════════════════════════════════════════════════════════════════╣
║ ║
║ 1 - Choose default manager ║
║ 2 - Choose default image ║
║ 3 - Automatically open terminals on startup ║
║ 4 - Choose device shell to be used ║
║ 5 - Choose terminal emulator to be used ║
║ 6 - Choose Kathara prefixes ║
║ 7 - Choose logging level to be used ║
║ 8 - Print Startup Logs on device startup ║
║ 9 - Enable IPv6 ║
║ 10 - Choose Docker Network Plugin version ║
║ 11 - Automatically mount /hosthome on startup ║
║ 12 - Automatically mount /shared on startup ║
║ 13 - Docker Image Update Policy ║
║ 14 - Enable Shared Collision Domains ║
║ 15 - Configure a remote Docker connection ║
║ 16 - Exit ║
║ ║
║ ║
╚═════════════════════════════════════════════════════════════════════════╝
>> 5
Then, choose 2, to select gnome-terminal:
╔═════════════════════════════════════════════════════════════════════════╗
║ ║
║ Choose terminal emulator to be used ║
║ ║
║ Current: /usr/bin/xterm ║
║ ║
╠═════════════════════════════════════════════════════════════════════════╣
║ ║
║ Terminal emulator application to be used for device terminals. ║
║ **The application must be correctly installed in the host system!** ║
║ Default is `/usr/bin/xterm`. ║
║ ║
╠═════════════════════════════════════════════════════════════════════════╣
║ ║
║ 1 - /usr/bin/xterm ║
║ 2 - /usr/bin/gnome-terminal ║
║ 3 - TMUX ║
║ 4 - Choose another terminal emulator ║
║ 5 - Return to Kathara Settings ║
║ ║
║ ║
╚═════════════════════════════════════════════════════════════════════════╝
>> 2
Then select 16 to Exit.
Pull the FRR Docker Image
We’ll use the kathara/frr Docker image, which includes FRRouting, an open-source routing suite that supports BGP, OSPF, and other protocols. Pull it now to save time later:
$ docker pull kathara/frr
Test a very simple lab
To verify that Kathará is working, and to get an initial view of how Kathara labs are created and nodes are configured, let’s create a minimal lab with two FRR routers connected to each other and test connectivity between them.
First, create a directory for your test lab:
$ mkdir -p ~/Kathara/kathara-test
$ cd ~/Kathara/kathara-test
Create the lab.conf file that defines two routers connected by a shared network segment:
$ cat > lab.conf << 'EOF'
LAB_NAME="Simple Two-Router Test"
r1[0]="link1"
r1[image]="kathara/frr"
r2[0]="link1"
r2[image]="kathara/frr"
EOF
Create startup scripts to assign IP addresses to each router:
$ cat > r1.startup << 'EOF'
ip addr add 10.0.0.1/24 dev eth0
ip link set eth0 up
EOF
$ cat > r2.startup << 'EOF'
ip addr add 10.0.0.2/24 dev eth0
ip link set eth0 up
EOF
The lab directory should now contain:
kathara-test/
├── lab.conf
├── r1.startup
└── r2.startup
Start the lab:
$ kathara lstart
Kathara reads the lab.conf file and the two startup files to set up and configure the lab. You should see output indicating both routers have started:
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Starting Network Scenario │
└─────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Name: Simple Two-Router Test │
└─────────────────────────────────────────────────────────────────────────────────────┘
[Deploying collision domains] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/1
[Deploying devices] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2/2
And, you should see two new terminal windows. Each one is connected to one of the routers in the lab. By default, Kathara starts terminals with the Bash shell.
Inside the r1 container’s terminal window, ping r2’s IP address:
root@r1:/# ping -c2 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.995 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=1.08 ms
--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.995/1.038/1.081/0.043 ms
root@r1:/#
We demonstrated that a simple lab with two routers works as expected. Clean up the lab:
$ kathara lclean
This removes all containers and networks created for the lab.
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Stopping Network Scenario │
└─────────────────────────────────────────────────────────────────────────────────────┘
[Deleting devices] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2/2
[Deleting collision domains] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/1
With Kathará working correctly, we’re ready to build more complex topologies.
Understanding BGP Hijacks and Route Leaks
BGP hijacks and route leaks are among the most significant threats to Internet routing security. Understanding how these incidents occur helps network engineers implement proper safeguards. By recreating these scenarios in a safe, isolated lab environment, one can observe exactly how prefix hijacks propagate through a network and experiment with mitigation techniques without affecting real infrastructure.
Origin Hijack
An origin hijack occurs when an AS announces a prefix it doesn’t legitimately own. The hijacking AS claims to be the origin of the route, essentially saying “I own this IP address range” when it doesn’t.
For example, if AS400 legitimately owns the prefix 40.40.0.0/16, an origin hijack would occur if AS300 started announcing that same prefix as if it originated there. Routers receiving both announcements would choose between them based on BGP path selection rules. Depending on network topology, some parts of the Internet might start sending traffic for 40.40.0.0/16 toward AS300 instead of the legitimate owner, AS400.
More-Specific Prefix Hijack
More-specific prefix hijack is a variant of origin hijacking. Instead of announcing the same prefix as the victim, the attacker announces a more-specific, or longer, prefix that falls within the victim’s address space.
BGP routers always prefer more-specific routes. If AS400 announces 40.40.0.0/16 and an attacker announces 40.40.0.0/17 and 40.40.128.0/17, the attacker’s more-specific /17 routes will be preferred everywhere in the Internet, completely overriding the legitimate /16 announcement.
Route Leak
A route leak occurs when an AS violates the expected routing policies by redistributing routes in ways that break the traditional customer-provider-peer relationships on the Internet. Unlike origin hijacks or more-specific prefix hijacks, the origin AS information remains correct. The problem is that the route is propagated where it shouldn’t be.
Route leaks are almost always accidental and are usually caused by misconfiguration, but their effects can be severe. When a small customer AS suddenly appears to offer a shortcut to major networks, traffic can flood through infrastructure that was never designed to handle it.
The 2008 Pakistan YouTube Hijack
The incident we’ll recreate is the famous YouTube hijacking that occurred on February 24, 2008, when Pakistan Telecom (AS17557) accidentally blocked YouTube globally. This event has become a textbook example of how BGP vulnerabilities can have worldwide impact and is well-documented by RIPE NCC and other organizations.
The key players were:
- YouTube (AS36561): The victim, legitimately announcing prefix 208.65.152.0/22
- Pakistan Telecom (AS17557): The hijacker, who announced the more-specific prefix 208.65.153.0/24
- PCCW (AS3491): Pakistan Telecom’s upstream provider who propagated the hijack
- Various upstream providers: Who received and further propagated the bogus route
What Happened
The Pakistan government ordered local ISPs to block access to YouTube due to content the government deemed offensive. Pakistan Telecom attempted to comply by creating a blackhole route for a more specific prefix that was part of YouTube’s allocated IP address space. However, instead of keeping this route prefix internal to their own network, they accidentally announced it to the global Internet through their upstream provider PCCW (AS3491).
YouTube was announcing their address space as a /22 prefix (208.65.152.0/22), which covers IP addresses from 208.65.152.0 to 208.65.155.255. Pakistan Telecom announced a /24 prefix (208.65.153.0/24), which is a subset of YouTube’s range.
BGP’s “longest prefix match” rule means routers always prefer more-specific routes. A /24 prefix is more specific than a /22, so routers receiving both announcements would send traffic for 208.65.153.0/24 toward Pakistan Telecom where it was blackholed. This affected global YouTube traffic because PCCW propagated the announcement to their peers and transit providers, who propagated the more-specific prefixes worldwide.
YouTube responded to the attack by announcing even-more-specific prefixes 208.65.153.128/25 and 208.65.153.0/25. Routers that received these announcements would have preferred the more-specific prefix and sent the traffic to YouTube. Eventually, PCCW properly resolved the problem by filtering the offending route.
This incident represents a straightforward BGP hijack with no other complications like AS-path manipulation. It demonstrates both the attack and the mitigation so it is a good BGP security example to study in a lab.
Kathará BGP Lab Setup
When you start a lab, Kathará reads the lab configuration files in the lab folder, creates Docker containers for each device, and sets up virtual network interfaces to connect them. The Kathará man pages provide information about how to use the command line interface and the Kathará Lab man pages provide information about building lab configuration files.
The kathara/frr image we pulled earlier contains FRRouting, which enables us to create fully-featured routers capable of running BGP, OSPF, IS-IS, and other routing protocols. Kathará also provides base images for simple hosts, and you can use other Kathará device images or any other Docker image that suits your needs.
What We’ll Build
In our lab, we’ll create a simplified 4-AS topology that will help us emulate this incident:
+----------+
| upstream |
| AS400 |
+----+-----+
|
| 10.0.3.0/24
|
+----+-----+
| transit |
| AS300 |
+----+-----+
/ \
10.0.1.0/24 / \ 10.0.2.0/24
/ \
+-----+----+ +-----+-----+
| youtube | | pakistan |
| AS100 | | AS200 |
+----------+ +-----------+
(Victim) (Hijacker)
In this topology:
- AS100 (YouTube) is the victim, legitimately announcing 100.100.0.0/22
- AS200 (Pakistan Telecom) is the hijacker, who will announce a more-specific 100.100.0.0/24
- AS300 (Transit/PCCW) is the transit provider connecting both ASes to the Internet
- AS400 (Upstream) represents upstream providers who observe the hijack propagation
We’ll first configure this topology during normal BGP operations where only AS100 announces its prefix. Then we’ll introduce the hijack by having AS200 announce a more-specific prefix, and observe how it overrides the legitimate route. Finally, we’ll demonstrate how AS100 can counter the hijack using even more-specific announcements.
Lab Structure
As you saw in our simple test, above, a Kathará lab is simply a directory containing configuration files that describe your network topology and configuration. The lab file and directory structure is straightforward. The lab.conf file is mandatory. Other files or folders are optional.
| File/Directory | Purpose |
|---|---|
| lab.conf | Main configuration file that defines devices and network connections |
| lab.dep | Optional network scenario dependencies defines the order in which devices start |
| lab.ext | Optional direct connections between virtual lab devices and physical host interfaces |
| <device>/ | Directory for each device containing configuration files (optional) |
| <device>.startup | Shell script that runs when a device starts (optional) |
Lab Configuration File Syntax
The best way to learn the lab configuration file syntax is to look at the example labs provided by the Kathará team.
If you want to see all options that are available, the Kathará team provides man-pages documentation for the syntax of each lab configuration file. See the links below:
- lab.conf: mandatory configuration file syntax manual
- lab.dep: optional configuration file syntax manual
- lab.ext: optional configuration file syntax manual
Device Directories and Lab Structure
For each device in your lab, you will usually create a directory with the same name. Files in this directory are copied into the container’s filesystem when the lab starts. This is how you provide configuration files to your devices.
In this lab example, you will create a directory structure like the one shown below:
bgp-youtube-hijack/
├── lab.conf
├── youtube/
│ └── etc/
│ └── frr/
│ ├── daemons
│ └── frr.conf
├── youtube.startup
├── pakistan/
│ └── etc/
│ └── frr/
│ ├── daemons
│ └── frr.conf
├── pakistan.startup
├── transit/
│ └── etc/
│ └── frr/
│ ├── daemons
│ └── frr.conf
├── transit.startup
├── upstream/
│ └── etc/
│ └── frr/
│ ├── daemons
│ └── frr.conf
└── upstream.startup
The contents of youtube/etc/frr/ will appear at /etc/frr/ inside the youtube container. This allows you to pre-configure FRR’s routing daemons with the required BGP settings.
BGP Lab Config File
To emulate a small network in which we can “replay” the famous YouTube BGP Hijack incident, we create a lab.conf file that creates four routers connected as shown in the diagram above.
First, create the lab directory
$ mkdir -p ~/Kathara/bgp-youtube-hijack
$ cd ~/Kathara/bgp-youtube-hijack
Create the lab.conf file in your favorite editor and enter the following configuration information:
# ~/bgp-youtube-hijack/lab.conf
LAB_NAME="YouTube BGP Hijack 2008"
LAB_DESCRIPTION="This lab recreates the famous February 24, 2008 incident where Pakistan Telecom (AS17557) hijacked YouTube's traffic by announcing a more-specific prefix within YouTube's allocated IP address space."
LAB_VERSION=1.0
# YouTube (Victim) - AS100
youtube[0]="link_youtube_transit"
youtube[image]="kathara/frr"
# Pakistan Telecom (Hijacker) - AS200
pakistan[0]="link_pakistan_transit"
pakistan[image]="kathara/frr"
# Transit/PCCW - AS300
transit[0]="link_youtube_transit"
transit[1]="link_pakistan_transit"
transit[2]="link_transit_upstream"
transit[image]="kathara/frr"
# Upstream Observer - AS400
upstream[0]="link_transit_upstream"
upstream[image]="kathara/frr"
The syntax follows a simple pattern: device[interface]="collision_domain", where “collision domain” is simply the name you assign a network segment. All devices with interfaces on the same network segment can communicate directly with each other.
The device[image] property specifies which Docker image to use for each device. In this example, we are using the kathara/frr image for all routers, but you could use different images like kathara/bird or vyos, if you wish.
IP Addressing Scheme
Before we configure the routers, we must first establish the IP addressing plan:
| Link | Network | Device | Interface | IP Address |
|---|---|---|---|---|
| YouTube to Transit | 10.0.1.0/30 | youtube | eth0 | 10.0.1.1/30 |
| transit | eth0 | 10.0.1.2/30 | ||
| Pakistan to Transit | 10.0.2.0/30 | pakistan | eth0 | 10.0.2.1/30 |
| transit | eth1 | 10.0.2.2/30 | ||
| Transit to Upstream | 10.0.3.0/30 | transit | eth2 | 10.0.3.1/30 |
| upstream | eth0 | 10.0.3.2/30 |
Loopback addresses
Each AS router will have one or two loopback addresses that are reachable within its advertised prefix. The loopback addresses and announced prefixes for this hijack scenario will be:
| AS | Role | Loopback | Announced Prefix |
|---|---|---|---|
| AS100 (YouTube) | Victim | 100.100.0.1/32<br>100.100.1.1/32 | 100.100.0.0/22 (the /22 aggregate) |
| AS200 (Pakistan) | Hijacker | 200.200.0.1/32 | 100.100.0.0/24 (hijacked more-specific) |
| AS300 (Transit) | PCCW | 30.30.0.1/32 | 30.30.0.0/16 |
| AS400 (Upstream) | Observer | 40.40.0.1/32 | 40.40.0.0/16 |
Notice that YouTube announces 100.100.0.0/22 while Pakistan will announce 100.100.0.0/24, which is a more-specific prefix within YouTube’s range, after we trigger the hijack.
FRR Daemons Configuration
Each router needs a daemons file to tell FRR which routing protocols to enable. Create the directory structure and daemons file for each device. The content is identical for all routers:
$ mkdir -p youtube/etc/frr
$ mkdir -p pakistan/etc/frr
$ mkdir -p transit/etc/frr
$ mkdir -p upstream/etc/frr
Create the daemons file for each router. Here’s the content, which is the same for all four:
For the YouTube router, create the daemons file. In this lab scenario, the /etc/frr/daemons file copied to each router will contain the following configuration:
# /etc/frr/daemons
zebra=yes
bgpd=yes
vtysh_enable=yes
zebra_options=" -A 127.0.0.1 -s 90000000"
bgpd_options=" -A 127.0.0.1"
Save this content to:
- youtube/etc/frr/daemons
- pakistan/etc/frr/daemons
- transit/etc/frr/daemons
- upstream/etc/frr/daemons
frr.conf Files
Each router is pre-configured with an frr.conf file.
YouTube Configuration (AS100) — The Victim
The following FRR configuration file sets up BGP with AS number 100, representing YouTube’s AS36561, peers with Transit at 10.0.1.2 (AS300), and announces the 100.100.0.0/16 prefix, representing YouTube’s 208.65.152.0/22.
Create youtube/etc/frr/frr.conf:
frr version 9.1
frr defaults traditional
hostname youtube
log syslog informational
no ipv6 forwarding
service integrated-vtysh-config
!
interface eth0
ip address 10.0.1.1/24
description Link to Transit
exit
!
interface lo
ip address 100.100.0.1/32
ip address 100.100.1.1/32
description Loopbacks - within announced /22 prefix
exit
!
router bgp 100
bgp router-id 100.100.0.1
no bgp ebgp-requires-policy
neighbor 10.0.1.2 remote-as 300
neighbor 10.0.1.2 description Transit-PCCW
address-family ipv4 unicast
network 100.100.0.0/22
neighbor 10.0.1.2 activate
exit-address-family
exit
!
ip route 100.100.0.0/22 blackhole
!
end
This lab scenario, YouTube is the legitimate owner of the 100.100.0.0/22 prefix.
Pakistan Telecom Configuration (AS200) — The Hijacker
Initially, Pakistan Telecom will NOT announce the hijacked prefix. We’ll add that later to demonstrate the hijack. For now, it only announces its own legitimate prefix.
Create pakistan/etc/frr/frr.conf:
frr version 9.1
frr defaults traditional
hostname pakistan
log syslog informational
no ipv6 forwarding
service integrated-vtysh-config
!
interface eth0
ip address 10.0.2.2/24
description Link to Transit
exit
!
interface lo
ip address 200.200.0.1/32
description Loopback - within announced /16 prefix
exit
!
router bgp 200
bgp router-id 200.200.0.1
no bgp ebgp-requires-policy
neighbor 10.0.2.1 remote-as 300
neighbor 10.0.2.1 description Transit-PCCW
address-family ipv4 unicast
network 200.200.0.0/16
neighbor 10.0.2.1 activate
exit-address-family
exit
!
ip route 200.200.0.0/16 blackhole
!
end
Transit/PCCW Configuration (AS300)
Transit represents PCCW (AS3491), the provider that connected both YouTube and Pakistan Telecom and inadvertently propagated the hijack. It peers with all three other ASes and provides transit.
Create transit/etc/frr/frr.conf:
frr version 9.1
frr defaults traditional
hostname transit
log syslog informational
no ipv6 forwarding
service integrated-vtysh-config
!
interface eth0
ip address 10.0.1.2/24
description Link to YouTube
exit
!
interface eth1
ip address 10.0.2.1/24
description Link to Pakistan
exit
!
interface eth2
ip address 10.0.3.1/24
description Link to Upstream
exit
!
interface lo
ip address 30.30.0.1/32
description Loopback - within announced /16 prefix
exit
!
router bgp 300
bgp router-id 30.30.0.1
no bgp ebgp-requires-policy
!
neighbor 10.0.1.1 remote-as 100
neighbor 10.0.1.1 description YouTube
!
neighbor 10.0.2.2 remote-as 200
neighbor 10.0.2.2 description Pakistan-Telecom
!
neighbor 10.0.3.2 remote-as 400
neighbor 10.0.3.2 description Upstream
!
address-family ipv4 unicast
network 30.30.0.0/16
neighbor 10.0.1.1 activate
neighbor 10.0.2.2 activate
neighbor 10.0.3.2 activate
exit-address-family
exit
!
ip route 30.30.0.0/16 blackhole
!
end
Note that Transit has no outbound filtering—it simply propagates all routes it learns. This is the configuration weakness that allowed the real-world hijack to spread globally.
Upstream Configuration (AS400)
Upstream represents the broader Internet—a provider that will receive and observe routes from Transit. This is where we’ll see the hijack propagate.
Create upstream/etc/frr/frr.conf:
frr version 9.1
frr defaults traditional
hostname upstream
log syslog informational
no ipv6 forwarding
service integrated-vtysh-config
!
interface eth0
ip address 10.0.3.2/24
description Link to Transit
exit
!
interface lo
ip address 40.40.0.1/32
description Loopback - within announced /16 prefix
exit
!
router bgp 400
bgp router-id 40.40.0.1
no bgp ebgp-requires-policy
neighbor 10.0.3.1 remote-as 300
neighbor 10.0.3.1 description Transit-PCCW
address-family ipv4 unicast
network 40.40.0.0/16
neighbor 10.0.3.1 activate
exit-address-family
exit
!
ip route 40.40.0.0/16 blackhole
!
end
Startup Files
The <device>.startup file is a shell script that runs inside the container when it starts. This is where you configure network interfaces, start services, or run any initialization commands.
How Kathará Creates Ethernet Interfaces
Before each node’s startup script runs, Kathará creates network interfaces on each node based on the lab.conf file. So, to avoid conflicts or weird behaviour, we should not create interfaces in the device startup files or by copying network interface configuration files into the node container.
When the kathara lstart command is run, Kathará creates the Docker container for a node, creates virtual ethernet interfaces like eth0, eth1, etc. and attaches them to the container, connects each interface to the specified collision domain (virtual network bridge), and then runs the node’s startup script.
The interfaces exist and are in “DOWN” state when your startup script begins.
Interface Naming Convention
The Ethernet device numbering convention matches the numbers defines in the lab.conf file. For example, the Transit router’s interfaces would be mapped from teh configuration file to the container as follows:
- transit[0] = eth0
- transit[1] = eth1
- transit[2] = eth2
youtube.startup
Create the file youtube.startup and add the following startup commands:
#!/bin/bash
ip link set eth0 up
/etc/init.d/frr start
Save the file in the lab directory, ~/bgp-youtube-hijack/.
The startup file executes after the device directory contents are copied into the container, so you can reference any configuration files you’ve provided.
pakistan.startup
Create pakistan.startup:
#!/bin/bash
ip link set eth0 up
/etc/init.d/frr start
transit.startup
Create transit.startup:
#!/bin/bash
ip link set eth0 up
ip link set eth1 up
ip link set eth2 up
/etc/init.d/frr start
upstream.startup
Create upstream.startup:
#!/bin/bash
ip link set eth0 up
/etc/init.d/frr start
Ready to start
Now we have a Kathará lab directory that contains a lab.conf file, router startup files, and sub-directories containing the configuration files for each router. We are ready to use the Kathará command-line interface.
Kathará Command Line Interface
Kathará provides a simple set of commands to manage your labs. Here are the ones you’ll use most often:
Starting the Lab
To start a lab, navigate to the lab directory and run:
$ kathara lstart
Kathará reads lab.conf, creates the necessary containers and networks, and executes each device’s startup script. You’ll see output as each device comes online:
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Starting Network Scenario │
└─────────────────────────────────────────────────────────────────────────────────────┘
[Deploying collision domains] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3/3
[Deploying devices] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4/4
You will also see four terminal windows appear. each one is connected to a different router in the lab.
Connecting to a Device
If you closed a router’s terminal window, you can open another terminal session on a running device. Open a terminal window and enter the command:
$ kathara connect router1
This drops you into a shell inside the router container where you can run commands, check routing tables, or configure the device interactively. To exit, type exit or press Ctrl+D.
Checking Lab Status
To see information about a running lab:
$ kathara linfo
This displays details about all running devices, their interfaces, and which collision domains they’re connected to.
┌──────────────────────┬──────────┬─────────────────────┬─────────┬────────────────────┬──────┬───────────┬─────────────────────┬─────────────┬───────────────────┬──────────────────────┐
│ NETWORK SCENARIO ID │ NAME │ USER │ STATUS │ IMAGE │ PIDS │ CPU USAGE │ MEM USAGE │ MEM PERCENT │ NET USAGE │ INTERFACES │
╞══════════════════════╪══════════╪═════════════════════╪═════════╪════════════════════╪══════╪═══════════╪═════════════════════╪═════════════╪═══════════════════╪══════════════════════╡
│ GBhCCLpizE6xM9yUZKj… │ pakistan │ blinklet-hlipcf4s0… │ running │ kathara/frr:latest │ 17 │ 0.02% │ 22.77 MB / 62.55 GB │ 0.04 % │ 1.77 KB / 1.66 KB │ 0:link_pakistan_tra… │
├──────────────────────┼──────────┼─────────────────────┼─────────┼────────────────────┼──────┼───────────┼─────────────────────┼─────────────┼───────────────────┼──────────────────────┤
│ GBhCCLpizE6xM9yUZKj… │ youtube │ blinklet-hlipcf4s0… │ running │ kathara/frr:latest │ 17 │ 0.02% │ 22.75 MB / 62.55 GB │ 0.04 % │ 1.77 KB / 1.66 KB │ 0:link_youtube_tran… │
├──────────────────────┼──────────┼─────────────────────┼─────────┼────────────────────┼──────┼───────────┼─────────────────────┼─────────────┼───────────────────┼──────────────────────┤
│ GBhCCLpizE6xM9yUZKj… │ upstream │ blinklet-hlipcf4s0… │ running │ kathara/frr:latest │ 17 │ 0.03% │ 22.81 MB / 62.55 GB │ 0.04 % │ 1.77 KB / 1.66 KB │ 0:link_transit_upst… │
├──────────────────────┼──────────┼─────────────────────┼─────────┼────────────────────┼──────┼───────────┼─────────────────────┼─────────────┼───────────────────┼──────────────────────┤
│ GBhCCLpizE6xM9yUZKj… │ transit │ blinklet-hlipcf4s0… │ running │ kathara/frr:latest │ 17 │ 0.02% │ 24.87 MB / 62.55 GB │ 0.04 % │ 5.25 KB / 5.04 KB │ 0:link_youtube_tran… │
│ │ │ │ │ │ │ │ │ │ │ 1:link_pakistan_tra… │
│ │ │ │ │ │ │ │ │ │ │ 2:link_transit_upst… │
└──────────────────────┴──────────┴─────────────────────┴─────────┴────────────────────┴──────┴───────────┴─────────────────────┴─────────────┴───────────────────┴──────────────────────┘
Stopping and Cleaning Up
When you’re done with a lab, clean up all containers and networks:
$ kathara lclean
This stops and removes all containers created for the lab. Always run this before starting a modified version of your lab to ensure you’re working with a fresh environment.
With these fundamentals covered, you now understand how Kathará structures labs and how to interact with them.
In the next sections, we’ll use the virtual routers that have been created and interconnected by Kathará, as described in the lab.cong file and the router configuration files, to explore how the 2008 YouTube Hijack occurred and how it was mitigated.
Discover the Normal BGP State
First, we will establish the “normal” state of the lab. On each router, verify that the BGP sessions are established and YouTube’s prefix is being announced correctly to “upstream” systems.
Check Upstream (Observer)
We’ll start with Upstream since this is where we’ll observe the hijack’s effect. Connect and check the BGP table on the router named upstream. A terminal window connected to upstream should already be open on your desktop. If not, use Kathará’s connect command:
$ kathara connect upstream
The, start the FRR CLI, vtysh, and check BGP status:
root@upstream:/# vtysh
upstream# show ip bgp summary
You should see output showing the BGP session with Transit (AS300) is established:
IPv4 Unicast Summary (VRF default):
BGP router identifier 40.40.40.1, local AS number 400 vrf-id 0
BGP table version 4
RIB entries 7, using 672 bytes of memory
Peers 1, using 20 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
10.0.3.1 4 300 11 12 4 0 0 00:04:42 3 4 Transit-PCCW
Total number of neighbors 1
Check the BGP route table to see the routes:
upstream# show ip bgp
This is the crucial view. See below that:
- 100.100.0.0/22 is YouTube’s legitimate prefix, learned via AS path “300 100” (Transit → YouTube)
- 200.200.0.0/16 is Pakistan Telecom’s own prefix
- 30.30.0.0/16 is Transit’s prefix
BGP table version is 4, local router ID is 40.40.40.1, vrf id 0
Default local pref 100, local AS 400
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 10.0.3.1 0 0 300 i
*> 40.40.0.0/16 0.0.0.0 0 32768 i
*> 100.100.0.0/22 10.0.3.1 0 300 100 i
*> 200.200.0.0/16 10.0.3.1 0 300 200 i
Displayed 4 routes and 4 total paths
There is no more-specific /24 route for YouTube’s address space yet. This is the normal, pre-hijack state.
Check Transit
Verify Transit is properly peering with all neighbors. Use the terminal window connected to the transit router:
root@transit:/# vtysh
transit# show ip bgp summary
We see Transit BGP has three peers, as expected. Sessions are established with YouTube (AS100), Pakistan (AS200), and Upstream (AS400):
IPv4 Unicast Summary (VRF default):
BGP router identifier 30.30.30.1, local AS number 300 vrf-id 0
BGP table version 4
RIB entries 7, using 672 bytes of memory
Peers 3, using 60 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
10.0.1.1 4 100 15 15 4 0 0 00:08:59 1 4 YouTube
10.0.2.2 4 200 15 15 4 0 0 00:08:59 1 4 Pakistan-Telecom
10.0.3.2 4 400 15 15 4 0 0 00:08:59 1 4 Upstream
Total number of neighbors 3
Check the BGP route table to see the routes:
upstream# show ip bgp
See below that Transit is receiving:
- 1 prefix from Upstream (AS400): its 40.40.0.0/16
- 1 prefix from YouTube (AS100): the 100.100.0.0/22
- 1 prefix from Pakistan (AS200): its legitimate 200.200.0.0/16
BGP table version is 4, local router ID is 30.30.30.1, vrf id 0
Default local pref 100, local AS 300
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 0.0.0.0 0 32768 i
*> 40.40.0.0/16 10.0.3.2 0 0 400 i
*> 100.100.0.0/22 10.0.1.1 0 0 100 i
*> 200.200.0.0/16 10.0.2.2 0 0 200 i
Displayed 4 routes and 4 total paths
Check YouTube
Verify YouTube is properly peering with all neighbors.
root@youtube:/# vtysh
youtube# show ip bgp summary
We see YouTube BGP has one BGP peer, as expected. It has established a BGP session with Transit (AS300):
IPv4 Unicast Summary (VRF default):
BGP router identifier 100.100.100.1, local AS number 100 vrf-id 0
BGP table version 4
RIB entries 7, using 672 bytes of memory
Peers 1, using 20 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
10.0.1.2 4 300 40 41 4 0 0 00:33:25 3 4 Transit-PCCW
Total number of neighbors 1
Verify YouTube is announcing its prefix correctly:
root@youtube:/# vtysh
youtube# show ip bgp
As shown below, YouTube sees:
- Its own 100.100.0.0/22 (locally originated)
- Routes to other ASes via Transit
BGP table version is 4, local router ID is 100.100.100.1, vrf id 0
Default local pref 100, local AS 100
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 10.0.1.2 0 0 300 i
*> 40.40.0.0/16 10.0.1.2 0 300 400 i
*> 100.100.0.0/22 0.0.0.0 0 32768 i
*> 200.200.0.0/16 10.0.1.2 0 300 200 i
Displayed 4 routes and 4 total paths
Check Pakistan
Verify Pakistan is properly peering with all neighbors.
root@transit:/# vtysh
transit# show ip bgp summary
We see Pakistan BGP has established a BGP peering session with Transit:
IPv4 Unicast Summary (VRF default):
BGP router identifier 200.200.200.1, local AS number 200 vrf-id 0
BGP table version 4
RIB entries 7, using 672 bytes of memory
Peers 1, using 20 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
10.0.2.1 4 300 35 36 4 0 0 00:28:18 3 4 Transit-PCCW
Total number of neighbors 1
Check the BGP route table to see the routes:
pakistan# show ip bgp
See below that Pakistan is receiving:
- 1 prefix from Transit (AS300): its 30.30.0.0/16
- 1 prefix from Upstream (AS400): its 40.40.0.0/16
- 1 prefix from YouTube (AS100): the 100.100.0.0/22
BGP table version is 4, local router ID is 200.200.200.1, vrf id 0
Default local pref 100, local AS 200
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 10.0.2.1 0 0 300 i
*> 40.40.0.0/16 10.0.2.1 0 300 400 i
*> 100.100.0.0/22 10.0.2.1 0 300 100 i
*> 200.200.0.0/16 0.0.0.0 0 32768 i
Displayed 4 routes and 4 total paths
Verifying Connectivity
Let’s test connectivity to YouTube’s address space. From Upstream’s loopback interface, ping YouTube’s loopback address 100.100.0.1:
root@upstream:/# ping -I 40.40.0.1 -c 3 100.100.0.1
PING 100.100.0.1 (100.100.0.1) from 40.40.0.1 : 56(84) bytes of data.
64 bytes from 100.100.0.1: icmp_seq=1 ttl=63 time=1.70 ms
64 bytes from 100.100.0.1: icmp_seq=2 ttl=63 time=2.06 ms
64 bytes from 100.100.0.1: icmp_seq=3 ttl=63 time=1.80 ms
--- 100.100.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 1.704/1.853/2.058/0.149 ms
Traffic from Upstream, which represents traffic from Internet users in this lab example, reaches YouTube correctly. This is the normal, pre-hijack state.
Use the traceroute command to check the path that the traffic between Upstream and Youtube follows:
root@upstream:/# traceroute -s 40.40.0.1 100.100.0.1
traceroute to 100.100.0.1 (100.100.0.1), 30 hops max, 60 byte packets
1 10.0.3.1 (10.0.3.1) 0.730 ms 1.239 ms 1.827 ms
2 100.100.0.1 (100.100.0.1) 2.428 ms 3.025 ms 3.541 ms
At this point, we have a fully functional 4-AS BGP topology with normal routing:
In the next section, we’ll introduce Pakistan Telecom’s more-specific /24 hijack and observe how it overrides YouTube’s legitimate route.
Recreating the Prefix Hijack
Now we will introduce the more-specific prefix announcement that hijacks YouTube’s traffic, recreating the 2008 Pakistan incident. This demonstrates how BGP’s longest-prefix-match rule can be exploited, even unintentionally.
The Before State
Before making changes, let’s confirm YouTube’s route is the only one for the 100.100.x.x address space. In the Upstream terminal window:
root@upstream:/# vtysh
upstream# show ip bgp 100.100.0.1
When we query BGP for the specific IP 100.100.0.1, we see that it matches the /22 prefix owned by YouTube (AS100). The AS path “300 100” shows the route comes via Transit (AS300) from YouTube (AS100).
BGP routing table entry for 100.100.0.0/22, version 3
Paths: (1 available, best #1, table default)
Advertised to non peer-group peers:
10.0.3.1
300 100
10.0.3.1 from 10.0.3.1 (30.30.0.1)
Origin IGP, valid, external, best (First path received)
Last update: Sat Jan 31 16:31:16 2026
Starting the Hijack
Now we’ll simulate Pakistan Telecom announcing the more-specific prefix. In the Pakistan terminal window:
root@pakistan:/# vtysh
pakistan# configure terminal
First, we need to create a blackhole route for the prefix we’re about to announce, just like Pakistan Telecom did when trying to block YouTube:
pakistan(config)# ip route 100.100.0.0/24 blackhole
Now, add the more-specific prefix to BGP:
pakistan(config)# router bgp 200
pakistan(config-router)# address-family ipv4 unicast
pakistan(config-router-af)# network 100.100.0.0/24
pakistan(config-router-af)# exit
pakistan(config-router)# exit
pakistan(config)# exit
Verify the new route is in Pakistan’s BGP table:
pakistan# show ip bgp
In the output below, notice that there are two routes for YouTube’s address space:
- 100.100.0.0/22 is YouTube’s legitimate announcement (learned via Transit)
- 100.100.0.0/24 is Our hijacked announcement (locally originated)
BGP table version is 5, local router ID is 200.200.0.1, vrf id 0
Default local pref 100, local AS 200
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 10.0.2.1 0 0 300 i
*> 40.40.0.0/16 10.0.2.1 0 300 400 i
*> 100.100.0.0/22 10.0.2.1 0 300 100 i
*> 100.100.0.0/24 0.0.0.0 0 32768 i
*> 200.200.0.0/16 0.0.0.0 0 32768 i
Displayed 5 routes and 5 total paths
The hijack is now being advertised to Transit.
In our lab YouTube announces 100.100.0.0/22, which covers 100.100.0.0 – 100.100.3.255, and Pakistan is now announcing 100.100.0.0/24, which covers 100.100.0.0 – 100.100.0.255.
The /24 is more specific than the /22, so routers will prefer it for any traffic destined to addresses in the 100.100.0.0/24 range.
Observing the Hijack Propagation
Let’s see how the hijack propagates through the network. Go to the Transit terminal window and enter the following commands.
root@transit:/# vtysh
transit# show ip bgp
You can see that the more specific route has reached the Transit AS router.
BGP table version is 5, local router ID is 30.30.0.1, vrf id 0
Default local pref 100, local AS 300
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 0.0.0.0 0 32768 i
*> 40.40.0.0/16 10.0.3.2 0 0 400 i
*> 100.100.0.0/22 10.0.1.1 0 0 100 i
*> 100.100.0.0/24 10.0.2.2 0 0 200 i
*> 200.200.0.0/16 10.0.2.2 0 0 200 i
Displayed 5 routes and 5 total paths
It now has two routes covering YouTube’s address space:
- 100.100.0.0/22 from YouTube (AS100) via 10.0.1.1
- 100.100.0.0/24 from Pakistan (AS200) via 10.0.2.1
Transit will forward the hijacked route to its other neighbors, including Upstream.
Check Upstream, which is the observer that represents the broader Internet. Go to the Upstream terminal window and enter the following commands.
root@upstream:/# vtysh
upstream# show ip bgp
You can see that the more specific route has reached the Upstream AS router, from which we will assume it propagates to all other routers in the Internet.
BGP table version is 6, local router ID is 40.40.40.1, vrf id 0
Default local pref 100, local AS 400
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 10.0.3.1 0 0 300 i
*> 40.40.0.0/16 0.0.0.0 0 32768 i
*> 100.100.0.0/22 10.0.3.1 0 300 100 i
*> 100.100.0.0/24 10.0.3.1 0 300 200 i
*> 200.200.0.0/16 10.0.3.1 0 300 200 i
Displayed 5 routes and 5 total paths
Notice the two routes:
- 100.100.0.0/22 with AS path “300 100” (Transit → YouTube), which is the legitimate route
- 100.100.0.0/24 with AS path “300 200” (Transit → Pakistan), which is the hijacked route
In the real incident, Pakistan Telecom was trying to block YouTube internally by creating a blackhole route. The problem was that this route was accidentally announced to their transit provider PCCW, who propagated it globally.
Understanding the Impact
Now let’s see what happens when Upstream tries to reach an IP address in the hijacked range:
upstream# show ip bgp 100.100.0.1
BGP routing table entry for 100.100.0.0/24, version 5
Paths: (1 available, best #1, table default)
Advertised to non peer-group peers:
10.0.3.1
300 200
10.0.3.1 from 10.0.3.1 (30.30.0.1)
Origin IGP, valid, external, best (First path received)
Last update: Sat Jan 31 17:38:36 2026
This is the hijack in action! When querying for IP 100.100.0.1:
- Before the hijack, this command matched the /22 route to YouTube and we saw that it originated from AS100 (Youtube)
- After the hijack, it matches the /24 route to Pakistan and we see it originates from AS200 (Pakistan)
The more-specific /24 prefix “wins” due to BGP’s longest-prefix-match rule. Traffic for 100.100.0.x is now being sent toward Pakistan instead of YouTube.
Let’s verify with a traceroute. Exit vtysh first:
upstream# exit
Try to ping the YouTube loopback address and see that you cannot reach YouTube at 100.100.0.1 from the Upstream router:
root@upstream:/# ping -I 40.40.0.1 -c 3 100.100.0.1
PING 100.100.0.1 (100.100.0.1) from 40.40.0.1 : 56(84) bytes of data.
--- 100.100.0.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2056ms
Next, trace the path to an address in the hijacked range:
root@upstream:/# traceroute -s 40.40.0.1 100.100.0.1
traceroute to 100.100.0.1 (100.100.0.1), 30 hops max, 60 byte packets
1 10.0.3.1 (10.0.3.1) 1.592 ms 2.020 ms 2.429 ms
2 * * *
3 * * *
The traceroute shows:
- First hop: Transit (10.0.3.1)
- Second hop: Nothing shows because Pakistan is blackholing the traffic.
This is exactly what happened in 2008: YouTube traffic flowed toward Pakistan where it was dropped, causing a global YouTube outage.
Compare this to the other YouTube address 100.100.1.1, which is outside the hijacked /24 but still within YouTube’s /22:
root@upstream:/# traceroute -s 40.40.0.1 100.100.1.1
traceroute to 100.100.1.1 (100.100.1.1), 30 hops max, 60 byte packets
1 10.0.3.1 (10.0.3.1) 0.895 ms 1.173 ms 1.573 ms
2 100.100.1.1 (100.100.1.1) 1.762 ms 2.185 ms 2.586 ms
Traffic to 100.100.1.1 still reaches YouTube (via Transit) because that address is covered by the /22 but NOT by the hijacked /24.
YouTube’s Response
In the real incident, YouTube responded by announcing their own more-specific prefixes to compete with Pakistan’s hijack. Let’s simulate this defense.
Go to the YouTube terminal window and enter the following commands:
root@youtube:/# vtysh
youtube# configure terminal
YouTube will announce two /25 prefixes which are more specific than Pakistan’s /24 and which, together, cover the name address range as the /24 that Pakistan announced:
youtube(config)# ip route 100.100.0.0/25 blackhole
youtube(config)# ip route 100.100.0.128/25 blackhole
youtube(config)# router bgp 100
youtube(config-router)# address-family ipv4 unicast
youtube(config-router-af)# network 100.100.0.0/25
youtube(config-router-af)# network 100.100.0.128/25
youtube(config-router-af)# exit
youtube(config-router)# exit
youtube(config)# exit
Verify YouTube is now announcing the counter-attack routes:
youtube# show ip bgp
BGP table version is 7, local router ID is 100.100.0.1, vrf id 0
Default local pref 100, local AS 100
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 10.0.1.2 0 0 300 i
*> 40.40.0.0/16 10.0.1.2 0 300 400 i
*> 100.100.0.0/22 0.0.0.0 0 32768 i
*> 100.100.0.0/24 10.0.1.2 0 300 200 i
*> 100.100.0.0/25 0.0.0.0 0 32768 i
*> 100.100.0.128/25 0.0.0.0 0 32768 i
*> 200.200.0.0/16 10.0.1.2 0 300 200 i
Displayed 7 routes and 7 total paths
YouTube is now announcing /25s that will override Pakistan’s /24 prefix
Check Upstream to see the effect. Go to the Upstream terminal window and enter the following commands:
root@upstream:/# vtysh
upstream# show ip bgp
This will show there are three routes covering the 100.100.0.0/24 range:
- 100.100.0.0/24 from Pakistan (AS200)
- 100.100.0.0/25 from YouTube (AS100), which is more specific
- 100.100.0.128/25 from YouTube (AS100), which is more specific
BGP table version is 7, local router ID is 40.40.0.1, vrf id 0
Default local pref 100, local AS 400
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 30.30.0.0/16 10.0.3.1 0 0 300 i
*> 40.40.0.0/16 0.0.0.0 0 32768 i
*> 100.100.0.0/22 10.0.3.1 0 300 100 i
*> 100.100.0.0/24 10.0.3.1 0 300 200 i
*> 100.100.0.0/25 10.0.3.1 0 300 100 i
*> 100.100.0.128/25 10.0.3.1 0 300 100 i
*> 200.200.0.0/16 10.0.3.1 0 300 200 i
Displayed 7 routes and 7 total paths
Let’s verify Upstream traffic now goes to YouTube:
upstream# show ip bgp 100.100.0.1
This will show that the Upstream router now will send traffic addressed to 100.100.0.1 to YouTube (AS100) instead of to Pakistan (AS200).
upstream# show ip bgp 100.100.0.1
BGP routing table entry for 100.100.0.0/25, version 6
Paths: (1 available, best #1, table default)
Advertised to non peer-group peers:
10.0.3.1
300 100
10.0.3.1 from 10.0.3.1 (30.30.0.1)
Origin IGP, valid, external, best (First path received)
Last update: Sat Jan 31 19:41:08 2026
YouTube has reclaimed control. The /25 routes from YouTube (AS100) override Pakistan’s /24 route. Traffic for 100.100.0.1 now correctly flows to YouTube.
Cleanup
When you’re finished experimenting with the hijack scenario clean up the lab:
$ kathara lclean
┌──────────────────────────────────────────────────────────────────────────────┐
│ Stopping Network Scenario │
└──────────────────────────────────────────────────────────────────────────────┘
[Deleting devices] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4/4
[Deleting collision domains] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3/3
Summary: The Attack and Defense
This exercise demonstrated the lifecycle of the Pakistan YouTube hijack.
The key lesson is that in the BGP “longest prefix match” game, the most specific route wins. However, while that was possible in 2008, that’s a game that attackers and defenders a less able to play in modern networks due to the use of modern BGP security practices.
Modern BGP Security Practices
Now that you’ve seen how a prefix hijack works, let’s discuss the techniques network operators use to prevent them. The Pakistan YouTube incident highlighted critical weaknesses in BGP that the industry has been working to address ever since.
Pakistan Telecom’s /24 BGP Hijack and YouTube’s emergency /25 de-aggregation response worked in 2008 because prefix filtering and origin validation were weak. Today, strict prefix-length filtering and the widespread use of RPKI mean that such more-specific announcements would often be rejected.
Prefix Filtering with Prefix Lists
The most fundamental protection against prefix hijacks is explicit prefix filtering. Transit providers can configure their routers to only accept announcements for prefixes the customer is authorized to announce. To accomplish this, they need to maintain a comprehensive list of valid customer prefixes.
Internet providers maintain prefix filter lists using tools like bgpq4 that automatically generate prefix lists from data stored in Internet Routing Registry (IRR) databases like RADB, RIPE, and ARIN.
RPKI and Route Origin Validation
Resource Public Key Infrastructure (RPKI) represents a fundamental shift in BGP security. Instead of relying on trusted databases or manual coordination, RPKI provides cryptographic proof of route authorization. RPKI would have prevented the Pakistan YouTube hijack, if RPKI had existed in 2008.
RPKI adoption has grown dramatically since the Pakistan YouTube incident. Major networks and tier-1 providers now validate routes and drop RPKI-invalid announcements.
BGPsec
BGPsec extends RPKI to provide path validation, cryptographically signing each AS hop in the path. While RPKI validates the origin AS, BGPsec validates the entire path, detecting route leaks and path manipulation attacks. However, BGPsec faces significant deployment challenges because every AS in the path must support BGPsec.
Conclusion
In this post, I’ve walked you through using Kathará to recreate the 2008 Pakistan YouTube BGP prefix hijack. We’ve learned how to use Kathará to gain hands-on experience with how prefix hijacks occur and propagate, and how to detect and counter them.
The beauty of network emulation, using tools like Kathará, is that you can experiment freely without risking production infrastructure. If you want to continue exploring BGP scenarios with Kathará, the project maintains an excellent collection of ready-to-use labs:
Further Reading
To get more information about BGP security, I recommend these resources:
- RIPE NCC Case Study: Pakistan YouTube Hijack: Detailed analysis of the 2008 YouTube incident with routing data
- NIST BGP Security Guidelines (SP 800-189): Comprehensive guidance on securing BGP infrastructure
- MANRS (Mutually Agreed Norms for Routing Security): Industry initiative promoting routing security best practices
- Cloudflare’s BGP Security Blog: Accessible explanations of BGP incidents and mitigations
- RPKI Documentation at ARIN, RIPE, or APNIC: Guides for creating and managing RPKI data
[^1] https://github.com/KatharaFramework/Kathara/wiki/Linux