Iran's BGP Behavior under Fire

Iran’s HTTP requests from February 24 to March 8, 2026 from the perspective of Cloudflare. Courtesy of Cloudflare Radar.
Iran’s HTTP requests from February 24 to March 8, 2026 from the perspective of Cloudflare. Courtesy of Cloudflare Radar.

At approximately 06:15 UTC on February 28, 2026, the United States and Israel began air strikes against Iran. Less than two hours later, at around 08:00 UTC, Cloudflare Radar recorded HTTP traffic from Iran dropping to zero. The internet, by every observable measure of actual usage, went dark. But the BGP routes were never withdrawn from the global routing table.

To investigate further, I pulled 30 hours of BGP data from three RIPE RIS route collectors covering February 28, 00:00 UTC through March 1, 06:00 UTC. The three collectors were rrc00 in Amsterdam (a multi-hop collector with broad global peering), rrc13 in Moscow, and rrc26 in Dubai. Moscow and Dubai are particularly relevant here because of their geographic and network proximity to Iran’s upstream providers.

The dataset captures 7.3 million BGP update messages involving Iran’s three international gateway autonomous systems: AS49666 (Telecommunication Infrastructure Company, or TIC), AS12880 (Iran Information Technology Company, or ITCO), and AS6736 (Institute for Research in Fundamental Sciences, or IPM). For readers who want background on how these gateways form the funnel apex of Iran’s internet architecture, I covered that in detail in a previous post.

Air Strikes

The air strikes began at 06:15 UTC. For roughly two hours afterward, the BGP data from Iran’s gateways looked largely normal. Update volumes during the 06:00 and 07:00 UTC hours were elevated but not dramatically so compared to earlier in the day. Then, at approximately 08:00 UTC, Cloudflare Radar showed HTTP traffic from Iran collapsing to a flatline. NetBlocks.org confirmed the outage.

The BGP data during this throttle window tells its own story. There were zero route withdrawals. Across the entire 30-hour dataset not a single BGP WITHDRAW message was recorded for any prefix routed through Iran’s three international internet gateways.

This provides an excellent insight into the pragmatic approach by Iranian technocrats. Rather than withdrawing BGP routes, which would be immediately visible to the global routing community, the regime instead applied filtering or rate limiting at the application and transport layers. The routes stayed in the global routing table and packets could still technically reach Iranian address space. But HTTP traffic, DNS queries, and other application-layer protocols were being silently dropped or throttled at the gateway.

For the regime, this approach has a clear advantage. Withdrawn routes take time to reconverge when restored, and the act of withdrawal itself is a loud signal to the international community. Keeping routes announced while filtering traffic at a higher layer allows for faster restoration and less visible evidence of deliberate action to public observers.

Fluctuations

At 09:00 UTC, BGP events spiked considerably, which was about an hour after HTTP traffic out of Iran flatlined. The below table starts at 00:00 on February 28 and extends to March 1 at 06:00 UTC.

Hour (UTC)Total EventsUnique PrefixesTIC (AS49666)ITCO (AS12880)IPM (AS6736)
00:00121,7621,8221,80137428
01:0070,5991,6121,59141122
02:0095,6751,0411,02036922
03:0020,8931,1481,12737921
04:0027,1221,2571,098382190
05:0020,07847945624223
06:0063,83982980424727
07:00244,1342,8362,81471956
08:0034,1301,4891,46845051
09:003,886,0098,3548,3381,96824
10:001,259,8098,1808,0211,945166
11:00388,6887,1416,978792167
12:00368,4567,1366,969790167
13:00294,5337,1186,956780172
14:00251,7287,4277,265790178
15:0015,5708268032723
16:009,9077297082521
17:004,0243042833227
18:0034,0071,5181,49729322
19:0011,2363,6053,58748422
20:009,4631,2771,25639121
21:004,25897695520721
22:007,2703643438221
23:007,3677367174821
00:0010,2343823613721
01:0018,4351,1181,0972627
02:009,2993473262521
03:0010,3173102892521
04:0013,8233162953021
05:0015,7446,4776,313625164
06:001,90180978818221

The 09:00 UTC hour alone produced 3.88 million BGP announcements. For context, the baseline hours before the strikes averaged roughly 50,000 to 120,000 events. This represents a 30x to 70x increase in BGP churn.

These were not withdrawals. They were announcements, the same prefixes being re-announced over and over with modified AS paths. This pattern is called route flapping, and it indicates that routers along the path were repeatedly losing and re-establishing BGP sessions, or that upstream providers were seeing constant path changes from Iranian networks.

The number of unique downstream autonomous systems visible in the update stream jumped from 227 during the baseline period to 557 during the spike. Networks that were quietly stable before the strikes suddenly began generating massive volumes of BGP chatter. The top contributors to this instability were Iranian ISPs sitting directly behind the TIC gateway:

ASNameSpike EventsBaseline EventsIncrease
AS42337Respina Networks840,39227,535214x
AS43754Asiatech Data Transmission348,39116,212111x
AS48715Sefroyek Pardaz Engineering217,700271882x
AS49556Hesab Rasam Rayaneh142,7280N/A
AS62442Fara Saba Aria95,250408396x
AS214922Unknown86,9770N/A
AS204650Unknown76,1750N/A
AS198154Tose-eh Fanavari Ertebat Pasargad75,2451,364426x
AS41881Iran Telecommunication Company71,0238,86353x
AS50558Ertebatat Zirsakht Shahr69,4850N/A

Several of these networks went from near silence to generating tens or hundreds of thousands of BGP updates in a two-hour window. AS49556, AS214922, AS204650, AS200370, and AS51469 had produced zero BGP events during the baseline period and then suddenly appeared during the spike. This suggests that the instability was propagating outward from the gateways, affecting networks deeper in Iran’s routing hierarchy that are normally invisible to the global BGP table.

The AS path length data reinforces this picture. During baseline hours, the average AS path length for Iranian routes was 6.9 hops, with roughly 19% of announcements containing path prepending (consecutive duplicate ASNs in the path). During the 09:00 UTC spike, the average path length jumped to 8.7 hops, and 39.2% of all announcements contained prepending.

PeriodAvg Path LengthPrepending %Total Announcements
Baseline (00:00–05:00)6.919.1%336,051
Strikes begin, pre-throttle (06:00–08:00)6.412.8%307,973
HTTP Flatline (08:00–11:00)8.333.8%5,424,082
Elevated (11:00–15:00)7.328.3%1,303,405
Settling (15:00–24:00)7.216.1%103,102
Next day (Mar 1 00:00–06:00)7.022.8%77,852

Path prepending is often used deliberately by network operators to make certain routes less preferred. In a crisis scenario, it could indicate routers cycling through backup paths, upstream providers de-preferring Iranian routes, or Iranian operators themselves attempting to shift traffic between gateways. The 09:00 UTC explosion of prepending suggests that whatever was happening inside Iran’s network was creating widespread path instability that rippled outward through every upstream provider peering with TIC and ITCO.

The most striking behavior in the dataset belongs to ITCO (AS12880), Iran’s second-largest international gateway. ITCO carried 88,603 routes in the RIB table at midnight UTC and was actively participating in normal BGP operations through the early morning hours. Then, during the spike at 09:00 UTC, ITCO generated over 2 million BGP updates in two hours, its networks clearly caught in the same instability cascade as TIC.

At approximately 10:40 UTC, ITCO effectively went silent.

Time (UTC)ITCO EventsUnique Prefixes
09:00244,7281,173
09:05275,7191,936
09:10241,5871,166
09:1580,2911,235
09:2058,781580
09:25208,8711,171
09:3067,642533
09:35309,8321,140
09:40331,2321,183
09:45194,0151,145
09:50839225
09:5543,763325
10:00262,1981,360
10:0593052
10:10873306
10:153,6391,924
10:2070,063947
10:25303,2791,136
10:304,6381,168
10:35971252
10:4084
10:4585094
10:501327
10:55414
11:001534

The transition is dramatic. At 10:35, ITCO was still generating 971 events across 252 prefixes. Five minutes later, it produced 8 events across 4 prefixes. By 11:00 UTC, it was generating single-digit events per five-minute window.

The RIB table snapshots confirm this was not temporary. At midnight UTC, ITCO was visible in routes to 1,975 unique prefixes. By the 16:00 UTC RIB snapshot, that number had dropped to 787, a 60% reduction. It never recovered during the observation window. The March 1 midnight snapshot still showed 787 prefixes.

This did not happen through explicit BGP withdrawals. Remember, zero withdrawals were observed across the entire dataset. Instead, ITCO’s routes simply aged out of the global routing table as neighboring routers stopped hearing announcements for those prefixes. When a BGP speaker stops sending keepalive messages or route refreshes for a prefix, its peers will eventually remove that route from their RIB after the hold timer expires (typically 90 seconds by default, though many operators configure longer timers). The route disappears, but no withdrawal message is ever generated by the originating AS.

This is a different kind of silence than the HTTP requests flatline. The application-layer throttle at 08:00 UTC was a deliberate policy action, a filter applied while keeping the routing infrastructure intact. ITCO’s disappearance at 10:40 UTC looks more like infrastructure failure, whether from physical damage to network equipment, power loss at critical facilities, or a deliberate decision to take ITCO’s international links offline.

AS6736, the academic gateway operated by the Institute for Research in Fundamental Sciences, barely registered on any of this. Its BGP activity remained flat throughout the entire 30-hour period, generating between 21 and 190 unique prefix updates per hour regardless of what was happening around it. The RIB snapshots show it lost only 4 of its 192 prefixes.

This makes sense given IPM’s role. It primarily serves academic and research institutions, not commercial ISPs. Its traffic volume and prefix count are tiny compared to TIC or ITCO. Whatever filtering or instability was affecting the commercial gateways either spared IPM or was irrelevant to its much smaller footprint.

Across all three gateways, the overall picture is one of contraction. The RIB table at rrc00 showed 8,689 unique Iranian prefixes at midnight UTC on February 28. By 16:00 UTC that same day, that number had fallen to 7,526. A total of 1,169 prefixes disappeared from the global routing table.

RIB SnapshotUnique PrefixesTIC PrefixesITCO PrefixesIPM Prefixes
Feb 28, 00:00 UTC8,6898,5291,975192
Feb 28, 08:00 UTC8,629
Feb 28, 16:00 UTC7,5267,373787188
Mar 1, 00:00 UTC7,5267,373787188

None of those 1,169 prefixes returned by the March 1 midnight snapshot. The routing table contracted and stayed contracted. For the networks behind those prefixes, this represents a complete loss of global reachability, not because someone sent a withdrawal message, but because the routers that were announcing those routes stopped talking.

The BGP data from those 30 hours reveals a layered sequence. The air strikes began at 06:15 UTC. The Iranian government’s response came roughly two hours later at 08:00 UTC: application-layer filtering that killed HTTP traffic while leaving the routing infrastructure untouched. This is consistent with the regime’s established practice of throttling internet access during crises, likely triggered here by the need to control information flow once strikes were underway.

Then came the uncontrolled variable. An hour after the throttle, Iranian networks experienced a massive instability event that generated millions of BGP updates, caused widespread path prepending, and ultimately led to the partial disappearance of ITCO as a functioning international gateway. Whether this instability was caused by physical damage to networking infrastructure, power disruptions at critical facilities, or a deliberate decision to consolidate traffic through TIC alone is impossible to determine from BGP data alone.

What the data does make clear is the distinction between these two events. The throttle didn’t specifically show up in BGP data. However, the infrastructure failure was recorded across millions of events. And the routing table shows us what remained: 1,169 prefixes that went dark and hadn’t come back 24 hours later.

For a country whose entire internet architecture depends on two commercial gateways and one academic link, losing 60% of one gateway’s routing capacity in the span of ten minutes is significant. Iran’s centralized internet design gives the government the ability to control information flow during a crisis. It also means that when that infrastructure is damaged, there is no redundancy to absorb the loss.

Replication

The data used in this analysis is publicly available from RIPE RIS. RIPE NCC archives all BGP update and RIB table dumps at data.ris.ripe.net. The files follow a predictable naming convention: updates.YYYYMMDD.HHMM.gz for five-minute update intervals and bview.YYYYMMDD.HHMM.gz for periodic RIB snapshots.

I used the BGPKIT parser library for Python (pybgpkit) to read the MRT files. Each BGP update element exposes the timestamp, prefix, AS path, origin ASN, element type (announcement or withdrawal), and other attributes. The core of the analysis is a filter: for every update element, check whether AS49666, AS12880, or AS6736 appears anywhere in the AS path.

Here is the script that extracts all Iranian gateway-related events from the update files:

import pybgpkit_parser
import os
import json

IRAN_GATEWAY_ASNS = {49666, 12880, 6736}
DATA_DIR = "/path/to/ris-data"

results = []

for rrc in ["rrc00", "rrc13", "rrc26"]:
    rrc_dir = os.path.join(DATA_DIR, rrc)
    files = sorted([f for f in os.listdir(rrc_dir) if f.startswith("updates.")])

    for fname in files:
        fpath = os.path.join(rrc_dir, fname)
        parser = pybgpkit_parser.Parser(fpath)
        for elem in parser:
            as_path_str = elem.as_path or ""
            as_path_list = [int(x) for x in as_path_str.split() if x.isdigit()]
            if IRAN_GATEWAY_ASNS.intersection(set(as_path_list)):
                results.append({
                    "rrc": rrc,
                    "timestamp": elem.timestamp,
                    "type": elem.elem_type,
                    "prefix": elem.prefix,
                    "as_path": as_path_str,
                    "peer_asn": elem.peer_asn,
                    "origin_asns": str(elem.origin_asns),
                })

with open("iran_bgp_events.json", "w") as f:
    json.dump(results, f)

This script produces the hourly event table shown above:

import json
from datetime import datetime, timezone
from collections import defaultdict

with open("iran_bgp_events.json") as f:
    events = json.load(f)

hourly_announce = defaultdict(int)
hourly_withdraw = defaultdict(int)
hourly_pfx = defaultdict(set)
gateway_hourly_pfx = {49666: defaultdict(set), 12880: defaultdict(set), 6736: defaultdict(set)}

for e in events:
    dt = datetime.fromtimestamp(e["timestamp"], tz=timezone.utc)
    hour_key = dt.strftime("%m-%d %H:00")

    if e["type"] == "A":
        hourly_announce[hour_key] += 1
    else:
        hourly_withdraw[hour_key] += 1

    hourly_pfx[hour_key].add(e["prefix"])
    as_path_list = [int(x) for x in e["as_path"].split() if x.isdigit()] if e["as_path"] else []

    for gw in [49666, 12880, 6736]:
        if gw in as_path_list:
            gateway_hourly_pfx[gw][hour_key].add(e["prefix"])

for h in sorted(hourly_announce.keys()):
    print(
        h,
        hourly_announce[h],
        hourly_withdraw.get(h, 0),
        len(hourly_pfx[h]),
        len(gateway_hourly_pfx[49666][h]),
        len(gateway_hourly_pfx[12880][h]),
        len(gateway_hourly_pfx[6736][h]),
    )

The RIB table comparison, which reveals the 1,169 lost prefixes, parses the bview files the same way and compares prefix sets across snapshots:

import pybgpkit_parser

def get_rib_prefixes(bview_path):
    parser = pybgpkit_parser.Parser(bview_path)
    prefixes = set()
    for elem in parser:
        as_path_list = [int(x) for x in elem.as_path.split() if x.isdigit()] if elem.as_path else []
        if {49666, 12880, 6736}.intersection(set(as_path_list)):
            prefixes.add(elem.prefix)
    return prefixes

pre = get_rib_prefixes("rrc00/bview.20260228.0000.gz")
post = get_rib_prefixes("rrc00/bview.20260228.1600.gz")

lost = pre - post
print(f"Prefixes before: {len(pre)}")
print(f"Prefixes after:  {len(post)}")
print(f"Lost:            {len(lost)}")

BGP data was sourced from RIPE RIS route collectors rrc00 (Amsterdam, Netherlands), rrc13 (Moscow, Russia), and rrc26 (Dubai, UAE). Update files and RIB table dumps were parsed using the BGPKIT parser library. The analysis filtered for all BGP update messages where AS49666, AS12880, or AS6736 appeared anywhere in the AS path, capturing both direct announcements from these gateways and updates from their downstream networks. All timestamps are in UTC.

*networking *bgp *technology *iran