MANRS in Practice: Filtering, Anti-Spoofing, and Good Peering

MANRS — Mutually Agreed Norms for Routing Security — is often treated as a logo for the website and nothing more. That is a waste. The four actions are a concrete checklist that, implemented properly, stop you from being the source of the next big route leak or spoofed-traffic DDoS. None of it is exotic; it is filtering discipline applied consistently.

Here is each action as configuration, not principle.

Action 1: Filtering

You must not propagate incorrect routing information. Two filters do most of the work: prefix filters built from IRR/RPKI data, and AS-path sanity.

Prefix filters from IRR. Building these by hand does not scale. bgpq4 queries IRR (and can use RPKI) to generate router config for a customer’s AS-SET:

Terminal window
# Cisco-style prefix-list for an AS-SET, built from IRR (-A aggregates the output)
bgpq4 -h whois.radb.net -R 24 -A -l CUSTOMER64500 AS-CUSTOMER
# JSON for automation pipelines
bgpq4 -j -l v4 AS-CUSTOMER > customer_v4.json
# IPv6
bgpq4 -6 -R 48 -l CUSTOMER64500-V6 AS-CUSTOMER

-R 24 caps generated prefixes at /24 (no more-specifics than that). Regenerate on a schedule — customers add prefixes, and a filter from three months ago will silently drop their new space.

AS-path filters. Reject paths that should never appear: your own AS in a received path (loop), private ASNs from the public internet, and absurd lengths.

Terminal window
# FRR — drop paths containing private or reserved ASNs, then accept customer prefixes
bgp as-path access-list BOGON-ASN permit _(0|23456|65535)_
bgp as-path access-list BOGON-ASN permit _(6451[2-9]|645[2-9][0-9]|64[6-9][0-9][0-9]|65[0-4][0-9][0-9]|655[0-2][0-9]|6553[0-4])_
route-map FROM-CUSTOMER deny 10
match as-path BOGON-ASN
route-map FROM-CUSTOMER permit 20
match ip address prefix-list CUSTOMER64500

Max-prefix is the seatbelt. Every eBGP session gets a ceiling so a customer leak trips a limit instead of melting your RIB:

Terminal window
neighbor 192.0.2.1 maximum-prefix 1000 90 restart 30

RPKI as a filter input. IRR data is only as honest as whoever registered it; RPKI ROAs are cryptographically signed, so combine them. bgpq4 can pull origin validation into the same generation step with -S to select sources, and modern routers do RPKI origin validation inline alongside the IRR-derived prefix-list. The two are complementary: RPKI proves the origin AS is authorized for the prefix, the IRR prefix-list bounds which prefixes a customer may send at all. A customer with a valid ROA for 203.0.113.0/24 but no IRR entry for 198.51.100.0/24 should still be dropped on the second prefix — RPKI says nothing about it.

Terminal window
# Prefer RPKI-backed sources, fall back to IRR, for the customer's AS-SET
bgpq4 -S RPKI,RADB,RIPE -R 24 -l CUSTOMER64500 AS-CUSTOMER

Action 2: Anti-Spoofing (BCP38)

Traffic with a forged source address is the raw material of reflection/amplification DDoS. You stop it at the edge facing customers, where you know which sources are legitimate.

Strict uRPF on single-homed customer ports — the source must be reachable back out the same interface:

Terminal window
# Cisco IOS-XE, single-homed customer
interface GigabitEthernet0/0/1
ip verify unicast source reachable-via rx

Loose uRPF where paths are asymmetric (multihomed customers) — the source just has to be in the table, not via this interface:

Terminal window
ip verify unicast source reachable-via any

For customers, prefer an explicit inbound ACL built from their assigned prefixes — it is unambiguous and does not depend on FIB symmetry:

Terminal window
ip access-list extended CUST64500-ANTISPOOF
permit ip 203.0.113.0 0.0.0.255 any
deny ip any any log
interface GigabitEthernet0/0/1
ip access-group CUST64500-ANTISPOOF in

The principle is simple: a packet entering from a customer must have a source address that customer is allowed to use. Anything else is dropped at ingress, before it can become someone else’s attack traffic.

Drop, do not just discard. A loose ACL that ends with an implicit permit defeats the point. The last line of every anti-spoof ACL is an explicit deny ip any any log, and you watch that counter — a non-zero, climbing count is either a misconfigured customer or an attack in progress:

Terminal window
# Cisco IOS-XE — how much is the anti-spoof ACL actually dropping?
show ip access-lists CUST64500-ANTISPOOF
# 10 permit ip 203.0.113.0 0.0.0.255 any (4521 matches)
# 20 deny ip any any log (137 matches) <- investigate this line

A steadily climbing deny count on a quiet customer port usually means they renumbered and never told you — fix the permit line before they open a ticket blaming your network for dropping “random” traffic. uRPF has an equivalent counter worth alerting on:

Terminal window
show ip interface GigabitEthernet0/0/1 | include drop
# X verification drops <- spoofed or asymmetric-path packets

Action 3: Coordination

When something breaks at 3 a.m., the other network’s NOC has to be able to reach you. This is the cheapest action and the most neglected.

  • Keep your PeeringDB record accurate: NOC contact, peering policy, IXP presence, max-prefix counts. Other networks build their filters and limits from it.
  • Maintain a real whois contact on your resources with a monitored address.
  • Publish your peering and filtering policy so peers know what you accept and why a prefix was dropped.

There is no config block here — that is the point. It is operational hygiene, and route servers and peers increasingly automate against your PeeringDB entry, so stale data directly causes broken sessions.

Action 4: Global Validation

Make your routing data verifiable so others can filter you correctly.

  • Register prefixes in an IRR with route/route6 objects matching your origin AS.
  • Publish ROAs so RPKI-validating networks accept your prefixes. Get the max-length right — a ROA for 203.0.113.0/24 with max-length 24 will mark a /25 deaggregate as invalid.
Terminal window
# Sanity-check your own origin the way a peer would
bgpq4 -l check AS64500 | grep 203.0.113
routinator validate --asn AS64500 --prefix 203.0.113.0/24

If your own prefix comes back Invalid or missing from IRR, you will be filtered by every diligent network — and you will blame “the internet” instead of your own records.

Verifying the Filters Actually Bite

Config that looks right and config that drops the right routes are different things. After applying a customer filter, prove it rejects what it should.

Terminal window
# FRR — what did this neighbor actually send vs. what we accepted?
vtysh -c "show bgp ipv4 unicast neighbors 192.0.2.1 received-routes" | wc -l
vtysh -c "show bgp ipv4 unicast neighbors 192.0.2.1 routes" | wc -l
# received > accepted means the prefix-list is dropping something — confirm it's the right something

To see why a specific prefix was denied, FRR’s soft-reconfig inbound keeps the pre-policy table so you can inspect rejects without bouncing the session:

Terminal window
neighbor 192.0.2.1 soft-reconfiguration inbound
Terminal window
# Then re-apply policy in-place and re-check
vtysh -c "clear bgp ipv4 unicast 192.0.2.1 soft in"
vtysh -c "show bgp ipv4 unicast neighbors 192.0.2.1 received-routes 198.51.100.0/24"
# If present in received but absent from accepted routes, the filter caught it

A frequent gotcha: bgpq4 regenerates the prefix-list with the same name, but pushing the new list does not re-evaluate already-accepted routes until a soft-clear. Schedule the regeneration and the soft-clear together, or filters drift from reality between runs. Another: an AS-SET that expands to tens of thousands of prefixes can blow past a platform’s prefix-list size limits — check the generated line count before pushing.

Terminal window
bgpq4 -R 24 -l CUST AS-CUSTOMER | wc -l
# Sanity-check against the platform limit before you commit it

A Rollout Order That Works

StepActionRisk if skipped
1Max-prefix on every eBGP sessionOne leak melts your RIB
2Inbound prefix + AS-path filters on customersYou propagate their mistakes
3uRPF / anti-spoof ACLs on customer edgesYou source spoofed DDoS
4PeeringDB + IRR + ROAs accuratePeers filter you, sessions break

Do them in this order because steps 1–3 protect the rest of the internet from your customers immediately, while step 4 protects you from being filtered. Start at the edge, work outward, and re-run bgpq4 on a cron so the filters never go stale.

MANRS is not a certification you earn once. It is a set of filters you keep current. The networks that cause leaks are almost never malicious — they are the ones whose prefix filters were built once and never regenerated.