Views: 2
After setting up SNMP monitoring for BIRD BGP, the next important topic is route filtering.
One of the first filters I usually add to BGP edge routers is a bogon-prefix filter. This filter prevents invalid, reserved, private, documentation, multicast, and other non-global prefixes from being accepted or propagated through BGP.
In production networks such as ISPs, hosting providers, data centers, or CDN-connected environments, bogon filtering is one of the basic hygiene controls that should be in place before more advanced policies such as RPKI validation, customer-specific prefix lists, AS-path filtering, and community-based traffic engineering.
This article provides a practical example of configuring bogon filters in BIRD/BIRD2.
1. What Are Bogon Prefixes?
Bogon prefixes are IP prefixes that should not appear in the global Internet routing table.
Examples include:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
127.0.0.0/8
169.254.0.0/16
224.0.0.0/4
These networks are valid in specific contexts, such as private LAN, loopback, link-local, multicast, or documentation, but they should not be accepted from an internet BGP peer.
If a router accepts bogon prefixes from upstream, downstream, route server, or customer BGP sessions, the network may experience:
- route leaks,
- invalid routing,
- blackholing,
- spoofed-source traffic paths,
- monitoring noise,
- accidental propagation of private routes,
- security and abuse-handling issues.
Bogon filtering is not a replacement for RPKI, IRR filtering, or customer prefix validation. It is a baseline safety filter.
2. Bogon Filtering Scope
There are two common places to apply bogon filtering:
Inbound filter : reject bogon prefixes received from BGP peers
Outbound filter : prevent bogon prefixes from being advertised to BGP peers
Recommended deployment:
| BGP Session Type | Inbound Bogon Filter | Outbound Bogon Filter |
|---|---|---|
| Transit upstream | Yes | Yes |
| IX route server | Yes | Yes |
| Private peering | Yes | Yes |
| Customer BGP | Yes | Yes |
| Internal iBGP | Depends | Depends |
For internet-facing BGP sessions, bogon filtering should generally be enabled both inbound and outbound.
3. BIRD Prefix Set for IPv4 Bogons
Create or edit your BIRD filter file.
Example:
sudo nano /etc/bird/filter-bogon.conf
Add this IPv4 bogon prefix set:
define BOGON_PREFIXES_V4 = [
0.0.0.0/8+,
10.0.0.0/8+,
100.64.0.0/10+,
127.0.0.0/8+,
169.254.0.0/16+,
172.16.0.0/12+,
192.0.0.0/24+,
192.0.2.0/24+,
192.168.0.0/16+,
198.18.0.0/15+,
198.51.100.0/24+,
203.0.113.0/24+,
224.0.0.0/4+,
240.0.0.0/4+
];
Explanation:
| Prefix | Purpose |
|---|---|
| 0.0.0.0/8 | “This network” |
| 10.0.0.0/8 | RFC1918 private address |
| 100.64.0.0/10 | Carrier-grade NAT |
| 127.0.0.0/8 | Loopback |
| 169.254.0.0/16 | Link-local |
| 172.16.0.0/12 | RFC1918 private address |
| 192.168.0.0/16 | RFC1918 private address |
| 192.0.2.0/24 | Documentation prefix |
| 198.18.0.0/15 | Benchmarking |
| 198.51.100.0/24 | Documentation prefix |
| 203.0.113.0/24 | Documentation prefix |
| 224.0.0.0/4 | Multicast |
| 240.0.0.0/4 | Reserved/future use |
The + operator means the prefix itself and all more-specific prefixes.
For example:
10.0.0.0/8+
matches:
10.0.0.0/8
10.1.0.0/16
10.10.10.0/24
10.10.10.10/32
4. IPv4 Bogon Filter Function
Add a function to check whether the received route is a bogon:
function is_bogon_v4()
{
if net ~ BOGON_PREFIXES_V4 then return true;
return false;
}
Then create a reject function:
function reject_bogon_v4()
{
if is_bogon_v4() then {
print "Reject bogon IPv4 prefix: ", net;
reject;
}
}
5. Basic IPv4 Import Filter Example
Example inbound filter for an upstream or route server:
filter TRANSIT_IN_V4
{
reject_bogon_v4();
# Reject too-specific prefixes
if net.len > 24 then {
print "Reject too-specific IPv4 prefix: ", net;
reject;
}
# Optional: reject default route from peer
if net = 0.0.0.0/0 then {
print "Reject default route from peer: ", net;
reject;
}
accept;
}
For most Internet BGP sessions, IPv4 prefixes longer than /24 should not be accepted from the global table.
6. Basic IPv4 Export Filter Example
Outbound filtering is equally important.
Example:
filter TRANSIT_OUT_V4
{
reject_bogon_v4();
# Only advertise your own prefixes
if net ~ [
116.0.0.0/21{21,24},
103.253.0.0/22{22,24}
] then accept;
reject;
}
This ensures that only your own public prefixes are advertised.
Example meaning:
116.0.0.0/21{21,24}
matches:
116.0.0.0/21
116.0.0.0/22
116.0.4.0/22
116.0.0.0/23
116.0.2.0/23
116.0.4.0/23
116.0.6.0/23
116.0.x.0/24
Adjust this list to reflect your actual delegated prefixes.
7. BIRD Protocol Example for IPv4
Example BGP session:
protocol bgp bgp_transit_ntt_v4 {
description "Transit NTT IPv4";
local as 59139;
neighbor 203.0.113.1 as 10217;
ipv4 {
import filter TRANSIT_IN_V4;
export filter TRANSIT_OUT_V4;
};
}
Example for route server:
protocol bgp bgp_ix_rs1_v4 {
description "IX Route Server IPv4";
local as 59139;
neighbor 198.51.100.1 as 65000;
ipv4 {
import filter TRANSIT_IN_V4;
export filter TRANSIT_OUT_V4;
};
}
Replace neighbor IP and ASN with your real peer information.
8. IPv6 Bogon Prefix Set
For IPv6, create another prefix set:
define BOGON_PREFIXES_V6 = [
::/8+,
100::/64+,
2001:2::/48+,
2001:10::/28+,
2001:db8::/32+,
3ffe::/16+,
fc00::/7+,
fe80::/10+,
ff00::/8+
];
Common examples:
| Prefix | Purpose |
|---|---|
| ::/8 | Reserved |
| 100::/64 | Discard-only prefix |
| 2001:2::/48 | Benchmarking |
| 2001:db8::/32 | Documentation |
| fc00::/7 | Unique local address |
| fe80::/10 | Link-local unicast |
| ff00::/8 | Multicast |
9. IPv6 Bogon Filter Function
Add:
function is_bogon_v6()
{
if net ~ BOGON_PREFIXES_V6 then return true;
return false;
}
Reject function:
function reject_bogon_v6()
{
if is_bogon_v6() then {
print "Reject bogon IPv6 prefix: ", net;
reject;
}
}
10. Basic IPv6 Import Filter Example
filter TRANSIT_IN_V6
{
reject_bogon_v6();
# Reject too-specific IPv6 prefixes
if net.len > 48 then {
print "Reject too-specific IPv6 prefix: ", net;
reject;
}
# Optional: reject default route from peer
if net = ::/0 then {
print "Reject IPv6 default route from peer: ", net;
reject;
}
accept;
}
For most Internet BGP sessions, IPv6 prefixes longer than /48 are usually filtered.
11. Basic IPv6 Export Filter Example
filter TRANSIT_OUT_V6
{
reject_bogon_v6();
# Only advertise your own IPv6 prefixes
if net ~ [
2001:db8:1234::/48{48,48}
] then accept;
reject;
}
Replace the example IPv6 documentation prefix with your real allocated IPv6 prefix.
12. BIRD Protocol Example for IPv6
protocol bgp bgp_transit_ntt_v6 {
description "Transit NTT IPv6";
local as 59139;
neighbor 2001:db8:ffff::1 as 10217;
ipv6 {
import filter TRANSIT_IN_V6;
export filter TRANSIT_OUT_V6;
};
}
13. Full Example File Layout
A clean BIRD configuration can be split into multiple files:
/etc/bird/
├── bird.conf
├── filters/
│ ├── bogon.conf
│ ├── rpki.conf
│ ├── customer-prefix.conf
│ └── communities.conf
└── peers/
├── transit-ntt.conf
├── transit-pgas.conf
├── ix-openixp.conf
└── customer-example.conf
In bird.conf:
include "/etc/bird/filters/bogon.conf";
include "/etc/bird/filters/rpki.conf";
include "/etc/bird/filters/customer-prefix.conf";
include "/etc/bird/peers/*.conf";
This makes the configuration easier to maintain as the number of peers grows.
14. Complete Bogon Filter Example
Example /etc/bird/filters/bogon.conf:
define BOGON_PREFIXES_V4 = [
0.0.0.0/8+,
10.0.0.0/8+,
100.64.0.0/10+,
127.0.0.0/8+,
169.254.0.0/16+,
172.16.0.0/12+,
192.0.0.0/24+,
192.0.2.0/24+,
192.168.0.0/16+,
198.18.0.0/15+,
198.51.100.0/24+,
203.0.113.0/24+,
224.0.0.0/4+,
240.0.0.0/4+
];
define BOGON_PREFIXES_V6 = [
::/8+,
100::/64+,
2001:2::/48+,
2001:10::/28+,
2001:db8::/32+,
3ffe::/16+,
fc00::/7+,
fe80::/10+,
ff00::/8+
];
function is_bogon_v4()
{
if net ~ BOGON_PREFIXES_V4 then return true;
return false;
}
function is_bogon_v6()
{
if net ~ BOGON_PREFIXES_V6 then return true;
return false;
}
function reject_bogon_v4()
{
if is_bogon_v4() then {
print "Reject bogon IPv4 prefix: ", net;
reject;
}
}
function reject_bogon_v6()
{
if is_bogon_v6() then {
print "Reject bogon IPv6 prefix: ", net;
reject;
}
}
15. Production Import Filter Example
IPv4:
filter EBGP_IMPORT_V4
{
reject_bogon_v4();
if net.len > 24 then {
print "Reject IPv4 prefix longer than /24: ", net;
reject;
}
# Optional: reject default route unless expected
if net = 0.0.0.0/0 then {
print "Reject unexpected IPv4 default route";
reject;
}
accept;
}
IPv6:
filter EBGP_IMPORT_V6
{
reject_bogon_v6();
if net.len > 48 then {
print "Reject IPv6 prefix longer than /48: ", net;
reject;
}
# Optional: reject default route unless expected
if net = ::/0 then {
print "Reject unexpected IPv6 default route";
reject;
}
accept;
}
16. Production Export Filter Example
IPv4:
define MY_PREFIXES_V4 = [
116.0.0.0/21{21,24},
103.253.0.0/22{22,24}
];
filter EBGP_EXPORT_V4
{
reject_bogon_v4();
if net ~ MY_PREFIXES_V4 then accept;
print "Reject unauthorized IPv4 export: ", net;
reject;
}
IPv6:
define MY_PREFIXES_V6 = [
2001:db8:1234::/48{48,48}
];
filter EBGP_EXPORT_V6
{
reject_bogon_v6();
if net ~ MY_PREFIXES_V6 then accept;
print "Reject unauthorized IPv6 export: ", net;
reject;
}
Important: never use a wide-open export filter on an internet-facing BGP session.
Avoid this:
export all;
Use an explicit export policy instead.
17. Testing the Configuration
Before reloading BIRD, always validate the config:
bird -p -c /etc/bird/bird.conf
For BIRD2 systems, where the binary is named bird:
bird -p
If the syntax is valid, reload:
birdc configure
Or using systemd:
sudo systemctl reload bird
Check BGP protocol status:
birdc show protocols
Check received routes from a peer:
birdc show route protocol bgp_transit_ntt_v4
Check filtered routes, if the table/filtering setup supports it:
birdc show route filtered protocol bgp_transit_ntt_v4
18. Testing a Bogon Prefix
To test the filter logic, you can temporarily add a static route in a lab router or route reflector test environment.
Example:
protocol static static_test_bogon_v4 {
ipv4;
route 10.10.10.0/24 reject;
}
Then apply the export filter and confirm that the route is rejected.
Do not test bogon advertisements on production upstream sessions.
Use a lab session, internal test peer, or route-server simulator.
19. Logging Rejected Bogons
The examples above use:
print "Reject bogon IPv4 prefix: ", net;
This is helpful for early deployment, but it can become noisy on busy routers.
For production, you may eventually remove the print lines or only keep them during troubleshooting.
Example quieter version:
function reject_bogon_v4()
{
if is_bogon_v4() then reject;
}
20. Static Bogon List vs Dynamic Fullbogon List
There are two common approaches:
Static bogon list
This is what we configured above.
Advantages:
- simple,
- easy to audit,
- no external dependency,
- safe for baseline filtering.
Disadvantages:
- does not automatically include newly unallocated RIR space,
- requires manual review and update.
Dynamic fullbogon list
A full Bogon list includes not only reserved/private ranges but also unallocated prefixes.
Advantages:
- more complete,
- better abuse prevention,
- useful for security-focused environments.
Disadvantages:
- Must be updated regularly,
- Wrong automation can cause accidental filtering,
- Requires operational discipline.
For most edge BGP routers, I prefer to use a static baseline bogon filter directly in BIRD, optionally using the Team Cymru fullbogon feed or another trusted source for additional automation.
21. Important Operational Notes
Bogon filtering must be tested carefully.
Before deploying to production:
- Confirm your own prefixes are not accidentally included in the bogon list.
- Validate the BIRD config with
bird -p. - Reload the bird service using
birdc configure, not a hard restart. - Check the BGP session state after reload.
- Compare the route count before and after.
- Monitor NMS alerts.
- Keep rollback config ready.
Useful pre-check:
birdc show route count
birdc show protocols
Useful post-check:
birdc show route count
birdc show protocols
birdc show route protocol PEER_NAME count
22. Recommended Baseline BGP Filter Chain
Bogon filtering should be one part of a larger BGP policy.
Recommended import policy order:
1. Reject bogon prefixes
2. Reject too-specific prefixes
3. Reject invalid prefix length
4. Reject RPKI invalid
5. Apply IRR/customer prefix validation
6. Apply local preference
7. Apply communities
8. Accept
Recommended export policy order:
1. Reject bogon prefixes
2. Only allow owned/customer-authorized prefixes
3. Apply AS prepend/community policy
4. Apply blackhole policy, if used
5. Accept
The most dangerous mistake is not on import, but on export.
A bad import policy can hurt your network.
A bad export policy can hurt the internet.
23. Conclusion
Bogon filtering is one of the simplest and most important safety filters for BGP edge routers.
In BIRD, the implementation is straightforward:
define BOGON_PREFIXES_V4 = [ ... ];
define BOGON_PREFIXES_V6 = [ ... ];
function reject_bogon_v4() { ... }
function reject_bogon_v6() { ... }
Then apply the functions inside your import and export filters.
For production, the most important rule is:
Never use export all on an internet-facing BGP session.
Always explicitly define which prefixes are allowed to leave your ASN.
Bogon filters, RPKI validation, IRR validation, prefix-length filtering, and strict export policy together form a solid baseline for safe BGP operation.