Skip to content

desec-io/desec-networking-minimal-ex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dual-Stack Anycast UDP Hostname (Docker Compose Minimal Example)

This project runs a single container exposing a UDP service that replies with its own hostname to any incoming datagram.

The intent is to publish the service on IPv4 and IPv6 anycast addresses on the host, so the service becomes reachable via anycast when the host advertises those addresses/prefixes.

What You Get

  • 1 container: udp-hostname
  • 1 dual-stack Docker network (anycast_net)
    • IPv4: 10.200.0.0/24 (container: 10.200.0.2)
    • IPv6: fd00:200::/64 (container: fd00:200::2)
  • Host-published UDP port (default 5300/udp) on both IPv4 and IPv6

Run

docker compose up --build

Test Without Disrupting Existing Services (e.g. desec-ns)

Avoid port conflicts (especially :53) and avoid touching other Compose projects by:

  • Using a different COMPOSE_PROJECT_NAME (separate containers/networks), and
  • Binding to a high UDP port on loopback only.

Example:

# Pick a free UDP port (example: 15300)
ss -lun | rg ':15300' || true

export COMPOSE_PROJECT_NAME=udp-hostname-test
export PUBLISHED_PORT=15300
export ANYCAST_IPV4=127.0.0.1
export ANYCAST_IPV6=::1

docker compose up -d --build

Test:

echo -n ping | nc -u -w1 127.0.0.1 15300

python3 - <<'PY'
import socket
s=socket.socket(socket.AF_INET6, socket.SOCK_DGRAM); s.settimeout(1)
s.sendto(b'ping', ('::1', 15300))
print(s.recvfrom(1024)[0].decode().strip())
PY

Tear down only this stack:

COMPOSE_PROJECT_NAME=udp-hostname-test docker compose down -v

Test locally from the host (or anywhere that can reach the host):

echo -n ping | nc -u -w1 127.0.0.1 5300

# For IPv6, target a non-loopback IPv6 address of the host (any global/ULA on an interface).
HOST_IPV6="$(ip -6 -br addr show scope global | awk 'NR==1{print $3}' | cut -d/ -f1)"
echo -n ping | nc -u -w1 -6 "$HOST_IPV6" 5300

If nc on your system doesn’t print UDP responses reliably, use socat:

echo -n ping | socat - UDP4-DATAGRAM:127.0.0.1:5300,so-broadcast
echo -n ping | socat - UDP6-DATAGRAM:[::1]:5300

Compose Configuration (Anycast Bind Addresses)

compose.yml publishes the container port to the host, and by default binds on all addresses:

  • IPv4: 0.0.0.0:${PUBLISHED_PORT}:5300/udp
  • IPv6: [::]:${PUBLISHED_PORT}:5300/udp

To bind only on the anycast addresses (recommended), set:

export ANYCAST_IPV4=45.54.76.1
export ANYCAST_IPV6=2607:f740:e633:deec::2
export PUBLISHED_PORT=5300
docker compose up --build

Host Requirements For Anycast Reachability

Anycast reachability is a host/network property. Docker Compose can only publish the UDP port; the host must have the anycast addresses configured and must advertise them (typically via BGP).

1) Put Anycast Addresses On The Host

The host must have the anycast addresses configured on an interface that receives the anycast traffic. Common patterns:

  • Add them to the physical uplink interface (e.g. enp1s0), or
  • Add them to lo (loopback) and ensure appropriate routing/ARP/NDP behavior (depends on provider design).

Example (temporary, for illustration):

ip addr add 45.54.76.1/32 dev lo
ip -6 addr add 2607:f740:e633:deec::2/128 dev lo

If your provider expects the addresses on the uplink interface, configure them there instead, and persist via netplan/systemd-networkd.

2) Ensure Forwarding And Netfilter Are Enabled

Docker’s published ports rely on netfilter (nftables via iptables-nft on Ubuntu) and conntrack.

Recommended sysctls:

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
sysctl -w net.bridge.bridge-nf-call-iptables=1
sysctl -w net.bridge.bridge-nf-call-ip6tables=1

3) Advertise Anycast (BGP)

The anycast addresses must be routed to this host. In many setups this means:

  • Your upstream(s) establish BGP sessions with the host, and
  • The host advertises the anycast prefix(es) (not just a host route), and
  • The upstream accepts those announcements.

Example FRR approach (high level):

  • Run bgpd (FRR) on the host.
  • Announce the prefix containing your anycast address (e.g. 45.54.76.0/24 and 2607:f740:e633:deec::/48, depending on your allocation and policy).
  • Ensure you have filtering in place so you only announce what you intend.

This repository does not attempt to automate BGP on a real host; it only documents the expected moving parts.

4) Allow Inbound UDP

Allow inbound UDP on the published port to the anycast addresses, and allow established/related return traffic.

At minimum:

  • UDP 5300 to 45.54.76.1
  • UDP 5300 to 2607:f740:e633:deec::2

5) Docker Configuration Notes

  • Binding published ports to a specific host IP is supported via the ports: entries in compose.yml.
  • If you use port 53/udp instead of 5300/udp, you’ll need privileges on the host (or CAPs) and likely to stop any existing DNS service bound to :53.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published