10

I've managed to setup OpenVPN for full IPv4 connectivity using tap0. Now I want to do the same for IPv6.

Addresses and network setup (note that my real prefix is replaced by 2001:db8):

2001:db8::100:0:0/96    my assigned IPv6 range
2001:db8::100:abc:0/112 OpenVPN IPv6 range
2001:db8::100:abc:1     tap0 (on server) (set as gateway on client)
2001:db8::100:abc:2     tap0 (on client)
2001:db8::1:2:3:4       gateway for server

 Home laptop   (tap0: 2001:db8::100:abc:2/112 gateway 2001:db8::100:abc:1/112)
  |      | |      (running Kubuntu 10.10; OpenVPN 2.1.0-3ubuntu1)
  | wifi | |
   router  |
      |   OpenVPN
  INTERNET |
eth0  |   /tap0
     VPS        (eth0:2001:db8::1:2:3:4/64    gateway 2001:db8::1)
               (tap0: 2001:db8::100:abc:1/112)
                  (running Debian 6; OpenVPN 2.1.3-2)

The server has both native IPv4 and IPv6 connectivity, the client has only IPv4.

I can ping6 to and from my server over OpenVPN, but not to other machines (for example, ipv6.google.com).

net.ipv6.conf.all.forwarding is set to 1, I've tried disabling net.ipv6.conf.all.accept_ra as well, without luck.

Using tcpdump on both the server and client, I can see that packets are actually transferred over tap0 to eth0. The router (2001:db8::1) send a neighbor solicitation for the client (2001:db8::100:abc:2) to eth0 after it receives the ICMP6 echo-request. The server does not respond to that solicitation, which causes the ICMP6 echo-request not be routed to the destination.

How can I make this IPv6 connection work?

Lekensteyn
  • 6,111
  • 6
  • 37
  • 55

2 Answers2

6

Timothy Baldwins answer put me on the right track, although the answer was rather cryptic. IPv6 neighbor advertisements/solicitation is like ARP for IPv6. It's used to "see" other machines on the network. The router send a neighbor solicitation on which the machine (server or client) should reply on with a neighbor advertisement.

Even with net.ipv6.conf.all.forwarding set to 1, neighbor advertisements and solicitations are not forwarded. To make eth0 forward neighbor advertisements and solicitations, eth0 should be set as proxy for the IPv6 address of the client behind tap0, and proxying for neighbor stuff should be enabled for eth0:

echo 1 > /proc/sys/net/ipv6/conf/eth0/proxy_ndp
/sbin/ip -6 neigh add proxy 2001:db8::100:abc:2 dev eth0

Unfortunately, it's not possible to retrieve the list of proxies added, nor does ip -6 show error messages on repeatedly executing the command. Neither am I sure if "neigh del proxy" works, it does not give an error message and the C source is not really meaningful to me.


As I do not want to do everything manually, I've created a script which does the work for me.

Server configuration

IPv6 addresses are based on the IPv4 part (the 1 in 10.8.0.1). The prefix and netmask are stored in /etc/openvpn/variables.

The next steps are made for setting up OpenVPN with encrypted IPv4/IPv6 connectivity to the Internet over a native IPv4 connection. RSA keys and tls-auth are used for authentication and MITM prevention.

/etc/openvpn/variables contains variables which are used for the up script (run on startup, after creation of tap0 device) and client-connect script (run after the client has authenticated).

# this prefix is handled out by the provider, replace it with your own prefix
prefix=2001:db8::abc
# netmask, 2001:db9::abc:0000 - 2001:db9::abc:FFFF
prefixlen=112

/etc/openvpn/server-clientconnect.sh is executed as root and makes sure that IPv6 is routed properly by adding the IPv6 address to the eth0 proxy. Because client-connect is called after OpenVPN switched to the user specified by the User setting, sudo is needed to give the script sufficient permissions to run as root. Of course, variables should be checked before using, the number should be between and including 2 ad 254. (1 is the gateway, 255 the broadcast address).

#!/bin/sh
. /etc/openvpn/variables
if [ -z "$ifconfig_pool_remote_ip" ]; then
        echo "Missing environment variable."
        exit 1
fi
ipp=$(echo "$ifconfig_pool_remote_ip" | cut -d. -f4)
if ! [ "$ipp" -ge 2 -a "$ipp" -le 254 ] 2>/dev/null; then
        echo "Invalid IP part."
        exit 1
fi
hexipp=$(printf '%x' $ipp)
/sbin/ip -6 neigh add proxy $pfx:$hexipp dev eth0

To make this work, the user vpn should be allowed to run the script while preserving $ifconfig_pool_remote_ip which contains the remote network IPv4 address. Add the next lines to the sudoers file by executing sudo visudo and appending:

Defaults:vpn env_keep=ifconfig_pool_remote_ip
vpn ALL=NOPASSWD: /etc/openvpn/server-clientconnect.sh

/etc/openvpn/server-up.sh enables IPv4, IPv6 forwarding (eth0+tap0 did not work, it really had to be all) and neighbor proxy on eth0. It adds the gateway address to servers tap0 too.

#!/bin/sh
. /etc/openvpn/variables
/sbin/ip -6 addr add $pfx:1/$pfxlen dev $dev
echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
echo 1 > /proc/sys/net/ipv6/conf/eth0/proxy_ndp

Finally, the OpenVPN configuration file at /etc/openvpn/internet.conf:

proto udp
dev tap
ca ca.crt
cert server.crt
key server.key
dh dh1024.pem
server 10.8.0.0 255.255.255.0
script-security 2
up /etc/openvpn/server-up.sh
client-connect "/usr/bin/sudo -u root /etc/openvpn/server-clientconnect.sh"
# encrypt all traffic
push "redirect-gateway def1"
# keep the same IP addresses each time
ifconfig-pool-persist ipp.txt
keepalive 10 120
tls-auth ta.key 0
cipher BF-CBC
comp-lzo
# OpenVPN will switch to this user, it is also used for sudo
user vpn
group vpn
persist-key
persist-tun

For completeness, permissions and ownerships of files in /etc/openvpn:

drwx------  root root  .
-rw-------  root root  ca.crt
-rw-------  root root  dh1024.pem
drwx------  root root  easy-rsa      <-- left from creation of keys
-rw-------  root root  ipp.txt
-rwx------  root root  server-clientconnect.sh
-rw-------  root root  internet.conf
-rw-------  root root  variables
-rwx------  root root  server-up.sh
-rw-------  root root  server.crt
-rw-------  root root  server.key
-rw-------  root root  ta.key
-rwx------  root root  update-resolv-conf <-- this was installed by default

Firewall settings:

itpables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -s 10.8.0.0/24 -i tap0 -o eth0 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
ip6tables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A FORWARD -s 2001::db8::abc:0/112 -i tap0 -o eth0 -j ACCEPT

Configuration on client

/etc/openvpn/client.conf:

client
dev tap
proto udp
remote 178.21.112.251 1194
script-security 2
up /etc/openvpn/client-up.sh
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
ca ca.crt
cert home.crt
key home.key
ns-cert-type server
tls-auth ta.key 1
cipher BF-CBC
comp-lzo

ta.key and ca.key are the same files from the server. home.key and home.crt are files, created on the server.

client-up.sh adds the IPv6 address and route (based on IPv4 address):

#!/bin/sh
pfx='2001:db8::abc'
pfxlen=112
hexippart=`printf '%x' "$(echo $ifconfig_local | cut -d. -f4)"`
/sbin/ip -6 addr add $pfx:$hexippart/$pfxlen dev $dev
/sbin/ip -6 route add default via $pfx:1 dev $dev

The guide at http://www.ipsidixit.net/2010/03/24/239/ was very helpful and OpenVPN manual page is useful for information about various settings.

Lekensteyn
  • 6,111
  • 6
  • 37
  • 55
  • Presumably eth0 is the interface that has IPv6 connectivity that you are trying to expose over OpenVPN? Can you please confirm this? – Ivan Vučica Dec 14 '13 at 21:17
  • @IvanVučica That is correct, `eth0` is the interface that routes all traffic (including IPv6) by default. – Lekensteyn Dec 15 '13 at 10:11
0

The upstream router is configured for 2001:db8::100:abc:2 to be on the directly attached link, set net.ipv6.conf.eth0.proxy_ndp = 1 to pretend that it is.