Iran's BGP Behavior under Fire

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 Events | Unique Prefixes | TIC (AS49666) | ITCO (AS12880) | IPM (AS6736) |
|---|---|---|---|---|---|
| 00:00 | 121,762 | 1,822 | 1,801 | 374 | 28 |
| 01:00 | 70,599 | 1,612 | 1,591 | 411 | 22 |
| 02:00 | 95,675 | 1,041 | 1,020 | 369 | 22 |
| 03:00 | 20,893 | 1,148 | 1,127 | 379 | 21 |
| 04:00 | 27,122 | 1,257 | 1,098 | 382 | 190 |
| 05:00 | 20,078 | 479 | 456 | 242 | 23 |
| 06:00 | 63,839 | 829 | 804 | 247 | 27 |
| 07:00 | 244,134 | 2,836 | 2,814 | 719 | 56 |
| 08:00 | 34,130 | 1,489 | 1,468 | 450 | 51 |
| 09:00 | 3,886,009 | 8,354 | 8,338 | 1,968 | 24 |
| 10:00 | 1,259,809 | 8,180 | 8,021 | 1,945 | 166 |
| 11:00 | 388,688 | 7,141 | 6,978 | 792 | 167 |
| 12:00 | 368,456 | 7,136 | 6,969 | 790 | 167 |
| 13:00 | 294,533 | 7,118 | 6,956 | 780 | 172 |
| 14:00 | 251,728 | 7,427 | 7,265 | 790 | 178 |
| 15:00 | 15,570 | 826 | 803 | 27 | 23 |
| 16:00 | 9,907 | 729 | 708 | 25 | 21 |
| 17:00 | 4,024 | 304 | 283 | 32 | 27 |
| 18:00 | 34,007 | 1,518 | 1,497 | 293 | 22 |
| 19:00 | 11,236 | 3,605 | 3,587 | 484 | 22 |
| 20:00 | 9,463 | 1,277 | 1,256 | 391 | 21 |
| 21:00 | 4,258 | 976 | 955 | 207 | 21 |
| 22:00 | 7,270 | 364 | 343 | 82 | 21 |
| 23:00 | 7,367 | 736 | 717 | 48 | 21 |
| 00:00 | 10,234 | 382 | 361 | 37 | 21 |
| 01:00 | 18,435 | 1,118 | 1,097 | 26 | 27 |
| 02:00 | 9,299 | 347 | 326 | 25 | 21 |
| 03:00 | 10,317 | 310 | 289 | 25 | 21 |
| 04:00 | 13,823 | 316 | 295 | 30 | 21 |
| 05:00 | 15,744 | 6,477 | 6,313 | 625 | 164 |
| 06:00 | 1,901 | 809 | 788 | 182 | 21 |
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:
| AS | Name | Spike Events | Baseline Events | Increase |
|---|---|---|---|---|
| AS42337 | Respina Networks | 840,392 | 27,535 | 214x |
| AS43754 | Asiatech Data Transmission | 348,391 | 16,212 | 111x |
| AS48715 | Sefroyek Pardaz Engineering | 217,700 | 271 | 882x |
| AS49556 | Hesab Rasam Rayaneh | 142,728 | 0 | N/A |
| AS62442 | Fara Saba Aria | 95,250 | 408 | 396x |
| AS214922 | Unknown | 86,977 | 0 | N/A |
| AS204650 | Unknown | 76,175 | 0 | N/A |
| AS198154 | Tose-eh Fanavari Ertebat Pasargad | 75,245 | 1,364 | 426x |
| AS41881 | Iran Telecommunication Company | 71,023 | 8,863 | 53x |
| AS50558 | Ertebatat Zirsakht Shahr | 69,485 | 0 | N/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.
| Period | Avg Path Length | Prepending % | Total Announcements |
|---|---|---|---|
| Baseline (00:00–05:00) | 6.9 | 19.1% | 336,051 |
| Strikes begin, pre-throttle (06:00–08:00) | 6.4 | 12.8% | 307,973 |
| HTTP Flatline (08:00–11:00) | 8.3 | 33.8% | 5,424,082 |
| Elevated (11:00–15:00) | 7.3 | 28.3% | 1,303,405 |
| Settling (15:00–24:00) | 7.2 | 16.1% | 103,102 |
| Next day (Mar 1 00:00–06:00) | 7.0 | 22.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 Events | Unique Prefixes |
|---|---|---|
| 09:00 | 244,728 | 1,173 |
| 09:05 | 275,719 | 1,936 |
| 09:10 | 241,587 | 1,166 |
| 09:15 | 80,291 | 1,235 |
| 09:20 | 58,781 | 580 |
| 09:25 | 208,871 | 1,171 |
| 09:30 | 67,642 | 533 |
| 09:35 | 309,832 | 1,140 |
| 09:40 | 331,232 | 1,183 |
| 09:45 | 194,015 | 1,145 |
| 09:50 | 839 | 225 |
| 09:55 | 43,763 | 325 |
| 10:00 | 262,198 | 1,360 |
| 10:05 | 930 | 52 |
| 10:10 | 873 | 306 |
| 10:15 | 3,639 | 1,924 |
| 10:20 | 70,063 | 947 |
| 10:25 | 303,279 | 1,136 |
| 10:30 | 4,638 | 1,168 |
| 10:35 | 971 | 252 |
| 10:40 | 8 | 4 |
| 10:45 | 850 | 94 |
| 10:50 | 132 | 7 |
| 10:55 | 41 | 4 |
| 11:00 | 153 | 4 |
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 Snapshot | Unique Prefixes | TIC Prefixes | ITCO Prefixes | IPM Prefixes |
|---|---|---|---|---|
| Feb 28, 00:00 UTC | 8,689 | 8,529 | 1,975 | 192 |
| Feb 28, 08:00 UTC | 8,629 | — | — | — |
| Feb 28, 16:00 UTC | 7,526 | 7,373 | 787 | 188 |
| Mar 1, 00:00 UTC | 7,526 | 7,373 | 787 | 188 |
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.
⁂