Total Pageviews

Sunday 29 January 2012

使用 OpenVPN 将 HE Tunnel Broker 的 IPv6 搬回家

之前我们已经给 VPS 配置好了 HE Tunnel Broker 提供的 IPv6 地址,但是这 2^80 个 IPv6 地址都放在服务器上有些太浪费了,为何不弄到家里电脑来,让家里电脑也可以使用 IPv6 呢?等着国内运营商提供 IPv6 恐怕得猴年马月了吧?
Google 了一下,使用 OpenVPN Tunnel 可以轻松完成这个工作,有两种方法:第一种是用 tap 模式建立网桥,服务器端运行 radvd 给客户端分配 IPv6 地址并作路由。第二种使用 sit 设备,不需要配置服务,但是需要客户端做相应的绑定。我选择第二种,主要是想将 OpenVPN 维持在 tun 模式。
基 本思路是根据给客户端分配的内部 IPv4 地址的最后一位(X)在服务器端(在 Debian / Ubuntu 测试通过)起一个 sitX 设备,并且绑定 2001:1111:2222:X::1 这个地址,同时客户端(我这里是 Mac OS X,Windows / Linux 也可以分别使用批处理 / Bash 脚本调用 ip 命令搞定) gif 设备绑定 2001:1111:2222:X::2,并将默认路由设置为 2001:1111:2222:X::1,从而实现 IPv6 通路。下面是简单的设置过程和脚本文件:
服务器端设置:
vi /etc/openvpn/server.conf
最后加入:
script-security 2
client-connect /etc/openvpn/client-connect.sh
client-disconnect /etc/openvpn/client-disconnect.sh
编辑客户连接脚本
vi /etc/openvpn/client-connect.sh
内容:
#!/bin/bash
# This is a script that is run each time a remote client connects
# to this openvpn server.
# it will setup the ipv6 tunnel depending on the ip address that was
# given to the client
BASERANGE="2001:xxxx:xxxx"
# v6net is the last section of the ipv4 address that openvpn allocated
V6NET=$(echo ${ifconfig_pool_remote_ip} | awk -F. '{print $NF}')
SITID="sit${V6NET}"
# setup the sit between the local and remote openvpn addresses
sudo /sbin/ip tunnel add ${SITID} mode sit ttl 255 remote ${ifconfig_pool_remote_ip} local ${ifconfig_local}
sudo /sbin/ip link set dev ${SITID} up
# config routing for the new network
sudo /sbin/ip -6 addr add ${BASERANGE}:${V6NET}::1/64 dev ${SITID}
sudo /sbin/ip -6 route add ${BASERANGE}:${V6NET}::/64 via ${BASERANGE}:${V6NET}::2 dev ${SITID} metric 1
# log to syslog
echo "${script_type} client_ip:${trusted_ip} common_name:${common_name} local_ip:${ifconfig_local} \
remote_ip:${ifconfig_pool_remote_ip} sit:${SITID} ipv6net:${V6NET}" | /usr/bin/logger -t ovpn
客户断开脚本
vi /etc/openvpn/client-disconnect.sh
内容:
#!/bin/bash
# This is a script that is run each time a remote client disconnects
# to this openvpn server.
BASERANGE="2001:xxxx:xxxx"
# v6net is the last section of the ipv4 address that openvpn allocated
V6NET=$(echo ${ifconfig_pool_remote_ip} | awk -F. '{print $NF}')
SITID="sit${V6NET}"
sudo /sbin/ip -6 addr del ${BASERANGE}:${V6NET}::1/64 dev ${SITID}
# remove the sit between the local and:q
remote openvpn addresses
sudo /sbin/ip link set dev ${SITID} down
sudo /sbin/ip tunnel del ${SITID} mode sit ttl 255 remote ${ifconfig_pool_remote_ip} local ${ifconfig_local}
# log to syslog
echo "${script_type} client_ip:${trusted_ip} common_name:${common_name} local_ip:${ifconfig_local} \
remote_ip:${ifconfig_pool_remote_ip} sit:${SITID} ipv6net:${V6NET} duration:${time_duration} \
received:${bytes_received} sent:${bytes_sent}" | /usr/bin/logger -t ovpn
开启 IPv6 包转发:
sudo vi /etc/sysctl.conf
设置
net.ipv6.conf.all.forwarding=1
之后
sudo sysctl -p
客户端,编辑 client.conf,加入
up ./up.sh
down ./down.sh
如果选中了 Set nameserver 的话,这时候 TunnelBlick 在连接时就会调用
--up /Applications/Tunnelblick.app/Contents/Resources/client.up.tunnelblick.sh
从而造成 up ./up.sh 失败,所以我们不选 Set nameserver,然后将那个脚本并入我们自己的脚本中
up.sh 内容:
#!/bin/bash -e
bash /Applications/Tunnelblick.app/Contents/Resources/client.up.tunnelblick.sh -m -w -d
INTERFACE=$1; shift;
TUN_MTU=$1; shift;
UDP_MTU=$1; shift;
LOCAL_IP=$1; shift;
REMOTE_IP=$1; shift;
MODUS=$1; shift;
#script that is run on the client when it creates a tunnel to the remote OpenVPN server
IPV6BASE=2001:xxxx:xxxx
SERVER_IP=10.8.0.1
V6NET=$(echo ${LOCAL_IP} | cut -d. -f4)
GIFID="gif0"
sudo /sbin/ifconfig ${GIFID} tunnel ${LOCAL_IP} ${SERVER_IP}
sudo /sbin/ifconfig ${GIFID} inet6 ${IPV6BASE}:${V6NET}::2/64
sudo /sbin/route delete -inet6 default
sudo /sbin/route add -inet6 default ${IPV6BASE}:${V6NET}::1
exit 0
down.sh 内容
#!/bin/bash –e
INTERFACE=$1; shift;
TUN_MTU=$1; shift;
UDP_MTU=$1; shift;
LOCAL_IP=$1; shift;
REMOTE_IP=$1; shift;
MODUS=$1; shift;
# script that is run on the client when it creates a tunnel to the remote OpenVPN server
IPV6BASE=2001:xxxx:xxxx
SERVER_IP=10.8.0.1
V6NET=$(echo ${LOCAL_IP} | cut -d. -f4)
GIFID="gif0"
sudo /sbin/route delete -inet6 default
sudo /sbin/ifconfig ${GIFID} inet6 ${IPV6BASE}:${V6NET}::2 -alias
sudo /sbin/ifconfig ${GIFID} deletetunnel
bash /Applications/Tunnelblick.app/Contents/Resources/client.down.tunnelblick.sh -m -w -d --up-restart
exit 0
至此设置完毕,如果一切顺利的话以后再连接这个 OpenVPN 就可以在 gif0 上获取到 IPv6 地址了。
参考:Personal IPv6 Tunnel Broker with OpenVPN
-----------------------------------------------------------------

This document details how I setup an ipv6 tunnel broker system with OpenVPN

Why I did it
In the past I have used various ipv6 tunnel brokers but seemed to always be having connection problems. To get around this, and to learn about OpenVPN and IPv6 I decided to setup my own tunnel broker.
I have a Xen VM from Goscomb Technologies. As part of the package they also provide a /48 of ipv6 addresses for each VPS. This is good if you want to play with ipv6 to see how it works.

There are different methods to tunnel ipv6 packets over an ipv4 network. One of the easiest is to use the sit device to create a tunnel between two ipv4 systems. This method does have some problems though -
  • Each end of the tunnel must have a static ipv4 address
  • Each of the ipv4 endpoints must be reachable by the other - i.e. one end can not be a private ip address like 192.168.22.58
The question then become -
How do you provide a static ipv4 address when you live on the other side of the world, only have a private ip address and only have ADSL with a dynamic public ipv4 address.

The Open source OpenVPN Project is provided with most Linux distributions and can be easily installed. When I get a chance I will provide details on how I installed OpenVPN but in the mean time see your distribution for installation details. When OpenVPN is running it can provide static ipv4 addresses at each endpoint. If my public ipv4 address changes then OpenVPN will still maintain the tunnel ipv4 addresses. Just what we want.
Yes I know that OpenVPN has a tun-ipv6 device that can carry native ipv6 packets. The problem is you currently can not have a server with a tun-ipv6 device. It must be a tap device in bridge mode. I do not want to do this because it means changing the network configuration on my remote server which I do not have console access to. If anything goes wrong I could easily be locked out of my machine.

I received an email from Ian who mentioned that he was having some problems with this setup. It seems that not all providers configure ipv6 the same and he had to ser up Neighbor Discovery Proxy to get his system working.
Here is what he said -
One thing stopped it working. Packets from the internet were not making it back to my VM and from there back down the tunnel. A tcpdump on the VM revealed 'Neighbor Discovery Packets' for my machine being broadcast by the ISPs router. As soon as I added 'Neighbor Discovery Proxy' on my VM for the machine at my home end of the tunnel, it worked perfectly. It's similar to Proxy ARP in ipv4, I read about it here:
and added this to my server's client-connect.sh script:

# config Neighbor Discovery Proxy (like proxy ARP)
# also requires 'echo 1 >/proc/sys/net/ipv6/conf/all/proxy_ndp'
# e.g. in rc.local or using sysctl
sudo /sbin/ip -6 neigh add proxy ${BASERANGE}:${V6NET}::2 dev eth0
It works like a charm.
Here is the server.conf file I have running on the Xen VM from Goscomb -
# Local IP address for the server to listen on.
local 9.8.7.6

# set the port or use the standard 1194
port 56789

# udp is the recommended transport
proto udp

# there is a tun-ipv6 device but I want to use the tun device
dev tun

# the keys I generated during the OpenVPN install process
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/server.crt
key /etc/openvpn/keys/server.key  # This file should be kept secret

dh /etc/openvpn/keys/dh2048.pem

# the ip range that OpenVPN will use for its static ipv4 addresses
server 10.18.0.0 255.255.255.0

tls-auth ta.key 0 # This file is secret

comp-lzo

max-clients 10

keepalive 18 83

user ovpn
group nogroup

persist-key
persist-tun

status openvpn-status.log

verb 5

# I added these to setup and tear down the ipv6 tunnels when a client connects or disconnects. See below
client-connect /etc/openvpn/client-connect.sh
client-disconnect /etc/openvpn/client-disconnect.sh
And here is the client.conf I used at each client
client

dev tun

proto udp

remote 9.8.7.6 56789

resolv-retry infinite

nobind

keepalive 27 79

user ovpn
group nogroup

persist-key
persist-tun

ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/client1.crt
key /etc/openvpn/keys/client1.key

ns-cert-type server

tls-auth ta.key 1

comp-lzo

verb 3

# create the ipv6 tunnel
up /etc/openvpn/up.sh
down /etc/openvpn/down.sh

# need this so when the client disconnects it tells the server so the server can remove the ipv6 tunnel the client was using
explicit-exit-notify


With the above configurations OpenVPN will create a tunnel with static ipv4 address at each end. We now use those ipv4 addresses to create the ipv6 network. The ipv4 network the OpenVPN server uses is in the 10.18.0.0/24 network and it will allocate an address in this range to each remote client. For example 10.18.0.14 As we have a /48 of ipv6 addresses to play with we can then allocate a /64 to each connecting client. A /64 by the way is the smallest network you are meant to allocate in the ipv6 world.
The range of ipv6 addresses you get from your provider will look something like 2001:f5a:53::/48
This means to get to a /64 for each remote client then we have to add some number to the above. Why not add the last octet from the ipv4 of the remote OpenVPN client.
For example
OpenVPN allocates the remote client an ipv4 address of 10.18.0.14

The ipv6 range is 2001:f5a:53::/48

We therefore allocate 2001::f5a:53:14::/64 to the remote client

From this we use 2001::f5a:53:14::1 as the local end of the ipv6 tunnel
and we use 2001::f5a:53:14::2 as the remote ipv6 address for the client

Yes we waste the rest of the /64 of ipv6 addresses

This is the script we run on the server each time a client connects. OpenVPN is good because it provides various environment variables with information about the client that has connected. You will notice that the following script uses sudo. This is because the script runs as the same user that OpenVPN runs as so it will not have access to the /sbin/ip command. To get around this we need to add the following to the /etc/sudoers file. This will allow the ovpn user to run only the /sbin/ip command
ovpn ALL=(ALL)  NOPASSWD: /sbin/ip
client-connect.sh script file
#!/bin/bash

# This is a script that is run each time a remote client connects
# to this openvpn server.
# it will setup the ipv6 tunnel depending on the ip address that was 
# given to the client

BASERANGE="2001:f5a:53"
# v6net is the last section of the ipv4 address that openvpn allocated
V6NET=$(echo ${ifconfig_pool_remote_ip} | awk -F. '{print $NF}')

SITID="sit${V6NET}"

# setup the sit between the local and remote openvpn addresses
sudo /sbin/ip tunnel add ${SITID} mode sit ttl 255 remote ${ifconfig_pool_remote_ip} local ${ifconfig_local}
sudo /sbin/ip link set dev ${SITID} up

# config routing for the new network
sudo /sbin/ip -6 addr add ${BASERANGE}:${V6NET}::1/64 dev ${SITID}
sudo /sbin/ip -6 route add ${BASERANGE}:${V6NET}::/64 via ${BASERANGE}:${V6NET}::2 dev ${SITID} metric 1

# log to syslog
echo "${script_type} client_ip:${trusted_ip} common_name:${common_name} local_ip:${ifconfig_local} \
remote_ip:${ifconfig_pool_remote_ip} sit:${SITID} ipv6net:${V6NET}" | /usr/bin/logger -t ovpn 


When the remote client disconnects from the OpenVPN server we need to clean up the ipv6 tunnel on the server. client-disconnect.sh script
#!/bin/bash

# This is a script that is run each time a remote client disconnects
# to this openvpn server.

BASERANGE="2001:f5a:53"
# v6net is the last section of the ipv4 address that openvpn allocated
V6NET=$(echo ${ifconfig_pool_remote_ip} | awk -F. '{print $NF}')

SITID="sit${V6NET}"

sudo /sbin/ip -6 addr del ${BASERANGE}:${V6NET}::1/64 dev ${SITID}

# remove the sit between the local and remote openvpn addresses
sudo /sbin/ip link set dev ${SITID} down
sudo /sbin/ip tunnel del ${SITID} mode sit ttl 255 remote ${ifconfig_pool_remote_ip} local ${ifconfig_local}

# log to syslog
echo "${script_type} client_ip:${trusted_ip} common_name:${common_name} local_ip:${ifconfig_local} \
remote_ip:${ifconfig_pool_remote_ip} sit:${SITID} ipv6net:${V6NET} duration:${time_duration} \
received:${bytes_received} sent:${bytes_sent}" | /usr/bin/logger -t ovpn 
I have also added the following lines to /etc/rc.local on the server to setup things for OpenVPN. The firewall rules restrict the tunnel to only carry ipv6inipv4 packets
# allow forwarding of ipv6 packets
echo "1" >/proc/sys/net/ipv6/conf/all/forwarding

# openvpn tunnel will only accept ipv6-in-v4 packets
iptables -A INPUT -i tun0 ! -p 41 -j REJECT --reject-with icmp-host-unreachable
iptables -A OUTPUT -o tun0 ! -p 41 -j REJECT --reject-with icmp-host-unreachable


At the client end we also need to setup and remove the tunnel The up.sh script on the client
#!/bin/bash

# script that is run on the client when it creates a tunnel to the remote OpenVPN server
IPV6BASE=2001:f5a:53

V6NET=$(echo ${ifconfig_local} | awk -F. '{print $NF}')

# NOTE!!! The following has a hard coded ipv4 address because I can not find a way for the client to find
# out the server ipv4 end point of the OpenVPN tunnel
/sbin/ip tunnel add sit1 mode sit ttl 255 remote 10.18.0.1 local ${ifconfig_local}
/sbin/ip link set dev sit1 up
/sbin/ip -6 addr add ${IPV6BASE}:${V6NET}::2/64 dev sit1

/sbin/ip route add ::/0 via ${IPV6BASE}:${V6NET}::1

exit 0

And the following is the down.sh script that is run on the client when the OpenVPN tunnel is shut down
#!/bin/bash

IPV6BASE=2001:f5a:53
V6NET=$(echo ${ifconfig_local} | awk -F. '{print $NF}')

sudo /sbin/ip -6 addr del ${IPV6BASE}:${V6NET}:2/64 dev sit1
sudo /sbin/ip link set dev sit1 down
sudo /sbin/ip tunnel del sit1 mode sit ttl 255 remote 10.18.0.1 local ${ifconfig_local}

sudo /sbin/ip route del ::/0 via ${IPV6BASE}:${V6NET}:1

exit 0


And that is about that. Start OpenVPN on the server and connect from the clients and they should create devices like this on the client -
human@dave:~$ ifconfig tun0
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:10.18.0.6  P-t-P:10.18.0.5  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:1184 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1207 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100 
          RX bytes:1244833 (1.2 MB)  TX bytes:160282 (160.2 KB)


human@dave:~$ ifconfig sit1
sit1      Link encap:IPv6-in-IPv4  
          inet6 addr: 2001:f5a:53:6::2/64 Scope:Global
          inet6 addr: fe80::a12:6/128 Scope:Link
          UP POINTOPOINT RUNNING NOARP  MTU:1480  Metric:1
          RX packets:1184 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1207 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1221153 (1.2 MB)  TX bytes:136142 (136.1 KB)
And this on the server
sit6      Link encap:IPv6-in-IPv4  
          inet6 addr: 2001:f5a:53:6::1/64 Scope:Global
          inet6 addr: fe80::a12:1/128 Scope:Link
          UP POINTOPOINT RUNNING NOARP  MTU:1480  Metric:1
          RX packets:544 errors:0 dropped:0 overruns:0 frame:0
          TX packets:485 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:74953 (73.1 KB)  TX bytes:432683 (422.5 KB)

tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:10.18.0.1  P-t-P:10.18.0.2  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:97712 errors:0 dropped:0 overruns:0 frame:0
          TX packets:93189 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100 
          RX bytes:10047601 (9.5 MB)  TX bytes:71844638 (68.5 MB)

Now you can surf the web 128 bits at a time - Have Fun.

from http://www.zagbot.com/openvpn_ipv6_tunnel.html

No comments:

Post a Comment