<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: IPYE</title>
    <description>The latest articles on DEV Community by IPYE (@ipye_com).</description>
    <link>https://dev.to/ipye_com</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4208865%2F8c1ffd4d-c9be-4f04-824b-dc390f062016.png</url>
      <title>DEV Community: IPYE</title>
      <link>https://dev.to/ipye_com</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ipye_com"/>
    <language>en</language>
    <item>
      <title>tcpdump and Wireshark Filters for IPv6: Practical Recipes and the Extension Header Caveat</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 19:49:31 +0000</pubDate>
      <link>https://dev.to/ipye_com/tcpdump-and-wireshark-filters-for-ipv6-practical-recipes-and-the-extension-header-caveat-1hme</link>
      <guid>https://dev.to/ipye_com/tcpdump-and-wireshark-filters-for-ipv6-practical-recipes-and-the-extension-header-caveat-1hme</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When an IPv6 problem is not obvious from logs, a packet capture usually settles it: is the Router Advertisement arriving, is the Neighbor Solicitation answered, does the handshake complete, is something sending ICMPv6 errors? The IPv6 filter syntax has a few differences from IPv4 that cause silent mistakes. This article gives recipes for tcpdump (which uses the libpcap filter language) and for Wireshark display filters, and explains the limitation that catches most people. Examples use &lt;code&gt;2001:db8:100::25&lt;/code&gt;, &lt;code&gt;2001:db8:100::/48&lt;/code&gt;, and &lt;code&gt;eth0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two different filter languages
&lt;/h2&gt;

&lt;p&gt;Both tools have filters, and they are not the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;capture filter&lt;/strong&gt; (tcpdump's expression, or Wireshark's capture filter box) uses BPF syntax and decides what is recorded at all.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;display filter&lt;/strong&gt; (Wireshark) works on dissected packets and decides what is shown from a capture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Capture filters are efficient but crude. Display filters are expressive but need the packets to have been captured first. A typical workflow is a broad capture filter, then a display filter in Wireshark to narrow things down. Quote tcpdump expressions in the shell, because &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;)&lt;/code&gt;, and &lt;code&gt;!&lt;/code&gt; have meaning there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic tcpdump options
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tcpdump &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; eth0 &lt;span class="nt"&gt;-vv&lt;/span&gt; &lt;span class="s1"&gt;'ip6'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-n&lt;/code&gt; stops name resolution, which avoids delays and extra DNS queries that pollute the capture.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-i any&lt;/code&gt; captures on all interfaces; it uses a different link-layer header, but &lt;code&gt;ip6&lt;/code&gt; filters still work.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-vv&lt;/code&gt; prints more detail, including hop limit.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-w file.pcap&lt;/code&gt; writes a capture file for Wireshark.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Addresses and prefixes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight bpf"&gt;&lt;code&gt;host &lt;span class="m"&gt;2001&lt;/span&gt;:&lt;span class="nl"&gt;db8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;::&lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;src host &lt;span class="m"&gt;2001&lt;/span&gt;:&lt;span class="nl"&gt;db8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;::&lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;net &lt;span class="m"&gt;2001&lt;/span&gt;:&lt;span class="nl"&gt;db8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;::/&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;ip&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;and not host &lt;span class="m"&gt;2001&lt;/span&gt;:&lt;span class="nl"&gt;db8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;::&lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;host&lt;/code&gt; matches either direction, &lt;code&gt;net&lt;/code&gt; takes a prefix, and the &lt;code&gt;ip6&lt;/code&gt; primitive restricts the filter to IPv6.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protocols and ports
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;tcp port 443&lt;/code&gt;, &lt;code&gt;udp port 53&lt;/code&gt;, and &lt;code&gt;icmp6&lt;/code&gt; all work for IPv6. &lt;code&gt;icmp6&lt;/code&gt; is a shorthand for IPv6 packets with next header 58. Port filters apply to both IPv4 and IPv6 unless you add &lt;code&gt;ip6&lt;/code&gt; or &lt;code&gt;ip&lt;/code&gt;, so write &lt;code&gt;ip6 and tcp port 443&lt;/code&gt; when you want IPv6 only.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extension header caveat
&lt;/h2&gt;

&lt;p&gt;This is the limitation that matters. In libpcap's filter language, &lt;code&gt;ip6 proto 6&lt;/code&gt; and similar expressions look only at the &lt;strong&gt;Next Header&lt;/strong&gt; field in the fixed IPv6 header. If a packet has a Hop-by-Hop, Routing, or Fragment extension header, the next header is that extension, so a filter for TCP will not match it. Similarly, filters for ports or ICMPv6 types read at fixed offsets and assume the upper-layer header follows the 40-byte fixed header immediately. For ordinary traffic this works. For packets with extension headers it can silently miss. When a capture seems to be missing traffic you know exists, widen the filter, or capture everything for a short period and filter in Wireshark, whose dissector follows the extension header chain.&lt;/p&gt;

&lt;p&gt;There is also a primitive for chains: &lt;code&gt;ip6 protochain 44&lt;/code&gt; matches packets that have a Fragment header anywhere in the chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  ICMPv6 and neighbor discovery
&lt;/h2&gt;

&lt;p&gt;The ICMPv6 type is the first byte after the 40-byte header, so with the no-extension-header assumption you can match it at offset 40:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Filter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Router Solicitation (type 133)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;icmp6 and ip6[40] == 133&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router Advertisement (134)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;icmp6 and ip6[40] == 134&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neighbor Solicitation (135)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;icmp6 and ip6[40] == 135&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neighbor Advertisement (136)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;icmp6 and ip6[40] == 136&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All neighbor discovery (133 to 136)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;icmp6 and ip6[40] &amp;gt;= 133 and ip6[40] &amp;lt;= 136&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Packet Too Big (type 2)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;icmp6 and ip6[40] == 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Echo request and reply (128, 129)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;icmp6 and (ip6[40] == 128 or ip6[40] == 129)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neighbor discovery messages must be sent with a hop limit of 255, and receivers reject anything else, which stops off-link senders from spoofing them. The hop limit is the byte at offset 7, so &lt;code&gt;icmp6 and ip6[7] == 255 and ip6[40] &amp;gt;= 133 and ip6[40] &amp;lt;= 136&lt;/code&gt; shows only well-formed discovery packets, and a capture with &lt;code&gt;ip6[7] != 255&lt;/code&gt; on the same types shows suspicious ones. For multicast, &lt;code&gt;ip6 multicast&lt;/code&gt; matches any IPv6 multicast destination.&lt;/p&gt;

&lt;p&gt;Useful checks with these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Is SLAAC working?&lt;/strong&gt; Capture type 134 on a client interface. If none arrive, the problem is upstream of the host: router, switch, or MLD snooping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is a neighbour answering?&lt;/strong&gt; Capture types 135 and 136 for the target address and look for the advertisement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path MTU trouble?&lt;/strong&gt; Capture type 2 to see whether Packet Too Big reaches the sender. Absence in the face of black-holed large packets suggests filtering, as described in the earlier MTU and ICMPv6 articles.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  TCP handshake and flags
&lt;/h2&gt;

&lt;p&gt;For a SYN on IPv6 without extension headers, the TCP flags byte is at offset 53 (40 plus 13 in the TCP header):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight bpf"&gt;&lt;code&gt;ip&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;and tcp and (ip&lt;span class="m"&gt;6&lt;/span&gt;[&lt;span class="m"&gt;53&lt;/span&gt;] &amp;amp; &lt;span class="m"&gt;0x02&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behaviour of protocol-relative expressions such as &lt;code&gt;tcp[13]&lt;/code&gt; with IPv6 has varied between libpcap versions, so the explicit offset is more predictable, and you should verify any filter against known traffic first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fragments
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ip6 protochain 44&lt;/code&gt; matches fragmented packets. IPv6 fragmentation is done only by the source, so fragments you see came from the endpoint or from a tunnel entry point, and a flow of fragments often points to an MTU problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wireshark display filters
&lt;/h2&gt;

&lt;p&gt;Display filters use field names:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ipv6.addr == 2001:db8:100::25&lt;/code&gt;, &lt;code&gt;ipv6.src&lt;/code&gt;, and &lt;code&gt;ipv6.dst&lt;/code&gt; for addresses.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;icmpv6&lt;/code&gt; for all ICMPv6, and &lt;code&gt;icmpv6.type == 135&lt;/code&gt; for a specific type.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ipv6.hlim == 255&lt;/code&gt; or &lt;code&gt;ipv6.hlim &amp;lt; 64&lt;/code&gt; for hop limit.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ipv6.nxt == 44&lt;/code&gt; for packets whose fixed header points to a fragment header.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tcp.flags.syn == 1 &amp;amp;&amp;amp; tcp.flags.ack == 0&lt;/code&gt; for new connections, regardless of address family.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ipv6 &amp;amp;&amp;amp; !icmpv6&lt;/code&gt; to remove ICMPv6 noise while looking at application traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Use capture filters to limit what you record and display filters to explore it. Remember that libpcap IPv6 offsets assume no extension headers, check the hop limit of 255 for neighbor discovery, and test a new filter against traffic you know exists before trusting an empty result.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ipv6</category>
      <category>networking</category>
      <category>tcpdump</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>IXP Basics for Small Networks: Route Servers, Peering Policies, and PeeringDB</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 19:46:16 +0000</pubDate>
      <link>https://dev.to/ipye_com/ixp-basics-for-small-networks-route-servers-peering-policies-and-peeringdb-4317</link>
      <guid>https://dev.to/ipye_com/ixp-basics-for-small-networks-route-servers-peering-policies-and-peeringdb-4317</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An Internet Exchange Point (IXP) is a shared layer 2 network where many networks connect so they can exchange traffic directly instead of through a transit provider. For a small network the attraction is shorter paths and less transit traffic; the price is operational care, because a mistake on a shared LAN affects other members. This article explains how an exchange works, the difference between bilateral peering and route servers, what PeeringDB is for, and the safety habits that make you a good neighbour. Examples use AS64496 as you, AS64497 as a peer, and &lt;code&gt;2001:db8:ffff::/64&lt;/code&gt; standing in for an IXP peering LAN.&lt;/p&gt;

&lt;h2&gt;
  
  
  How an IXP works
&lt;/h2&gt;

&lt;p&gt;Members connect a port from their router to the exchange's switching fabric and receive an address from the IXP's peering LAN, in both IPv4 and IPv6. They then run eBGP sessions with each other across the fabric. The exchange only forwards Ethernet frames; it does not route, and it does not see your BGP sessions as anything but traffic. Exchanges publish member rules, which commonly include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One MAC address per port, and no proxy ARP or similar tricks.&lt;/li&gt;
&lt;li&gt;Only IPv4, ARP, and IPv6 frames on the peering LAN, with no discovery protocols that leak onto the fabric, such as spanning tree or vendor neighbour-discovery protocols.&lt;/li&gt;
&lt;li&gt;Do not announce the peering LAN prefix into global BGP, and do not point a default route at another member.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last rule matters: a default route toward a peer uses that peer's network as transit without asking. Send across an IXP only traffic for prefixes the peer announced to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bilateral sessions and route servers
&lt;/h2&gt;

&lt;p&gt;There are two ways to learn routes at an exchange.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;Strengths&lt;/th&gt;
&lt;th&gt;Limits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bilateral&lt;/td&gt;
&lt;td&gt;You configure a separate eBGP session with each peer&lt;/td&gt;
&lt;td&gt;Full control of policy and per-peer limits&lt;/td&gt;
&lt;td&gt;One agreement and one session per peer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Route server&lt;/td&gt;
&lt;td&gt;You peer with the IXP's route server, which redistributes members' routes&lt;/td&gt;
&lt;td&gt;One or two sessions give many peers&lt;/td&gt;
&lt;td&gt;You accept what members announce, filtered by the server&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A route server (RFC 7947) is a BGP speaker that passes routes between members without adding its own AS number to the AS_PATH, and without changing the next hop, so traffic still flows directly between the members. Route servers are an efficient way for a small network to reach many peers quickly. Many networks use both: route servers for the long tail and bilateral sessions with the largest partners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peering policies and PeeringDB
&lt;/h2&gt;

&lt;p&gt;Every network chooses whom it will peer with. Policies are often summarised as open, selective, or restrictive, which are the values the PeeringDB policy field uses. Open means the network will usually agree to peer with anyone who asks. Selective means it applies conditions, such as a minimum traffic level or a presence in specific locations. Restrictive means peering only in particular circumstances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PeeringDB&lt;/strong&gt; is a community-maintained database where networks, exchanges, and facilities publish their details. A network record typically includes its ASN, the AS-SET used for filtering, expected prefix counts for IPv4 and IPv6, its policy, contact addresses, and the exchanges where it has ports. Use it two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;As a requester:&lt;/strong&gt; look up a prospective peer, read its policy, and send a short message to its listed peering contact with your ASN, the exchange, and the traffic you expect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;As an operator:&lt;/strong&gt; keep your own record accurate. Many networks build filters and maximum-prefix limits from the listed AS-SET and prefix counts, and many refuse to peer with networks that have no usable record.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Treat the data as a starting point and check it against the IRR and RPKI.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to configure on each session
&lt;/h2&gt;

&lt;p&gt;The baseline filters for any peer, whether bilateral or via a route server, follow RFC 7454:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prefix filters:&lt;/strong&gt; accept only the prefixes the peer is entitled to announce, built from its AS-SET, or rely on the route server's filtering and still apply your own checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No bogons:&lt;/strong&gt; reject private, documentation, and reserved address space and ASNs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RPKI:&lt;/strong&gt; reject routes that validate as invalid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maximum prefixes:&lt;/strong&gt; set a limit from the peer's expected count, with a margin, so a leak ends the session instead of filling your table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next hop check:&lt;/strong&gt; accept routes from a peer only if the next hop is that peer's address on the exchange, unless you are using a route server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First AS check:&lt;/strong&gt; for a bilateral session, require the peer's own ASN to be first in the AS_PATH. Do not enable it on route server sessions, since the route server does not insert its own ASN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outbound:&lt;/strong&gt; announce only your own prefixes and your customers' prefixes, never routes learned from other peers or transit, or you turn yourself into a free transit path.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A sketch in FRR for a bilateral IPv6 peer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="kt"&gt;router bgp&lt;/span&gt;&lt;span class="nf"&gt; 64496&lt;/span&gt;
&lt;span class="k"&gt; neighbor&lt;/span&gt; 2001:db8:ffff::2 remote-as 64497
&lt;span class="k"&gt; neighbor&lt;/span&gt; 2001:db8:ffff::2 &lt;span class="k"&gt;description&lt;/span&gt;&lt;span class="c1"&gt; AS64497 at IXP&lt;/span&gt;
&lt;span class="k"&gt; !&lt;/span&gt;
&lt;span class="k"&gt; address-family&lt;/span&gt; ipv6 unicast
&lt;span class="k"&gt;  neighbor&lt;/span&gt; 2001:db8:ffff::2 activate
&lt;span class="k"&gt;  neighbor&lt;/span&gt; 2001:db8:ffff::2 maximum-prefix 100
&lt;span class="k"&gt;  neighbor&lt;/span&gt; 2001:db8:ffff::2 prefix-list PEER-AS64497-IN in
&lt;span class="k"&gt;  neighbor&lt;/span&gt; 2001:db8:ffff::2 route-map PEER-OUT out
&lt;span class="k"&gt; exit-address-family&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The names and the limit of 100 are placeholders. Your prefix-list and route-map must still be written, as discussed in the earlier customer filtering and communities articles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local preference and traffic engineering
&lt;/h2&gt;

&lt;p&gt;Operators commonly give peer routes a higher local preference than transit routes, which is a policy choice, not a protocol rule. Tag routes with communities on receipt, so you can recognise their origin and avoid re-exporting them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it worth it?
&lt;/h2&gt;

&lt;p&gt;An exchange port has a cost, and you need a presence or a remote connection. Before joining, use flow data, as described in the NetFlow article, to estimate how much of your traffic goes to networks present there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;An IXP is a shared Ethernet fabric over which you run BGP with other members. Use route servers for breadth and bilateral sessions where you need control, keep your PeeringDB record accurate, apply the baseline filters to every session, and announce only what you are entitled to announce.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bgp</category>
      <category>networking</category>
      <category>peering</category>
      <category>internet</category>
    </item>
    <item>
      <title>NetFlow, sFlow, and IPFIX for a Small ISP: Choosing a Flow Export and Reading It</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 19:43:25 +0000</pubDate>
      <link>https://dev.to/ipye_com/netflow-sflow-and-ipfix-for-a-small-isp-choosing-a-flow-export-and-reading-it-i2d</link>
      <guid>https://dev.to/ipye_com/netflow-sflow-and-ipfix-for-a-small-isp-choosing-a-flow-export-and-reading-it-i2d</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Interface counters tell you how much traffic crossed a link. They do not tell you which prefix, port, or customer produced it. Flow telemetry fills that gap: the router, switch, or a Linux host summarises traffic as flows and exports records to a collector. For a small ISP or hosting network it answers the practical questions of who is using the bandwidth, what an attack looked like, and where capacity is going. This article compares the main formats, shows a small Linux setup, and covers IPv6-specific points. Examples use &lt;code&gt;2001:db8:100::/48&lt;/code&gt; and &lt;code&gt;203.0.113.0/24&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a flow is
&lt;/h2&gt;

&lt;p&gt;A flow is a set of packets sharing key fields, typically the source and destination address, protocol, and source and destination ports, observed within a time window. The exporter keeps a cache of active flows and sends a record when a flow ends or after a timeout. Each record holds the key fields plus counters for packets and bytes, timestamps, interfaces, and often TCP flags, AS numbers, and next hop. This is metadata; there is no payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  The formats
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NetFlow v5&lt;/td&gt;
&lt;td&gt;Fixed-format records&lt;/td&gt;
&lt;td&gt;IPv4 only, so it cannot describe IPv6 traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NetFlow v9 (RFC 3954)&lt;/td&gt;
&lt;td&gt;Template-based records&lt;/td&gt;
&lt;td&gt;Supports IPv6 and flexible fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPFIX (RFC 7011)&lt;/td&gt;
&lt;td&gt;Template-based, IETF standard, derived from NetFlow v9&lt;/td&gt;
&lt;td&gt;Registered fields; the vendor-neutral choice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sFlow&lt;/td&gt;
&lt;td&gt;Samples packets and interface counters&lt;/td&gt;
&lt;td&gt;Does not keep a flow cache; the collector builds flows from samples&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The IPv6 point matters: if your exporter only speaks NetFlow v5, IPv6 traffic will be missing from your picture. Use v9, IPFIX, or sFlow. Template-based formats first send a template that describes the record layout, followed by data records, so collectors must receive the templates; a collector restarted mid-stream may discard records until the next template arrives.&lt;/p&gt;

&lt;p&gt;By convention NetFlow is often sent to UDP port 2055, though this is not a standard for NetFlow. IANA registers port 4739 for IPFIX and 6343 for sFlow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sampling and what it costs
&lt;/h2&gt;

&lt;p&gt;Exporting every flow is expensive on busy links, so most devices sample, examining one packet in N. The collector then multiplies byte and packet counts by the sampling rate to estimate totals. Consequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large flows are estimated well. Small and short flows may be missed completely.&lt;/li&gt;
&lt;li&gt;A sampled record is evidence that traffic existed, not an exact count.&lt;/li&gt;
&lt;li&gt;Mixing devices with different sampling rates without recording the rate gives wrong totals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Record the sampling rate in your documentation and make sure your collector uses it. sFlow is built around this idea, since its samples are packet headers taken at a defined rate, while NetFlow and IPFIX exporters can run either sampled or unsampled, depending on the hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small Linux setup
&lt;/h2&gt;

&lt;p&gt;On a Linux router without hardware flow export, a software exporter can read traffic from an interface. One option is &lt;code&gt;softflowd&lt;/code&gt;, which can export NetFlow v9 or IPFIX, and another is &lt;code&gt;pmacctd&lt;/code&gt;. For sFlow on a host, &lt;code&gt;hsflowd&lt;/code&gt; is common. A collector can be &lt;code&gt;nfdump&lt;/code&gt; with &lt;code&gt;nfcapd&lt;/code&gt;, or pmacct's &lt;code&gt;nfacctd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A sketch with softflowd and nfdump:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;softflowd &lt;span class="nt"&gt;-i&lt;/span&gt; eth0 &lt;span class="nt"&gt;-n&lt;/span&gt; 127.0.0.1:2055 &lt;span class="nt"&gt;-v&lt;/span&gt; 9
nfcapd &lt;span class="nt"&gt;-l&lt;/span&gt; /var/cache/nfdump &lt;span class="nt"&gt;-p&lt;/span&gt; 2055 &lt;span class="nt"&gt;-D&lt;/span&gt;
nfdump &lt;span class="nt"&gt;-R&lt;/span&gt; /var/cache/nfdump &lt;span class="nt"&gt;-s&lt;/span&gt; srcip/bytes &lt;span class="nt"&gt;-n&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command exports flows from &lt;code&gt;eth0&lt;/code&gt; as NetFlow v9; the second receives and stores them; the third prints the top ten source addresses by bytes. Add a filter for the IPv6 family using the syntax your nfdump version documents. Option names differ between tools and versions, so check the manual pages. Keep the collector on a separate machine or at least a separate volume for any real network, because flow storage grows steadily.&lt;/p&gt;

&lt;h2&gt;
  
  
  IPv6 considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aggregate by /64.&lt;/strong&gt; As in the logging article, one subscriber can use many addresses within a /64. Ranking individual IPv6 addresses by bytes will mislead you, so most tools let you group by prefix length. Use /64, and widen to /48 for delegations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extension headers.&lt;/strong&gt; Some exporters classify packets with extension headers poorly, so ports may be zero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual-stack views.&lt;/strong&gt; Report IPv4 and IPv6 separately before combining them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fragments.&lt;/strong&gt; Non-first fragments have no port information, so they appear as port zero or in separate flows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Useful questions to ask the data
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Top talkers:&lt;/strong&gt; which destination prefixes or customers use the most bytes in the last hour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attack triage:&lt;/strong&gt; packets per second by destination address and protocol, to see whether a spike is a flood aimed at one host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capacity planning:&lt;/strong&gt; daily peaks by upstream, peer, or customer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Peering decisions:&lt;/strong&gt; which origin ASes carry the most traffic, if your records include AS numbers, to judge whether a direct peering would be worthwhile.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Abuse and complaints:&lt;/strong&gt; whether a host did contact a destination at a stated time, with timestamps that you should verify against NTP-synced clocks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Operational notes
&lt;/h2&gt;

&lt;p&gt;Make sure router and collector clocks are synchronised. Choose flow timeouts deliberately, since active timeouts break long flows into several records and short inactive timeouts split idle connections. Flow records are personal data in some jurisdictions, so set retention, and restrict access. Finally, protect the collector: it receives unauthenticated UDP, so accept exports only from known router addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Use NetFlow v9, IPFIX, or sFlow, because NetFlow v5 cannot carry IPv6. Know your sampling rate and apply it, aggregate IPv6 by /64, keep clocks and timeouts sane, and treat flow data as an estimate that answers "who and how much" rather than an exact bill of every packet.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>monitoring</category>
      <category>isp</category>
      <category>devops</category>
    </item>
    <item>
      <title>Rate Limiting and Banning IPv6 Clients by /64 with nftables</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 19:00:52 +0000</pubDate>
      <link>https://dev.to/ipye_com/rate-limiting-and-banning-ipv6-clients-by-64-with-nftables-4k97</link>
      <guid>https://dev.to/ipye_com/rate-limiting-and-banning-ipv6-clients-by-64-with-nftables-4k97</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Rate limits and ban lists assume that an address stands for a client. In IPv4 that is a decent approximation. In IPv6 it fails: a single customer with a /64 has 2^64 addresses available, and a script that picks a fresh source address for every request will sail past any per-address limit and fill your ban list with entries that never match again. The fix is to aggregate: limit and ban on a prefix, usually the /64. This article shows how to do that with nftables and what to watch out for with fail2ban. Examples use &lt;code&gt;2001:db8:100::/48&lt;/code&gt; and &lt;code&gt;203.0.113.0/24&lt;/code&gt;; test every rule on a non-production machine, and check syntax against your nftables version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the unit
&lt;/h2&gt;

&lt;p&gt;The reasoning is covered in the article on IPv6 logging and abuse handling: a /64 is a normal subnet, and the host inside it can use any address in it. So the default unit for IPv6 limits is the /64. For IPv4 the equivalent is the single address (or a /32), which is a poor stand-in for a person behind carrier-grade NAT, but that is a separate issue.&lt;/p&gt;

&lt;p&gt;Some cautions apply before you start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A /64 can be shared between many users on some networks, such as public Wi-Fi or mobile networks. A strict limit on a shared /64 hurts innocent users. Use limits that suit your service, and treat bans as temporary.&lt;/li&gt;
&lt;li&gt;Some customers receive more than a /64 (a /56 or /48), so a determined client can hop between /64s. Widen the unit when evidence supports it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Per-/64 rate limiting with a meter
&lt;/h2&gt;

&lt;p&gt;nftables can limit using a &lt;em&gt;dynamic set&lt;/em&gt; keyed on a masked address. The following limits new TCP connections to port 443, counting all addresses within the same /64 together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;

    ct state established,related accept
    iif lo accept
    meta l4proto ipv6-icmp accept

    tcp dport 443 ct state new \
      meter flood6 { ip6 saddr &amp;amp; ffff:ffff:ffff:ffff:: \
                     timeout 5m limit rate over 20/second burst 40 packets } \
      counter drop

    tcp dport 443 accept
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;ip6 saddr &amp;amp; ffff:ffff:ffff:ffff::&lt;/code&gt; masks the source address to its top 64 bits, so every address in the /64 maps to the same meter entry. The &lt;code&gt;limit rate over&lt;/code&gt; clause matches packets above the rate, and these are dropped. The &lt;code&gt;timeout&lt;/code&gt; removes idle entries so the meter does not grow without bound. Meter syntax has changed between nftables releases, so check &lt;code&gt;nft -c -f file.nft&lt;/code&gt; for validity and the wiki for your version. Add an equivalent rule for IPv4 with &lt;code&gt;ip saddr&lt;/code&gt;, whose natural unit is the single address.&lt;/p&gt;

&lt;p&gt;Keep ICMPv6 accepted ahead of any rate rule, as the earlier article on ICMPv6 explains: dropping neighbour discovery or Packet Too Big messages causes outages that look like unrelated problems. Rate-limit ICMPv6 separately and generously if you need to, instead of blocking it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A ban list of prefixes
&lt;/h2&gt;

&lt;p&gt;For persistent offenders, keep a set of prefixes. An &lt;em&gt;interval&lt;/em&gt; set holds ranges, and &lt;code&gt;timeout&lt;/code&gt; lets entries expire:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vcl"&gt;&lt;code&gt;table inet filter &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; banned6 &lt;span class="p"&gt;{&lt;/span&gt;
    type ipv6_addr
    flags interval&lt;span class="p"&gt;,&lt;/span&gt; timeout
  &lt;span class="p"&gt;}&lt;/span&gt;
  chain input &lt;span class="p"&gt;{&lt;/span&gt;
    type filter hook input priority &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; policy accept&lt;span class="p"&gt;;&lt;/span&gt;
    ip6 saddr @banned6 drop
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add and remove entries at runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nft add element inet filter banned6 &lt;span class="o"&gt;{&lt;/span&gt; 2001:db8:100:1::/64 &lt;span class="nb"&gt;timeout &lt;/span&gt;1h &lt;span class="o"&gt;}&lt;/span&gt;
nft delete element inet filter banned6 &lt;span class="o"&gt;{&lt;/span&gt; 2001:db8:100:1::/64 &lt;span class="o"&gt;}&lt;/span&gt;
nft list &lt;span class="nb"&gt;set &lt;/span&gt;inet filter banned6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An entry is one prefix, regardless of how many addresses inside it were used, so the list stays small. Always set a timeout: prefixes get reassigned, and a permanent ban can end up blocking an unrelated user months later. Review hits with a counter on the rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  fail2ban and IPv6
&lt;/h2&gt;

&lt;p&gt;fail2ban watches logs and bans the addresses it sees. Current versions support IPv6, and ban actions exist for nftables. Two points need attention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It bans individual addresses by default.&lt;/strong&gt; An attacker rotating inside a /64 will not be stopped by a ban on one address. Options are to use an action that adds the whole /64 to a prefix set, which means a custom action or filter configuration, or to make rate limiting by /64 in nftables your primary defence and use fail2ban for slower, credential-based abuse such as SSH.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matching log lines.&lt;/strong&gt; The filter must capture IPv6 addresses in the format your service logs. Make sure normalisation and the form of the address are what the regex expects. Test with &lt;code&gt;fail2ban-regex&lt;/code&gt; against real log lines containing IPv6 addresses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember &lt;code&gt;ignoreip&lt;/code&gt;: put your own management addresses and prefixes in the ignore list, including IPv6 ones, so a typo does not lock you out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Application-level limits
&lt;/h2&gt;

&lt;p&gt;Reverse proxies and web servers have their own limits, keyed by whatever variable you choose. By default, nginx's &lt;code&gt;limit_req_zone&lt;/code&gt; keys on the client address, and this is the per-address problem again. Where the proxy cannot aggregate easily, apply the limit in the firewall in front of it. If the proxy sits behind a load balancer, use the real client address, as the article on the PROXY protocol explains, or all limits would apply to the balancer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nft &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/nftables.conf     &lt;span class="c"&gt;# check syntax without applying&lt;/span&gt;
nft list meter inet filter flood6   &lt;span class="c"&gt;# inspect the entries (name may differ by version)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate traffic from several source addresses in a test /64 and confirm they share a counter, and that traffic from a different /64 does not. Then check that a normal client, with a few connections, is never limited.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Aggregate on the /64, expire every ban, keep ICMPv6 flowing, and test from a real IPv6 host. A limit that counts addresses in IPv6 is a limit that attackers can ignore with no effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ipv6</category>
      <category>security</category>
      <category>linux</category>
      <category>networking</category>
    </item>
    <item>
      <title>IPv6 Logging and Abuse Handling: Why the /64 Is the Unit</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 19:00:22 +0000</pubDate>
      <link>https://dev.to/ipye_com/ipv6-logging-and-abuse-handling-why-the-64-is-the-unit-5eo5</link>
      <guid>https://dev.to/ipye_com/ipv6-logging-and-abuse-handling-why-the-64-is-the-unit-5eo5</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In IPv4, one address usually identifies one customer or one host, so counting, blocking, and reporting by address works well enough. In IPv6 that stops being true. A single subscriber can have a /64 or larger, and a host with privacy addresses (RFC 8981) changes its source address regularly. A log that treats each IPv6 address as a separate client counts one machine as thousands, misses abuse patterns, and fills with entries that never repeat. This article covers what to log, how to aggregate, how to find the right contact, and what to put in an abuse report. Examples use &lt;code&gt;2001:db8:100::/48&lt;/code&gt; and &lt;code&gt;203.0.113.0/24&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log the full address, aggregate for analysis
&lt;/h2&gt;

&lt;p&gt;Keep the complete address in the raw log, since you may need it later. Then derive an aggregate for analysis. Useful reasoning units are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observation&lt;/th&gt;
&lt;th&gt;Block or count by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One misbehaving client, stable address&lt;/td&gt;
&lt;td&gt;The single address, only if it stays fixed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client rotating within its subnet&lt;/td&gt;
&lt;td&gt;The /64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client rotating across several /64s&lt;/td&gt;
&lt;td&gt;The /56 or /48 of the delegation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Whole network misbehaving&lt;/td&gt;
&lt;td&gt;The announced prefix or ASN, after checking it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The reason for the /64 is that it is the standard size of a subnet, and a device on that subnet can pick any address in it, so no one address is meaningful. Home networks and mobile networks differ in what they delegate, and you cannot see this from the outside, so be ready to widen the unit when evidence shows an attacker moving between /64s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normalise the text
&lt;/h2&gt;

&lt;p&gt;IPv6 allows many textual forms of the same address: leading zeros, &lt;code&gt;::&lt;/code&gt; compression, and upper or lower case. RFC 5952 defines a canonical form (lowercase, leading zeros removed, longest run of zeros compressed). If you search logs with &lt;code&gt;grep&lt;/code&gt;, differently formatted values will not match each other. Normalise addresses at ingestion, or store them in a type that understands them. In PostgreSQL, for instance, the &lt;code&gt;inet&lt;/code&gt; type stores addresses numerically, and you can group by /64 with a query like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;set_masklen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;access_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In scripting, Python's &lt;code&gt;ipaddress&lt;/code&gt; module can do the same: &lt;code&gt;ipaddress.ip_network('2001:db8:100:1::25/64', strict=False)&lt;/code&gt; returns the enclosing /64.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take care with proxies and NAT
&lt;/h2&gt;

&lt;p&gt;Behind a load balancer, the logged address may be the balancer's. Restore the real client address first, using the PROXY protocol or a trusted header, as discussed in an earlier article, or your records will say nothing about the client. IPv4 clients behind carrier-grade NAT share one address among many users, so IPv4 evidence is weaker than it looks. IPv6 evidence, though better, is also not a person.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time and records
&lt;/h2&gt;

&lt;p&gt;Record time in UTC with its zone, and record the time zone of any report you send. For abuse, an address without a timestamp cannot be traced, because a prefix may be reassigned and a subscriber's address may rotate. Keep what you need, for as long as you need it, and no more. IP addresses are treated as personal data in some jurisdictions, so follow your own retention policy and applicable law, and decide in advance who may query these logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find the right contact
&lt;/h2&gt;

&lt;p&gt;To report abuse you need the responsible network's contact. Look up the address with RDAP or WHOIS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;whois 2001:db8:100:1::25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the most specific record that covers the address, not the parent allocation: a sub-delegation to a customer or hosting service often has its own contact. Look for the &lt;code&gt;abuse-c&lt;/code&gt; or abuse mailbox, the organisation, and the &lt;code&gt;inet6num&lt;/code&gt; range. If the specific record has no abuse contact, go up a level. The routing registry or &lt;code&gt;origin&lt;/code&gt; AS data show who announces the prefix, which can lead to the upstream when the registered organisation does not respond. The article on WHOIS and RDAP describes reading these records.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a useful abuse report contains
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The offending address and the prefix (the /64) it came from.&lt;/li&gt;
&lt;li&gt;Timestamps in UTC, with the time zone stated.&lt;/li&gt;
&lt;li&gt;A short, factual description of the behaviour, such as repeated login attempts or scraping against a specific service.&lt;/li&gt;
&lt;li&gt;A few sample log lines, with your own sensitive data removed.&lt;/li&gt;
&lt;li&gt;Whether the traffic is ongoing.&lt;/li&gt;
&lt;li&gt;Your contact details, and what action you ask for.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep it brief and factual, one incident per report, and sent to the registered contact. Do not attach large log files unless requested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blocking responsibly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Start narrow: block the /64, not the /48, unless evidence supports widening.&lt;/li&gt;
&lt;li&gt;Use expiry on every block, so mistakes and reassigned prefixes age out.&lt;/li&gt;
&lt;li&gt;Check what you are blocking: a /64 in a hosting network might be a shared service, and a mobile network /64 may be shared between users, depending on how the operator assigns them.&lt;/li&gt;
&lt;li&gt;Do not block ICMPv6 as a side effect of blocking addresses.&lt;/li&gt;
&lt;li&gt;Record why each block was added.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Treat the /64 as the basic unit, log in canonical form, keep the full address, aggregate for analysis, and send precise reports to the contact in the most specific registry record. Done consistently, IPv6 abuse handling works much like IPv4, with the unit of identity changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ipv6</category>
      <category>security</category>
      <category>logging</category>
      <category>networking</category>
    </item>
    <item>
      <title>GeoIP and Geofeeds: Getting an IPv6 Prefix Located Correctly</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 18:53:59 +0000</pubDate>
      <link>https://dev.to/ipye_com/geoip-and-geofeeds-getting-an-ipv6-prefix-located-correctly-50bi</link>
      <guid>https://dev.to/ipye_com/geoip-and-geofeeds-getting-an-ipv6-prefix-located-correctly-50bi</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Anyone who has had a new address block mislocated knows the symptoms: a website shows content in the wrong language, a streaming service refuses access, or a fraud check flags a user because the address "is in" another country. IP geolocation is not a property of the network; it is an inference made by commercial and open datasets from many signals. Because they are inferences, they can lag behind changes and be plain wrong, especially for new prefixes, moved prefixes, and IPv6, where address space is large and measurement signals are sparse. This article explains where location data comes from, what a &lt;strong&gt;geofeed&lt;/strong&gt; (RFC 8805) is, and how to maintain accurate data. Examples use &lt;code&gt;2001:db8:100::/48&lt;/code&gt; and &lt;code&gt;192.0.2.0/24&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where location data comes from
&lt;/h2&gt;

&lt;p&gt;Geolocation providers combine several kinds of evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Registry data:&lt;/strong&gt; the country in the allocation or assignment record in WHOIS or RDAP. It is coarse and reflects where the holder registered the block, not where traffic originates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network measurements:&lt;/strong&gt; latency from probes in known places, and traceroute paths with location hints in router names.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing data:&lt;/strong&gt; which AS announces the prefix, and where that AS operates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer-submitted corrections:&lt;/strong&gt; the data providers accept from address holders and users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-published geofeeds:&lt;/strong&gt; the topic of this article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these is authoritative, which is why two providers can disagree about the same address, and why a block that moved from one country to another can keep its old location for a long time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a geofeed is
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;geofeed&lt;/strong&gt; is a plain CSV file, published by the party that knows where its address space is used, listing prefixes and their locations. RFC 8805 defines the format: one line per prefix, with these fields:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ip_prefix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An IPv4 or IPv6 prefix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2001:db8:100::/48&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alpha2code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ISO 3166-1 country code&lt;/td&gt;
&lt;td&gt;&lt;code&gt;US&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;region&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ISO 3166-2 subdivision code&lt;/td&gt;
&lt;td&gt;&lt;code&gt;US-CA&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;city&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Free-text city name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Los Angeles&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;postal_code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Postal code&lt;/td&gt;
&lt;td&gt;usually left empty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Lines starting with &lt;code&gt;#&lt;/code&gt; are comments, and the file is UTF-8 text. A complete example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Geofeed for AS64496
192.0.2.0/24,US,US-CA,Los Angeles,
2001:db8:100::/48,US,US-CA,Los Angeles,
2001:db8:101::/48,US,US-NY,New York,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The RFC discourages postal codes because of privacy concerns, and recommends not publishing location data more precise than needed. A prefix can be given a country only, or country and region, by leaving later fields empty. Geofeed data is a statement by the publisher, meant to be consumed by providers who choose how much to trust it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making a geofeed discoverable
&lt;/h2&gt;

&lt;p&gt;A file nobody finds does nothing. RFC 8805 describes publishing its URL in the address registration record, and RFC 9632 specifies finding and using it in more detail, including a &lt;code&gt;geofeed:&lt;/code&gt; attribute for RPSL-based registries, with the older practice of a &lt;code&gt;remarks:&lt;/code&gt; line also in use. The URL must be served over HTTPS. The mechanism available differs among the five RIRs, so read your registry's documentation on where the URL can be recorded. RFC 9632 also describes how the file can optionally be authenticated using RPKI, which helps consumers verify that it was published by the holder of the space.&lt;/p&gt;

&lt;p&gt;An RPSL-style record for a registry that supports the attribute might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;inet6num&lt;/span&gt;: &lt;span class="m"&gt;2001&lt;/span&gt;:&lt;span class="n"&gt;db8&lt;/span&gt;:&lt;span class="m"&gt;100&lt;/span&gt;::/&lt;span class="m"&gt;48&lt;/span&gt;
&lt;span class="n"&gt;geofeed&lt;/span&gt;:  &lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;/&lt;span class="n"&gt;geofeed&lt;/span&gt;.&lt;span class="n"&gt;csv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check your registry's schema, as this varies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maintaining it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep it in sync with reality.&lt;/strong&gt; When you move or lease out a prefix, update the file. A stale line is worse than none.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match the announced prefixes.&lt;/strong&gt; Entries can cover more specific prefixes than you announce, but a feed that does not correspond to the BGP table is harder for consumers to trust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serve it reliably.&lt;/strong&gt; Use HTTPS, and a stable URL, and keep it available. Consumers fetch it periodically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate the syntax&lt;/strong&gt; before publishing: well-formed CIDR, correct country codes, no stray whitespace, valid UTF-8.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Correcting a provider's data
&lt;/h2&gt;

&lt;p&gt;A geofeed is a hint, and providers pick it up at their own pace. For a prefix that is still wrong:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look it up at several providers' public lookup pages, and note which are wrong.&lt;/li&gt;
&lt;li&gt;Make sure your registry record and geofeed are correct and consistent.&lt;/li&gt;
&lt;li&gt;Use each provider's correction process, which typically accepts a prefix and the intended location, sometimes with a link to the geofeed.&lt;/li&gt;
&lt;li&gt;Recheck after a while. Corrections take time to propagate into the databases that applications download.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  IPv6 specifics
&lt;/h2&gt;

&lt;p&gt;Geolocation databases often handle IPv6 at larger granularity, so announcing and registering a prefix as a single /48 with one location gives the cleanest result. If you split one /48 between cities, providers have little to go on below the /48, and a /64-level split is rarely honoured. Users on IPv6 also move through privacy addresses and dynamic prefixes, so data about a whole site's prefix generalises better than about single addresses. Plan your address layout so that each location gets its own prefix of a size providers can use, as discussed in the subnetting articles.&lt;/p&gt;

&lt;h2&gt;
  
  
  What not to rely on
&lt;/h2&gt;

&lt;p&gt;Do not use IP geolocation for anything that must be correct, such as legal decisions, or treat it as proof of a user's location. It is a statistical aid. For a new block, publish the geofeed before the block carries traffic, correct what is wrong early, and keep it current.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ipv6</category>
      <category>networking</category>
      <category>geoip</category>
      <category>internet</category>
    </item>
    <item>
      <title>BFD Basics: Fast Failure Detection for BGP and Static Routes</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 18:53:05 +0000</pubDate>
      <link>https://dev.to/ipye_com/bfd-basics-fast-failure-detection-for-bgp-and-static-routes-2jp9</link>
      <guid>https://dev.to/ipye_com/bfd-basics-fast-failure-detection-for-bgp-and-static-routes-2jp9</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When a link fails cleanly, the interface goes down and routing reacts at once. Many failures are not clean: a switch or media converter in the middle keeps the link light on while packets stop flowing, a line card stops forwarding without dropping the interface, or a remote process hangs. In those cases the router learns of the problem only when a protocol timer runs out. BGP's default hold time is commonly 90 or 180 seconds, depending on the implementation, which is a long time to send traffic into a black hole. &lt;strong&gt;Bidirectional Forwarding Detection (BFD)&lt;/strong&gt; exists to shrink that to a fraction of a second or a few seconds. This article explains how BFD works, how to configure it, and when it causes more harm than good. Examples use AS64496, AS64511, and &lt;code&gt;2001:db8:ffff::/64&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What BFD is
&lt;/h2&gt;

&lt;p&gt;BFD (RFC 5880) is a lightweight hello protocol, independent of any routing protocol. Two systems exchange small control packets at a negotiated rate over a path. If a system stops receiving them for a set time, it declares the path down and tells the routing protocols that registered an interest. BGP, OSPF, IS-IS, and static routes can all use it, so one fast detector can serve many protocols.&lt;/p&gt;

&lt;p&gt;Two things make it effective. The packets are tiny and simple, so implementations can run them frequently, sometimes in a router's forwarding hardware instead of its control CPU. And BFD tests the &lt;strong&gt;forwarding path&lt;/strong&gt; between the two systems, not just the routing process, which is why it catches failures that the link state does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The timers
&lt;/h2&gt;

&lt;p&gt;Each side advertises two intervals: the minimum interval at which it wants to transmit, and the minimum at which it is willing to receive. The actual rates are negotiated, and the slower side wins. A third parameter, the &lt;strong&gt;detect multiplier&lt;/strong&gt;, says how many consecutive packets can be missed before the session is declared down. The detection time is roughly the multiplier times the negotiated interval.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Interval&lt;/th&gt;
&lt;th&gt;Multiplier&lt;/th&gt;
&lt;th&gt;Detection time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1000 ms&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;about 3 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;300 ms&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;about 900 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100 ms&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;about 300 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50 ms&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;about 150 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Shorter is not always better. A multiplier of 3 is a common starting point, and an interval of 300 ms is a reasonable one for software-based implementations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transport details
&lt;/h2&gt;

&lt;p&gt;For the common single-hop case, RFC 5881 specifies that BFD control packets use UDP destination port 3784, over both IPv4 and IPv6, and that the TTL (or hop limit) is set to 255. The receiver checks that value, which restricts packets to the directly attached neighbour in the same way as the generalised TTL security mechanism. For paths that cross more than one hop, such as an iBGP session between loopbacks, RFC 5883 uses UDP port 4784. An optional &lt;strong&gt;echo&lt;/strong&gt; function, on UDP port 3785, makes the remote system loop packets back through its forwarding plane. Do not forget these ports in firewall rules: if BFD packets are filtered, the sessions never come up, or they flap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring BFD with BGP (FRR example)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;bfd&lt;/span&gt;
&lt;span class="k"&gt; profile&lt;/span&gt; fast
&lt;span class="k"&gt;  detect-multiplier&lt;/span&gt; 3
&lt;span class="k"&gt;  receive-interval&lt;/span&gt; 300
&lt;span class="k"&gt;  transmit-interval&lt;/span&gt; 300
&lt;span class="k"&gt; exit&lt;/span&gt;
&lt;span class="k"&gt;exit&lt;/span&gt;

&lt;span class="kt"&gt;router bgp&lt;/span&gt;&lt;span class="nf"&gt; 64496&lt;/span&gt;
&lt;span class="k"&gt; neighbor&lt;/span&gt; 2001:db8:ffff::1 remote-as 64511
&lt;span class="k"&gt; neighbor&lt;/span&gt; 2001:db8:ffff::1 bfd
&lt;span class="k"&gt; neighbor&lt;/span&gt; 2001:db8:ffff::1 bfd profile fast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FRR runs &lt;code&gt;bfdd&lt;/code&gt; as a separate daemon and needs it enabled in the daemons file. In BIRD, the BFD protocol is defined separately, and a BGP protocol uses it with &lt;code&gt;bfd on;&lt;/code&gt;, with the timers in the &lt;code&gt;protocol bfd&lt;/code&gt; block. The names and syntax of options vary between versions, so verify against your documentation. Both ends have to be configured; BFD only starts when the peer also wants it.&lt;/p&gt;

&lt;p&gt;To inspect the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;show bfd peers            # FRR: state, intervals, uptime
show bgp neighbors 2001:db8:ffff::1 | include BFD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A session in state &lt;code&gt;Up&lt;/code&gt; with the negotiated intervals you expect is what you want to see. &lt;code&gt;Down&lt;/code&gt; or &lt;code&gt;AdminDown&lt;/code&gt;, together with the diagnostic code, indicates why a session is not up.&lt;/p&gt;

&lt;h2&gt;
  
  
  When BFD is the wrong tool
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aggressive timers on a busy CPU.&lt;/strong&gt; If the router handles BFD in software and is busy, delayed packets can lead to false "down" events, and BFD then causes the flapping it was meant to prevent. Begin with conservative timers, and tighten only after observing stability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paths that legitimately jitter.&lt;/strong&gt; Wireless links, congested tunnels, and long-haul circuits with variable delay do poorly with sub-second timers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where recovery is not faster.&lt;/strong&gt; Detecting a failure in 300 ms is pointless if the rest of the network takes 30 seconds to converge, or if there is no alternate path. In that case BFD gives you an earlier failure and nothing more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bundles of links.&lt;/strong&gt; In link aggregation, a BFD session over the logical interface may not notice a single member failing. RFC 7130 defines BFD on individual member links of a bundle for that purpose, where the hardware supports it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Interaction with other features
&lt;/h2&gt;

&lt;p&gt;BFD speeds up reaction to failure but does not stop instability. If a link bounces regularly, BFD makes each bounce visible faster. The article on route flapping describes what to do about the sources. It also interacts with graceful restart: some implementations declare BFD down while a neighbour is restarting its control plane, which cancels the benefit of graceful restart, so test combinations before relying on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical advice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Use BFD on links where a middle device can hide failures, and where you have a real alternative path.&lt;/li&gt;
&lt;li&gt;Start with a 3x multiplier and a moderate interval, and confirm both ends agree.&lt;/li&gt;
&lt;li&gt;Allow UDP 3784 (and 4784 for multihop) in firewall rules, and restrict them to your neighbours.&lt;/li&gt;
&lt;li&gt;Alert on BFD sessions leaving &lt;code&gt;Up&lt;/code&gt;, in the same dashboard as BGP state.&lt;/li&gt;
&lt;li&gt;Review after any hardware change, since hardware offload can change what timers are safe.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Used selectively, BFD turns a minute-long blackhole into a sub-second reroute.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bgp</category>
      <category>networking</category>
      <category>routing</category>
      <category>devops</category>
    </item>
    <item>
      <title>ICMPv6 Type by Type: A Reference for What a Firewall Must Allow</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 16:23:02 +0000</pubDate>
      <link>https://dev.to/ipye_com/icmpv6-type-by-type-a-reference-for-what-a-firewall-must-allow-alg</link>
      <guid>https://dev.to/ipye_com/icmpv6-type-by-type-a-reference-for-what-a-firewall-must-allow-alg</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In IPv4, ICMP is a diagnostic extra, and blocking all of it hurts but rarely breaks everything. In IPv6, ICMPv6 is part of the protocol itself: address resolution, router discovery, path MTU discovery, and error reporting all depend on it. A firewall that drops ICMPv6 wholesale produces failures that look random. RFC 4890 ("Recommendations for Filtering ICMPv6 Messages in Firewalls") is the reference for what to permit. This article is a type-by-type table built from it, with the reasoning, plus an nftables sketch. Examples use &lt;code&gt;2001:db8::/32&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two families of messages
&lt;/h2&gt;

&lt;p&gt;ICMPv6 (RFC 4443) splits by type number:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error messages&lt;/strong&gt; have types 0 to 127: Destination Unreachable (1), Packet Too Big (2), Time Exceeded (3), Parameter Problem (4).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Informational messages&lt;/strong&gt; have types 128 to 255: Echo Request (128), Echo Reply (129), the Neighbor Discovery family (133 to 137), and multicast listener messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reference table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Guidance (from RFC 4890)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Destination Unreachable&lt;/td&gt;
&lt;td&gt;Transit and local&lt;/td&gt;
&lt;td&gt;Must not be dropped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Packet Too Big&lt;/td&gt;
&lt;td&gt;Transit and local&lt;/td&gt;
&lt;td&gt;Must not be dropped; path MTU discovery depends on it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Time Exceeded (code 0, hop limit)&lt;/td&gt;
&lt;td&gt;Transit and local&lt;/td&gt;
&lt;td&gt;Must not be dropped; traceroute and loop reporting need it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Parameter Problem (codes 1 and 2)&lt;/td&gt;
&lt;td&gt;Transit and local&lt;/td&gt;
&lt;td&gt;Must not be dropped; code 0 should also be allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;Echo Request&lt;/td&gt;
&lt;td&gt;Inbound to your hosts&lt;/td&gt;
&lt;td&gt;Allow, ideally rate-limited, for services you want to be testable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;129&lt;/td&gt;
&lt;td&gt;Echo Reply&lt;/td&gt;
&lt;td&gt;Return&lt;/td&gt;
&lt;td&gt;Allow for replies to your own pings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;133&lt;/td&gt;
&lt;td&gt;Router Solicitation&lt;/td&gt;
&lt;td&gt;Link-local only&lt;/td&gt;
&lt;td&gt;Allow on the local link; never forward off-link&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;134&lt;/td&gt;
&lt;td&gt;Router Advertisement&lt;/td&gt;
&lt;td&gt;Link-local only&lt;/td&gt;
&lt;td&gt;Allow on the local link, from routers only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;135&lt;/td&gt;
&lt;td&gt;Neighbor Solicitation&lt;/td&gt;
&lt;td&gt;Link-local only&lt;/td&gt;
&lt;td&gt;Allow on the local link&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;136&lt;/td&gt;
&lt;td&gt;Neighbor Advertisement&lt;/td&gt;
&lt;td&gt;Link-local only&lt;/td&gt;
&lt;td&gt;Allow on the local link&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;137&lt;/td&gt;
&lt;td&gt;Redirect&lt;/td&gt;
&lt;td&gt;Link-local only&lt;/td&gt;
&lt;td&gt;Allow only if you use it; many hosts ignore or disable it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;130, 131, 132, 143&lt;/td&gt;
&lt;td&gt;Multicast Listener (MLD)&lt;/td&gt;
&lt;td&gt;Link-local only&lt;/td&gt;
&lt;td&gt;Allow on-link where multicast is used&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The principle behind the "transit" versus "link-local" split: error messages and echo cross networks, so they need to pass through border firewalls. Neighbor Discovery and MLD are confined to one link, so they must work on the link but should not cross it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why each group matters
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Packet Too Big (2).&lt;/strong&gt; IPv6 routers never fragment, so the sender learns the path MTU only from this message (RFC 8201). Drop it and large transfers hang after the handshake while small packets work. This is the most common ICMPv6 mistake in firewalls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Destination Unreachable (1) and Time Exceeded (3).&lt;/strong&gt; Without them, connections to closed ports or dead addresses time out rather than failing fast, and traceroute shows nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameter Problem (4).&lt;/strong&gt; Reports a malformed header or an unrecognised option or Next Header. Code 1 (unrecognised Next Header) and code 2 (unrecognised IPv6 option) are meaningful for upper layers and for extension header handling, so allow them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neighbor Discovery (133 to 137).&lt;/strong&gt; Hosts find each other's link-layer addresses with Neighbor Solicitation and Advertisement, and find routers with Router Solicitation and Advertisement (RFC 4861). Blocking these on a link breaks the link. These messages are sent with a hop limit of 255, and receivers verify it: a packet arriving with a lower value has crossed a router and must be discarded, which is the defence against off-link forgery. Therefore never forward them across links, and do not change hop limits on them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Echo (128, 129).&lt;/strong&gt; Allowing inbound echo to servers is a policy choice. Blocking it gains little security and makes diagnosis harder. RFC 4890 suggests allowing it, with rate limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MLD (130, 131, 132, 143).&lt;/strong&gt; Multicast Listener Discovery reports which multicast groups a host listens to. IPv6 Neighbor Discovery uses solicited-node multicast addresses, so MLD matters on switches that do MLD snooping: if the switch does not see the reports, it can prune the multicast traffic that Neighbor Solicitation needs. If you see intermittent neighbor failures on a snooping switch, check MLD.&lt;/p&gt;

&lt;h2&gt;
  
  
  nftables sketch for a host
&lt;/h2&gt;

&lt;p&gt;This is a starting point for a host input chain; adapt it, and keep the policy default-deny for everything else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;

    ct state established,related accept
    iif lo accept

    # Error messages and path MTU discovery
    icmpv6 type { destination-unreachable, packet-too-big,
                  time-exceeded, parameter-problem } accept

    # Neighbor Discovery: only valid with hop limit 255
    icmpv6 type { nd-router-solicit, nd-router-advert,
                  nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept

    # Echo, rate-limited
    icmpv6 type echo-request limit rate 10/second accept
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hosts that are not routers do not need to accept Router Solicitation, so remove &lt;code&gt;nd-router-solicit&lt;/code&gt; there. A router, in turn, needs the forward chain handled separately: allow the error messages and echo to pass, and do not forward the link-local ones. Check the syntax against your nftables version. The rate figure in the example is arbitrary; choose a value for your own traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rate-limit, do not block
&lt;/h2&gt;

&lt;p&gt;The usual worry about permitting ICMPv6 is abuse. The proportionate response is rate limiting for the types that can be triggered by outsiders, such as echo and error generation, not a blanket drop. Router CPUs also limit how quickly they generate ICMPv6 errors, which is why traceroute and mtr can show missing or slow hops that do not reflect real forwarding problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to test
&lt;/h2&gt;

&lt;p&gt;From a different network, &lt;code&gt;ping -6&lt;/code&gt; your server, then fetch a large page with &lt;code&gt;curl -6&lt;/code&gt; to exercise path MTU discovery. On a link, &lt;code&gt;ndisc6&lt;/code&gt; or &lt;code&gt;ip -6 neigh&lt;/code&gt; shows whether Neighbor Discovery works. If anything fails only over IPv6 and only for larger transfers, suspect a drop of Packet Too Big first.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ipv6</category>
      <category>networking</category>
      <category>firewall</category>
      <category>security</category>
    </item>
    <item>
      <title>DHCPv6 Prefix Delegation Explained: How a Router Gets Its Own IPv6 Prefix</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 16:22:08 +0000</pubDate>
      <link>https://dev.to/ipye_com/dhcpv6-prefix-delegation-explained-how-a-router-gets-its-own-ipv6-prefix-1blg</link>
      <guid>https://dev.to/ipye_com/dhcpv6-prefix-delegation-explained-how-a-router-gets-its-own-ipv6-prefix-1blg</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With IPv4, a small-office router usually gets one address and uses NAT for everything behind it. With IPv6, the provider hands the router a whole &lt;strong&gt;prefix&lt;/strong&gt;, which the router subdivides among its internal networks. The standard mechanism is DHCPv6 Prefix Delegation (DHCPv6-PD), defined in the DHCPv6 specification, RFC 8415, which obsoleted the original RFC 3633 for this purpose. This article explains the roles, the message exchange, and the points where it commonly fails. Examples use &lt;code&gt;2001:db8::/32&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The roles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Delegating router:&lt;/strong&gt; the provider-side device (often a BNG or an edge router) that owns a pool of prefixes and hands them out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requesting router:&lt;/strong&gt; the customer's router, which asks for a prefix and then uses it on its own downstream interfaces.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Delegation is a lease, not a gift: the prefix has lifetimes, and the delegating router remembers which client holds it. Delegated sizes vary by provider (/48, /56, /60 and /64 all occur), and the requesting router can include a &lt;em&gt;hint&lt;/em&gt; of the length it wants, which the server is free to ignore. A /64 delegation leaves room for only one downstream network.&lt;/p&gt;

&lt;h2&gt;
  
  
  The message exchange
&lt;/h2&gt;

&lt;p&gt;DHCPv6 clients use UDP port 546 and servers and relays use UDP port 547. The client begins by sending to the link-local multicast address &lt;code&gt;ff02::1:2&lt;/code&gt; (All_DHCP_Relay_Agents_and_Servers). The four-message exchange is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Message&lt;/th&gt;
&lt;th&gt;Direction&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solicit&lt;/td&gt;
&lt;td&gt;client to server&lt;/td&gt;
&lt;td&gt;"Is any delegating router there?" It carries an IA_PD option, which is the request for a prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advertise&lt;/td&gt;
&lt;td&gt;server to client&lt;/td&gt;
&lt;td&gt;Offers a prefix, with lifetimes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request&lt;/td&gt;
&lt;td&gt;client to server&lt;/td&gt;
&lt;td&gt;Asks for the offered prefix from a chosen server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reply&lt;/td&gt;
&lt;td&gt;server to client&lt;/td&gt;
&lt;td&gt;Confirms; the client now holds the prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;RFC 8415 also defines a two-message variant using Rapid Commit. Afterwards the client uses Renew (extend the lease with the same server), Rebind (ask any server) and Release (give the prefix back). The option that carries the prefix is &lt;code&gt;IA_PD&lt;/code&gt;, which contains one or more &lt;code&gt;IAPREFIX&lt;/code&gt; entries with the prefix, its length and two lifetimes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preferred lifetime:&lt;/strong&gt; how long the prefix should be used for new communication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Valid lifetime:&lt;/strong&gt; how long it remains usable at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The IA_PD also carries timers T1 and T2 which tell the client when to try Renew and Rebind respectively. If the client cannot renew before the valid lifetime ends, it must stop using the prefix.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens after the prefix arrives
&lt;/h2&gt;

&lt;p&gt;Receiving a prefix does not configure anything by itself. The requesting router must then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Split the delegated prefix into /64s, one per downstream interface (a /56 yields 256, a /60 yields 16).&lt;/li&gt;
&lt;li&gt;Assign an address to each downstream interface from its /64.&lt;/li&gt;
&lt;li&gt;Advertise each /64 to its LAN with Router Advertisements (RFC 4861) so hosts can use SLAAC (RFC 4862), or run a DHCPv6 server for stateful addressing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hosts on those LANs never see DHCPv6-PD; they see ordinary Router Advertisements. The requesting router also needs its own WAN-side address and default route, and DHCPv6 does not provide a default gateway: that comes from a Router Advertisement on the WAN link, while the WAN address may come from SLAAC or a DHCPv6 IA_NA request. RFC 7084 lists these behaviours for IPv6 customer edge routers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The M and O flags in Router Advertisements
&lt;/h2&gt;

&lt;p&gt;Router Advertisements carry two flags: M ("managed address configuration") says to use DHCPv6 for addresses, and O ("other configuration") says to use DHCPv6 for other information such as DNS servers. They do &lt;strong&gt;not&lt;/strong&gt; control prefix delegation. A requesting router asks for a prefix because it is configured to, not because of an RA flag, so a missing M or O flag is not the explanation if PD fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  The routing step that is easy to miss
&lt;/h2&gt;

&lt;p&gt;The delegating router must be able to send traffic for the delegated prefix to the requesting router. That requires a route: delegated prefix, next hop the client's link-local (or WAN) address. Some servers install it automatically; others rely on a script, a relay, or a manual static route. If a client holds a prefix but nothing outside can reach hosts in it, check for this route first. Equally, the requesting router must not send unused parts of the delegated prefix back out its WAN, or traffic may loop; many CE routers install an unreachable route for the whole prefix, with more specific routes for the subnets in use.&lt;/p&gt;

&lt;h2&gt;
  
  
  A configuration example (systemd-networkd)
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;systemd-networkd&lt;/code&gt;, the WAN side requests a prefix and the LAN side receives a subnet of it. The exact option names have changed between releases, so check the documentation of your version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight systemd"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/systemd/network/10-wan.network&lt;/span&gt;
&lt;span class="k"&gt;[Match]&lt;/span&gt;
&lt;span class="nt"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;wan0
&lt;span class="k"&gt;[Network]&lt;/span&gt;
&lt;span class="nt"&gt;DHCP&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;ipv6
&lt;span class="nt"&gt;IPv6AcceptRA&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;yes

&lt;span class="c"&gt;# /etc/systemd/network/20-lan.network&lt;/span&gt;
&lt;span class="k"&gt;[Match]&lt;/span&gt;
&lt;span class="nt"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;lan0
&lt;span class="k"&gt;[Network]&lt;/span&gt;
&lt;span class="nt"&gt;DHCPPrefixDelegation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;yes
&lt;span class="nt"&gt;IPv6SendRA&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other clients, such as &lt;code&gt;dhcpcd&lt;/code&gt; or &lt;code&gt;wide-dhcpv6-client&lt;/code&gt;, use different syntax; on the server side, ISC Kea supports prefix delegation pools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Capture the exchange: &lt;code&gt;tcpdump -ni wan0 'udp port 546 or udp port 547'&lt;/code&gt;. You should see Solicit, Advertise, Request, Reply. If you see only Solicit, nothing is answering on that link.&lt;/li&gt;
&lt;li&gt;If Advertise arrives with a status code other than success inside the IA_PD, such as &lt;code&gt;NoPrefixAvail&lt;/code&gt;, the server has no prefix to give or the request does not match its configuration.&lt;/li&gt;
&lt;li&gt;Check what you hold with &lt;code&gt;ip -6 addr&lt;/code&gt; and &lt;code&gt;ip -6 route&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If hosts have addresses but no connectivity, test routes in both directions and check that the firewall allows DHCPv6 and ICMPv6.&lt;/li&gt;
&lt;li&gt;Prefixes can change when a lease lapses or a link is reset, depending on the provider's policy. A server may, but need not, hand the same prefix back to a returning client, so do not hard-code delegated prefixes into DNS or firewall rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The common failure points are a delegated prefix too small for the networks you need, a missing route on the delegating side, and renewal problems when the WAN link flaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space; a /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled by IPYE. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ipv6</category>
      <category>networking</category>
      <category>dhcp</category>
      <category>linux</category>
    </item>
    <item>
      <title>IPv6 for Web Servers: Dual-Stack nginx and Apache, and How to Test It</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 14:48:56 +0000</pubDate>
      <link>https://dev.to/ipye_com/ipv6-for-web-servers-dual-stack-nginx-and-apache-and-how-to-test-it-37d2</link>
      <guid>https://dev.to/ipye_com/ipv6-for-web-servers-dual-stack-nginx-and-apache-and-how-to-test-it-37d2</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Adding IPv6 to a web server is mostly four small jobs: put an address on the host, make the web server listen on it, publish an AAAA record, and let the traffic through the firewall. Each step has a common mistake, and the worst one, publishing the AAAA record before the other steps work, breaks the site for IPv6 visitors. This article walks through nginx and Apache and then shows how to test each layer separately. Examples use &lt;code&gt;2001:db8:100::10&lt;/code&gt; for the server and &lt;code&gt;www.example.com&lt;/code&gt; for the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: the address and route
&lt;/h2&gt;

&lt;p&gt;Confirm the host has the address and a default route before touching the web server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip &lt;span class="nt"&gt;-6&lt;/span&gt; addr show dev eth0
ip &lt;span class="nt"&gt;-6&lt;/span&gt; route show default
ping &lt;span class="nt"&gt;-6&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 3 2001:db8:100::1     &lt;span class="c"&gt;# the gateway&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the provider gave you a /64 or larger, configure &lt;code&gt;2001:db8:100::10&lt;/code&gt; with a prefix length that matches the subnet (typically /64) and the gateway they specify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: nginx
&lt;/h2&gt;

&lt;p&gt;nginx listens per address family, so you add an IPv6 &lt;code&gt;listen&lt;/code&gt; directive next to each IPv4 one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="s"&gt;[::]:80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="s"&gt;[::]:443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;www.example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt;     &lt;span class="n"&gt;/etc/ssl/example/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/ssl/example/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Details that cause trouble:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On Linux, &lt;code&gt;listen [::]:80;&lt;/code&gt; by default creates an IPv6-only socket (the &lt;code&gt;ipv6only=on&lt;/code&gt; default). That is what you want, since &lt;code&gt;listen 80;&lt;/code&gt; already covers IPv4. Writing &lt;code&gt;[::]:80 ipv6only=off&lt;/code&gt; and also &lt;code&gt;listen 80;&lt;/code&gt; conflicts and nginx reports "address already in use".&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ipv6only&lt;/code&gt; parameter can be set only once for a given port, on the first &lt;code&gt;listen&lt;/code&gt; that defines it. Parameters such as &lt;code&gt;default_server&lt;/code&gt; apply per &lt;code&gt;listen&lt;/code&gt; directive, so if you mark the IPv4 listener of a block as the default, mark its IPv6 listener too.&lt;/li&gt;
&lt;li&gt;Access rules accept IPv6 syntax directly: &lt;code&gt;allow 2001:db8:200::/48;&lt;/code&gt;. A rule list that only has IPv4 entries silently allows or denies IPv6 clients according to the final &lt;code&gt;deny all&lt;/code&gt;, so review each.&lt;/li&gt;
&lt;li&gt;Behind a proxy or load balancer, set &lt;code&gt;real_ip_header&lt;/code&gt; and &lt;code&gt;set_real_ip_from&lt;/code&gt; with both IPv4 and IPv6 ranges of the proxy, or your logs will show the proxy's address.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check and reload with &lt;code&gt;nginx -t &amp;amp;&amp;amp; systemctl reload nginx&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Apache
&lt;/h2&gt;

&lt;p&gt;Apache's &lt;code&gt;Listen&lt;/code&gt; directive without an address, such as &lt;code&gt;Listen 80&lt;/code&gt;, binds to all interfaces. On Linux that normally includes IPv6, with IPv4 connections handled through the same dual-stack socket. To be explicit, or to bind specific addresses, give them separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;Listen&lt;/span&gt; 192.0.2.10:443
&lt;span class="nc"&gt;Listen&lt;/span&gt; [2001:db8:100::10]:443

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;VirtualHost&lt;/span&gt;&lt;span class="sr"&gt; 192.0.2.10:443 [2001:db8:100::10]:443&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="nc"&gt;ServerName&lt;/span&gt; www.example.com
    &lt;span class="nc"&gt;SSLEngine&lt;/span&gt; &lt;span class="ss"&gt;on&lt;/span&gt;
    &lt;span class="nc"&gt;SSLCertificateFile&lt;/span&gt;    /etc/ssl/example/fullchain.pem
    &lt;span class="nc"&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/ssl/example/privkey.pem
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;VirtualHost&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use &lt;code&gt;&amp;lt;VirtualHost *:443&amp;gt;&lt;/code&gt;, the wildcard already matches IPv6. Address-based access rules use &lt;code&gt;Require ip 2001:db8:200::/48&lt;/code&gt;. Validate with &lt;code&gt;apachectl configtest&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: the firewall
&lt;/h2&gt;

&lt;p&gt;Open the same ports in the IPv6 ruleset. It is common to see &lt;code&gt;iptables&lt;/code&gt; rules for 80 and 443 with nothing in &lt;code&gt;ip6tables&lt;/code&gt;, or an nftables &lt;code&gt;ip&lt;/code&gt; table without an &lt;code&gt;ip6&lt;/code&gt; or &lt;code&gt;inet&lt;/code&gt; equivalent. Also keep ICMPv6 (Packet Too Big, in particular) working, otherwise some clients will connect and then hang on large responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: test before publishing the AAAA record
&lt;/h2&gt;

&lt;p&gt;Do not add DNS yet. Test the server by address, with the right hostname, so TLS and virtual hosts still match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ss &lt;span class="nt"&gt;-tlnp&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;':(80|443)\b'&lt;/span&gt;
curl &lt;span class="nt"&gt;-6&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="nt"&gt;--resolve&lt;/span&gt; www.example.com:443:[2001:db8:100::10] https://www.example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ss&lt;/code&gt; should show a listener on &lt;code&gt;[::]:443&lt;/code&gt; (or the specific IPv6 address). &lt;code&gt;--resolve&lt;/code&gt; makes curl connect to the given address while still sending &lt;code&gt;www.example.com&lt;/code&gt; in the SNI field and Host header; the brackets are required for IPv6 literals. Test from a different network than the server, since local tests can succeed through the loopback path and miss firewall problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: publish the AAAA record
&lt;/h2&gt;

&lt;p&gt;Add the record with a modest TTL so you can pull it back quickly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;www.example.com.  300  IN  AAAA  2001:db8:100::10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then query it and test through normal resolution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig +short AAAA www.example.com
curl &lt;span class="nt"&gt;-6&lt;/span&gt; &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{remote_ip} %{http_code}\n'&lt;/span&gt; https://www.example.com/
curl &lt;span class="nt"&gt;-4&lt;/span&gt; &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{remote_ip} %{http_code}\n'&lt;/span&gt; https://www.example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both should return a success code. The two address families should serve identical content: run both checks and compare. Also check that the certificate is the same, since a stray default server on only one family can present a different certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that break only on IPv6
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Applications that store or validate IP addresses.&lt;/strong&gt; Database columns sized for 15 characters, regular expressions that accept only dotted quads, and libraries that mis-parse a colon as a port separator all show up once IPv6 clients arrive. A full textual IPv6 address can be 39 characters long, and forms with an embedded IPv4 address reach 45.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting and bans.&lt;/strong&gt; One IPv6 user commonly has a /64 or more, so limits keyed on a single /128 are easy to evade. Aggregate by /64 where that fits your policy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging and analytics.&lt;/strong&gt; Log parsers and fail2ban rules need IPv6 patterns. Make sure ban actions apply to &lt;code&gt;ip6&lt;/code&gt; firewall tables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverse DNS.&lt;/strong&gt; Mail servers and some services check PTR records; delegate and set &lt;code&gt;ip6.arpa&lt;/code&gt; entries for addresses that send mail.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard-coded addresses in configuration or allow lists.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rolling back
&lt;/h2&gt;

&lt;p&gt;If IPv6 users have trouble, remove the AAAA record. Clients fall back to IPv4 once cached records expire. A low TTL during rollout shortens that window, and you can raise it again once the service has been stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) offers leased IPv4, IPv6, and ASN space. The first year of a /48 IPv6 block is free, and IPYE handles LOA, ROA, rDNS, and WHOIS. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ipv6</category>
      <category>nginx</category>
      <category>webdev</category>
      <category>networking</category>
    </item>
    <item>
      <title>Dual-Stack Hygiene: Happy Eyeballs, MTU and Path MTU Discovery, and the ICMPv6 You Must Not Filter</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 14:09:34 +0000</pubDate>
      <link>https://dev.to/ipye_com/dual-stack-hygiene-happy-eyeballs-mtu-and-path-mtu-discovery-and-the-icmpv6-you-must-not-filter-35af</link>
      <guid>https://dev.to/ipye_com/dual-stack-hygiene-happy-eyeballs-mtu-and-path-mtu-discovery-and-the-icmpv6-you-must-not-filter-35af</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dual-stack service, where a host answers on both IPv4 and IPv6, usually works because clients are forgiving. That forgiveness can hide faults, such as an IPv6 path that silently drops large packets. This article covers three things that often go wrong: how clients choose between address families, how packet size is negotiated, and which ICMPv6 messages a firewall has to let through. Examples use documentation addresses: &lt;code&gt;2001:db8::/32&lt;/code&gt; and &lt;code&gt;192.0.2.0/24&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Happy Eyeballs: why clients usually cope
&lt;/h2&gt;

&lt;p&gt;When a client resolves a name with both A and AAAA records, default address selection (RFC 6724) generally prefers IPv6. Happy Eyeballs (RFC 6555, updated by version 2 in RFC 8305) stops a broken IPv6 path from making users wait for a full TCP timeout. In outline, RFC 8305 describes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending the AAAA and A queries together, and giving the AAAA answer a short head start, the &lt;em&gt;Resolution Delay&lt;/em&gt;, recommended at 50 ms.&lt;/li&gt;
&lt;li&gt;Starting connection attempts in turn rather than all at once, with a &lt;em&gt;Connection Attempt Delay&lt;/em&gt; recommended at 250 ms, with a minimum of 100 ms and a maximum of 2 seconds.&lt;/li&gt;
&lt;li&gt;Using whichever attempt completes first and cancelling the rest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementations differ, and some simpler clients fall back slowly or not at all. The lesson for a server operator: Happy Eyeballs makes IPv6 faults &lt;em&gt;less visible&lt;/em&gt;, not absent. A user on a bad IPv6 path may see a delay on every new connection and never report it.&lt;/p&gt;

&lt;p&gt;Operator habits that follow from this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Publish AAAA only for services you run and test on IPv6.&lt;/strong&gt; Do not remove the AAAA record to "fix" a problem you have not diagnosed; fix the path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test and monitor each family on its own.&lt;/strong&gt; &lt;code&gt;curl -4 https://example.com/&lt;/code&gt; and &lt;code&gt;curl -6 https://example.com/&lt;/code&gt; isolate the problem.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  MTU and path MTU discovery
&lt;/h2&gt;

&lt;p&gt;The link MTU is the largest packet a link can carry. Ethernet is typically 1500 bytes. The two IP versions handle oversize packets differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IPv4:&lt;/strong&gt; a router may fragment a packet unless the Don't Fragment (DF) bit is set. Most modern TCP stacks set DF and rely on Path MTU Discovery (RFC 1191): a router that cannot forward a DF packet returns ICMP type 3, code 4 ("Fragmentation Needed").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPv6:&lt;/strong&gt; routers never fragment. Only the source can, and every link must support at least 1280 bytes (RFC 8200). A router that cannot forward a packet sends ICMPv6 type 2, "Packet Too Big", carrying the next-hop MTU (RFC 8201).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So IPv6 depends on Packet Too Big messages even more than IPv4 depends on its equivalent, because there is no router-side fragmentation to fall back on. If a firewall drops those messages, the sender never learns the real limit. Small packets (the TCP handshake, a short HTTP request) work; larger ones vanish. The symptom is a connection that stalls after the handshake or hangs during a TLS exchange or a large download. This is a &lt;em&gt;PMTUD black hole&lt;/em&gt;. RFC 4821 describes packetization-layer discovery as a mitigation, but it is slower and no substitute for letting the errors through.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common sources of a smaller MTU
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path element&lt;/th&gt;
&lt;th&gt;Typical effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PPPoE&lt;/td&gt;
&lt;td&gt;8 bytes overhead, so 1492&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6in4 tunnel (protocol 41)&lt;/td&gt;
&lt;td&gt;20 bytes over IPv4, so 1480&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GRE over IPv4&lt;/td&gt;
&lt;td&gt;24 bytes, so 1476&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WireGuard&lt;/td&gt;
&lt;td&gt;60 bytes over IPv4 or 80 over IPv6; default interface MTU of 1420 covers the larger case&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  MSS clamping
&lt;/h3&gt;

&lt;p&gt;TCP's Maximum Segment Size excludes the IP and TCP headers. For a 1500-byte MTU the MSS is 1460 over IPv4 (1500 minus 20 minus 20) and 1440 over IPv6 (1500 minus 40 minus 20). On a router in front of a tunnel or PPPoE link, clamping the MSS in the SYN packets avoids the problem for TCP even if ICMP is lost. On Linux with nftables, &lt;code&gt;tcp option maxseg size set rt mtu&lt;/code&gt; in a forward chain does this. It is a safety net, not a reason to filter ICMP, and it does nothing for UDP.&lt;/p&gt;

&lt;h2&gt;
  
  
  ICMPv6 you must not filter
&lt;/h2&gt;

&lt;p&gt;Neighbor discovery, the IPv6 replacement for ARP, runs on ICMPv6, so blanket ICMP filtering breaks more than diagnostics. RFC 4890 gives filtering recommendations; the essentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type 1, Destination Unreachable (all codes), type 2, Packet Too Big, type 3, Time Exceeded, and type 4, Parameter Problem:&lt;/strong&gt; these are the error messages. Dropping them causes black holes and slow failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Types 133 to 137, Router Solicitation and Advertisement, Neighbor Solicitation and Advertisement, Redirect:&lt;/strong&gt; required on the local link. Without neighbor solicitation and advertisement, hosts cannot resolve each other's addresses. Discard ND packets with a hop limit other than 255, which proves they did not cross a router.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Types 128 and 129, Echo Request and Reply:&lt;/strong&gt; RFC 4890 recommends permitting these to your servers, optionally rate-limited.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A host firewall sketch in nftables, placed in a &lt;code&gt;table inet filter&lt;/code&gt; input chain with a default drop policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ct state established,related accept
meta l4proto ipv6-icmp icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept
meta l4proto icmp icmp type { destination-unreachable, time-exceeded, echo-request } accept
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A router's forward chain needs the error types too. Connection tracking usually marks matching ICMP errors &lt;code&gt;related&lt;/code&gt;, but an explicit rule is clearer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Probe with DF set:&lt;/strong&gt; &lt;code&gt;ping -6 -M do -s 1452 2001:db8::10&lt;/code&gt; sends a 1500-byte packet (1452 data plus 8 ICMPv6 and 40 IPv6 header bytes). For IPv4, use &lt;code&gt;-s 1472&lt;/code&gt; with &lt;code&gt;192.0.2.10&lt;/code&gt;. Lower the size until it succeeds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;tracepath -6&lt;/code&gt;&lt;/strong&gt; reports the path MTU it finds hop by hop, and &lt;code&gt;ip route get 2001:db8::10&lt;/code&gt; shows a cached MTU after a Packet Too Big arrives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capture:&lt;/strong&gt; run &lt;code&gt;tcpdump -ni eth0 icmp6&lt;/code&gt; during a stall. If Packet Too Big never arrives, something upstream is dropping it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare families:&lt;/strong&gt; if &lt;code&gt;curl -4&lt;/code&gt; works and &lt;code&gt;curl -6&lt;/code&gt; stalls on large responses, suspect MTU first.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space. A /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled for you. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ipv6</category>
      <category>networking</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Reading a Looking Glass and BGP Route Data to Debug an Unreachable Prefix</title>
      <dc:creator>IPYE</dc:creator>
      <pubDate>Mon, 26 Oct 2026 13:46:04 +0000</pubDate>
      <link>https://dev.to/ipye_com/reading-a-looking-glass-and-bgp-route-data-to-debug-an-unreachable-prefix-2fgh</link>
      <guid>https://dev.to/ipye_com/reading-a-looking-glass-and-bgp-route-data-to-debug-an-unreachable-prefix-2fgh</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I run IPYE, a company that leases IP space. It gets one short paragraph at the end; the rest is plain networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"My prefix is announced but nobody can reach it" is one of the most common BGP support questions, and the answer is almost never found by staring at your own router. You need outside views of the routing system. This article walks through a repeatable order of checks using public tools: route collectors (RIPE RIS, RouteViews), RIPEstat, bgp.tools, and the looking glasses that many networks publish. Examples use documentation values (&lt;code&gt;AS64496&lt;/code&gt;, &lt;code&gt;2001:db8:abcd::/48&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  First, split the problem in two
&lt;/h2&gt;

&lt;p&gt;Reachability has two halves, and they fail differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Control plane:&lt;/strong&gt; does the world have a route to your prefix, with your ASN as origin?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data plane:&lt;/strong&gt; if packets arrive, does a host answer, and can the replies get back?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check the control plane first. If outside vantage points see no route, nothing downstream matters. If they do see it, the problem is usually on your side of the edge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Is the prefix visible at all?
&lt;/h2&gt;

&lt;p&gt;Search for the exact prefix in RIPEstat (the "Routing status" and "BGP looking glass" widgets) or on the bgp.tools prefix page. You want to see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The prefix listed as &lt;strong&gt;announced&lt;/strong&gt;, with your ASN as the &lt;strong&gt;origin&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It is seen by &lt;strong&gt;many&lt;/strong&gt; collector peers, not just one or two. A prefix seen by only a handful of peers has usually been accepted by one upstream and stopped there, often because of a filter further along.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;first-seen/last-seen&lt;/strong&gt; or routing history is sensible. A prefix that appears and disappears repeatedly points to a flapping session or a flapping static route feeding the export.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it is missing entirely, go back to your router: is the session Established, is the route in the export table (&lt;code&gt;show route export&lt;/code&gt; or the equivalent), and does your export policy actually match the prefix and its length?&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Read the AS path
&lt;/h2&gt;

&lt;p&gt;Every route in a looking glass shows an AS path, read from the neighbor on the left to the origin on the right. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AS_PATH: 64510 64497 64496
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means the observer learned the route via AS64510, which learned it from AS64497, which learned it from the origin AS64496. Things to look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The origin (rightmost) AS is yours.&lt;/strong&gt; A different origin means someone else is announcing the prefix, or a provider is originating on your behalf, and ROA/IRR data may not match.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unexpected intermediate ASNs.&lt;/strong&gt; If your path goes through a network you do not buy transit from, you may have a leak or a surprising peering relationship.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excessive prepending.&lt;/strong&gt; A heavily prepended path loses to shorter alternatives, which can move traffic in ways you did not intend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Compare vantage points
&lt;/h2&gt;

&lt;p&gt;Run the same lookup from several looking glasses: one in your upstream's network, one at a large transit network, one on a different continent. The pattern tells you where the problem is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visible at your upstream, nowhere else:&lt;/strong&gt; the upstream is not exporting you onward. Usually an IRR or prefix-filter update is pending, or the prefix was not on their customer filter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visible widely but missing in one network:&lt;/strong&gt; that network is filtering you, commonly because of RPKI-invalid status, a missing or mismatched IRR object, or a prefix length they do not accept.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Check RPKI and IRR status
&lt;/h2&gt;

&lt;p&gt;Both RIPEstat and bgp.tools show RPKI validation state for the prefix and origin pair. &lt;strong&gt;Invalid&lt;/strong&gt; is the one that bites: networks doing route origin validation (RFC 6811) commonly drop it. Invalid means a ROA covers the prefix but the origin ASN differs or the announced length exceeds maxLength. &lt;strong&gt;NotFound&lt;/strong&gt; means no ROA exists and is usually still accepted. Then check that an IRR &lt;code&gt;route6&lt;/code&gt; object exists with your origin ASN, because many providers still build prefix lists from IRR data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Check the length
&lt;/h2&gt;

&lt;p&gt;Large networks commonly filter IPv6 announcements more specific than /48 and IPv4 announcements more specific than /24. This is convention, not a protocol rule, but it is widely followed. If you announce a /56 or a /25, expect it to be absent from most looking glasses. Also look for more-specific prefixes announced by someone else: they win longest-prefix match regardless of your announcement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Use the looking glass for the data plane
&lt;/h2&gt;

&lt;p&gt;Most looking glasses allow &lt;code&gt;ping&lt;/code&gt; and &lt;code&gt;traceroute&lt;/code&gt; as well as &lt;code&gt;show route&lt;/code&gt;. From a vantage point that has a valid route:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ping and traceroute to a specific address&lt;/strong&gt; inside the prefix, not the network address.&lt;/li&gt;
&lt;li&gt;See where the trace stops. If it reaches your upstream and then dies, check that the address is actually configured and that the route inside your network points to it.&lt;/li&gt;
&lt;li&gt;Test the &lt;strong&gt;return path&lt;/strong&gt;: from your host, traceroute back to the looking glass's source. Asymmetric routing is normal, but a missing or filtered return route makes everything look broken.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 7: Local causes once the control plane is clean
&lt;/h2&gt;

&lt;p&gt;If the world has a valid route and paths look right, work through the usual suspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nothing owns the address.&lt;/strong&gt; Announcing a prefix that points at no configured host is the classic case. Check the address is assigned and the router has a route toward it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Host or edge firewall&lt;/strong&gt; dropping inbound traffic, especially ICMPv6, which IPv6 needs for neighbor discovery and path MTU discovery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPv6 not enabled&lt;/strong&gt; on the session or on the service itself (a listener bound only to IPv4).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Report what you saw
&lt;/h2&gt;

&lt;p&gt;Write down the result of each step. Provider support teams respond much faster to "prefix X is seen by upstream Y but not by network Z, path below" than to "BGP is broken."&lt;/p&gt;

&lt;h2&gt;
  
  
  About IPYE
&lt;/h2&gt;

&lt;p&gt;IPYE (&lt;a href="https://my.ipye.com" rel="noopener noreferrer"&gt;https://my.ipye.com&lt;/a&gt;) leases IPv4, IPv6, and ASN space. A /48 IPv6 block is free for the first year. LOA, ROA, rDNS, and WHOIS are handled for you. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, and Frankfurt. Questions: &lt;a href="mailto:ipye@turnel.com"&gt;ipye@turnel.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I run IPYE&lt;/em&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>bgp</category>
      <category>ipv6</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
