ubuntu 连校园网 via l2tp

因为在树莓派上写脚本会有点卡,
就先在台式机上写写看, 还能边写边用浏览器查...

连校园网, 这次是用脚本实现的, 上次是用一个下载的软件, 但是那个被我重新装之后, 就不能用了,因为在以前没有记录下怎么配置的过程,
那现在, 用现在的方法,可以做到开机就连上网络,

首先 先说一下, 这个拨号的过程,

  1. 学校的局域网内有个 192.168.254.1 的服务器是作为l2tp的server.
    学生作为client, 可以和他建立vpn, 也就是l2tp隧道.
  2. 在隧道建立完成之后, 会使用ppp协议作为载体, 把隧道内传输的数据按照ppp来打包, 然后这些ppp包就从这个隧道中发到server. 从而实现上网.

有个链接: 解释了为啥还是在使用l2tp作为上网的认证手段,而不是用ppop啥的:
https://www.zhihu.com/question/26810403
简单的说, 就是认证用户是用ppp协议的, 但是宿舍到server不是一条线的, 中间要经过好多个路由啥的, 就不是peer to peer的了, 那么ppp的包就过不去了, 最后要借助l2tp这个在ip层的协议来帮助发送ppp包.

然后再来看怎么配置:

要下的软件:

要建立l2tp连接, 那么就要用xl2tpd这个软件.
要用ppp协议发送包, 那么就要用pppd这个软件.
( 如果l2tp是要加密的话, 好像还要下载其他的东西, 但是我发现, 联通的这个东西, 是不加密的, 密码都是明文发送的......)
你可以用apt-get 来下载这两个包.

给软件的配置文件:

xl2tpd 的配置文件:
/etc/xl2tpd/xl2tpd.conf
内容:

[lac testvpn]
name = test   
lns = 192.168.254.1
pppoptfile = /etc/ppp/peers/testvpn.l2tpd
ppp debug = yes

第一个name,这个选项不晓得干啥的,但是例子上有..
第二个就是远端服务器的ip.
第三个是ppp协议的配置文件, 因为xl2tpd在建立完成隧道之后, 就会自己启动pppd, 所以他就需要知道pppd的配置文件在哪里.
第4个是 是否要输出ppp的详细运行信息.
更多的有关配置的信息可以在这里找到:https://linux.die.net/man/5/xl2tpd.conf
配置是分lac 和lns和global的, global和lns的配置不用去管, lns是服务器的配置信息.
因为xl2tpd还是可以用作服务端的, 我们就只用到了作为客户的功能.

然后就是要设置 pppd 的配置文件:
/etc/ppp/peers/testvpn.l2tpd
内容:

remotename testvpn
user "账号"
passwrod 密码
unit 0
nodeflate
noauth
persist
noaccomp
maxfail 5
usepeerdns 
debug

这些参数可以用 man pppd来查询,
这个option文件是我抄网上的教程后修修改改出来的,
有些东西也不知道为啥....
我发现, 我们的机器的ip和dns都是需要server告诉我们的, 所以加了 usepeerdns.
然后ppp 有两种认证的方式PAP和CHAP, 我选的是PAP, 因为感觉chap比较高级, chap比较耗费运算??
这些认证过程可以/var/log/syslog文件中找到.

有个中文的翻译:http://blog.csdn.net/chenliang0224/article/details/8572699
然后两个文件设置完成之后, 就要启动这个连接了.

首先启动xl2tp:

xl2tpd -c /etc/xl2tpd/xl2tpd.conf -D

-c 是指定配置文件
你不加这个也可以, 因为xl2tpd的默认的配置文件就是这个目录上的文件.
-D 是debug模式, 不加的话, xl2tpd就会变成后台进程, 但可以用ps aux | grep xl2tpd 和 kill 杀死...
然后你就可以在当前的terminal中看到他的执行情况了.

然后再发送连接指令给xl2tpd

echo 'c testvpn' > /var/run/xl2tpd/l2tp-control

这里的testvpn这个名字, 就是上面设置的remotename, 我不清楚这两个名字是不是有关系的, 其实改一下就好知道, 但是太懒....

echo 'd testvpn' > /var/run/xl2tpd/l2tp-control 是断开连接.

成功的话, 就可以在ifconfig中看到ppp0接口了.
如果不成功, 就需要查看日志来找出错误.
我碰到的大部分的错误是可以在 xl2tpd -D的那个terminal中可以看出来的,
我经常就是 ppp 的参数设置错误, 然后xl2tpd检测到错误后就杀死了pppd啥的, 反正就改改配置文件后再来一边试试看.
还有一个可以看到日志的地方就是 /var/log/message 或者 /var/log/syslog 文件.
你可以再开个窗口, 然后用 tail -f 看.
反正目标就是 看不到 fail的字样. 要看到: 隧道成功建立和ppp认证成功.
这里是我的成功后的两个日志的情况:


syslog.png

上图是 syslog 的. 可以看到, 在l2tp连接建立之后, 就会有
Mar 8 18:08:11 dogegg-HP pppd[3618]: sent [LCP EchoReq id=0x2 magic=0x2a789e01]
Mar 8 18:08:11 dogegg-HP pppd[3618]: rcvd [LCP EchoRep id=0x2 magic=0x4dd4d216]
这样子的收发信息, 这个是代表这个隧道是存在的,30s一次( 这个东西很重要, 和路由有关)
然后我们可以看到服务器发给我们, 我们的ip地址, 我们的主/次dns服务器地址, 还有他的地址.

xl2tpd_-D.png

上图是xl2tpd进程的日志, 可以看到他一步步的把配置文件中的内容给解析出来, 如果有解析错的, 那么肯定会打印出来的.

设置路由

这样弄完之后, 网上的教程都说, 你就可以上网了, 但是我不行.....

因为是路由的问题.....
我们要让电脑的所有流量都经过ppp0端口出去, 而不是原来的eth0啥的.
现在我们的情况是 我们和服务器连上了, 但是我们包还是从默认的路由默认的网关发送出去的.
用route -n看到的情况大概是这样子的.

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0            10.64.70.1       255.255.255.255   ?????????
10.64.70.0      0.0.0.0         255.255.255.0   U     100    0        0 enx000ec6d2bc57
101.68.75.84    0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 enx000ec6d2bc57

第一条的??参数是我忘记了... 就乱打上去.
destination是 0.0.0.0的那条是叫做default路由. 数据包不知道往哪里发的话, 就发那边去.
我的路由表在 没有连上ppp0之前就只有3个路由, 就是现在的去掉第三条的样子.
最后一条169.254.0.0的是local-link, 查了百度, 也没怎么弄清楚这是干啥的, 反正不影响.

如果想把流量都改了的话, 那么就应该把default给删除再加上一条去ppp0的default,
但是, 并不是把所有的流量都给导过去, 我们和server的通讯是要走网卡的不能走ppp0.
所以, 就需要3条route命令来改:

echo 'add route to 192..' 
route add -host 192.168.254.1 gw $getway dev enx000ec6d2bc57 
echo 'del default' 
route del default
echo 'add default to ppp0' 
route add default gw $remote dev ppp0

这是脚本里面写着的, 这样子改完之后, 应该就好上网了.如果还不行...
可以试试看ping remote通不通. 然后ping那个dns服务器.
我本来以为加上 ping 的-I 参数 就可以跳过路由, 但是如果路由不对, 就算加上-I ppp0, ping的包好像也是不会顺利的发送出去的.

下面是脚本:

#!/bin/bash
dir=/home/dogegg/Desktop/log.txt
#因为xl2tpd进程是自动随着系统开机而运行的, 就不用写入脚本了.
echo 'c testvpn' > /var/run/xl2tpd/l2tp-control

#在发送完连接命令之后, 就每隔2s检查下有没有ppp0的接口在ifconfig中出现. 次数超过10次就exit.
count=0
while [ $count -lt 10 ]; do
    haveppp0=`ifconfig | grep ppp0`
    if [[ $haveppp0 != "" ]];then
        break
    fi  
    echo 'check ppp0 is exist, time:'$count > $dir
    let count=count+1
    sleep 2s
done 
if [[ $count == 10 ]];then
    echo 'time out!' >> $dir
    exit 0
fi
echo 'ppp0 is exist!' >> $dir

#匹配出 网关的地址. 
getway=`ifconfig enx000ec6d2bc57 | grep 'inet addr'`
reg='.*inet addr\:([0-9]+\.[0-9]+\.[0-9]+\.)([0-9]+).*'
if [[ "$getway" =~ $reg ]];then 
        pre=${BASH_REMATCH[1]}
        last=${BASH_REMATCH[2]}
else
    exit 222
fi  
getway=$pre'1'

# 匹配出 远程server的地址
remote=`ifconfig ppp0 | grep 'P-t-P'`
reg='.*P-t-P:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*'
if [[ "$remote" =~ $reg ]];then 
        remote=${BASH_REMATCH[1]}
else
    exit 223
fi  

### debug!!
echo 'the getway is '$getway >> $dir
echo 'the remote is '$remote >> $dir
###

#改改路由:
echo 'add route to 192..' >> $dir
route add -host 192.168.254.1 gw $getway dev enx000ec6d2bc57 
echo 'del default' >> $dir
route del default
echo 'add default to ppp0' >> $dir
route add default gw $remote dev ppp0


exit 0

最后就是配置开机了

在/etc/rc.local
文件中加入运行脚本的语句
如果 想知道一些出错的信息, 我用的是笨办法, 就是让我的脚本里面的echo把字符串输出到一个桌面的文件中($dir), 但是好像网上有比较优雅的办法, 看上去是改输出流啥的:

exec 2> /tmp/rc.local.log 
exec 1>&2
set -x

不懂.... 用不来, 但是在 /tmp/rc.local.log里面可以看到:

+ ./home/dogegg/Desktop/checkppp0.sh
+ exit 0

下一步就是把这个东西转到树梅pi上.