这几天看linux tunnel 技术,感觉linux很好很强大。记录如下:( 所有测试系统 CentOS5.2 )
linux 支持的 tunnel 有 ipip gre sit 其他非内核隧道这几种。
ipip 需要内核模块 ipip.ko 下面的描述说出了ipip的特点。
简单之极!但是你不能通过IP-in-IP隧道转发广播或者IPv6数据包。你只是连接了两个一般情况下无法直接通讯的IPv4网络而已。至于兼容性,这部分代码已经有很长一段历史了,它的兼容性可以上溯到1.3版的内核。据我所知,Linux的IP-in-IP隧道不能与其他操作系统或路由器互相通讯。它很简单,也很有效。需要它的时候尽管使用,否则就使用GRE。
GRE 需要内核模块 ip_gre.ko
GRE是最初由CISCO开发出来的隧道协议,能够做一些IP-in-IP隧道做不到的事情。比如,你可以使用GRE隧道传输多播数据包和IPv6数据包。
还有一个 sit 我也不知道这个该不该算在隧道里面,他的作用是连接 ipv4 与 ipv6 的网络,这里也我也把他当作隧道的一种吧。
以上所有隧道都需要内核模块 tunnel4.ko 的支持。
在内核之外,还有很多实现隧道的方法,最闻名的当然要数PPP和PPTP,但实际上还有很多(有些是专有的,有些是安全的,有些甚至根本不用IP。
很多人都把隧道描写成一个专用的管子,我觉得这容易造成理解上的误区,当然你看到的结果的确像在一个专用的管子里那样通讯,我更喜欢把隧道看成一个装在大信封里面的一个小信封和一封信。因为不管理论如何,你的数据包还是要实实在在的,通过现有的网络、路由,一步一步的传送过去,这个是不可能省略掉的。
说了这么多,现在就开始从最基本的 ipip 来手工建立一个隧道。
环境:两台linux服务器,分别在两地。并且两台机器都有实ip与互联网向链接,能够互相通讯。每台机器后面都有带着一个LAN 。
图1
-------------------------------------INTERNET------------------------------------
| 192.168.100.0/24 | 211.167.237.218 <------> 123.127.177.195 |192.168.200.0/24 |
|- - - - | | - - - -|
| eth0 | eth1 | | eth1 | eth0 |
---------------------------------------------------------------------------------
结构就是这个样子,现在我们就依据上面的结构来建立 tunnel 。
在 211.167.237.218 上创建:
modprobe ipip
ip tunnel add tun1 mode ipip remote 123.127.177.195 local 211.167.237.218 ttl 64
ip link set tun1 mtu 1480 up
ip address add 192.168.200.253 brd 255.255.255.255 peer 123.127.177.195 dev tun1
ip route add 192.168.200.0/24 via 192.168.200.253
在 123.127.177.195 上创建:
modprobe ipip
ip tunnel add tun1 mode ipip remote 211.167.237.218 local 123.127.177.195 ttl 64
ip link set tun1 mtu 1480 up
ip address add 192.168.100.253 brd 255.255.255.255 peer 211.167.237.218 dev tun1
ip route add 192.168.100.0/24 via 192.168.100.253
上面的命令里出现了几个关键字,需要我们注意的地方:
1、mtu隧道会增加协议开销,因为它需要一个额外的IP包头。一般应该是每个包增加20个字节,所以如果一个网络的MTU是1500字节的话,使用隧道技术后,实际的IP包长度最长只能有1480字节了。这倒不是什么原则性的问题,但如果你想使用隧道技术构建一个比较大规模的网络的话,最好仔细研究一下关于IP包的分片和汇聚的知识。
2、ttl 数据包的生存期。设置为64是安全的。如果你的网络规模巨大就提高这个值。不要因为好玩而这么做,那样会产生有害的路由环路。实际上,在很多情况下你要考虑能否减小这个值。
3、ip 要写对端的内网ip,因为这可以减少vpn服务器不是默认网关的麻烦。对方看到的数据包实际是你本地绑定在 tun1 上的ip地址。
4、设置路由后就可以通讯了。
5、这样你已经可以和 你拨入的机器的内网卡通讯了,为了让你拨入方的其他机器也可以和你通讯,你需要增加一个 arp 的响应机制及打开ip转发功能。
arp -Ds source_ip -i lan_eth pub
sysctl -w net.ipv4.ip_forward=1
让你的内网卡可以响应这个ip的arp回应。
到此为止,一简单的 ip tunnel 已经完成了。当然如果你不想使用 ipip 你更喜欢gre 那你可以在开头简单的改成
moprobe ip_gre
ip tunnel add tun1 mode gre ... ...
来实现,而后面的参数基本上不需要改变。
上面是一个简单的没有任何加密的隧道建立过程,这样通讯可能会带来安全隐患,毕竟我们访问的是内网吗。
下面来给这个隧道加密。
ipsec 是一个复杂的东西,这里只简单的介绍,如果有问题请查阅在线的[url=http://control.cublog.cn/%5C%22%5C%22]文档[/url]
setkey 是 ipsec 的管理工具,语法类似 setkey -c 然后输入命令,按 ctrl^C 退出。
setkey 中的命令是
add src_ip dst_ip esp SPI -E 3des-cbc \"password\";
格式就是这个样子,也比较好理解, 源地址,目的地址,加密头还是数据,安全码(SPI)验证方式,及共享密钥。
下面在 211.167.237.218 上建立 ipsec
setkey -c
flush;
spdflush;
add 211.167.237.218 123.127.177.195 esp 11571 -E 3des-cbc \"__esp_test_3des_password\";
add 123.127.177.195 211.167.237.218 esp 11572 -E 3des-cbc \"__esp_test_3des_password\";
add 211.167.237.218 123.127.177.195 ah 15071 -A hmac-md5 \"ah_test_password\";
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
spdadd 211.167.237.218 123.127.177.195 any -P out ipsec
esp/transport/192.168.100.1-192.168.100.250/require
ah/transport/192.168.100.1-192.168.100.250/require;
spdadd 123.127.177.195 211.167.237.218 any -P in ipsec
esp/transport/192.168.200.1-192.168.200.250/require
ah/transport/192.168.200.1-192.168.200.250/require;
^C (ctrl+c)
这样就算配置完成了,你可以通过 setkey -D[P][p] 来检查,或者在 setkey 里使用 dump
为了方便,不用每次都敲一大堆命令,在 123.127.177.195 上写一个启动策略脚本。
#!/bin/bash
#
# chkconfig: 345 15 98
# description: Linux IPsec SA/SP database
#
# Source function library.
. /etc/init.d/functions
start() {
echo -n $\"ipsec start ... \"
/etc/setkey.conf && echo -e \"[ ]\"
}
case \"$1\" in
start)
start
;;
stop)
echo -n \"flush;spdflush;\" | \\
setkey -c && echo -e \"ipsec stoping ... [ ]\"
;;
reload)
$0 stop
$0 start
;;
*)
echo $\"Usage: $0 {start|stop|reload}\"
exit 1
esac
exit $?
# cat setkey.conf
#!/sbin/setkey -f
flush;
spdflush;
# ESP
add 211.167.237.218 123.127.177.195 esp 11571 -E 3des-cbc \"__esp_test_3des_password\";
add 123.127.177.195 211.167.237.218 esp 11572 -E 3des-cbc \"__esp_test_3des_password\";
# AH
add 211.167.237.218 123.127.177.195 ah 15071 -A hmac-md5 \"ah_test_password\";
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
# POLICY
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
spdadd 211.167.237.218 123.127.177.195 any -P in ipsec
esp/transport/192.168.100.1-192.168.100.250/require
ah/transport/192.168.100.1-192.168.100.250/require;
spdadd 123.127.177.195 211.167.237.218 any -P out ipsec
esp/transport/192.168.200.1-192.168.200.250/require
ah/transport/192.168.200.1-192.168.200.250/require;
接下来我们就运行 ipsec.sh start 就能启动 ipsec 了,如果想停止就运行 ipsec.sh stop
或者你还可以吧 ipsec 拷贝到 /etc/init.d/ipsec 然后运行 chkconfig --add ipsec 让他作为服务,开机就启动。
可能细心的读者已经发现在两个服务器上的脚本略有不同,实际就是把 Policy 里面的 in 和 out 对换一下,然后写上本地子网就可以了。
上面是一个简单的隧道建立过程,下面我们来个复杂一点的,也是我们常碰到的结构。
图2
---------- ------------- ------------ ---------------- -------
| client | <--> | nat server| <--> | internet | <--> | Linux server | <--> | Lan |
---------- ------------- ------------ ---------------- -------
|client ip 192.168.100.100/24 gateway 192.168.100.254 |
|nat server: lan_ip 192.168.100.254/24 wan_ip 123.119.206.165 |
|Linux server: lan_ip eth0 192.168.200.100/24 wan_ip eth1 123.127.177.210 |
|--------------------------------------------------------------------------------|
这个结构比较麻烦了,因为我们的源地址会被改写一次,这个该如何配置呢。
实际上在linux上配置这个也很简单,只要遵循原则,看见谁,就写谁的方法就没有问题。
比如在我们客户机上看见的一定是 由我们本地的ip(伪)到远程服务器的ip(实),而远程服务器看到的情况却有点不一样,服务器看到的是,客户机经过nat后的ip(实),和本机ip(实)在通讯,根据这个原则,我们写出如下命令。
A:client
modprobe ip_gre
ip tunnel add tun2 mode gre remote 123.127.177.210 local 192.168.100.100 ttl 64
ip link set tun2 mtu 1480 up
ip address add 192.168.200.253 brd 255.255.255.255 peer 123.127.177.210 dev tun2
B:Server
modprobe ip_gre
ip tunnel add tun2 mode gre remote 123.119.206.165 local 123.127.177.210 ttl 64
ip link set tun2 mtu 1480 up
ip address add 192.168.100.253 brd 255.255.255.255 peer 123.119.206.165 dev tun2
这样隧道就建立起来了。
服务器端配置:
果想让这个client能访问内网的其他机器需要加一个arp 的响应机制及ip转发。
arp -Ds source_ip -i lan_eth pub
sysctl -w net.ipv4.ip_forward=1
如果你做的 vpn_proxy ,不希望他访问你的内网,而仅仅是用来代理上网,那你就需要去掉这个。
arp -d source_ip dev lan_eth
添加一个ip伪装的功能。
iptables -t nat -A POSTROUTING -s 192.168.200.253 -j MASQUERADE
当然如果你二者都需要,那你就都添加就可以了。
客户机配置:
添加一个我们到对方服务器的路由
ip route add 123.127.177.210 via 192.168.100.254
用来保证我们能链接到远程的 Linux Server
如果我们想访问他的内网,我们就需要添加到对方内网的路由,当然这需要服务器给你做arp响应。
ip route 192.168.200.0/24 via 192.168.200.253
如果我们想像 vpn_proxy 一样使用他,那也非常简单,修改默认网关就可以了。
(也许你会觉得这有问题,请仔细想想,这里遍历了2次路由表,保证了链路、数据的畅通)
ip route change default via 192.168.200.253
隧道已经配置好了,但加密却有了问题:
我们知道客户机的原地址是经过1次nat的,而加密验证ip头是在nat之前,这个如和处理呢。
方法1、去掉头部验证,只对数据段加密,
对于一般的情况加密数据段已经足够了,我们可以简单的去掉这部分来实现。
setkey.conf # AH 里面的东西,然后在策略里禁止 AH 强制加密认证。
去掉# AH
add 211.167.237.218 123.127.177.195 ah 15071 -A hmac-md5 \"ah_test_password\";
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
修改策略为:
spdadd 211.167.237.218 123.127.177.195 any -P out ipsec
esp/transport/192.168.100.1-192.168.100.250/require;
... ...
好了我只写这么多,至于服务器两端具体如何修改,呵呵要自己动手了。
方法2、将访问我们的源地址换回去,在做验证。
这种方法涉及了很多的编程知识,可能我们还要专门为他写一个模块,这里不讨论了。
如果你觉得 ipsec 这个命令很麻烦,还需要自己写一大堆的脚本,那你可以使用 racoon
racoon 是 IKE 的守护进程,他的配置文件是 racoon.conf
racoon.conf
# Racoon IKE daemon configuration file.
# See \'man racoon.conf\' for a description of the format and entries.
path include \"/etc/racoon\";
path pre_shared_key \"/etc/racoon/psk.txt\";
path certificate \"/etc/racoon/certs\";
listen { isakmp 123.127.177.195 [500]; }
sainfo anonymous
{
pfs_group 2;
lifetime time 1 hour ;
encryption_algorithm 3des, blowfish 448, rijndael ;
authentication_algorithm hmac_sha1, hmac_md5 ;
compression_algorithm deflate ;
}
include \"/etc/racoon/211.167.237.218.conf\";
看见了吧,实际我就在最后加了一句话 include ... 上面加了一个监听的地址,剩下都不用改。
其实 racoon.conf 的配置也蛮复杂的,不过有人已经给我们写好了脚本来处理,这样就简单多了。
只需要修改这一点,其他的都不用管了。
然后建立 /etc/sysconfig/network-script/ifcfg-ipsec1 这个文件,这个就是我们的配置文件。
内容也很简单 :
DST=211.167.237.218
TYPE=IPSEC
ONBOOT=yes
IKE_METHOD=PSK
IKE_PSK=testpassword
文件的配置很少,注意两处就行了,第一 DST 要写对方的 ip 地址,从名字也很好认的,第二,共享密钥要完全一样,就是 IKE_PSK,配置到这里就算完了,书上推荐把密码单独放到一个文件里,然后设定这个文件的权限 600,为了安全你也可以这么做,但我喜欢放在一起好管理吗,(如果黑客已经有了你机器的shell,我想即使是普通用户,他也有办法看到root权限的文件的)接下来我们直接用 ifup ipsec1来启动就可以了。然后你会发现你的通讯也加密了。别忘了两边的机器都要加密才能通讯的哦,同理实际隧道也可以通过 ifcfg-ppp这样的配置文件来让脚本自动生成,到那那样你就看不到后面的这些东西了,ifcfg-ppp 就自己来写吧。
在补充一句,racoon 是在有通讯发生的时候才对数据加密的,所以你第一次连接远程主机会比较慢,当然这也仅仅是第一次,大概等待2~5秒。如果你想看策略最好是一边通讯,一边查看,要不然,你可能看不到哦。
3、其他方法,软件,pptp openvpn
从这里下载 pptpd 的软件。
我下载的是 1.3.4 解压,然后编译。
默认的 logwtmp 是 2.4.3 的版本,我系统的 pppd 是 2.4.4 的,不修改的话会报错。
把 plugins/patchlevel.h 中的 版本号改成 2.4.4 时间乱写一个就好了。
#define VERSION \"2.4.4\"
#define DATE \"13 Jan 2005\"
然后编译,安装。
./configure
make
make check
make install
安装完以后把编译出来的 logwtmp.so 拷贝到 /usr/lib/pptpd 下面。
mkdir /usr/lib/pptpd
cp plugins/pptpd-logwtmp.so /usr/lib/pptpd/pptpd-logwtmp.so
然后把配置文件也拷贝过去。
cp samples/options.pptpd /etc/ppp/
cp samples/pptpd.conf /etc
修改一下配置就可以启动了。
options.pptpd 全部注释掉,有着几行就行
name pptpd
refuse-chap
refuse-mschap
require-mschap-v2
require-mppe-128
proxyarp
lock
nobsdcomp
novj
novjccomp
nologfd
如果使用 mppe 的加密的话需要 kernel 2.6.15-rc1 以上。否则要打补丁。呵呵我的版本够高了,这就省事了。
pptpd.conf
ppp /usr/sbin/pppd
option /etc/ppp/options.pptpd
logwtmp
localip 123.127.177.195
remoteip 192.168.100.10-50
listen 123.127.177.195
speed 115200
connections 20
这样就配置完了,直接用 pptpd 启动。
接下来配置客户端。
下载 pptp 软件 我下载的是 1.7.2
我的系统 ip 命令在 /sbin 下 修改 routing.c 吧 /bin/ip 都换成 /sbin/ip
make
make install
然后测试连接
先在服务器的 /etc/ppp/chap-secrets 添加用户名和密码
admin pptpd admin *
然后在客户机上创建配置文件
pptpsetup --create vpntest --server 123.127.177.195 --username admin --password admin --encrypt
拨号练接
pppd call vpntest
如果一切正常的话,你应该用 ifconfig 就能看见 ppp0 这个设备了,而且数据通讯是 mppe 加密的。
总结一下:建立隧道的完整步骤为
1、两台实ip机器建立隧道。图1
A:Server
modprobe ipip
ip tunnel add tun1 mode ipip remote 123.127.177.195 local 211.167.237.218 ttl 64
ip link set tun1 mtu 1480 up
ip address add 192.168.200.253 brd 255.255.255.255 peer 123.127.177.195 dev tun1
ip route add 192.168.200.0/24 via 192.168.200.253
arp -Ds 192.168.100.253 eth0 pub
sysctl -w net.ipv4.ip_forward=1
service ipsec start
B:Server
ip tunnel add tun1 mode ipip remote 211.167.237.218 local 123.127.177.195 ttl 64
ip link set tun1 mtu 1480 up
ip address add 192.168.100.253 brd 255.255.255.255 peer 211.167.237.218 dev tun1
ip route add 192.168.100.0/24 via 192.168.100.253
arp -Ds 192.168.200.253 eth0 pub
sysctl -w net.ipv4.ip_forward=1
service ipsec start
2、client 通过 nat 和 服务器建立隧道。图2
A:client
modprobe ip_gre
ip tunnel add tun2 mode gre remote 123.127.177.210 local 192.168.100.100 ttl 64
ip link set tun2 mtu 1480 up
ip address add 192.168.200.253 brd 255.255.255.255 peer 123.127.177.210 dev tun2
ip route add 123.127.177.210 via 192.168.100.254
如果只想访问内网
ip route add 192.168.200.0/24 via 192.168.200.253
如果想全部都从远程出去(vpn_proxy)
ip route change default via 192.168.200.253
service ipsec start
B:Server
modprobe ip_gre
ip tunnel add tun2 mode gre remote 123.119.206.165 local 123.127.177.210 ttl 64
ip link set tun2 mtu 1480 up
ip address add 192.168.100.253 brd 255.255.255.255 peer 123.119.206.165 dev tun2
arp -Ds 192.168.200.253 eth0 pub
sysctl -w net.ipv4.ip_forward=1
ip route add 192.168.100.0/24 via 192.168.100.253
iptables -t nat -A POSTROUTIN -s 192.168.200.0/24 -j MASQUERADE
service ipsec start
ipsec 脚本
#!/bin/bash
#
# chkconfig: 345 15 98
# description: Linux IPsec SA/SP database
#
# Source function library.
. /etc/init.d/functions
start() {
echo -n $\"ipsec start ... \"
/etc/setkey.conf && echo -e \"[ ]\"
}
case \"$1\" in
start)
start
;;
stop)
echo -n \"flush;spdflush;\" | \\
setkey -c && echo -e \"ipsec stoping ... [ ]\"
;;
reload)
$0 stop
$0 start
;;
*)
echo $\"Usage: $0 {start|stop|reload}\"
exit 1
esac
exit $?
setkey.conf 脚本
#!/sbin/setkey -f
flush;
spdflush;
# ESP
add 211.167.237.218 123.127.177.195 esp 11571 -E 3des-cbc \"__esp_test_3des_password\";
add 123.127.177.195 211.167.237.218 esp 11572 -E 3des-cbc \"__esp_test_3des_password\";
# AH
add 211.167.237.218 123.127.177.195 ah 15071 -A hmac-md5 \"ah_test_password\";
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
# POLICY
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
spdadd 211.167.237.218 123.127.177.195 any -P in ipsec
esp/transport/192.168.100.1-192.168.100.250/require
ah/transport/192.168.100.1-192.168.100.250/require;
spdadd 123.127.177.195 211.167.237.218 any -P out ipsec
esp/transport/192.168.200.1-192.168.200.250/require
ah/transport/192.168.200.1-192.168.200.250/require;
3、racoon 方法
两台机器分别配置 racoon.conf ifcfg-ipsec1
racoon.conf
# Racoon IKE daemon configuration file.
# See racoon.conf\\\' for a description of the format and entries.
path include \"/etc/racoon\";
path pre_shared_key \"/etc/racoon/psk.txt\";
path certificate \"/etc/racoon/certs\";
listen { isakmp 123.127.177.195 [500]; }
sainfo anonymous
{
pfs_group 2;
lifetime time 1 hour ;
encryption_algorithm 3des, blowfish 448, rijndael ;
authentication_algorithm hmac_sha1, hmac_md5 ;
compression_algorithm deflate ;
}
include \"/etc/racoon/211.167.237.218.conf\";
/etc/sysconfig/network-scripts/ifcfg-ipsec1
DST=211.167.237.218
SRCGW=192.168.100.254
DSTGW=192.168.200.254
SRCNET=192.168.100.0/24
DSTNET=192.168.200.0/24
TYPE=IPSEC
ONBOOT=yes
IKE_METHOD=PSK
IKE_PSK=testpassword
start ifup ipsec1
stop ifdown ipsec1
下面是 racoon.conf 里面的一些配置所使用参数
remote X.X.X.X
指明实例只应用于被 X.X.X.X IP 地址所识别的远程节点。
exchange_mode aggressive
IPsec 配置使用验证模式。默认为强硬模式,这种模式减少连接费用,允许到多个主机的多个IPsec配置。
my_identifier address
定义验证节点时要使用的身份识别方法。
encryption_algorithm 3des
定义验证时使用的加密术。
hash_algorithm sha1;
指定在节点商谈过程的第一阶段中使用的散列算式。
authentication_method pre_shared_key
定义节点商谈中使用的验证方法。
dh_group N
指定建立动态生成的会话钥匙所用的 Diffie-Hellman 组号。默认使用 1024 位组
sainfo anonymous
意思是只要 IPsec 证件匹配,SA 能够不具名地引发和任何对端的连接。
pfs_group N
定义 Diffie-Hellman 钥匙交换协议。该协议会决定 IPsec 节点为 IPsec 连接的第二阶段建立彼此使用的临时会话钥匙的方法。
lifetime time 1 hour
这个参数表明 SA 的整个过程可以使用时间或数据字节数量来衡量。
encryption_algorithm 3des, blowfish 448, rijndael
指定第二阶段中所用的被支持的加密术。
authentication_algorithm hmac_sha1, hmac_md5
列举被支持的用来验证的散列算式。
compression_algorithm deflate
定义用于 IP 载量压缩(IPCOMP)支持的压缩算式。它具备在较慢的连接中较快地传输 IP 数据报的潜在能力。
4、pptp 软件
安装软件,配置用户,每个软件都略有不同,但思路一样,比如上面说的 pptpd 通过抓包我们可以看出,他使用的就是 gre 隧道技术,具体配置要看软件的帮助了。
至此,我了解的tunnel知识讲完了,我在测试的时候发现一个奇怪的问题。
客户端 北京:ADSL 服务器端,网通固定IP
我使用 ipip 或 gre 数据包就无法到达,但只要数据一加密就没有问题,难道网通会过滤这些东西?!这几天看linux tunnel 技术,感觉linux很好很强大。记录如下:( 所有测试系统 CentOS5.2 )
linux 支持的 tunnel 有 ipip gre sit 其他非内核隧道这几种。
ipip 需要内核模块 ipip.ko 下面的描述说出了ipip的特点。
简单之极!但是你不能通过IP-in-IP隧道转发广播或者IPv6数据包。你只是连接了两个一般情况下无法直接通讯的IPv4网络而已。至于兼容性,这部分代码已经有很长一段历史了,它的兼容性可以上溯到1.3版的内核。据我所知,Linux的IP-in-IP隧道不能与其他操作系统或路由器互相通讯。它很简单,也很有效。需要它的时候尽管使用,否则就使用GRE。
GRE 需要内核模块 ip_gre.ko
GRE是最初由CISCO开发出来的隧道协议,能够做一些IP-in-IP隧道做不到的事情。比如,你可以使用GRE隧道传输多播数据包和IPv6数据包。
还有一个 sit 我也不知道这个该不该算在隧道里面,他的作用是连接 ipv4 与 ipv6 的网络,这里也我也把他当作隧道的一种吧。
以上所有隧道都需要内核模块 tunnel4.ko 的支持。
在内核之外,还有很多实现隧道的方法,最闻名的当然要数PPP和PPTP,但实际上还有很多(有些是专有的,有些是安全的,有些甚至根本不用IP。
很多人都把隧道描写成一个专用的管子,我觉得这容易造成理解上的误区,当然你看到的结果的确像在一个专用的管子里那样通讯,我更喜欢把隧道看成一个装在大信封里面的一个小信封和一封信。因为不管理论如何,你的数据包还是要实实在在的,通过现有的网络、路由,一步一步的传送过去,这个是不可能省略掉的。
说了这么多,现在就开始从最基本的 ipip 来手工建立一个隧道。
环境:两台linux服务器,分别在两地。并且两台机器都有实ip与互联网向链接,能够互相通讯。每台机器后面都有带着一个LAN 。
图1
-------------------------------------INTERNET------------------------------------
| 192.168.100.0/24 | 211.167.237.218 <------> 123.127.177.195 |192.168.200.0/24 |
|- - - - | | - - - -|
| eth0 | eth1 | | eth1 | eth0 |
---------------------------------------------------------------------------------
结构就是这个样子,现在我们就依据上面的结构来建立 tunnel 。
在 211.167.237.218 上创建:
modprobe ipip
ip tunnel add tun1 mode ipip remote 123.127.177.195 local 211.167.237.218 ttl 64
ip link set tun1 mtu 1480 up
ip address add 192.168.200.253 brd 255.255.255.255 peer 123.127.177.195 dev tun1
ip route add 192.168.200.0/24 via 192.168.200.253
在 123.127.177.195 上创建:
modprobe ipip
ip tunnel add tun1 mode ipip remote 211.167.237.218 local 123.127.177.195 ttl 64
ip link set tun1 mtu 1480 up
ip address add 192.168.100.253 brd 255.255.255.255 peer 211.167.237.218 dev tun1
ip route add 192.168.100.0/24 via 192.168.100.253
上面的命令里出现了几个关键字,需要我们注意的地方:
1、mtu隧道会增加协议开销,因为它需要一个额外的IP包头。一般应该是每个包增加20个字节,所以如果一个网络的MTU是1500字节的话,使用隧道技术后,实际的IP包长度最长只能有1480字节了。这倒不是什么原则性的问题,但如果你想使用隧道技术构建一个比较大规模的网络的话,最好仔细研究一下关于IP包的分片和汇聚的知识。
2、ttl 数据包的生存期。设置为64是安全的。如果你的网络规模巨大就提高这个值。不要因为好玩而这么做,那样会产生有害的路由环路。实际上,在很多情况下你要考虑能否减小这个值。
3、ip 要写对端的内网ip,因为这可以减少vpn服务器不是默认网关的麻烦。对方看到的数据包实际是你本地绑定在 tun1 上的ip地址。
4、设置路由后就可以通讯了。
5、这样你已经可以和 你拨入的机器的内网卡通讯了,为了让你拨入方的其他机器也可以和你通讯,你需要增加一个 arp 的响应机制及打开ip转发功能。
arp -Ds source_ip -i lan_eth pub
sysctl -w net.ipv4.ip_forward=1
让你的内网卡可以响应这个ip的arp回应。
到此为止,一简单的 ip tunnel 已经完成了。当然如果你不想使用 ipip 你更喜欢gre 那你可以在开头简单的改成
moprobe ip_gre
ip tunnel add tun1 mode gre ... ...
来实现,而后面的参数基本上不需要改变。
上面是一个简单的没有任何加密的隧道建立过程,这样通讯可能会带来安全隐患,毕竟我们访问的是内网吗。
下面来给这个隧道加密。
ipsec 是一个复杂的东西,这里只简单的介绍,如果有问题请查阅在线的[url=http://control.cublog.cn/%5C%22%5C%22]文档[/url]
setkey 是 ipsec 的管理工具,语法类似 setkey -c 然后输入命令,按 ctrl^C 退出。
setkey 中的命令是
add src_ip dst_ip esp SPI -E 3des-cbc \"password\";
格式就是这个样子,也比较好理解, 源地址,目的地址,加密头还是数据,安全码(SPI)验证方式,及共享密钥。
下面在 211.167.237.218 上建立 ipsec
setkey -c
flush;
spdflush;
add 211.167.237.218 123.127.177.195 esp 11571 -E 3des-cbc \"__esp_test_3des_password\";
add 123.127.177.195 211.167.237.218 esp 11572 -E 3des-cbc \"__esp_test_3des_password\";
add 211.167.237.218 123.127.177.195 ah 15071 -A hmac-md5 \"ah_test_password\";
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
spdadd 211.167.237.218 123.127.177.195 any -P out ipsec
esp/transport/192.168.100.1-192.168.100.250/require
ah/transport/192.168.100.1-192.168.100.250/require;
spdadd 123.127.177.195 211.167.237.218 any -P in ipsec
esp/transport/192.168.200.1-192.168.200.250/require
ah/transport/192.168.200.1-192.168.200.250/require;
^C (ctrl+c)
这样就算配置完成了,你可以通过 setkey -D[P][p] 来检查,或者在 setkey 里使用 dump
为了方便,不用每次都敲一大堆命令,在 123.127.177.195 上写一个启动策略脚本。
#!/bin/bash
#
# chkconfig: 345 15 98
# description: Linux IPsec SA/SP database
#
# Source function library.
. /etc/init.d/functions
start() {
echo -n $\"ipsec start ... \"
/etc/setkey.conf && echo -e \"[ ]\"
}
case \"$1\" in
start)
start
;;
stop)
echo -n \"flush;spdflush;\" | \\
setkey -c && echo -e \"ipsec stoping ... [ ]\"
;;
reload)
$0 stop
$0 start
;;
*)
echo $\"Usage: $0 {start|stop|reload}\"
exit 1
esac
exit $?
# cat setkey.conf
#!/sbin/setkey -f
flush;
spdflush;
# ESP
add 211.167.237.218 123.127.177.195 esp 11571 -E 3des-cbc \"__esp_test_3des_password\";
add 123.127.177.195 211.167.237.218 esp 11572 -E 3des-cbc \"__esp_test_3des_password\";
# AH
add 211.167.237.218 123.127.177.195 ah 15071 -A hmac-md5 \"ah_test_password\";
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
# POLICY
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
spdadd 211.167.237.218 123.127.177.195 any -P in ipsec
esp/transport/192.168.100.1-192.168.100.250/require
ah/transport/192.168.100.1-192.168.100.250/require;
spdadd 123.127.177.195 211.167.237.218 any -P out ipsec
esp/transport/192.168.200.1-192.168.200.250/require
ah/transport/192.168.200.1-192.168.200.250/require;
接下来我们就运行 ipsec.sh start 就能启动 ipsec 了,如果想停止就运行 ipsec.sh stop
或者你还可以吧 ipsec 拷贝到 /etc/init.d/ipsec 然后运行 chkconfig --add ipsec 让他作为服务,开机就启动。
可能细心的读者已经发现在两个服务器上的脚本略有不同,实际就是把 Policy 里面的 in 和 out 对换一下,然后写上本地子网就可以了。
上面是一个简单的隧道建立过程,下面我们来个复杂一点的,也是我们常碰到的结构。
图2
---------- ------------- ------------ ---------------- -------
| client | <--> | nat server| <--> | internet | <--> | Linux server | <--> | Lan |
---------- ------------- ------------ ---------------- -------
|client ip 192.168.100.100/24 gateway 192.168.100.254 |
|nat server: lan_ip 192.168.100.254/24 wan_ip 123.119.206.165 |
|Linux server: lan_ip eth0 192.168.200.100/24 wan_ip eth1 123.127.177.210 |
|--------------------------------------------------------------------------------|
这个结构比较麻烦了,因为我们的源地址会被改写一次,这个该如何配置呢。
实际上在linux上配置这个也很简单,只要遵循原则,看见谁,就写谁的方法就没有问题。
比如在我们客户机上看见的一定是 由我们本地的ip(伪)到远程服务器的ip(实),而远程服务器看到的情况却有点不一样,服务器看到的是,客户机经过nat后的ip(实),和本机ip(实)在通讯,根据这个原则,我们写出如下命令。
A:client
modprobe ip_gre
ip tunnel add tun2 mode gre remote 123.127.177.210 local 192.168.100.100 ttl 64
ip link set tun2 mtu 1480 up
ip address add 192.168.200.253 brd 255.255.255.255 peer 123.127.177.210 dev tun2
B:Server
modprobe ip_gre
ip tunnel add tun2 mode gre remote 123.119.206.165 local 123.127.177.210 ttl 64
ip link set tun2 mtu 1480 up
ip address add 192.168.100.253 brd 255.255.255.255 peer 123.119.206.165 dev tun2
这样隧道就建立起来了。
服务器端配置:
果想让这个client能访问内网的其他机器需要加一个arp 的响应机制及ip转发。
arp -Ds source_ip -i lan_eth pub
sysctl -w net.ipv4.ip_forward=1
如果你做的 vpn_proxy ,不希望他访问你的内网,而仅仅是用来代理上网,那你就需要去掉这个。
arp -d source_ip dev lan_eth
添加一个ip伪装的功能。
iptables -t nat -A POSTROUTING -s 192.168.200.253 -j MASQUERADE
当然如果你二者都需要,那你就都添加就可以了。
客户机配置:
添加一个我们到对方服务器的路由
ip route add 123.127.177.210 via 192.168.100.254
用来保证我们能链接到远程的 Linux Server
如果我们想访问他的内网,我们就需要添加到对方内网的路由,当然这需要服务器给你做arp响应。
ip route 192.168.200.0/24 via 192.168.200.253
如果我们想像 vpn_proxy 一样使用他,那也非常简单,修改默认网关就可以了。
(也许你会觉得这有问题,请仔细想想,这里遍历了2次路由表,保证了链路、数据的畅通)
ip route change default via 192.168.200.253
隧道已经配置好了,但加密却有了问题:
我们知道客户机的原地址是经过1次nat的,而加密验证ip头是在nat之前,这个如和处理呢。
方法1、去掉头部验证,只对数据段加密,
对于一般的情况加密数据段已经足够了,我们可以简单的去掉这部分来实现。
setkey.conf # AH 里面的东西,然后在策略里禁止 AH 强制加密认证。
去掉# AH
add 211.167.237.218 123.127.177.195 ah 15071 -A hmac-md5 \"ah_test_password\";
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
修改策略为:
spdadd 211.167.237.218 123.127.177.195 any -P out ipsec
esp/transport/192.168.100.1-192.168.100.250/require;
... ...
好了我只写这么多,至于服务器两端具体如何修改,呵呵要自己动手了。
方法2、将访问我们的源地址换回去,在做验证。
这种方法涉及了很多的编程知识,可能我们还要专门为他写一个模块,这里不讨论了。
如果你觉得 ipsec 这个命令很麻烦,还需要自己写一大堆的脚本,那你可以使用 racoon
racoon 是 IKE 的守护进程,他的配置文件是 racoon.conf
racoon.conf
# Racoon IKE daemon configuration file.
# See \'man racoon.conf\' for a description of the format and entries.
path include \"/etc/racoon\";
path pre_shared_key \"/etc/racoon/psk.txt\";
path certificate \"/etc/racoon/certs\";
listen { isakmp 123.127.177.195 [500]; }
sainfo anonymous
{
pfs_group 2;
lifetime time 1 hour ;
encryption_algorithm 3des, blowfish 448, rijndael ;
authentication_algorithm hmac_sha1, hmac_md5 ;
compression_algorithm deflate ;
}
include \"/etc/racoon/211.167.237.218.conf\";
看见了吧,实际我就在最后加了一句话 include ... 上面加了一个监听的地址,剩下都不用改。
其实 racoon.conf 的配置也蛮复杂的,不过有人已经给我们写好了脚本来处理,这样就简单多了。
只需要修改这一点,其他的都不用管了。
然后建立 /etc/sysconfig/network-script/ifcfg-ipsec1 这个文件,这个就是我们的配置文件。
内容也很简单 :
DST=211.167.237.218
TYPE=IPSEC
ONBOOT=yes
IKE_METHOD=PSK
IKE_PSK=testpassword
文件的配置很少,注意两处就行了,第一 DST 要写对方的 ip 地址,从名字也很好认的,第二,共享密钥要完全一样,就是 IKE_PSK,配置到这里就算完了,书上推荐把密码单独放到一个文件里,然后设定这个文件的权限 600,为了安全你也可以这么做,但我喜欢放在一起好管理吗,(如果黑客已经有了你机器的shell,我想即使是普通用户,他也有办法看到root权限的文件的)接下来我们直接用 ifup ipsec1来启动就可以了。然后你会发现你的通讯也加密了。别忘了两边的机器都要加密才能通讯的哦,同理实际隧道也可以通过 ifcfg-ppp这样的配置文件来让脚本自动生成,到那那样你就看不到后面的这些东西了,ifcfg-ppp 就自己来写吧。
在补充一句,racoon 是在有通讯发生的时候才对数据加密的,所以你第一次连接远程主机会比较慢,当然这也仅仅是第一次,大概等待2~5秒。如果你想看策略最好是一边通讯,一边查看,要不然,你可能看不到哦。
3、其他方法,软件,pptp openvpn
从这里下载 pptpd 的软件。
我下载的是 1.3.4 解压,然后编译。
默认的 logwtmp 是 2.4.3 的版本,我系统的 pppd 是 2.4.4 的,不修改的话会报错。
把 plugins/patchlevel.h 中的 版本号改成 2.4.4 时间乱写一个就好了。
#define VERSION \"2.4.4\"
#define DATE \"13 Jan 2005\"
然后编译,安装。
./configure
make
make check
make install
安装完以后把编译出来的 logwtmp.so 拷贝到 /usr/lib/pptpd 下面。
mkdir /usr/lib/pptpd
cp plugins/pptpd-logwtmp.so /usr/lib/pptpd/pptpd-logwtmp.so
然后把配置文件也拷贝过去。
cp samples/options.pptpd /etc/ppp/
cp samples/pptpd.conf /etc
修改一下配置就可以启动了。
options.pptpd 全部注释掉,有着几行就行
name pptpd
refuse-chap
refuse-mschap
require-mschap-v2
require-mppe-128
proxyarp
lock
nobsdcomp
novj
novjccomp
nologfd
如果使用 mppe 的加密的话需要 kernel 2.6.15-rc1 以上。否则要打补丁。呵呵我的版本够高了,这就省事了。
pptpd.conf
ppp /usr/sbin/pppd
option /etc/ppp/options.pptpd
logwtmp
localip 123.127.177.195
remoteip 192.168.100.10-50
listen 123.127.177.195
speed 115200
connections 20
这样就配置完了,直接用 pptpd 启动。
接下来配置客户端。
下载 pptp 软件 我下载的是 1.7.2
我的系统 ip 命令在 /sbin 下 修改 routing.c 吧 /bin/ip 都换成 /sbin/ip
make
make install
然后测试连接
先在服务器的 /etc/ppp/chap-secrets 添加用户名和密码
admin pptpd admin *
然后在客户机上创建配置文件
pptpsetup --create vpntest --server 123.127.177.195 --username admin --password admin --encrypt
拨号练接
pppd call vpntest
如果一切正常的话,你应该用 ifconfig 就能看见 ppp0 这个设备了,而且数据通讯是 mppe 加密的。
总结一下:建立隧道的完整步骤为
1、两台实ip机器建立隧道。图1
A:Server
modprobe ipip
ip tunnel add tun1 mode ipip remote 123.127.177.195 local 211.167.237.218 ttl 64
ip link set tun1 mtu 1480 up
ip address add 192.168.200.253 brd 255.255.255.255 peer 123.127.177.195 dev tun1
ip route add 192.168.200.0/24 via 192.168.200.253
arp -Ds 192.168.100.253 eth0 pub
sysctl -w net.ipv4.ip_forward=1
service ipsec start
B:Server
ip tunnel add tun1 mode ipip remote 211.167.237.218 local 123.127.177.195 ttl 64
ip link set tun1 mtu 1480 up
ip address add 192.168.100.253 brd 255.255.255.255 peer 211.167.237.218 dev tun1
ip route add 192.168.100.0/24 via 192.168.100.253
arp -Ds 192.168.200.253 eth0 pub
sysctl -w net.ipv4.ip_forward=1
service ipsec start
2、client 通过 nat 和 服务器建立隧道。图2
A:client
modprobe ip_gre
ip tunnel add tun2 mode gre remote 123.127.177.210 local 192.168.100.100 ttl 64
ip link set tun2 mtu 1480 up
ip address add 192.168.200.253 brd 255.255.255.255 peer 123.127.177.210 dev tun2
ip route add 123.127.177.210 via 192.168.100.254
如果只想访问内网
ip route add 192.168.200.0/24 via 192.168.200.253
如果想全部都从远程出去(vpn_proxy)
ip route change default via 192.168.200.253
service ipsec start
B:Server
modprobe ip_gre
ip tunnel add tun2 mode gre remote 123.119.206.165 local 123.127.177.210 ttl 64
ip link set tun2 mtu 1480 up
ip address add 192.168.100.253 brd 255.255.255.255 peer 123.119.206.165 dev tun2
arp -Ds 192.168.200.253 eth0 pub
sysctl -w net.ipv4.ip_forward=1
ip route add 192.168.100.0/24 via 192.168.100.253
iptables -t nat -A POSTROUTIN -s 192.168.200.0/24 -j MASQUERADE
service ipsec start
ipsec 脚本
#!/bin/bash
#
# chkconfig: 345 15 98
# description: Linux IPsec SA/SP database
#
# Source function library.
. /etc/init.d/functions
start() {
echo -n $\"ipsec start ... \"
/etc/setkey.conf && echo -e \"[ ]\"
}
case \"$1\" in
start)
start
;;
stop)
echo -n \"flush;spdflush;\" | \\
setkey -c && echo -e \"ipsec stoping ... [ ]\"
;;
reload)
$0 stop
$0 start
;;
*)
echo $\"Usage: $0 {start|stop|reload}\"
exit 1
esac
exit $?
setkey.conf 脚本
#!/sbin/setkey -f
flush;
spdflush;
# ESP
add 211.167.237.218 123.127.177.195 esp 11571 -E 3des-cbc \"__esp_test_3des_password\";
add 123.127.177.195 211.167.237.218 esp 11572 -E 3des-cbc \"__esp_test_3des_password\";
# AH
add 211.167.237.218 123.127.177.195 ah 15071 -A hmac-md5 \"ah_test_password\";
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
# POLICY
add 123.127.177.195 211.167.237.218 ah 15072 -A hmac-md5 \"ah_test_password\";
spdadd 211.167.237.218 123.127.177.195 any -P in ipsec
esp/transport/192.168.100.1-192.168.100.250/require
ah/transport/192.168.100.1-192.168.100.250/require;
spdadd 123.127.177.195 211.167.237.218 any -P out ipsec
esp/transport/192.168.200.1-192.168.200.250/require
ah/transport/192.168.200.1-192.168.200.250/require;
3、racoon 方法
两台机器分别配置 racoon.conf ifcfg-ipsec1
racoon.conf
# Racoon IKE daemon configuration file.
# See racoon.conf\\\' for a description of the format and entries.
path include \"/etc/racoon\";
path pre_shared_key \"/etc/racoon/psk.txt\";
path certificate \"/etc/racoon/certs\";
listen { isakmp 123.127.177.195 [500]; }
sainfo anonymous
{
pfs_group 2;
lifetime time 1 hour ;
encryption_algorithm 3des, blowfish 448, rijndael ;
authentication_algorithm hmac_sha1, hmac_md5 ;
compression_algorithm deflate ;
}
include \"/etc/racoon/211.167.237.218.conf\";
/etc/sysconfig/network-scripts/ifcfg-ipsec1
DST=211.167.237.218
SRCGW=192.168.100.254
DSTGW=192.168.200.254
SRCNET=192.168.100.0/24
DSTNET=192.168.200.0/24
TYPE=IPSEC
ONBOOT=yes
IKE_METHOD=PSK
IKE_PSK=testpassword
start ifup ipsec1
stop ifdown ipsec1
下面是 racoon.conf 里面的一些配置所使用参数
remote X.X.X.X
指明实例只应用于被 X.X.X.X IP 地址所识别的远程节点。
exchange_mode aggressive
IPsec 配置使用验证模式。默认为强硬模式,这种模式减少连接费用,允许到多个主机的多个IPsec配置。
my_identifier address
定义验证节点时要使用的身份识别方法。
encryption_algorithm 3des
定义验证时使用的加密术。
hash_algorithm sha1;
指定在节点商谈过程的第一阶段中使用的散列算式。
authentication_method pre_shared_key
定义节点商谈中使用的验证方法。
dh_group N
指定建立动态生成的会话钥匙所用的 Diffie-Hellman 组号。默认使用 1024 位组
sainfo anonymous
意思是只要 IPsec 证件匹配,SA 能够不具名地引发和任何对端的连接。
pfs_group N
定义 Diffie-Hellman 钥匙交换协议。该协议会决定 IPsec 节点为 IPsec 连接的第二阶段建立彼此使用的临时会话钥匙的方法。
lifetime time 1 hour
这个参数表明 SA 的整个过程可以使用时间或数据字节数量来衡量。
encryption_algorithm 3des, blowfish 448, rijndael
指定第二阶段中所用的被支持的加密术。
authentication_algorithm hmac_sha1, hmac_md5
列举被支持的用来验证的散列算式。
compression_algorithm deflate
定义用于 IP 载量压缩(IPCOMP)支持的压缩算式。它具备在较慢的连接中较快地传输 IP 数据报的潜在能力。
4、pptp 软件
安装软件,配置用户,每个软件都略有不同,但思路一样,比如上面说的 pptpd 通过抓包我们可以看出,他使用的就是 gre 隧道技术,具体配置要看软件的帮助了。
至此,我了解的tunnel知识讲完了,我在测试的时候发现一个奇怪的问题。
客户端 北京:ADSL 服务器端,网通固定IP
我使用 ipip 或 gre 数据包就无法到达,但只要数据一加密就没有问题,难道网通会过滤这些东西?!