Python script to check if your IPv6 Mostly Network is running ok
--- cut here validate_mostly_v6.py ---
--- cut here validate_mostly_v6.py ---
Site dedicated mainly to internetworking. The goal is to share experiences, teach IP, IPv6. Talk about Linux, IP services, servers, promote IPv6 adoption, routing protocols, security and in some cases just some thoughts. Keywords: linux, cisco, ospf, bgp, eigrp, ip, ipv6, sla, link, routers, routings, telco, telecommunications, security, ipv4
Python script to check if your IPv6 Mostly Network is running ok
--- cut here validate_mostly_v6.py ---
--- cut here validate_mostly_v6.py ---
Imagine you connect to an IPv6 Mostly Network, is it ok?
--- cut here validate_mostly_v6.sh ---
#!/bin/bash
# Terminal output colors
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "=================================================="
echo " Starting IPv6-Mostly Network Validation Test"
echo "=================================================="
# Detect Host Operating System
OS="$(uname)"
# --- TEST 1: Verify Global IPv6 Allocation ---
echo -n "Test 1: Checking Global IPv6 Address... "
if [ "$OS" = "Darwin" ]; then
# macOS network interface scanning
IPV6_GBL=$(ifconfig en0 2>/dev/null | grep 'inet6 ' | grep -v 'fe80::' | grep -v '::1' | awk '{print $2}')
else
# Linux network interface scanning
IPV6_GBL=$(ip -6 addr show scope global | grep 'inet6' | awk '{print $2}')
fi
if [ -n "$IPV6_GBL" ]; then
echo -e "${GREEN}PASSED${NC} (Found: $(echo $IPV6_GBL | tr '\n' ' '))"
else
echo -e "${RED}FAILED${NC} (No Global IPv6 address detected on the main interface)"
fi
# --- TEST 2: Verify IPv6-Mostly / DHCPv4 Option 108 Behavior ---
echo -n "Test 2: Checking DHCPv4 Option 108 & CLAT Status... "
if [ "$OS" = "Darwin" ]; then
# macOS flags 'clat46' or 'nat64' when Option 108 forces an IPv6-only state with translation
CLAT_CHECK=$(ifconfig en0 2>/dev/null | grep -E 'clat46|nat64')
# Filter out the 192.0.0.2 dummy address created locally by the macOS CLAT process
IPV4_REAL=$(ifconfig en0 2>/dev/null | grep 'inet ' | grep -v '192.0.0.2')
else
# Linux native CLAT or node state verification
CLAT_CHECK=$(ip addr 2>/dev/null | grep 'clat')
IPV4_REAL=$(ip -4 addr show scope global 2>/dev/null | grep 'inet' | grep -v '192.0.0.2')
fi
if [ -n "$CLAT_CHECK" ] && [ -z "$IPV4_REAL" ]; then
echo -e "${GREEN}PASSED${NC} (IPv6-Only Preferred active. Network IPv4 is disabled. Local CLAT active)"
elif [ -n "$IPV4_REAL" ]; then
echo -e "${YELLOW}WARNING${NC} (Real native IPv4 address found: $IPV4_REAL. Option 108 might be missing or ignored)"
else
echo -e "${RED}FAILED${NC} (Neither Option 108 behavior nor local CLAT was detected)"
fi
# --- TEST 3: Native IPv6 Egress Connectivity ---
echo -n "Test 3: Testing Native IPv6 Connectivity... "
# Sending ICMPv6 packets to Google Public DNS to verify native routing
if ping6 -c 2 2001:4860:4860::8888 > /dev/null 2>&1; then
echo -e "${GREEN}PASSED${NC}"
else
echo -e "${RED}FAILED${NC} (Cannot reach Google IPv6 DNS via native routing)"
fi
# --- TEST 4: OS-Level IPv4-Only Hostname Resolution ---
echo -n "Test 4: Checking IPv4-only Resolution via CLAT/DNS64... "
# Verifies if the OS subsystem can resolve and route an IPv4-only domain name natively
if ping -c 2 ://google.com > /dev/null 2>&1; then
echo -e "${GREEN}PASSED${NC} (System successfully routes IPv4-only hostnames)"
else
echo -e "${RED}FAILED${NC} (System cannot reach or resolve an IPv4-only hostname)"
fi
# --- TEST 4b: Optional Network-Side DNS64 Synthesis Verification ---
echo -n "Test 4b: Checking Optional Network-side DNS64 Synthesis... "
# Querying the network DNS server directly for a AAAA record on an IPv4-only target.
# Per RFC 8925, DNS64 is optional if the client runs a local CLAT (464XLAT) environment.
DNS64_SYNTH=$(host -t AAAA ://google.com 2>/dev/null | grep 'has AAAA address')
if [ -n "$DNS64_SYNTH" ]; then
SYNTH_IP=$(echo "$DNS64_SYNTH" | awk '{print $NF}')
echo -e "${GREEN}ACTIVE${NC} (Network DNS is actively synthesizing AAAA records: $SYNTH_IP)"
else
echo -e "${YELLOW}NOT ACTIVE${NC} (Network DNS provides clean IPv4 records. Expected behavior for native CLAT)"
fi
# --- TEST 5: Literal IPv4 Address Translation (End-to-End NAT64/CLAT) ---
echo -n "Test 5: Testing NAT64/CLAT Translation (Ping to Literal IPv4)... "
# Sending a ping to a literal IPv4 address.
# Success proves that the local CLAT engine successfully translates and encapsulates legacy raw IPv4 traffic into IPv6
if ping -c 2 8.8.8.8 > /dev/null 2>&1; then
echo -e "${GREEN}PASSED${NC} (End-to-end legacy IPv4 literal translation works perfectly)"
else
echo -e "${RED}FAILED${NC} (Literal IPv4 traffic is blocked or translation gateway failed)"
fi
echo "=================================================="
echo " Validation Completed."
echo "=================================================="
--- cut here validate_mostly_v6.sh ---
Situation
FRR always displays "No connection to RPKI cache server."
Solution
Specify the source address in the RPKI cache declaration. Example:
rpki cache tcp 108.162.192.12 8282 source X.Y.Z.N preference 1
Situation
You're not receiving IPv6 on your computer even though your phone has IPv6 provided by your mobile device.
Solution
In your mobile network settings --> APN, check if "APN roaming protocol" is set to "IPv4/IPv6".
If it is like the previous image, it won't work.
The correct way is as follows:
Personally, I never imagined that the APN roaming protocol was the problem, but it is.
I hope this helps.
After using the World Happiness Report and Google's IPv6 penetration statistics, I found a correlation of 0.4648. So, what does this number mean?
- In statistics, correlation is measured on a scale of -1 to 1.
- 0 means no relationship.
- 1 means a perfect relationship.
- -1 means the variables are inversely proportional.
- A value of 0.4648 is considered a moderate correlation. The two data points move together with some frequency, but not identically.
- Since it's a positive number (+0.4648), the relationship is direct.
- This means that the higher the percentage of IPv6 penetration in a country, the higher its happiness score tends to be.
Don't believe me? Look at the graph below.
What does the graph tell us?
It shows that countries that manage to exceed 40% or 60% of native IPv6 adopters almost never have critically low happiness levels (few score below 5).
Yes, I know it sounds crazy, but it was a fun exercise.
What do you think?
Info
[1] World Happiness Report: 'https://files.worldhappiness.report/WHR26_Data_Figure_2.1.xlsx?_gl=1*zmm7kk*_gcl_au*MzI5Nzg1NTM4LjE3Nzg5NTQ3Mjk.'
[2] Google IPv6 stats: 'https://www.google.com/intl/en_ALL/ipv6/statistics/data/worldmap.js'
[3] Available in google colab here: https://colab.research.google.com/drive/1G8-KObej157c75lNl8kGzywWkBh1VhoW#scrollTo=87c9d1a2
Case:
fig.show() using Plotly does not work in jupyter
What to do:
Force rendering adding this line just before fig.show() using pio
Example:
import plotly.io as pio
pio.renderers.default = 'iframe'
fig.show()
Listo!
If you are running FRRouting (FRR), you might have encountered a frustrating quirk: after a system reboot, kernel routes (like a static default route) fail to redistribute into RIP or OSPF. Curiously, as soon as you manually restart the FRR service, everything works perfectly.
Here is a breakdown of why this happens and how to fix it for good.
The Problem
During a cold boot, FRR starts its daemons (Zebra, RIPd, etc.), but routes defined at the OS level aren’t being advertised to neighbors. This breaks connectivity after an automated reboot and forces manual intervention (systemctl restart frr), which defeats the purpose of an automated routing stack.
The Root Cause: The Startup "Race Condition"
The culprit is typically a race condition between your network manager (like Netplan or systemd-networkd) and the FRR service.
Interface Renaming: Modern tools like Netplan often rename interfaces during boot (e.g., from eth0 to enp1s0). If FRR initializes while an interface is in transition, Zebra may ignore routes associated with a "missing" or "changing" interface.
The "Up" State: If Zebra scans the kernel routing table before the physical or virtual interface is fully marked as "UP" and operational, the routing protocols (like RIP) will deem the route invalid for redistribution.
Dependency Timing: By default, the FRR service might attempt to load before the network is "fully online," leading to a failed initial synchronization between the kernel and Zebra.
Step-by-Step Solution
The fix involves modifying the systemd unit file to ensure FRR waits until the network stack is completely ready and interface names are finalized.
1. Edit the Service Configuration
Instead of editing the file in /lib/systemd/system/ directly, use a systemd "override" to keep your changes safe during updates:
bash
sudo systemctl edit frr.service
2. Adjust Network Dependencies
In the editor that opens, insert the following lines:
ini
[Unit]
After=network-online.target
Wants=network-online.target
This tells systemd that FRR should only start after the system reports that the network is fully up and functional (network-online.target).
3. Reload and Apply
Save the file and exit the editor. Then, reload the systemd manager to pick up the changes:
bash
sudo systemctl daemon-reload
Verification
On your next reboot, you can verify that Zebra is correctly picking up the routes by checking your FRR logs or using the following debug commands in vtysh:
vtysh
debug zebra kernel
debug rip events
Summary
In modern Linux distributions where interface naming and IP addressing are dynamic, startup timing is everything. Forcing FRR to wait for the network to be "online" ensures that when the daemons ask the kernel for routes, the kernel actually has the final, stable answers ready to give.