Diego Pino
Diego Pino

Reputation: 11576

Ping external IPv6 address from a network namespace

I need to reach an external IPv6 address from a network namespace.

In my host I have setup a SIT tunnel (IPv6-in-IPv4) that does tunnelling of IPv6 packets and sends it through the default interface (eth0). The SIT tunnel relies on the Hurricane Electric tunnel broker service. I can ping an external IPv6 address from the host.

$ ping6 ipv6.google.com
PING ipv6.google.com(lis01s13-in-x0e.1e100.net) 56 data bytes
64 bytes from lis01s13-in-x0e.1e100.net: icmp_seq=1 ttl=57 time=98.1 ms
64 bytes from lis01s13-in-x0e.1e100.net: icmp_seq=2 ttl=57 time=98.7 ms

Here are some details about the tunnel:

$ ip -6 route sh
2001:470:1f14:10be::/64 dev he-ipv6  proto kernel  metric 256
default dev he-ipv6  metric 1024

Here comes the interesting part. For reasons that are beyond the scope of this question, I need to do the same thing (ping ipv6.google.com) from within a network namespace.

Here is how I create and setup my network namespace:

ns1.sh

#!/bin/bash

set -x

if [[ $EUID -ne 0 ]]; then
   echo "You must run this script as root."
   exit 1
fi

# Create network namespace 'ns1'.
ip netns del ns1 &>/dev/null
ip netns add ns1

# Create veth pair.
ip li add name veth1 type veth peer name vpeer1

# Setup veth1 (host).
ip -6 addr add fc00::1/64 dev veth1
ip li set dev veth1 up

# Setup vpeer1 (network namespace).
ip li set dev vpeer1 netns ns1
ip netns exec ns1 ip li set dev lo up
ip netns exec ns1 ip -6 addr add fc00::2/64 dev vpeer1
ip netns exec ns1 ip li set vpeer1 up

# Make vpeer1 default gw.
ip netns exec ns1 ip -6 route add default dev vpeer1

# Get into ns1.
ip netns exec ns1 /bin/bash --rcfile <(echo "PS1=\"ns1> \"")

Then I run ns1.sh and ping veth1 (fc00::1) vpeer1 (fc00::2) from 'ns1'.

ns1> ping6 fc00::1
PING fc00::1(fc00::1) 56 data bytes
64 bytes from fc00::1: icmp_seq=1 ttl=64 time=0.075 ms
^C
ns1> ping6 fc00::2
PING fc00::2(fc00::2) 56 data bytes
64 bytes from fc00::2: icmp_seq=1 ttl=64 time=0.056 ms

However, if I try to ping an external IPv6 address:

ns1> ping6 2a00:1450:4004:801::200e
PING 2a00:1450:4004:801::200e(2a00:1450:4004:801::200e) 56 data bytes
^C
--- 2a00:1450:4004:801::200e ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1008ms

All packets are loss.

I opened veth1 with tcpdump and checked what's going on. What I'm seeing is that Neighbor Solicitation packets are reaching the interface. These packets are trying to resolve the MAC address of the the IPv6 destination address:

$ sudo tcpdump -qns 0 -e -i veth1
IPv6, length 86: fc00::2 > ff02::1:ff00:200e: ICMP6, neighbor solicitation,
   who has 2a00:1450:4004:801::200e, length 32
IPv6, length 86: fc00::2 > ff02::1:ff00:200e: ICMP6, neighbor solicitation,
   who has 2a00:1450:4004:801::200e, length 32

I don't really understand why this is happening. I have enabled IPv6 forwarding in the host too but it had no effect:

$ sudo sysctl -w net.ipv6.conf.default.forwarding=1

Thanks for reading this question. Suggestions welcome :)

EDIT:

Routing table in the host:

2001:470:1f14:10be::/64 dev he-ipv6  proto kernel  metric 256 
fc00::/64 dev veth1  proto kernel  metric 256 
default dev he-ipv6  metric 1024

I added a NDP proxy in the host, that solves the NDP solicitations. Still the address is not reachable from the nsnet (looking into this):

sudo sysctl -w net.ipv6.conf.all.proxy_ndp=1
sudo ip -6 neigh add proxy 2a00:1450:4004:801::200e dev veth1

Upvotes: 4

Views: 2660

Answers (1)

ysdx
ysdx

Reputation: 9325

ULAs are not routable

You have given an Unique Local Address (fc00::2) to the network namespace: this IP address is not routable in the global internet but only in your local network.

When your ISP receives the ICMP packet coming from this address it will drop it. Even if this packet was successfully reaching ipv6.google.com, it could not possibly send the answer back to you because there is no announced route for this IP address.

Routing table problem (NDP notications)

You get NDP notifications because of this line:

ip netns exec ns1 ip -6 route add default dev vpeer1

which tells the kernel that (in the netns) all IP address are directly connected on the vpeer1 interface. The kernel thinks that this IP address is present on the Ethernet link: that's why it's trying to resolve its MAC address with NDP.

Instead, you want to say that they are reachable through a given router (in your case, the router is your host):

ip netns exec ns1 ip -6 route add default dev vpeer1 via $myipv6

Solutions

You can either:

  • associate an public IPv6 address (of your public IPv6 prefix) to your netns and setup a NDP proxy on the host for this address;

  • subnet your IPv6 prefix and route a subnet to your host (if you can);

  • use NAT (bad, ugly, don't do that).

You should be able to achieve the first one using something like this:

#!/bin/bash
set -x

myipv6=2001:470:1f14:10be::42
peeripv6=2001:470:1f14:10be::43

#Create the netns:
ip netns add ns1

# Create and configure the local veth:
ip link add name veth1 type veth peer name vpeer1
ip -6 address add $myipv6/128 dev veth1
ip -6 route add $peeripv6/128 dev veth1
ip li set dev veth1 up

# Setup vpeer1 in the netns:
ip link set dev vpeer1 netns ns1
ip netns exec ns1 ip link set dev lo up
ip netns exec ns1 ip -6 address add $peeripv6/128 dev vpeer1
ip netns exec ns1 ip -6 route add $myipv6/128 dev vpeer1
ip netns exec ns1 ip link set vpeer1 up    
ip netns exec ns1 ip -6 route add default dev vpeer1 via $peeripv6

# IP forwarding
sysctl -w net.ipv6.conf.default.forwarding=1

# NDP proxy for the netns
ip -6 neigh add proxy $myipv6 dev veth1

Upvotes: 6

Related Questions