Example Bogon Filter Configuration in BIRD BGP

9 Apr

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 TypeInbound Bogon FilterOutbound Bogon Filter
Transit upstreamYesYes
IX route serverYesYes
Private peeringYesYes
Customer BGPYesYes
Internal iBGPDependsDepends

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:

PrefixPurpose
0.0.0.0/8“This network”
10.0.0.0/8RFC1918 private address
100.64.0.0/10Carrier-grade NAT
127.0.0.0/8Loopback
169.254.0.0/16Link-local
172.16.0.0/12RFC1918 private address
192.168.0.0/16RFC1918 private address
192.0.2.0/24Documentation prefix
198.18.0.0/15Benchmarking
198.51.100.0/24Documentation prefix
203.0.113.0/24Documentation prefix
224.0.0.0/4Multicast
240.0.0.0/4Reserved/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:

PrefixPurpose
::/8Reserved
100::/64Discard-only prefix
2001:2::/48Benchmarking
2001:db8::/32Documentation
fc00::/7Unique local address
fe80::/10Link-local unicast
ff00::/8Multicast

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:

  1. Confirm your own prefixes are not accidentally included in the bogon list.
  2. Validate the BIRD config with bird -p.
  3. Reload the bird service using birdc configure, not a hard restart.
  4. Check the BGP session state after reload.
  5. Compare the route count before and after.
  6. Monitor NMS alerts.
  7. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.