Skip to content

Commit 67ef587

Browse files
committed
cilium nat46x64gw post
1 parent 1491567 commit 67ef587

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

content/posts/cilium-nat64.md

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
---
2+
title: Using Cilium as a standalone NAT46x64Gateway
3+
date: 2025-05-01
4+
tags: ["IPv6", "Cilium", "eBPF"]
5+
authors: ["Kapil Agrawal"]
6+
comments: false
7+
---
8+
9+
# Cilium
10+
11+
Since IPv4 and IPv6 are two completely different protocols they are incompatible with one another i.e a host with IPv4 address cannot connect to an application that is only being served over IPv6 and vice-versa. This is where a v4 to v6 translator comes into play. Having a NAT46x64Gateway on the local network simplifies the transition from IPv4 to IPv6 while providing seamless connectivity to applications.
12+
13+
In this blog post I cover how I am running [Cilium](https://cilium.io) as a standalone NAT46x64 gateway which harnesses the power of [eBPF](https://docs.ebpf.io) in the linux kernel. Cilium is a CNCF graduate project which brings advanced networking capabilities to Kubernetes. While it is most commonly used as a CNI (Container Network Interface), not much has been documented about it's capabilities outside of Kubernetes, specially as a standalone NAT46x64 gateway. For my fellow kernel nerds and C lovers, Cilium's NAT46x64 implementation can be found [here](https://github.com/cilium/cilium/blob/main/bpf/lib/nat_46x64.h)
14+
15+
## Create a standalone NAT46x64Gateway
16+
17+
Before we get to the real meat and potatoes we need to do some prep work.
18+
19+
- Provision a VM - I am using Ubuntu 22.04LTS with kernel version 5.15.0-138-generic in my setup.
20+
- Configure networking - A `NAT46x64Gateway` must be dual stacked as it acts as a bridge between IPv4 and IPv6 networks. Here's an example netplan config I am using.
21+
22+
```yaml
23+
network:
24+
version: 2
25+
renderer: networkd
26+
ethernets:
27+
ens18:
28+
set-name: eth0
29+
match:
30+
macaddress: bc:24:11:ee:19:90
31+
accept-ra: false
32+
addresses:
33+
- 192.168.2.10/24
34+
- 2001:db8:abcd::2/64
35+
nameservers:
36+
addresses:
37+
- 1.1.1.1
38+
- 2606:4700:4700::64
39+
routes:
40+
- to: default
41+
via: 192.168.2.1
42+
- to: default
43+
via: 2001:db8:abcd::1/64
44+
```
45+
46+
To get Cilium up and running as a NAT46x64Gateway simply run the Cilium container image with the following options. Notice that we're running cilium with `enabled-k8s=false`. Also pay special attention to `--devices` flag as it must match the interface name (eth0) from our netplan config above. Traffic entering/leaving this interface will be subject to translation.
47+
48+
```sh
49+
docker run --name cilium-lb -itd \
50+
-v /sys/fs/bpf:/sys/fs/bpf \
51+
-v /lib/modules:/lib/modules \
52+
--privileged=true \
53+
--restart=always \
54+
--network=host \
55+
"quay.io/cilium/cilium:stable" cilium-agent --enable-ipv4=true --enable-ipv6=true --devices=eth0 --datapath-mode=lb-only --enable-k8s=false --bpf-lb-mode=snat --enable-nat46x64-gateway=true
56+
```
57+
58+
## Quick test
59+
60+
Let's create another Ubuntu VM as a test host with an IPv6 only address that points to our NAT46x64Gateway. Few noteworthy points in the netplan config shared below.
61+
62+
- The two nameservers are DNS64 servers from dns64.cloudflare-dns.com and dns64.dns.google respectively. You can use any dns server which has dns64 capability.When a client queries a DNS64 server for a hostname which only has an A record setup, the dns64 server sends a response containing the corresponding IPv4 address as well as a translated IPv6 address.
63+
64+
- static route to `64::ff9b/96` which is a special prefix that is used by IPv4/IPv6 translators as defined in [RFC6502](https://datatracker.ietf.org/doc/html/rfc6052). When the DNS64 server responds with the translated IPv6 address, our VM will forward the packet to our NAT46x64Gateway i.e `2001:db8:abcd::2`
65+
66+
```yaml
67+
root@controller:/home/kagraw# cat /etc/netplan/00-installer-config.yaml
68+
network:
69+
version: 2
70+
renderer: networkd
71+
ethernets:
72+
ens18:
73+
set-name: eth0
74+
match:
75+
macaddress: bc:24:11:55:02:a5
76+
accept-ra: false
77+
addresses:
78+
- 2001:db8:dead:beef::2/64
79+
nameservers:
80+
addresses:
81+
- 2606:4700:4700::64
82+
- 2001:4860:4860::64
83+
routes:
84+
- to: default
85+
via: 2001:db8:dead:beef::1
86+
- to: 64:ff9b::/96
87+
via: 2001:db8:abcd::2
88+
```
89+
90+
Example:
91+
92+
google.com has both an A record and a AAAA record.
93+
94+
```sh
95+
root@controller:/home/kagraw# host google.com
96+
google.com has address 142.250.190.78
97+
google.com has IPv6 address 2607:f8b0:4009:803::200e
98+
```
99+
100+
github.com only has an A record but since we're using a DNS64 server we receive a (translated) AAAA record as well.
101+
102+
```sh
103+
root@controller:/home/kagraw# host github.com
104+
github.com has address 140.82.113.4
105+
github.com has IPv6 address 64:ff9b::8c52:7104
106+
```
107+
108+
But since we have a static route to 64:ff9b::/96, any traffic going to github (64:ff9b::8c52:7203) will be forwarded via `2001:db8:abcd::2` i.e our Cilium based NAT46x64Gateway.
109+
110+
```sh
111+
root@controller:/home/kagraw# curl -6 -v github.com
112+
* Trying 64:ff9b::8c52:7104:80...
113+
* Connected to github.com (64:ff9b::8c52:7104) port 80 (#0)
114+
> GET / HTTP/1.1
115+
> Host: github.com
116+
> User-Agent: curl/7.81.0
117+
> Accept: */*
118+
>
119+
* Mark bundle as not supporting multiuse
120+
< HTTP/1.1 301 Moved Permanently
121+
< Content-Length: 0
122+
< Location: https://github.com/
123+
<
124+
* Connection #0 to host github.com left intact
125+
```
126+
127+
and Voila!🍾 our Cilium based NAT46x64Gateway is up and running!

themes/blowfish

0 commit comments

Comments
 (0)